// the problem: prompt-and-pray
You ask for JSON in the prompt and hope. So you get a markdown fence, a chatty intro, a missing key, a hallucinated enum — and JSON.parse throws in production.
The fix: bind a schema
Hand the model a schema and the output is forced to match it.
Both ensure valid JSON; only the schema path guarantees your schema (JSON mode alone doesn't).
Why it's guaranteed
It's not the model "trying harder." Structured outputs use constrained decoding: the schema is compiled into a grammar, and at every step the decoder masks any token that would break it. Off-schema output is unsamplable.
The one catch
Structure is not correctness.
email field will always be present and a string — but it might be "not-an-email". Constrained decoding fixes the format, never the facts. Still validate values, and know a refusal or a token cap can cut even a valid shape short.Rule of thumb: the moment another program reads the model's output — extraction, classification, tool arguments, pipelines — give it a schema. Don't parse free text.
Sources: OpenAI — Introducing Structured Outputs · Claude — Structured outputs · Efficient Guided Generation (Outlines) · llama.cpp GBNF grammars
One concept a week. Free.
The deeper, copy-paste version of each ToolCall short — in your inbox.
// total: 0.00 · spam: void · unsubscribe: one click
