Walk through BAML, Outlines, OpenAI Structured Outputs, and Pydantic with retry as paths to structured output. For each, name the layer it operates at, the guarantee it provides, and the failure mode it leaves open.
The four sit on a prevent versus detect spectrum: Outlines and OpenAI Structured Outputs prevent invalid output at sampling; BAML retries at the call site; Pydantic only detects after.
Imagine four ways to make sure a kid only colors inside the lines. The strongest way is to print the page with a raised plastic border so the crayon physically cannot cross it. The next strongest is to print only with crayons that turn invisible outside the lines. The middle way is to let the kid color freely, then before showing the picture to anyone, check whether they stayed inside and ask for a redo if not. The weakest way is to show the picture without checking and tell the kid afterward whether they did it right. All four end up with a coloring page; only the first two make the wrong outcome impossible.
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.
Structured output is one of the load-bearing capabilities of any production LLM system. Downstream code expects typed data, schemas evolve over time, and the difference between a 99 percent and 99.9 percent parse-success rate is the difference between a working pipeline and a paging incident.
Four tools dominate the landscape in 2026. They look superficially similar, all four end up producing JSON or a typed object, and they operate at completely different layers with completely different guarantees. This deep dive walks through each, the lifecycle point it sits at, the failure mode it leaves open, and how they compose.
The lifecycle-anchored framing
The clearest way to organize the tools is by the point in the LLM call lifecycle where they operate.
Before the first token: codegen and schema
What the model sees is the result of templating: the schema, plus instructions, plus the input data. BAML lives here. It generates the prompt template and the typed client at build time. The model receives a well-formed structured prompt; what comes back is parsed and retried by the generated client.
During sampling: decoding-layer prevention
During token generation, the model produces a probability distribution over the vocabulary at each step. Some of those tokens would produce invalid output given the partial result so far. Decoding-layer tools mask those tokens' probabilities to zero, so they cannot be sampled. Outlines and OpenAI Structured Outputs both live here. The output is structurally valid by construction.
After the response: detection and retry
Once the model has produced its output, you can parse it against a schema and react to failures. Pydantic plus retry lives here. Validation succeeds or fails after the fact; the response is a fait accompli at that point.
Why the lifecycle point determines the guarantee
The earlier in the lifecycle the constraint lives, the stronger the guarantee. Sampling-layer prevention cannot produce invalid output. Application-layer validation can only react to invalid output. Codegen sits in between. It shapes the prompt strongly but does not constrain sampling, so it relies on retry for guarantees.
Situations where this technique stops working.
2–4 min · Everything important, quickly.
| Tool | Layer | Guarantee | Primary failure mode |
|---|---|---|---|
| Outlines | Decoding (FSM logit mask) | Cannot produce invalid output | Needs sampling control; quality may degrade on restrictive schemas |
| OpenAI Structured Outputs | Decoding (provider-side) | Cannot produce invalid output on supported models | Vendor lock-in; limited to specific OpenAI models |
| BAML | Application (codegen + retry) | Eventual valid output within retry budget | Pathological inputs exhaust the budget |
| Pydantic + retry | Application (validate after) | Will detect invalid output; will not prevent it | Silent partial-validation; unbounded retry cost |
Real products, models, and research that use this idea.
- OpenAI Structured Outputs was introduced on gpt-4o-2024-08-06 and by 2026 is standard across gpt-5.5 and the o5 reasoning family.
- BAML is used by Notion-style and Vercel-style teams for schema-first typed LLM functions across TS and Python.
What an interviewer would ask next. Try answering before peeking at the approach.
QHow does Outlines handle a JSON schema with a recursive type?
Outlines supports a subset of JSON Schema; deep recursion is approximated with a depth limit or rejected; if your schema is genuinely recursive, you may need an application-layer parser that breaks it into non-recursive sub-schemas.
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.
Treating Pydantic plus retry and OpenAI Structured Outputs as equivalent. They are at opposite ends of the prevent vs detect spectrum.
60 second bullets to scan on the way to the call.
The lifecycle point each tool operates at
The specific guarantee each tool provides
Primary sources. Browse if you want the original framing.
Same topic, related formats. Practice these next.