Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Structured outputs make a model follow a JSON Schema definition that you provide as part of your inference API call. This approach contrasts with the older JSON mode feature, which guaranteed valid JSON but couldn't ensure strict adherence to the supplied schema. Use structured outputs for function calling, extracting structured data, and building complex multi-step workflows.
Getting started
You can use Pydantic to define object schemas in Python. Depending on what version of the OpenAI and Pydantic libraries you're running you might need to upgrade to a newer version. These examples were tested against openai 1.42.0 and pydantic 2.8.2.
pip install openai pydantic azure-identity --upgrade
If you are new to using Microsoft Entra ID for authentication see How to configure Azure OpenAI in Microsoft Foundry Models with Microsoft Entra ID authentication.
from pydantic import BaseModel
from openai import OpenAI
from azure.identity import DefaultAzureCredential, get_bearer_token_provider
token_provider = get_bearer_token_provider(
DefaultAzureCredential(), "https://ai.azure.com/.default"
)
client = OpenAI(
base_url = "https://YOUR-RESOURCE-NAME.openai.azure.com/openai/v1/",
api_key=token_provider,
)
class CalendarEvent(BaseModel):
name: str
date: str
participants: list[str]
completion = client.beta.chat.completions.parse(
model="MODEL_DEPLOYMENT_NAME", # replace with the model deployment name of your gpt-4o 2024-08-06 deployment
messages=[
{"role": "system", "content": "Extract the event information."},
{"role": "user", "content": "Alice and Bob are going to a science fair on Friday."},
],
response_format=CalendarEvent,
)
event = completion.choices[0].message.parsed
print(event)
print(completion.model_dump_json(indent=2))
Output
name='Science Fair' date='Friday' participants=['Alice', 'Bob']
{
"id": "chatcmpl-A1EUP2fAmL4SeB1lVMinwM7I2vcqG",
"choices": [
{
"finish_reason": "stop",
"index": 0,
"logprobs": null,
"message": {
"content": "{\n \"name\": \"Science Fair\",\n \"date\": \"Friday\",\n \"participants\": [\"Alice\", \"Bob\"]\n}",
"refusal": null,
"role": "assistant",
"function_call": null,
"tool_calls": [],
"parsed": {
"name": "Science Fair",
"date": "Friday",
"participants": [
"Alice",
"Bob"
]
}
}
}
],
"created": 1724857389,
"model": "gpt-4o-2024-08-06",
"object": "chat.completion",
"service_tier": null,
"system_fingerprint": "fp_1c2eaec9fe",
"usage": {
"completion_tokens": 27,
"prompt_tokens": 32,
"total_tokens": 59
}
}
Function calling with structured outputs
Structured Outputs for function calling can be enabled with a single parameter, by supplying strict: true.
Note
Structured outputs are not supported with parallel function calls. When using structured outputs set parallel_tool_calls to false.
import openai
from pydantic import BaseModel
from openai import OpenAI
from azure.identity import DefaultAzureCredential, get_bearer_token_provider
token_provider = get_bearer_token_provider(
DefaultAzureCredential(), "https://ai.azure.com/.default"
)
client = OpenAI(
base_url = "https://YOUR-RESOURCE-NAME.openai.azure.com/openai/v1/",
api_key=token_provider,
)
class GetDeliveryDate(BaseModel):
order_id: str
tools = [openai.pydantic_function_tool(GetDeliveryDate)]
messages = []
messages.append({"role": "system", "content": "You are a helpful customer support assistant. Use the supplied tools to assist the user."})
messages.append({"role": "user", "content": "Hi, can you tell me the delivery date for my order #12345?"})
response = client.chat.completions.create(
model="MODEL_DEPLOYMENT_NAME", # replace with the model deployment name of your gpt-4o 2024-08-06 deployment
messages=messages,
tools=tools
)
print(response.choices[0].message.tool_calls[0].function)
print(response.model_dump_json(indent=2))
Getting started
Add the following packages to your project:
- OpenAI: Standard OpenAI .NET library.
- Azure.Identity: Provides Microsoft Entra ID token authentication support across the Azure SDK libraries.
dotnet add package OpenAI
dotnet add package Azure.Identity
If you're new to using Microsoft Entra ID for authentication see How to configure Azure OpenAI in Microsoft Foundry Models with Microsoft Entra ID authentication.
using Azure.Identity;
using OpenAI;
using OpenAI.Chat;
using System.ClientModel.Primitives;
using System.Text.Json;
#pragma warning disable OPENAI001
BearerTokenPolicy tokenPolicy = new(
new DefaultAzureCredential(),
"https://ai.azure.com/.default");
ChatClient client = new(
model: "gpt-4.1",
authenticationPolicy: tokenPolicy,
options: new OpenAIClientOptions()
{
Endpoint = new Uri("https://YOUR-RESOURCE-NAME.openai.azure.com/openai/v1")
}
);
ChatCompletionOptions options = new()
{
ResponseFormat = ChatResponseFormat.CreateJsonSchemaFormat(
jsonSchemaFormatName: "math_reasoning",
jsonSchema: BinaryData.FromBytes("""
{
"type": "object",
"properties": {
"steps": {
"type": "array",
"items": {
"type": "object",
"properties": {
"explanation": { "type": "string" },
"output": { "type": "string" }
},
"required": ["explanation", "output"],
"additionalProperties": false
}
},
"final_answer": { "type": "string" }
},
"required": ["steps", "final_answer"],
"additionalProperties": false
}
"""u8.ToArray()),
jsonSchemaIsStrict: true)
};
// Create a list of ChatMessage objects
ChatCompletion completion = client.CompleteChat(
[
new UserChatMessage("How can I solve 8x + 7 = -23?")
],
options);
using JsonDocument structuredJson = JsonDocument.Parse(completion.Content[0].Text);
Console.WriteLine($"Final answer: {structuredJson.RootElement.GetProperty("final_answer")}");
Console.WriteLine("Reasoning steps:");
foreach (JsonElement stepElement in structuredJson.RootElement.GetProperty("steps").EnumerateArray())
{
Console.WriteLine($" - Explanation: {stepElement.GetProperty("explanation")}");
Console.WriteLine($" Output: {stepElement.GetProperty("output")}");
}
Getting started
response_format is set to json_schema with strict: true set.
curl -X POST https://YOUR_RESOURCE_NAME.openai.azure.com/openai/v1/chat/completions \
-H "api-key: $AZURE_OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "YOUR_MODEL_DEPLOYMENT_NAME",
"messages": [
{"role": "system", "content": "Extract the event information."},
{"role": "user", "content": "Alice and Bob are going to a science fair on Friday."}
],
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "CalendarEventResponse",
"strict": true,
"schema": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"date": {
"type": "string"
},
"participants": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"name",
"date",
"participants"
],
"additionalProperties": false
}
}
}
}'
Output:
{
"id": "chatcmpl-A1HKsHAe2hH9MEooYslRn9UmEwsag",
"object": "chat.completion",
"created": 1724868330,
"model": "gpt-4o-2024-08-06",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "{\n \"name\": \"Science Fair\",\n \"date\": \"Friday\",\n \"participants\": [\"Alice\", \"Bob\"]\n}"
},
"logprobs": null,
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 33,
"completion_tokens": 27,
"total_tokens": 60
},
"system_fingerprint": "fp_1c2eaec9fe"
}
Function calling with structured outputs
curl -X POST https://YOUR_RESOURCE_NAME.openai.azure.com/openai/v1/chat/completions \
-H "api-key: $AZURE_OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "YOUR_MODEL_DEPLOYMENT_NAME",
"messages": [
{
"role": "system",
"content": "You are a helpful assistant. The current date is August 6, 2024. You help users query for the data they are looking for by calling the query function."
},
{
"role": "user",
"content": "look up all my orders in may of last year that were fulfilled but not delivered on time"
}
],
"tools": [
{
"type": "function",
"function": {
"name": "query",
"description": "Execute a query.",
"strict": true,
"parameters": {
"type": "object",
"properties": {
"table_name": {
"type": "string",
"enum": ["orders"]
},
"columns": {
"type": "array",
"items": {
"type": "string",
"enum": [
"id",
"status",
"expected_delivery_date",
"delivered_at",
"shipped_at",
"ordered_at",
"canceled_at"
]
}
},
"conditions": {
"type": "array",
"items": {
"type": "object",
"properties": {
"column": {
"type": "string"
},
"operator": {
"type": "string",
"enum": ["=", ">", "<", ">=", "<=", "!="]
},
"value": {
"anyOf": [
{
"type": "string"
},
{
"type": "number"
},
{
"type": "object",
"properties": {
"column_name": {
"type": "string"
}
},
"required": ["column_name"],
"additionalProperties": false
}
]
}
},
"required": ["column", "operator", "value"],
"additionalProperties": false
}
},
"order_by": {
"type": "string",
"enum": ["asc", "desc"]
}
},
"required": ["table_name", "columns", "conditions", "order_by"],
"additionalProperties": false
}
}
}
]
}'
JSON Schema support and limitations
Azure OpenAI structured outputs support the same subset of the JSON Schema as OpenAI.
Supported types
- String
- Number
- Boolean
- Integer
- Object
- Array
- Enum
- anyOf
Note
Root objects can't be the anyOf type.
All fields must be required
Include all fields or function parameters as required. In the following example, both location and unit appear under "required": ["location", "unit"].
{
"name": "get_weather",
"description": "Fetches the weather in the given location",
"strict": true,
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The location to get the weather for"
},
"unit": {
"type": "string",
"description": "The unit to return the temperature in",
"enum": ["F", "C"]
}
},
"additionalProperties": false,
"required": ["location", "unit"]
}
}
If needed, you can emulate an optional parameter by using a union type with null. In this example, this approach is represented by the line "type": ["string", "null"],.
{
"name": "get_weather",
"description": "Fetches the weather in the given location",
"strict": true,
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The location to get the weather for"
},
"unit": {
"type": ["string", "null"],
"description": "The unit to return the temperature in",
"enum": ["F", "C"]
}
},
"additionalProperties": false,
"required": [
"location", "unit"
]
}
}
Nesting depth
A schema can have up to 100 object properties total, with up to five levels of nesting.
Always set additionalProperties: false in objects
This property controls if an object can have other key value pairs that weren't defined in the JSON Schema. To use structured outputs, set this value to false.
Key ordering
Structured outputs follow the same order as the provided schema. To change the output order, modify the order of the schema that you send as part of your inference request.
Unsupported type-specific keywords
| Type | Unsupported Keyword |
|---|---|
| String | minlength maxLength pattern format |
| Number | minimum maximum multipleOf |
| Objects | patternProperties unevaluatedProperties propertyNames minProperties maxProperties |
| Arrays | unevaluatedItems contains minContains maxContains minItems maxItems uniqueItems |
Nested schemas using anyOf must adhere to the overall JSON Schema subset
Example supported anyOf schema:
{
"type": "object",
"properties": {
"item": {
"anyOf": [
{
"type": "object",
"description": "The user object to insert into the database",
"properties": {
"name": {
"type": "string",
"description": "The name of the user"
},
"age": {
"type": "number",
"description": "The age of the user"
}
},
"additionalProperties": false,
"required": [
"name",
"age"
]
},
{
"type": "object",
"description": "The address object to insert into the database",
"properties": {
"number": {
"type": "string",
"description": "The number of the address. Eg. for 123 main st, this would be 123"
},
"street": {
"type": "string",
"description": "The street name. Eg. for 123 main st, this would be main st"
},
"city": {
"type": "string",
"description": "The city of the address"
}
},
"additionalProperties": false,
"required": [
"number",
"street",
"city"
]
}
]
}
},
"additionalProperties": false,
"required": [
"item"
]
}
Definitions are supported
Supported example:
{
"type": "object",
"properties": {
"steps": {
"type": "array",
"items": {
"$ref": "#/$defs/step"
}
},
"final_answer": {
"type": "string"
}
},
"$defs": {
"step": {
"type": "object",
"properties": {
"explanation": {
"type": "string"
},
"output": {
"type": "string"
}
},
"required": [
"explanation",
"output"
],
"additionalProperties": false
}
},
"required": [
"steps",
"final_answer"
],
"additionalProperties": false
}
Recursive schemas are supported
Example using # for root recursion:
{
"name": "ui",
"description": "Dynamically generated UI",
"strict": true,
"schema": {
"type": "object",
"properties": {
"type": {
"type": "string",
"description": "The type of the UI component",
"enum": ["div", "button", "header", "section", "field", "form"]
},
"label": {
"type": "string",
"description": "The label of the UI component, used for buttons or form fields"
},
"children": {
"type": "array",
"description": "Nested UI components",
"items": {
"$ref": "#"
}
},
"attributes": {
"type": "array",
"description": "Arbitrary attributes for the UI component, suitable for any element",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "The name of the attribute, for example onClick or className"
},
"value": {
"type": "string",
"description": "The value of the attribute"
}
},
"additionalProperties": false,
"required": ["name", "value"]
}
}
},
"required": ["type", "label", "children", "attributes"],
"additionalProperties": false
}
}
Example of explicit recursion:
{
"type": "object",
"properties": {
"linked_list": {
"$ref": "#/$defs/linked_list_node"
}
},
"$defs": {
"linked_list_node": {
"type": "object",
"properties": {
"value": {
"type": "number"
},
"next": {
"anyOf": [
{
"$ref": "#/$defs/linked_list_node"
},
{
"type": "null"
}
]
}
},
"additionalProperties": false,
"required": [
"next",
"value"
]
}
},
"additionalProperties": false,
"required": [
"linked_list"
]
}
Note
Currently, structured outputs aren't supported with:
- Bring your own data scenarios.
- Assistants or Foundry Agents Service.
gpt-4o-audio-previewandgpt-4o-mini-audio-previewversion:2024-12-17.
Supported models
gpt-5.1-codexversion:2025-11-13gpt-5.1-codex miniversion:2025-11-13gpt-5.1version:2025-11-13gpt-5.1-chatversion:2025-11-13gpt-5-proversion2025-10-06gpt-5-codexversion2025-09-11gpt-5version2025-08-07gpt-5-miniversion2025-08-07gpt-5-nanoversion2025-08-07codex-miniversion2025-05-16o3-proversion2025-06-10o3-miniversion2025-01-31o1version:2024-12-17gpt-4o-miniversion:2024-07-18gpt-4oversion:2024-08-06gpt-4oversion:2024-11-20gpt-4.1version2025-04-14gpt-4.1-nanoversion2025-04-14gpt-4.1-miniversion:2025-04-14o4-miniversion:2025-04-16o3version:2025-04-16
API support
API version 2024-08-01-preview is the first version that supports structured outputs. The latest preview APIs and the latest GA API, v1, also support structured outputs.