Structured Outputs
Structured outputs make the model answer with JSON that follows a JSON Schema you give it. Use them when your code reads the answer: extracting fields, filling a form, classifying, returning data to a UI.
With a schema you get:
- answers you can parse every time, with no “Sure! Here’s the JSON:” around them,
- the fields you asked for, with the types you asked for,
- no made-up fields when
additionalPropertiesisfalse.
Using response_format
Add response_format with type: "json_schema" and your schema:
The answer’s message.content is a JSON string that follows the schema:
JSON mode
{"type": "json_object"} only promises valid JSON, in any shape. Describe the shape you want in the prompt, and say “JSON” in it; some models refuse JSON mode otherwise. Prefer json_schema when the model supports it.
Examples
The samples use the OpenAI SDK set up as in the Quickstart.
Schemas from your types
The OpenAI SDKs can build the schema from a Pydantic model or a Zod schema, and parse the answer for you:
Streaming
Structured outputs work with stream: true. The JSON arrives in pieces; join the delta.content of every chunk and parse it once the stream ends. Partial JSON can’t be parsed until then.
Which models support it
Not every model can follow a schema. Most recent OpenAI, Google and Anthropic models can, as can many open models. The Models page doesn’t mark which can yet, so test your schema on a model before you rely on it.
Writing good schemas
- Describe every field.
descriptionis the model’s only guide to what goes where. - Use
strict: true. The model then follows the schema exactly instead of loosely. - List every field in
requiredand setadditionalProperties: false. Strict mode on most models needs both. For an optional field, allownull:{"type": ["string", "null"]}. - Prefer
enumfor fixed choices.{"type": "string", "enum": ["positive", "neutral", "negative"]}beats explaining the options in the prompt. - Keep it flat and small. Deep nesting and very long schemas cost input tokens and make mistakes more likely.
Troubleshooting
The answer is cut off and won’t parse. The model reached its output limit (your max_tokens, or the default allowance when you don’t set one); finish_reason is length. Raise max_tokens and always check finish_reason before parsing.
The answer ignores the schema. The model may not support structured outputs. Try another model, or fall back to JSON mode with the shape in the prompt, and validate the result yourself.
400 “The model rejected the request”. The model’s own error isn’t passed on. The schema may not be valid JSON Schema, or may use a feature the model doesn’t support, such as $ref or oneOf on some models. Simplify it.
Billing
The schema counts as input tokens on every request that sends it, and the JSON answer is output. There’s no extra charge for using structured outputs.