Structured outputs (JSON)

OpenAI API · Practical · 12 min

Programs need data that always parses and has the right fields, not prose that is usually JSON.

Asking for JSON in the prompt works most of the time; Structured Outputs make it work every time. You give a JSON Schema (a standard description of the shape of data) and the model's reply is guaranteed to match it.

Two ways in Python:

  • client.responses.parse(..., text_format=MyModel): pass a Pydantic model, a Python class with typed fields that validates data. The SDK builds the schema and returns a ready object in response.output_parsed.
  • client.responses.create(..., text={"format": {"type": "json_schema", "name": ..., "schema": ..., "strict": True}}): write the schema yourself and json.loads(response.output_text).

In strict mode the schema follows a few rules: list every property in required and set additionalProperties to false. To make a field optional, allow null as its type instead of leaving it out of required.

There is also an older JSON mode ({"type": "json_object"}), which only guarantees valid JSON, not your fields. Prefer Structured Outputs.

Two things can still go wrong. The model may refuse for safety reasons, which shows up as a refusal instead of your data. And a reply cut off by max_output_tokens is incomplete JSON. Check for both before using the result.

Use structured output for answers to your program; use function calling (next lesson) when the model should trigger an action.

Example

from openai import OpenAI
from pydantic import BaseModel

class Invoice(BaseModel):
    vendor: str
    total: float
    currency: str

client = OpenAI()
r = client.responses.parse(
    model="gpt-6-astra",
    input=[
        {"role": "system", "content": "Extract the invoice details."},
        {"role": "user", "content": "Acme Corp billed us 1,250.00 USD."},
    ],
    text_format=Invoice,
)
invoice = r.output_parsed
print(invoice.vendor, invoice.total, invoice.currency)
# Acme Corp 1250.0 USD

Remember

  • responses.parse(text_format=Model) -> output_parsed
  • Raw form: text={"format": {"type": "json_schema", ..., "strict": True}}
  • JSON mode only guarantees valid JSON; prefer Structured Outputs

Watch out for

  • Leaving optional fields out of required in strict mode; make them nullable instead.

Check yourself

  1. What does JSON mode guarantee compared with Structured Outputs?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: developers.openai.com/api/docs/guides/structured-outputs