@@ -10,6 +10,7 @@ ms.date: 01/30/2025
author: mrbullwinkle
ms.author: mbullwin
recommendations: false
+zone_pivot_groups: structured-outputs
---
# Structured outputs
@@ -33,426 +34,26 @@ Structured outputs make a model follow a [JSON Schema](https://json-schema.org/o
Support for structured outputs was first added in API version `2024-08-01-preview`. It is available in the latest preview APIs as well as the latest GA API: `2024-10-21`.
-## Getting started
-# [Python (Microsoft Entra ID)](#tab/python-secure)
+::: zone pivot="programming-language-python"
-You can use [`Pydantic`](https://docs.pydantic.dev/latest/) to define object schemas in Python. Depending on what version of the [OpenAI](https://pypi.org/project/openai/) and [`Pydantic` libraries](https://pypi.org/project/pydantic/) 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`.
+[!INCLUDE [structured-outputs-python](../includes/structured-outputs-python.md)]
-```cmd
-pip install openai pydantic --upgrade
-```
-
-If you are new to using Microsoft Entra ID for authentication see [How to configure Azure OpenAI Service with Microsoft Entra ID authentication](./managed-identity.md).
-
-```python
-from pydantic import BaseModel
-from openai import AzureOpenAI
-from azure.identity import DefaultAzureCredential, get_bearer_token_provider
-
-token_provider = get_bearer_token_provider(
- DefaultAzureCredential(), "https://cognitiveservices.azure.com/.default"
-)
-
-client = AzureOpenAI(
- azure_endpoint = os.getenv("AZURE_OPENAI_ENDPOINT"),
- azure_ad_token_provider=token_provider,
- api_version="2024-10-21"
-)
-
-
-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
-
-```json
-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
- }
-}
-```
-
-# [Python (key-based auth)](#tab/python)
-
-You can use [`Pydantic`](https://docs.pydantic.dev/latest/) to define object schemas in Python. Depending on what version of the [OpenAI](https://pypi.org/project/openai/) and [`Pydantic` libraries](https://pypi.org/project/pydantic/) 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`.
-
-```cmd
-pip install openai pydantic --upgrade
-```
-
-```python
-from pydantic import BaseModel
-from openai import AzureOpenAI
-
-client = AzureOpenAI(
- azure_endpoint = os.getenv("AZURE_OPENAI_ENDPOINT"),
- api_key=os.getenv("AZURE_OPENAI_API_KEY"),
- api_version="2024-10-21"
-)
-
-
-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
-
-```json
-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
- }
-}
-```
+::: zone-end
-# [REST](#tab/rest)
-`response_format` is set to `json_schema` with `strict: true` set.
+::: zone pivot="programming-language-csharp"
-```bash
-curl -X POST https://YOUR_RESOURCE_NAME.openai.azure.com/openai/deployments/YOUR_MODEL_DEPLOYMENT_NAME/chat/completions?api-version=2024-10-21 \
- -H "api-key: $AZURE_OPENAI_API_KEY" \
- -H "Content-Type: application/json" \
- -d '{
- "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
- }
- }
- }
- }'
-```
+[!INCLUDE [structured-outputs-dotnet](../includes/structured-outputs-dotnet.md)]
-Output:
+::: zone-end
-```json
-{
- "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"
-}
-```
+::: zone pivot="programming-language-rest"
----
-
-## 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`.
+[!INCLUDE [structured-outputs-rest](../includes/structured-outputs-rest.md)]
-# [Python (Microsoft Entra ID)](#tab/python-secure)
-
-```python
-from enum import Enum
-from typing import Union
-from pydantic import BaseModel
-import openai
-from openai import AzureOpenAI
-
-client = AzureOpenAI(
- azure_endpoint = os.getenv("AZURE_OPENAI_ENDPOINT"),
- api_key=os.getenv("AZURE_OPENAI_API_KEY"),
- api_version="2024-10-21"
-)
-
-
-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))
-```
-
-# [Python (key-based auth)](#tab/python)
-
-```python
-from enum import Enum
-from typing import Union
-from pydantic import BaseModel
-import openai
-from openai import AzureOpenAI
-
-client = AzureOpenAI(
- azure_endpoint = os.getenv("AZURE_OPENAI_ENDPOINT"),
- api_key=os.getenv("AZURE_OPENAI_API_KEY"),
- api_version="2024-10-21"
-)
-
-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))
-```
-
-# [REST](#tab/rest)
-
-```bash
-curl -X POST https://YOUR_RESOURCE_NAME.openai.azure.com/openai/deployments/YOUR_MODEL_DEPLOYMENT_NAME/chat/completions?api-version=2024-10-21 \
- -H "api-key: $AZURE_OPENAI_API_KEY" \
- -H "Content-Type: application/json" \
- -d '{
- "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
- }
- }
- }
- ]
-}'
-```
-
----
+::: zone-end
## Supported schemas and limitations
@@ -554,60 +155,60 @@ Example supported `anyOf` schema:
```json
{
- "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"
- ]
+ "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"
+ ]
}
```
@@ -617,41 +218,41 @@ Supported example:
```json
{
- "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
+ "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
}
```
@@ -713,40 +314,40 @@ Example of explicit recursion:
```json
{
- "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"
- ]
+ "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"
+ ]
}
```