15.1 JSON-first prompting

Overview and links for this section of the guide.

Why JSON-first works

JSON-first works because it reduces degrees of freedom. You’re telling the model:

  • what shape the output must have,
  • what fields must be present,
  • what types those fields must be,
  • what to do when it can’t comply.

That shrinks the space of “valid outputs,” which makes your app reliable.

The real reason JSON-first helps

It gives you an objective verification step: parse + schema validate. When you can verify, you can iterate fast.

When to use JSON-first (and when not to)

Use JSON-first when:

  • your code needs to parse the output,
  • you render output in a UI,
  • you write outputs to a database,
  • you call tools based on outputs,
  • you need predictable formatting for tests/evals.

Skip JSON-first when:

  • you’re brainstorming ideas,
  • you want exploratory writing,
  • the output is purely for a human to read and copy.

Even then, you can often use “structured markdown” (headings + lists) as a middle step, but JSON is the default for apps.

The core pattern: envelope + schema + validation

The most reliable JSON-first approach is an outcome envelope:

  • it makes “blocked/needs clarification” representable,
  • it gives your app a stable way to branch on outcomes,
  • it makes errors machine-readable.

Example envelope

{
  "status": "ok" | "blocked" | "needs_clarification",
  "result": { ... } | null,
  "safe_alternative": "string | null",
  "questions": ["string", "..."]
}

Then you validate result against a task-specific schema when status="ok".

Envelopes reduce “mystery failures”

If the model can’t answer safely or confidently, it still returns valid JSON. Your app stays stable.

A JSON-first prompt template (copy/paste)

This template is intentionally strict. Replace the schema and examples with your own.

You are producing JSON for a program to parse.

Rules (non-negotiable):
- Output MUST be valid JSON.
- Output MUST contain ONLY JSON (no markdown, no backticks, no commentary).
- If you cannot comply safely or the input is ambiguous, use the envelope status fields.
- Do not invent facts; use only the provided input.

Output envelope schema:
{
  "status": "ok" | "blocked" | "needs_clarification",
  "result": object | null,
  "safe_alternative": string | null,
  "questions": string[]
}

If status="ok", then result MUST match this schema:
(paste your JSON Schema or a precise field/type definition)

Examples:
1) Input: ...
   Output: {...}
2) Input: ...
   Output: {...}

Now process this input:
INPUT:
```text
...
```
Why “ONLY JSON” matters

Many models will wrap JSON in prose or markdown if you don’t forbid it. Your parser wants JSON only.

Examples as mini tests (JSON edition)

Examples do two jobs:

  • they teach the model the exact shape you expect,
  • they become test cases you can run repeatedly.

Include at least:

  • one happy-path example,
  • one ambiguous input → needs_clarification,
  • one unsafe input → blocked (in a safe, non-graphic way if needed),
  • one “empty input” → validation behavior (often handled before model call).

Settings that improve JSON reliability

Two settings usually help:

  • Lower randomness: reduce temperature so the model doesn’t “get creative” with formatting.
  • Output length limits: cap output so it doesn’t ramble and break structure.

Also: keep the schema small and strict. Complexity is the enemy of consistent structured output.

Common failure modes (and fixes)

Failure: extra text around JSON

Fix: restate “output ONLY JSON” and add a validator in your code. If it happens, treat it as invalid_output and optionally retry once with a repair prompt.

Failure: invalid JSON (trailing commas, comments)

Fix: add explicit “no trailing commas, no comments” rule; retry once with a repair prompt; keep schema simpler.

Failure: missing required fields

Fix: make fields required in schema and show an example with all fields present (including empty arrays). Also keep “unknown” fields nullable instead of optional when possible.

Failure: wrong types (string where array expected)

Fix: enforce schema validation and show examples; use enums and bounded arrays (15.4).

Where to go next