Structured output and JSON training¶
Goal¶
Make the model reliably produce machine-readable outputs.
Examples:
- JSON
- XML
- YAML
- SQL
- Regex-constrained text
- Function arguments
- Typed objects
- Tables
- Citations
- Tool-call plans
Training data should include¶
- Valid examples
- Invalid-to-valid repair examples (fix this malformed JSON)
- Nested schemas
- Optional fields
- Enum fields
- Arrays
- Empty arrays
- Null handling
- Escaping
- Unicode
- Long strings
- Schema changes
- Refusal in structured format
Repair examples are underrated
Real-world structured-output failures are not random — they are systematic (missing comma after the last array element, unescaped quotes inside string values, trailing prose after the JSON). Including repair examples in your training data ("here is broken JSON, here is the fixed version") teaches the model to self-correct.
Two paths to reliable structured output¶
Path 1: Train the model¶
Heavy SFT on schema-conforming examples + DPO on conforming-vs-broken pairs. The model learns to produce valid output by default.
Pros: Fast inference, no constraint overhead, generalizes to new schemas. Cons: Cannot give 100% guarantee. Schema drift is possible.
Path 2: Constrain at inference¶
Use constrained decoding — at each step, only allow tokens consistent with the schema. Open implementations:
- Outlines — regex/JSON-schema-constrained generation. github.com/dottxt-ai/outlines
xgrammar— fast grammar-constrained decoding. github.com/mlc-ai/xgrammarlm-format-enforcer— JSON-schema enforcement for HF/vLLM. github.com/noamgat/lm-format-enforcer- vLLM
guided_json— built into vLLM. - OpenAI Structured Outputs — server-side schema-enforced JSON.
Pros: Guarantees validity by construction. Cons: Slight inference overhead. Quality can degrade if the model "wanted" to write something that doesn't fit the schema.
In practice, do both: train the model to produce schema-conforming output, and use constrained decoding in production for guarantees.
Eval¶
Use validators, not just LLM judges.
Metrics:
- Parse rate — does it parse as JSON / valid SQL?
- Schema validity — does it match the schema?
- Required field accuracy — are required fields present and correct?
- Type correctness — strings vs numbers vs nulls.
- Semantic correctness — does the output mean the right thing?
- Robustness under adversarial prompts — can the user break it?
Practical tips¶
- Strict mode in training, strict mode in production. If you train on lenient JSON (with trailing commas, comments) the model will produce them at inference.
- Test schemas the model has never seen. Generalization to new schemas is the real test.
- Fail loudly on bad output. Don't silently retry — surface invalid JSON to the caller so they know there's a quality issue.
- Include refusal-as-structured-output examples. "If you can't answer, return
{\"error\": \"insufficient information\"}." - Consider Pydantic / TypeScript types as the source of truth and generate JSON Schema from them rather than hand-writing schemas.
Further reading¶
- OpenAI Structured Outputs — platform.openai.com/docs/guides/structured-outputs
- Anthropic Tool use & structured output — docs.claude.com
- Willard & Louf, "Efficient Guided Generation for Large Language Models" (Outlines paper), 2023. arxiv.org/abs/2307.09702
- Dong et al., "XGrammar", 2024. arxiv.org/abs/2411.15100
- Beurer-Kellner et al., "Prompts Should Be Code", 2023. arxiv.org/abs/2306.03081
- Pydantic — github.com/pydantic/pydantic
- Instructor — Pydantic-based structured-output library. github.com/jxnl/instructor