Structured Outputs with JSON Schema
Production AI systems rarely depend on freeform prose. They ask the model for a typed object that downstream code can validate.
Structured outputs are different from "please return JSON." A schema tells the model and your application exactly which fields, types, and constraints are allowed.
Why structured outputs matter
Freeform model output is fine for chat. It is risky for automation.
| Need | Freeform text | Structured output |
|---|---|---|
| Send data to code | brittle parsing | validated fields |
| Detect refusal | ambiguous | explicit branch |
| Retry safely | hard | schema-aware |
| Store in database | manual cleanup | typed insert |
| Test regressions | subjective | measurable |
Example schema
{
"type": "object",
"additionalProperties": false,
"required": ["priority", "summary", "actions"],
"properties": {
"priority": { "type": "string", "enum": ["low", "medium", "high"] },
"summary": { "type": "string" },
"actions": {
"type": "array",
"items": { "type": "string" }
}
}
}
Function calling vs response schema
Use function/tool calling when the model should decide to call code.
Use response schemas when the model should answer in a typed shape.
Need weather from API? -> tool call
Need extracted invoice JSON? -> response schema
Need both? -> tool call, then structured final answer
Validation still belongs in your app
Even when the model supports schema-constrained output, your application should:
- validate the returned object
- reject unknown fields
- enforce business rules
- handle refusals explicitly
- log schema failures for evals
- never execute tool arguments without authorization
Pattern: parse, validate, act
type Ticket = {
priority: "low" | "medium" | "high";
summary: string;
actions: string[];
};
function handleTicket(ticket: Ticket) {
if (ticket.priority === "high") {
// escalate through normal application permissions
}
}
Common pitfalls
- asking for JSON in the prompt but not using a schema
- allowing additional properties by default
- accepting strings where numbers/enums are expected
- treating structured output as trusted user input
- retrying forever when validation fails
Knowledge check
Q1: Why is a JSON schema better than "return JSON"?
It defines allowed fields, types, required properties, and constraints.
Q2: Should validated model output be trusted automatically?
No. It is well-shaped data, not necessarily correct or authorized data.