Ao final deste guia, você será capaz de chamar saídas estruturadas do OpenAI a partir do seu próprio código: forneça um JSON Schema ao modelo, defina strict: true e receba uma resposta que é garantida para corresponder ao formato que você solicitou. Você enviará uma primeira requisição, lerá a resposta, tratará os casos extremos e gerará coleções de testes de API no Apidog que afirmam que o payload realmente está em conformidade.
O que você precisa antes de começar
Saídas estruturadas restringem a geração do modelo para que a saída esteja em conformidade com um JSON Schema que você fornece. Ao passar um esquema com strict: true, o modelo não pode emitir um campo que o viole. Cada chave obrigatória está presente, cada tipo corresponde e cada valor de enumeração é um dos que você listou. Você para de escrever código de parsing defensivo e começa a confiar no payload.
Essa é uma verdadeira melhoria em relação à alternativa. Prompts de texto livre como "responda apenas com JSON" funcionam até que não funcionem mais. Um desvio de raciocínio e você obtém prosa envolvendo seu objeto, ou uma data onde você esperava um número inteiro. As saídas estruturadas movem o contrato de uma instrução esperançosa para uma restrição imposta no momento da decodificação.
Para acompanhar, você precisa:
- Uma chave de API OpenAI definida como
OPENAI_API_KEY. - Um modelo que suporte a aplicação estrita de esquema (mais sobre quais modelos abaixo).
- Um JSON Schema descrevendo o formato que você deseja de volta.
Escolha o modelo certo
Saídas estruturadas estão disponíveis nos modelos recentes do OpenAI, começando com a família GPT-4o e continuando com a série GPT-5. A documentação do OpenAI atualmente recomenda iniciar novos projetos em seu carro-chefe mais recente (gpt-5.5 no momento da escrita). Modelos mais antigos, e modelos da era gpt-3.5, suportam o modo JSON, mas não a aplicação estrita de esquema. Se você depende de strict: true, confirme se o ID do modelo específico o suporta antes de implantar, já que o suporte está vinculado às versões do modelo e o OpenAI as atualiza.
Ajuda saber qual recurso você está realmente buscando, porque o OpenAI oferece dois recursos relacionados que são fáceis de confundir.
Modo JSON (response_format: { "type": "json_object" }) garante que a saída é JSON sintaticamente válido. É só isso. Ele não conhece seus campos, seus tipos ou suas chaves obrigatórias. Você ainda precisa validar o formato por conta própria.
Saídas estruturadas (response_format com type: "json_schema" e strict: true) garante que a saída é JSON válido e corresponde ao seu esquema. O OpenAI descreve as saídas estruturadas como a evolução do modo JSON: ambos produzem JSON válido, mas apenas as saídas estruturadas impõem a aderência ao esquema. Para novos trabalhos, as saídas estruturadas são as que você deseja.
| Modo JSON | Saídas estruturadas (strict) | |
|---|---|---|
| Parâmetro | response_format: {"type":"json_object"} |
response_format com type: "json_schema", strict: true |
| JSON Válido | Sim | Sim |
| Corresponde ao seu esquema | Não | Sim |
| Campos obrigatórios impostos | Não | Sim |
| Tipos e enums impostos | Não | Sim |
| Você ainda valida a jusante | Sempre | Recomendado (veja abaixo) |
Uma nota sobre APIs: o endpoint de Chat Completions usa response_format conforme mostrado acima. A API de Respostas mais recente expressa a mesma coisa em text.format com type: "json_schema". As regras de esquema são idênticas; apenas o invólucro difere. Verifique a documentação atual para o caminho exato do campo no endpoint que você chama.
Faça sua primeira requisição
Digamos que você esteja extraindo um ticket de suporte para um registro tipado. Aqui está uma requisição de Chat Completions com um esquema estrito.
curl https://api.openai.com/v1/chat/completions \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-5.5",
"messages": [
{ "role": "system", "content": "Extract the ticket into the schema." },
{ "role": "user", "content": "My checkout 500s every time I use a saved card. Started today. Account: acct_8842." }
],
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "support_ticket",
"strict": true,
"schema": {
"type": "object",
"properties": {
"summary": { "type": "string" },
"category": { "type": "string", "enum": ["billing", "bug", "account", "other"] },
"severity": { "type": "integer" },
"account_id": {
"anyOf": [ { "type": "string" }, { "type": "null" } ]
}
},
"required": ["summary", "category", "severity", "account_id"],
"additionalProperties": false
}
}
}
}'
Leia a resposta
O modelo retorna uma mensagem cujo content é uma string JSON que corresponde a esse esquema, por exemplo:
{
"summary": "Checkout returns HTTP 500 when paying with a saved card",
"category": "bug",
"severity": 3,
"account_id": "acct_8842"
}
Observe que account_id usa anyOf com null. É assim que você modela um campo opcional, o que nos leva diretamente às regras que você deve seguir ao escrever seus próprios esquemas.
Mantenha-se dentro do subconjunto de esquema
Saídas estruturadas aceitam um subconjunto de JSON Schema. O subconjunto existe para que o OpenAI possa impor as restrições de forma confiável e armazenar em cache o esquema compilado. As regras que valem a pena memorizar:
- A raiz deve ser um objeto. Você não pode tornar o nível superior um array ou uma string simples. Envolva uma lista em uma propriedade de objeto.
- Toda propriedade deve estar listada em
required. Não há "opcional" no sentido usual. Para tornar um campo anulável, forneça-lheanyOfcom um tiponull, como no exemplo acima. additionalPropertiesdeve serfalseem todo objeto. Isso impede que o modelo invente chaves extras.- Limites de tamanho se aplicam. Um esquema pode conter até aproximadamente 100 propriedades de objeto com até 5 níveis de aninhamento. Esquemas profundamente aninhados ou muito extensos são rejeitados, então achate-os onde puder.
- Algumas palavras-chave não são impostas. Palavras-chave apenas de validação como
pattern,format,minLengtheminimumnão são garantidas pelo modelo. Se você precisa que uma regex ou um intervalo numérico seja respeitado, ainda terá que verificá-lo você mesmo após o recebimento da resposta. - Latência na primeira chamada. A primeira requisição com um novo esquema gasta tempo compilando-o (geralmente segundos, às vezes até um minuto para esquemas complexos). Depois disso, ele é armazenado em cache e é rápido.
Como as palavras-chave de validação não são impostas, "JSON garantido" não significa "negócio-válido garantido". A estrutura está bloqueada. Os valores internos ainda merecem um teste. Se você já modelou campos opcionais ou de união com oneOf/anyOf/allOf, o modelo mental é familiar: um esquema restringe a forma, mas você afirma os valores reais separadamente.
Lidar com recusas e truncamento
Existe um caso em que a saída não corresponderá ao seu esquema de propósito. Se o modelo recusar uma requisição insegura, ele retorna um campo refusal na mensagem em vez de conteúdo formatado pelo esquema. Seu código deve ramificar nesse ponto antes de fazer o parsing:
msg = response.choices[0].message
if msg.refusal:
handle_refusal(msg.refusal)
else:
ticket = json.loads(msg.content)
As recusas agora são detectáveis programaticamente, o que é mais limpo do que escanear o texto em busca de um pedido de desculpas. Duas outras maneiras pelas quais uma resposta pode não atender ao esquema: atingir max_tokens no meio do objeto (o JSON é truncado), ou usar chamadas de ferramentas paralelas, que as saídas estruturadas não suportam. Defina parallel_tool_calls como false ao combinar os dois.
Como testar no Apidog
O modo estrito impõe o esquema no momento da geração. Isso não o exime de testar. Modelos são trocados, esquemas mudam, um colega de equipe edita o array required, ou um caminho de recusa muda. Você quer um teste que falhe ruidosamente quando a resposta parar de corresponder ao contrato. É aí que o Apidog se encaixa.

Para ser preciso sobre a divisão de trabalho: o modo estrito do OpenAI é o que produz JSON válido para o esquema. O Apidog não impõe o esquema no modelo. O que o Apidog faz é validar a resposta que você recebeu contra o esquema que você espera, para que você detecte desvios na CI em vez de na produção.
Aqui está o fluxo de trabalho:
- Envie a requisição. Construa a chamada de Chat Completions no Apidog com seu bloco
response_format. Salve-o em uma coleção para que seja repetível. - Afirme o formato. Adicione asserções de resposta no Apidog. Verifique se
categoryé um dos seus valores de enumeração, seseverityé um número inteiro, seaccount_idé uma string ou nulo. O Apidog pode validar a resposta contra o JSON Schema, para que você anexe o esquema exato e falhe a execução quando o payload se desviar. - Execute na CI. Coloque a coleção em seu pipeline para que cada mudança de modelo ou prompt verifique novamente a conformidade. Uma quebra de esquema silenciosa se torna uma compilação vermelha.
- Simule o contrato. Antes que a chamada real exista, ou para testar consumidores a jusante sem gastar tokens, configure uma API mock que retorne respostas de exemplo válidas para o esquema. Seu frontend e seus testes são executados contra um formato estável enquanto a integração se solidifica.
Esse último ponto é o subestimado. Você pode desenvolver e testar tudo que consome a saída estruturada contra um mock que respeita o mesmo esquema, e então trocar pela chamada real do OpenAI quando estiver pronto. Baixe o Apidog e você poderá construir a requisição, as asserções e o mock em um só lugar.
Perguntas frequentes
O modo JSON foi descontinuado agora que existem saídas estruturadas? O modo JSON ainda funciona e ainda garante JSON válido. Ele apenas não impõe um esquema. Para código novo, saídas estruturadas com strict: true é a escolha mais forte. Use o modo JSON simples apenas em modelos que não suportam esquemas estritos, ou quando você realmente não tem um formato fixo.
A raiz do meu esquema pode ser um array? Não. O nível superior deve ser um objeto. Envolva sua lista em uma propriedade, como { "items": [...] }, e coloque items em required. Isso confunde muitas pessoas no primeiro dia.
Como faço para tornar um campo opcional? As saídas estruturadas exigem que toda propriedade esteja em required, então não há um campo opcional clássico. Modele "ausente" como anulável: use anyOf com uma string (ou qualquer tipo) e um null. A chave está sempre presente; seu valor pode ser null.
O modo estrito significa que posso pular a validação inteiramente? A estrutura é garantida, então você pode pular as verificações de formato. Mas palavras-chave como pattern, format e intervalos numéricos não são impostas pelo modelo, e recusas ou truncamento ainda podem produzir respostas fora das especificações. Um teste de conformidade ainda é útil. Se você é novo no formato, este manual básico de JSON Schema cobre os blocos de construção, e você pode executar a verificação em cada implantação.
Quais modelos devo usar? As saídas estruturadas funcionam no GPT-4o e posteriores, incluindo a série GPT-5. A documentação do OpenAI aponta novos projetos para o seu carro-chefe atual. Confirme se o ID do modelo exato suporta o modo estrito antes de depender dele, já que o suporte acompanha as versões do modelo.
Conclusão
Agora você tem o ciclo completo: escolha um modelo que suporte o modo estrito, envie uma requisição de Chat Completions com json_schema e strict: true, mantenha seu esquema dentro do subconjunto suportado, ramifique em refusal e lembre-se que as regras de nível de valor ainda precisam ser verificadas. Em seguida, prove isso com um teste: construa a requisição no Apidog, afirme a resposta contra seu esquema e simule-a para que o restante da sua pilha possa avançar enquanto a integração se estabelece. O modelo promete o formato. Seus testes provam que ele permaneceu assim.
