Structured Outputs: Getting Reliable JSON from LLMs
Structured outputs constrain an LLM's generation to match a schema, so responses parse reliably instead of relying on prompt instructions alone.
Structured outputs constrain an LLM’s generation so its response conforms to a schema you define — typically JSON — instead of relying on the model to follow formatting instructions in the prompt and hoping it complies. Where a plain prompt might say “respond only in JSON” and still occasionally produce a stray sentence, a trailing comma, or an extra explanation, structured output support enforces the shape at the decoding level, so the response is valid against the schema by construction.
Why “just ask for JSON” isn’t reliable
Prompting a model to output JSON works most of the time, which is exactly the problem — “most of the time” isn’t good enough when the output feeds directly into a parser. A model might wrap the JSON in a markdown code fence, add a conversational preamble, use a trailing comma a strict parser rejects, or invent a field name that’s close to but not exactly what the schema needs. Any of these breaks a naive JSON.parse() call, and the failure mode is silent until it hits production. Retrying with a slightly different prompt, or adding “return ONLY valid JSON, no other text” in increasingly emphatic language, is a real pattern teams reach for — and it only reduces the failure rate, it doesn’t eliminate it.
How constrained decoding works
Structured output support works at a lower level than the prompt. Instead of trusting the model to choose to follow a format, the decoding process itself is restricted so that only tokens consistent with the target schema can be selected at each step. If the schema says a field must be one of three enum values, the decoder simply can’t select a token sequence that produces a fourth. If a field must be a number, the decoder can’t emit a token that would start a string. This is typically implemented with something like a grammar or a JSON Schema compiled into a state machine that tracks which tokens are valid at each position in the output, ruling out everything else before the model even samples.
The result is a response that is structurally guaranteed to match the schema — valid JSON, correct types, only the fields you specified — even though the model’s underlying reasoning about what content to put in those fields is unchanged. Structured outputs constrain the shape of the answer, not the quality of the answer.
Structured outputs vs function calling
Function calling and structured outputs are closely related but not identical. Function calling is specifically about invoking a named tool with arguments — the model decides whether to call a function and which one, then produces arguments matching that function’s schema. Structured outputs are a more general mechanism: you can use them to shape any response, whether or not a tool is being called at all — for example, forcing a classification task to return {"category": "...", "confidence": 0.0} with no free text around it. Many APIs implement function calling using the same underlying structured-output machinery, but you don’t need a tool-calling scenario to benefit from a locked-down schema.
Where this matters in practice
Any pipeline that treats an LLM’s output as data rather than prose benefits from structured outputs: extracting fields from a document, classifying support tickets into categories, generating a batch of records to insert into a database, or producing arguments for a downstream API call. It also matters heavily for automated evaluation — an LLM eval harness that scores a model’s own output is far easier to build reliably when that output is guaranteed to parse.
Structured outputs don’t remove the need to design the schema carefully. Field names, descriptions, and enum values should still be written the way you’d write documentation for a human filling out the same form — the model uses the schema itself as part of its guidance for what content belongs where, on top of using it as a hard constraint on shape.
What structured outputs don’t fix
Constraining the shape of a response doesn’t constrain its truthfulness. A model can produce perfectly valid JSON that’s still wrong — a confidently incorrect classification, a fabricated field value, a plausible-sounding but nonexistent identifier. Structured outputs eliminate parsing failures, not hallucinations. They also add a small amount of latency and, in some implementations, restrict which decoding optimizations are available, since the token space is being filtered at every step rather than sampled freely.
The takeaway
Structured outputs move format compliance from “hope the model follows instructions” to “make invalid output structurally impossible,” by constraining which tokens the decoder can select at each step against a schema. They’re closely related to function calling but apply more broadly to any task where an LLM’s response needs to be parsed as data. They fix parsing reliability, not correctness — the schema still needs careful field design, and the content inside it still needs the usual scrutiny for accuracy.
Tagged
Keep reading
Chisato · · 4 min read What Is Prompt Chaining? Multi-Step LLM Pipelines
Prompt chaining splits a task into a sequence of smaller LLM calls, each one feeding the next, instead of asking one giant prompt to do everything.
Chisato · · 4 min read What Is Function Calling in LLMs? Tool Use Explained
Function calling lets an LLM emit a structured request to run a specific function, turning free-form text generation into reliable tool use.
Chisato · · 4 min read Build Your Own AI Agent in 100 Lines of Python
Build a real AI agent from scratch — no framework. Just the Anthropic API, a tool-use loop, and two tools the model can call to explore your files.