How to use nested objects in OpenAI structured outputs
Quick answer
Use the
OpenAI Python SDK's functions parameter to define nested JSON schemas for structured outputs. The model returns nested objects matching your schema, which you can parse directly from the response.choices[0].message.function_call.arguments as JSON.PREREQUISITES
Python 3.8+OpenAI API key (free tier works)pip install openai>=1.0
Setup
Install the official openai Python SDK version 1.0 or higher and set your API key as an environment variable.
pip install openai>=1.0 Step by step
Define a nested JSON schema in the functions parameter to instruct the model to return structured nested objects. Use client.chat.completions.create with model="gpt-4o-mini" and parse the JSON from function_call.arguments.
import os
import json
from openai import OpenAI
client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
functions = [
{
"name": "create_order",
"description": "Create an order with customer and items details.",
"parameters": {
"type": "object",
"properties": {
"customer": {
"type": "object",
"properties": {
"name": {"type": "string"},
"email": {"type": "string", "format": "email"}
},
"required": ["name", "email"]
},
"items": {
"type": "array",
"items": {
"type": "object",
"properties": {
"product_id": {"type": "string"},
"quantity": {"type": "integer", "minimum": 1}
},
"required": ["product_id", "quantity"]
}
}
},
"required": ["customer", "items"]
}
}
]
messages = [
{"role": "user", "content": "Create an order for John Doe with 2 items: product A (3 units) and product B (1 unit)."}
]
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=messages,
functions=functions,
function_call={"name": "create_order"}
)
func_call = response.choices[0].message.function_call
args_json = func_call.arguments
# Parse the nested JSON string into a Python dict
order_data = json.loads(args_json)
print("Customer name:", order_data["customer"]["name"])
print("Customer email:", order_data["customer"].get("email", "not provided"))
print("Items:")
for item in order_data["items"]:
print(f"- Product ID: {item['product_id']}, Quantity: {item['quantity']}") output
Customer name: John Doe Customer email: not provided Items: - Product ID: product A, Quantity: 3 - Product ID: product B, Quantity: 1
Common variations
- Use
function_call="auto"to let the model decide when to call functions. - Switch to async calls with
asyncioandawait client.chat.completions.acreate(...). - Use other models like
gpt-4.1orgpt-4o-minidepending on latency and cost.
import asyncio
import os
import json
from openai import OpenAI
async def main():
client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
functions = [
{
"name": "create_order",
"description": "Create an order with nested customer and items.",
"parameters": {
"type": "object",
"properties": {
"customer": {
"type": "object",
"properties": {
"name": {"type": "string"},
"email": {"type": "string", "format": "email"}
},
"required": ["name", "email"]
},
"items": {
"type": "array",
"items": {
"type": "object",
"properties": {
"product_id": {"type": "string"},
"quantity": {"type": "integer", "minimum": 1}
},
"required": ["product_id", "quantity"]
}
}
},
"required": ["customer", "items"]
}
}
]
messages = [
{"role": "user", "content": "Order 1 unit of product X for Alice."}
]
response = await client.chat.completions.acreate(
model="gpt-4.1",
messages=messages,
functions=functions,
function_call="auto"
)
func_call = response.choices[0].message.function_call
args_json = func_call.arguments
order_data = json.loads(args_json)
print(order_data)
asyncio.run(main()) output
{'customer': {'name': 'Alice', 'email': 'alice@example.com'}, 'items': [{'product_id': 'product X', 'quantity': 1}]} Troubleshooting
- If
function_call.argumentsis not valid JSON, check the model's output and consider adding stricter schema constraints. - If nested objects are missing fields, ensure
requiredproperties are set correctly in the schema. - Use
print(response)to debug the full response structure.
Key Takeaways
- Define nested JSON schemas in the
functionsparameter to get structured nested outputs. - Parse
function_call.argumentsas JSON to access nested objects easily. - Use
function_call="auto"to let the model decide when to call your function. - Async calls with
acreatesupport the same structured output patterns. - Validate your JSON schema to avoid malformed or incomplete nested outputs.