結構化輸出
結構化輸出會讓模型遵循您在推斷 API 呼叫中提供的 JSON 結構描述定義。 這與較舊的 JSON 模式功能相反,該功能保證會產生有效的 JSON,但無法確保嚴格遵循提供的結構描述。 建議使用結構化輸出來呼叫函式、擷取結構化數據,以及建置複雜的多步驟工作流程。
注意
目前不支援結構化輸出:
- 攜帶您自己的數據 案例。
- 助理或 Azure AI 代理程式服務。
-
gpt-4o-audio-preview
和gpt-4o-mini-audio-preview
版本:2024-12-17
。
支援的模型
-
o3-mini
版本2025-01-31
-
o1
版本:2024-12-17
-
gpt-4o-mini
版本:2024-07-18
-
gpt-4o
版本:2024-08-06
API 支援
API 版本 2024-08-01-preview
首次新增對結構化輸出的支援。 其可在最新的預覽 API 以及最新的 GA API 中使用: 2024-10-21
。
開始使用
您可以使用 Pydantic
以 Python 定義物件結構描述。 根據您執行的 OpenAI 版本和Pydantic
連結庫,您可能需要升級至較新版本。 這些範例是針對 openai 1.42.0
和 pydantic 2.8.2
進行測試。
pip install openai pydantic --upgrade
如果您不熟悉使用 Microsoft Entra ID 進行驗證,請參閱 如何使用 Microsoft Entra ID 驗證來設定 Azure OpenAI 服務。
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))
輸出
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
}
}
透過結構化輸出呼叫函式
可以透過提供 strict: true
,使用單一參數來允許結構化輸出用於函式呼叫。
注意
平行函數調用不支援結構化輸出。 當使用結構化輸出時,將 parallel_tool_calls
設定為 false
。
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))
開始使用
將下列套件新增至您的專案以使用 Azure OpenAI:
- Azure.AI.OpenAI:提供 Azure OpenAI 用戶端,其中包含以標準 OpenAI 連結庫相依性為基礎的 Azure 特定功能。
- Azure.Identity:在 Azure SDK 連結庫中提供Microsoft Entra ID 令牌驗證支援。
- Newtonsoft.Json.Schema:提供實用的公用程式來使用 JSON 架構。
dotnet add package Azure.AI.OpenAI --prerelease
dotnet add package Azure.Identity
dotnet add package Newtonsoft.Json.Schema
如果您不熟悉使用 Microsoft Entra ID 進行驗證,請參閱 如何使用 Microsoft Entra ID 驗證來設定 Azure OpenAI 服務。
using Azure.AI.OpenAI;
using Azure.Identity;
using Newtonsoft.Json.Schema.Generation;
using OpenAI.Chat;
using System.ClientModel;
// Create the clients
string endpoint = GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT");
AzureOpenAIClient openAIClient = new(
new Uri(endpoint),
new DefaultAzureCredential());
var client = openAIClient.GetChatClient("gpt-4o");
// Create a chat with initial prompts
var chat = new List<ChatMessage>()
{
new SystemChatMessage("Extract the event information and projected weather."),
new UserChatMessage("Alice and Bob are going to a science fair in Seattle on June 1st, 2025.")
};
// Get the schema of the class for the structured response
JSchemaGenerator generator = new JSchemaGenerator();
var jsonSchema = generator.Generate(typeof(CalendarEvent)).ToString();
// Get a completion with structured output
var chatUpdates = client.CompleteChatStreamingAsync(
chat,
new ChatCompletionOptions()
{
ResponseFormat = ChatResponseFormat.CreateJsonSchemaFormat(
"calenderEvent",
BinaryData.FromString(jsonSchema))
});
// Write the structured response
await foreach (var chatUpdate in chatUpdates)
{
foreach (var contentPart in chatUpdate.ContentUpdate)
{
Console.Write(contentPart.Text);
}
}
// The class for the structured response
public class CalendarEvent()
{
public string Name { get; set; }
public string Date { get; set; }
public List<string> Participants { get; set; }
}
透過結構化輸出呼叫函式
可以透過提供 strict: true
,使用單一參數來允許結構化輸出用於函式呼叫。
using Azure.AI.OpenAI;
using Newtonsoft.Json.Schema.Generation;
using OpenAI.Chat;
using System.ClientModel;
// Create the clients
string endpoint = GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT");
AzureOpenAIClient openAIClient = new(
new Uri(endpoint),
new DefaultAzureCredential());
var chatClient = openAIClient.GetChatClient("gpt-4o");
// Local function to be used by the assistant tooling
string GetTemperature(string location, string date)
{
// Placeholder for Weather API
if(location == "Seattle" && date == "2025-06-01")
{
return "75";
}
return "50";
}
// Create a tool to get the temperature
ChatTool GetTemperatureTool = ChatTool.CreateFunctionTool(
functionName: nameof(GetTemperature),
functionSchemaIsStrict: true,
functionDescription: "Get the projected temperature by date and location.",
functionParameters: BinaryData.FromBytes("""
{
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The location of the weather."
},
"date": {
"type": "string",
"description": "The date of the projected weather."
}
},
"required": ["location", "date"],
"additionalProperties": false
}
"""u8.ToArray())
);
// Create a chat with prompts
var chat = new List<ChatMessage>()
{
new SystemChatMessage("Extract the event information and projected weather."),
new UserChatMessage("Alice and Bob are going to a science fair in Seattle on June 1st, 2025.")
};
// Create a JSON schema for the CalendarEvent structured response
JSchemaGenerator generator = new JSchemaGenerator();
var jsonSchema = generator.Generate(typeof(CalendarEvent)).ToString();
// Get a chat completion from the AI model
var completion = chatClient.CompleteChat(
chat,
new ChatCompletionOptions()
{
ResponseFormat = ChatResponseFormat.CreateJsonSchemaFormat(
"calenderEvent",
BinaryData.FromString(jsonSchema)),
Tools = { GetTemperatureTool }
});
Console.WriteLine(completion.Value.ToolCalls[0].FunctionName);
// Structured response class
public class CalendarEvent()
{
public string Name { get; set; }
public string Date { get; set; }
public string Temperature { get; set; }
public List<string> Participants { get; set; }
}
開始使用
response_format
已設為 json_schema
,並設定了 strict: true
。
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
}
}
}
}'
輸出:
{
"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"
}
透過結構化輸出呼叫函式
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
}
}
}
]
}'
支援的結構描述與限制
Azure OpenAI 的結構化輸出支援與 OpenAI 相同的 JSON 結構描述子集。
支援的類型
- String
- 數值
- 布林值
- 整數
- Object
- 陣列
- 列舉
- anyOf
注意
根物件不能是 anyOf
類型。
所有欄位都必須是必要項目
所有欄位或函式參數都必須納入必要項目。 在下列範例中,location
和 unit
都是在 "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"]
}
如有需要,可以使用具有 null
的聯合類型來模擬選擇性參數。 在此範例中,使用了下列程式行來達成:"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"
]
}
}
巢狀項目深度
結構描述最多可以有總計 100 個物件屬性,最多五個巢狀項目層級
一律必須在物件中設定 additionalProperties: false
此屬性控制物件是否可以擁有在 JSON 結構描述中未定義的額外索引鍵/值組。 若要使用結構化輸出,您必須將此值設定為 false。
索引鍵排序
結構化輸出的排序方式與提供的結構描述相同。 若要變更輸出順序,請修改您在推斷要求中傳送的結構描述順序。
不支援的類型專屬關鍵字
類型 | 不支援的關鍵字 |
---|---|
String | minlength maxLength pattern format |
數字 | minimum maximum multipleOf |
物件 | patternProperties unevaluatedProperties propertyNames minProperties maxProperties |
陣列 | unevaluatedItems contains minContains maxContains minItems maxItems uniqueItems |
使用 anyOf 的巢狀結構描述必須遵守整體 JSON 結構描述子集
支援的 anyOf
結構描述範例:
{
"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": {
"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
}
支援遞迴結構描述
使用 # 進行根遞迴的範例:
{
"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
}
}
明確遞迴的範例:
{
"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"
]
}