AppliedAIPrep logoAppliedAI/Prep
RAG & Agent System Design / 07
medium★ EssentialOpenAIAnthropicMicrosoft

How do you get reliable structured output (JSON / function calls) from an LLM in production?

Agents and integrations live or die on the model returning valid, schema-conforming output. The signal is layering constrained decoding, schema validation, and retries, not hoping a prompt is enough. Here is the production-reliability answer.

Updated Aug 2026 · Grounded in real Applied AI Engineer interview loops and written to a senior-engineer editorial bar.

TL;DR: Do not trust a prompt alone to produce valid JSON. Use the strongest constraint available (constrained/grammar-based decoding or the provider's structured-output/function-calling mode that guarantees schema conformance), then still validate the parsed output against your schema and retry or repair on failure. Define a strict schema, handle partial/streaming output, and treat the model as an unreliable producer you must verify.

GUARDRAILS (send an input through the layers)
prompt injection
input filter
model
output filter
output
Guardrails wrap the non-deterministic model in deterministic checks. Send each input type and watch where it is stopped. A prompt injection should be caught; toggle off the layer that catches it and watch it slip through.

How to approach it. Frame it as a reliability problem: the model is a stochastic generator, so at scale it will occasionally emit malformed or off-schema output, and a single bad parse can break an agent step or an integration. Lay out the defense from strongest constraint to validation-and-retry, and note where each applies.

A strong answer. The levers, ordered by how strong a guarantee they give:

LeverGuaranteeWhen to use
Constrained / grammar decodingValid by construction at the token levelSelf-hosted serving, strict schemas
Provider structured-output / function callingSchema conformance from the APIThe production default when available
Schema validation + bounded retryCatches semantic errors and the rare missAlways, as a backstop
Prompt-onlyBest-effort, no guaranteeNever alone for a system that breaks on bad input

Constrained / grammar-based decoding is the most reliable: restrict the decoder so it can only emit tokens consistent with the schema (a JSON grammar or a regex/finite-state constraint), so the output is valid by construction. Provider structured-output mode (pass a JSON Schema and let the API enforce it) and function calling (a tool schema with conforming arguments returned) are the convenient managed form, and the practical default in production because they remove most parse failures.

Then, regardless of the above, parse and validate against your schema in code (types, required fields, enums, ranges). The flow on failure is bounded and explicit:

rendering diagram…

Operational details that matter: keep the schema strict (required fields, no free-form where an enum will do) so the model has less room to drift; handle streaming carefully (you cannot parse partial JSON, so buffer or use a streaming-tolerant parser); set sensible defaults and a clear error path when retries fail; and log schema-violation rates so you can see degradation. For function-calling agents, validate the tool name and arguments before executing, both for correctness and security (an unvalidated tool call is an injection and error surface).

The defensible framing: make invalid output structurally impossible where you can (constrained decoding / structured mode), and always verify-and-retry in code, because a production integration cannot tolerate "usually valid."

Key takeaways

  • Make invalid output impossible by construction with constrained decoding or provider structured-output mode.
  • Validate in code anyway: the API guarantees shape, not semantics (an in-range, sane value is your job).
  • On failure, retry with the error fed back, bounded, then fall to a safe default and alert; never proceed silently.
  • Validate a function call's name, types, and scope before executing it; treat tool args as an injection surface.

What interviewers probe next.

  • "Constrained decoding vs JSON mode vs prompting?" Constrained/grammar decoding guarantees validity at the token level; provider JSON/structured mode is the convenient managed form; prompting alone is best-effort and insufficient for production.
  • "How do you handle a validation failure?" Bounded retries with the error fed back, then a safe fallback/default and an alert; never silently proceed on malformed output.
  • "Streaming structured output?" You cannot parse incomplete JSON; buffer to completion or use incremental/partial-JSON parsing designed for it.
  • "Why validate if the API guarantees schema?" Defense in depth and because semantic validity (a field exists vs the value is sane/in-range) is yours to enforce; also tool arguments must be checked before execution.

Common mistakes.

  • Relying on a prompt to produce JSON and parsing it with no validation or retry.
  • No schema validation in code, so a subtly off-schema response corrupts downstream state.
  • Trying to parse partial streamed JSON.
  • Executing a function call's arguments without validating name, types, and scope first.
HOW DID IT GO?
0
UP NEXT ON YOUR JOURNEY
DISCUSSION · 0

No comments yet — be the first to share your approach.