Структурированные выходные данные
Структурированные выходные данные позволяют модели соответствовать определению схемы JSON, предоставленному в рамках вызова API вывода. Это отличается от более старой функции режима JSON, которая гарантирует, что будет создано допустимое JSON, но не удалось обеспечить строгое соблюдение предоставленной схемы. Структурированные выходные данные рекомендуется использовать для вызова функций, извлечения структурированных данных и создания сложных многофакторных рабочих процессов.
Примечание.
В настоящее время структурированные выходные данные не поддерживаются:
- Создание собственных сценариев данных .
- Помощники или служба агентов ИИ Azure.
-
gpt-4o-audio-preview
иgpt-4o-mini-audio-preview
версия:2024-12-17
.
Поддерживаемые модели
-
o3-mini
version2025-01-31
-
o1
Версия:2024-12-17
-
gpt-4o-mini
Версия:2024-07-18
-
gpt-4o
Версия:2024-08-06
поддержка API
Поддержка структурированных выходных данных была добавлена в версию 2024-08-01-preview
API. Он доступен в последних предварительных версиях API, а также в последней версии API общедоступной версии: 2024-10-21
Начало работы
Можно использовать Pydantic
для определения схем объектов в Python. В зависимости от версии OpenAI и Pydantic
библиотек , которые вы используете, может потребоваться обновить до более новой версии. Эти примеры были проверены на openai 1.42.0
и pydantic 2.8.2
.
pip install openai pydantic --upgrade
Если вы не знакомы с использованием идентификатора Microsoft Entra для проверки подлинности, см . инструкции по настройке Службы Azure OpenAI с проверкой подлинности Идентификатора Microsoft Entra.
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 с определенными функциями Azure, которые создаются на основе стандартной зависимости библиотеки OpenAI .
- Azure.Identity: обеспечивает поддержку проверки подлинности маркера идентификатора Microsoft Entra в библиотеках пакета SDK Azure.
- Newtonsoft.Json.Schema: предоставляет полезные служебные программы для работы со схемами JSON.
dotnet add package Azure.AI.OpenAI --prerelease
dotnet add package Azure.Identity
dotnet add package Newtonsoft.Json.Schema
Если вы не знакомы с использованием идентификатора Microsoft Entra для проверки подлинности, см . инструкции по настройке Службы Azure OpenAI с проверкой подлинности Идентификатора Microsoft Entra.
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
set 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 поддерживают то же подмножество схемы JSON, что и OpenAI.
Поддерживаемые типы
- Строка
- Число
- Логический
- Целое
- 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.
Порядок ключей
Структурированные выходные данные упорядочены так же, как и указанная схема. Чтобы изменить порядок вывода, измените порядок схемы, которую вы отправляете в рамках запроса вывода.
Неподдерживаемые ключевые слова типа
Тип | Неподдерживаемое ключевое слово |
---|---|
Строка | minlength maxLength pattern format |
Число | minimum maximum multipleOf |
Объект | patternProperties unevaluatedProperties propertyNames minProperties maxProperties |
Массивы | unevaluatedItems Содержит 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"
]
}