Drag each answer to line up with its matching prompt
Pydantic + Instructor (Python)
Provider-agnostic structured output with your own validate and retry loop; works with any LLM that accepts JSON mode or schema hints.
JSON Schema + repair loop
Zero tolerance for malformed output (e.g. embedded systems consuming the JSON downstream); willing to run your own model and maintain a grammar for guaranteed valid output.
Grammar-constrained decoding (Outlines, llama.cpp)
Node/Next.js backend where the rest of the type system is Zod-driven; runtime guards align with compile-time types.
Zod + TypeScript runtime validation
Production app on a single provider where you accept the provider's constraint enforcement and want the simplest integration.
Provider-native structured output mode (OpenAI Structured Outputs, Anthropic strict tool use)
Type-safe structured output in a Python backend where you already use Pydantic; tolerate one retry on validation failure.
Pick the validator by ecosystem first (Pydantic for Python, Zod for TS) and by strictness budget second (provider-native is easy, grammar-constrained is bulletproof).
Imagine you ordered a pizza and you only want round pizzas with cheese. Five restaurants offer five different guarantees. One says trust us, we'll send a round cheese pizza. One says we'll send something, you check it, and if it's wrong call us back for a retry. One says we built a machine that physically cannot produce anything except round cheese pizzas. It takes more setup, but you never get a bad pie. One says we use Python so we'll Pydantic-check it. One says we use TypeScript so we'll Zod-check it. Schema validation for LLMs is the same menu. You match the guarantee to how much pain a wrong order causes downstream. Then you match the validator to whatever language your kitchen already speaks.
Concept explanation~2 min read
Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example. Click to expand.
Concept explanation~2 min read
Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example. Click to expand.
Schema validation for LLM output looks simple in isolation. It gets complicated as soon as you account for ecosystem, retry budget, latency, and provider portability. There is no universal best tool. There are five common patterns, each a clean fit for a specific combination of constraints.
The organizing principle is two-axis: language ecosystem (Python vs TypeScript vs polyglot) and strictness budget (how much latency and complexity you can spend to guarantee valid output). Most production decisions fall out of those two axes cleanly.
Pydantic plus Instructor: the Python default
In a Python backend that already uses Pydantic for request and response models, schema validation for LLM output is a near zero cost addition. Instructor wraps an OpenAI, Anthropic, or other provider client, takes a Pydantic model as the response shape, and handles the parse and retry loop for you.
The shape of the call becomes client.chat.completions.create(response_model=UserProfile, ...) where UserProfile is a Pydantic class. On validation failure, Instructor re-prompts with the validation error appended and retries. After a configurable number of retries, it raises. The application code never sees malformed output.
The wins are obvious: type-safe outputs in a codebase that already speaks Pydantic, automatic retry on validation errors, IDE autocomplete on the response object. The cost is one library dependency and the occasional retry per request. For Python production teams, this is the path of least resistance.
Situations where this technique stops working.
2–4 min · Everything important, quickly.
Real products, models, and research that use this idea.
- Anthropic structured outputs (strict tool use or JSON outputs) and OpenAI Structured Outputs (strict JSON schema) cover the simplest provider-native integrations in production today.
- Instructor on FastAPI services is a widely used Python pattern for type-safe LLM output.
What an interviewer would ask next. Try answering before peeking at the approach.
QHow would you handle schema migration when the LLM output shape needs to change?
Version the schema explicitly and keep old fields readable for backfill. Add new fields as optional first, then promote them to required after the model has been retrained or re-prompted.
Red flags & common mistakes
The phrases that signal junior thinking. Click to expand.
Red flags & common mistakes
The phrases that signal junior thinking. Click to expand.
Picking the most strict tool by default (grammar-constrained decoding everywhere) instead of matching cost and strictness to actual downstream requirements.
60 second bullets to scan on the way to the call.
When provider-native structured output is the right default
Why Pydantic plus Instructor fits Python backends
Primary sources. Browse if you want the original framing.
Same topic, related formats. Practice these next.