15.1 JSON-first prompting
Overview and links for this section of the guide.
On this page
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.
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".
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
...
```
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).