Saídas estruturadas

As saídas estruturadas fazem com que um modelo siga uma definição de Esquema JSON, que é fornecida por si como parte da chamada de API de inferência. Isto contrasta com a antiga funcionalidade de modo JSON , que garantia que JSON válido seria gerado, mas não conseguia garantir a estrita adesão ao esquema fornecido. Recomendam-se saídas estruturadas para chamadas de funções, extração de dados estruturados e construção de fluxos de trabalho complexos em vários passos.

Como começar

Pode usar Pydantic para definir esquemas de objetos em Python. Dependendo da versão do OpenAI e Pydantic das bibliotecas que estás a usar, talvez precises de 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 azure-identity --upgrade

Se é novo a usar Microsoft Entra ID para autenticação, veja Como configurar Azure OpenAI em Microsoft Foundry Models com autenticação Microsoft Entra ID.

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))

Produção

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

Saídas estruturadas para chamada de funções podem ser ativadas com um único parâmetro, fornecendo strict: true.

Nota

As saídas estruturadas não são suportadas com chamadas de função paralelas. Ao usar saídas estruturadas, defina parallel_tool_calls para 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))

Como começar

Adicione os seguintes pacotes ao seu projeto:

  • OpenAI: Biblioteca .NET OpenAI padrão.
  • Azure.Identity: Fornece suporte à autenticação de tokens do Microsoft Entra ID nas bibliotecas da SDK do Azure.
dotnet add package OpenAI
dotnet add package Azure.Identity

Se é novo a usar Microsoft Entra ID para autenticação, veja Como configurar Azure OpenAI em Microsoft Foundry Models com autenticação Microsoft Entra ID.

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")}");
}

Como começar

response_format é definido para json_schema com strict: true definido.

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
                    }
                }
          }
  }'

Saída:

{
  "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"
}

Chamada de função com saídas estruturadas

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
        }
      }
    }
  ]
}'

Suporte e limitações de esquema JSON

As saídas estruturadas do Azure OpenAI suportam o mesmo subconjunto do JSON Schema que o OpenAI.

Tipos suportados

  • Corda
  • Número
  • booleano
  • Integer
  • Objetivo
  • Array
  • Enum
  • qualquer um de

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 são ambos especificados sob "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 union com null. Neste exemplo, isto é 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 nidificação

Um esquema pode ter até 100 propriedades de objeto no total, com até cinco níveis de aninhamento

additionalProperties: false deve sempre ser configurado em objetos

Esta propriedade controla se um objeto pode ter outros pares-chave-valor que não foram definidos no Esquema JSON. Para usar saídas estruturadas, deve definir este valor como falso.

Ordenação de teclas

As saídas estruturadas estão ordenadas da mesma forma que o esquema fornecido. Para alterar a ordem de saída, modifique a ordem do esquema que envia como parte do seu pedido de inferência.

Palavras-chave específicas de tipo não suportadas

Tipo Palavra-chave não suportada
Corda comprimento mínimo
comprimentoMáximo
padrão
Formato
Número Mínimo
máximo
multipleOf
Objetos patternPropriedades
propriedadesnãoavaliadas
nomes de propriedades
minPropriedades
maxPropriedades
Matrizes itens não avaliados
contém
minContains
maxContains
minItems
maxItems
itens únicos

Esquemas aninhados que usam anyOf devem aderir ao subconjunto global 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"
    ]
}

São suportadas definições

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
}

São suportados esquemas recursivos

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"
    ]
}

Nota

Atualmente, as saídas estruturadas não são suportadas com:

Modelos suportados

  • gpt-5.1-codex Versão: 2025-11-13
  • gpt-5.1-codex mini Versão: 2025-11-13
  • gpt-5.1 Versão: 2025-11-13
  • gpt-5.1-chat Versão: 2025-11-13
  • gpt-5-pro Versão 2025-10-06
  • gpt-5-codex Versão 2025-09-11
  • gpt-5 Versão 2025-08-07
  • gpt-5-mini Versão 2025-08-07
  • gpt-5-nano Versão 2025-08-07
  • codex-mini Versão 2025-05-16
  • o3-pro Versão 2025-06-10
  • o3-mini Versão 2025-01-31
  • o1 Versão: 2024-12-17
  • gpt-4o-mini Versão: 2024-07-18
  • gpt-4o Versão: 2024-08-06
  • gpt-4o Versão: 2024-11-20
  • gpt-4.1 Versão 2025-04-14
  • gpt-4.1-nano Versão 2025-04-14
  • gpt-4.1-mini Versão: 2025-04-14
  • o4-mini Versão: 2025-04-16
  • o3 Versão: 2025-04-16

Suporte para API

O suporte para saídas estruturadas foi adicionado pela primeira vez na versão 2024-08-01-previewda API. Está disponível nas APIs de pré-visualização mais recentes, bem como na mais recente API GA: v1.