Resultados estruturados
As saídas estruturadas fazem com que um modelo siga uma definição de esquema JSON que você fornece como parte de sua chamada de API de inferência. Isso contrasta com o recurso de modo JSON mais antigo, que garantia que JSON válido seria gerado, mas não era possível garantir a estrita adesão ao esquema fornecido. As saídas estruturadas são recomendadas para chamada de função, extração de dados estruturados e criação de fluxos de trabalho complexos em várias etapas.
Nota
- Atualmente, as saídas estruturadas não são suportadas no cenário bring your own data .
Modelos suportados
o1
Versão:2024-12-17
gpt-4o-mini
Versão:2024-07-18
gpt-4o
Versão:2024-08-06
Suporte de API
O suporte para saídas estruturadas foi adicionado pela primeira vez na versão 2024-08-01-preview
API. Ele está disponível nas APIs de visualização mais recentes, bem como na API GA mais recente: 2024-10-21
.
Introdução
Você pode usar Pydantic
para definir esquemas de objeto em Python. Dependendo da versão do OpenAI ePydantic
das bibliotecas que você está executando, talvez seja necessário atualizar para uma versão mais recente. Estes exemplos foram testados contra openai 1.42.0
e pydantic 2.8.2
.
pip install openai pydantic --upgrade
Se você é novo no uso do Microsoft Entra ID para autenticação, consulte Como configurar o Serviço Azure OpenAI com a autenticação do Microsoft Entra ID.
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))
Saída
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
}
}
Chamada de função com saídas estruturadas
As saídas estruturadas para chamada de função podem ser ativadas com um único parâmetro, fornecendo strict: true
.
Nota
Não há suporte para saídas estruturadas com chamadas de função paralelas. Ao usar saídas estruturadas definidas parallel_tool_calls
como 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))
Esquemas e limitações suportados
As saídas estruturadas do Azure OpenAI suportam o mesmo subconjunto do esquema JSON que o OpenAI.
Tipos suportados
- String
- Número
- Booleano
- Número inteiro
- Object
- Matriz
- Enumeração
- qualquerOf
Nota
Os objetos raiz não podem ser do anyOf
tipo.
Todos os campos devem ser obrigatórios
Todos os campos ou parâmetros de função devem ser incluídos conforme necessário. No exemplo abaixo location
, e unit
ambos são especificados em "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"]
}
Se necessário, é possível emular um parâmetro opcional usando um tipo de união com null
. Neste exemplo, isso é conseguido com a linha "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"
]
}
}
Profundidade de aninhamento
Um esquema pode ter até 100 propriedades de objeto no total, com até cinco níveis de aninhamento
additionalProperties: false deve sempre ser definido em objetos
Essa propriedade controla se um objeto pode ter pares de valores de chave adicionais que não foram definidos no esquema JSON. Para usar saídas estruturadas, você deve definir esse valor como false.
Ordenação de chaves
As saídas estruturadas são ordenadas da mesma forma que o esquema fornecido. Para alterar a ordem de saída, modifique a ordem do esquema que você envia como parte de sua solicitação de inferência.
Palavras-chave específicas do tipo não suportadas
Type | Palavra-chave não suportada |
---|---|
String | comprimento mínimo maxComprimento pattern format |
Número | mínimo máximo múltiploDe |
Objetos | patternProperties propriedades não avaliadas propertyNames minPropriedades maxPropriedades |
Matrizes | unevaluationItems contém: minContém maxContém minItens maxItens uniqueItems |
Os esquemas aninhados que usam anyOf devem aderir ao subconjunto geral do esquema JSON
Exemplo de esquema suportado 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"
]
}
As definições são suportadas
Exemplo suportado:
{
"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
}
Esquemas recursivos são suportados
Exemplo usando # para recursão raiz:
{
"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
}
}
Exemplo de recursão explícita:
{
"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"
]
}