Back to Blog
Python

Python OpenAI Structured Outputs with JSON Schema

python openai structured outputs json schema: Learn how to use Python with OpenAI's structured outputs feature to enforce a JSON schema on model responses, reducing pa...

OpenAI APIJSON SchemaStructured OutputsPythonLLM
Illustration of a Python code block transforming into a structured JSON object with a schema diagram, symbolizing OpenAI structured outputs.

When you call the OpenAI API and ask for JSON, the model may return valid JSON that does not match the shape your application expects. Field names drift, types change, or extra keys appear. The python openai structured outputs json schema approach solves this by making the model follow a schema you define, so the response is predictable and directly usable in your code.

What Structured Outputs Solve

Without a schema, a prompt like "return a JSON object with a name and age" can produce {"name": "Alice", "age": 30} one time and {"person": {"name": "Alice", "age": 30}} the next. Your parsing code then has to handle multiple possible shapes, and a single unexpected key can break the pipeline.

Structured outputs let you declare the exact JSON structure the model must produce. The API uses your JSON schema to constrain the generation process, so the returned object matches the schema far more consistently than free-form JSON. This is especially useful when the output feeds directly into a database, an API response, or a data-processing function that expects a fixed structure.

The feature works with the Chat Completions API. You provide a response_format parameter that specifies type: "json_schema" and the schema itself. The model then generates JSON that conforms to that schema, including required fields and type constraints.

Defining a JSON Schema for the Model

A JSON schema describes the expected structure using standard JSON Schema syntax. For structured outputs, the schema must be an object type. You define properties, their types, and which ones are required.

Here is a simple schema for a function that extracts a person's name and age from a text:

{ "name": "person_extraction", "strict": true, "schema": { "type": "object", "properties": { "name": { "type": "string" }, "age": { "type": "integer" } }, "required": ["name", "age"], "additionalProperties": false } }

The strict flag tells the API to enforce the schema strictly. When strict mode is on, the model cannot add properties that are not listed, and all required fields must be present. This is the behavior you want for most production use cases.

The schema itself is a standard JSON Schema object. You can use any tool that generates JSON Schema, or write it by hand. For complex nested structures, consider using a library like Pydantic to generate the schema from a Python model, then pass that schema to the API.

Passing the Schema to the OpenAI API

In the OpenAI Python SDK, you pass the schema through the response_format parameter of the chat completion call. The exact parameter name may vary slightly depending on the SDK version, but the general pattern is consistent.

from openai import OpenAI client = OpenAI() response = client.chat.completions.create( model="gpt-4o", messages=[ { "role": "user", "content": "Extract the name and age from: 'Alice is 30 years old.'" } ], response_format={ "type": "json_schema", "json_schema": { "name": "person_extraction", "strict": True, "schema": { "type": "object", "properties": { "name": {"type": "string"}, "age": {"type": "integer"} }, "required": ["name", "age"], "additionalProperties": False } } } ) content = response.choices[0].message.content print(content)

When you run this, the content field will contain a JSON string that matches the schema. In this example, it would be something like {"name": "Alice", "age": 30}.

Notice that the schema is nested inside json_schema. The name field is required and should be a descriptive identifier. The strict flag is set to True to enforce the constraints.

Handling the Response and Validating Output

Even with structured outputs, the API returns the JSON as a string in the content field. You still need to parse it with json.loads(). The advantage is that the structure is predictable, so you can safely deserialize it into a Python object or a Pydantic model without defensive parsing.

import json content = response.choices[0].message.content person = json.loads(content) print(person["name"], person["age"])

If you use Pydantic, you can define a model that matches the schema and validate the parsed data directly:

from pydantic import BaseModel, ValidationError class Person(BaseModel): name: str age: int try: person = Person.model_validate_json(content) print(person) except ValidationError as e: print("Validation failed:", e)

This gives you a second layer of safety. Even if the model occasionally violates the schema, the validation step catches it before the data reaches your business logic.

Strict Mode and Schema Constraints

Strict mode is the key to reliable structured outputs. When strict: true is set, the API enforces the following:

  • All required fields must be present.
  • No additional properties are allowed.
  • Property types must match the schema.
  • The response is guaranteed to be valid JSON.

This eliminates the most common failure modes: missing keys, extra keys, and type mismatches. However, strict mode has some limitations. The schema must be an object, and it cannot use certain JSON Schema features like anyOf, oneOf, or nullable in a way that conflicts with strict generation. For example, to allow a field to be null, you must use type: ["string", "null"] rather than nullable: true.

When you define the schema, keep it as simple as possible. Complex nested structures are allowed, but each level must follow the same rules. If you need an array of objects, define the item schema explicitly.

Practical Considerations: Cost, Latency, and Compatibility

Structured outputs do not change the token cost of the response itself, but they may affect the model's generation behavior. The model still generates the same number of tokens, but the constrained decoding can slightly increase latency because the API must check each token against the schema. In practice, the difference is small for typical schemas.

Compatibility depends on the model and the API version. Not all models support structured outputs with JSON schema. As of the current API, GPT-4o and newer models support it, but older models may only support json_object mode without a schema. Check the OpenAI documentation for the model you are using. The Python SDK version also matters; ensure you have a recent version that includes the json_schema response format.

Another operational concern is error handling. If the model fails to produce a response that conforms to the schema, the API may return an error. In that case, you should catch the exception and retry with a different prompt or fall back to a manual repair step. Do not assume that structured outputs are infallible; they reduce the probability of malformed output but do not eliminate it entirely.

Common Failure Patterns and How to Avoid Them

One common mistake is forgetting to set additionalProperties: false in the schema. Without it, the model may add extra fields that you did not anticipate, which can break downstream code that expects a strict structure. Always set it to false when you want exact output.

Another issue is using a schema that is too restrictive. For example, if you require a field that the model cannot infer from the input, it may hallucinate a value. Make sure the schema matches the information available in the prompt. If a field is optional, do not list it in required.

A third problem is mixing up the response_format syntax. The json_schema object must contain name, strict, and schema fields. If you omit strict, the API may still work but with less enforcement. Always set it explicitly.

Finally, be careful with nested schemas. Each nested object must also have additionalProperties: false if you want strict behavior at all levels. The API does not automatically apply that setting to nested objects; you must specify it in each object definition.

By following these patterns, you can rely on structured outputs to deliver consistent, schema-valid JSON from the OpenAI API, making your Python integration more robust and maintainable.

python openai structured outputs json schema: Practical Usag | RYUSLOG DEV