Structured Outputs
The output is a contract, not a suggestion
A model produces tokens. Your code needs a record: an order with a numeric quantity, a ticket with one of four priorities, a date that a database will accept. Somewhere between those two facts sits the single most common source of breakage in an LLM application — output that looks right to a human and fails JSON.parse.
There are three ways to close that gap, and they are not alternatives so much as layers. Prompt and parse asks nicely and hopes; it is the cheapest and the least reliable. Constrained decoding — grammar or schema enforcement at generation time, which is what a provider's structured-output or tool-call API gives you — makes malformed syntax impossible rather than unlikely. Validate and repair checks the result against your own schema and, on failure, sends the errors back for another attempt.
Use all three. Constrained decoding removes syntax errors; it does not remove semantic ones. A schema that says quantity: number will happily accept -4, and one that says status: string will accept "probably shipped". Syntax is the model's problem. Meaning is still yours.
prompt ──▶ model ──▶ raw output
│
constrained │ grammar makes malformed JSON
decoding │ impossible, not merely unlikely
▼
validate ── fails ──▶ repair prompt ──┐
│ │
passes │
▼ (another whole model call)
typed record ──▶ your system ◀───────────┘A schema is a shape check, not a truth check. It can prove the field is an integer; it cannot prove it is the right integer.