Skip to content

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:

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