
JSON válido ainda pode quebrar a automação — prenda a resposta ao schema

Para receber respostas tipadas na API da OpenAI, defina um JSON Schema compatível e use Structured Outputs com validação estrita. O guia de Structured Outputs da OpenAI distingue essa opção do JSON mode: este garante JSON válido, mas não exige que o objeto siga o schema esperado. A garantia estrutural pressupõe uma resposta concluída, sem recusa e com um schema aceito pela API.
Imagine, como exemplo hipotético, uma automação que espera uma categoria em texto. O objeto {"categoria": 7} é JSON válido, mas entrega um número no lugar da string esperada. Pedir no prompt que o modelo “responda neste formato” não estabelece a mesma exigência de estrutura; para migrar, é preciso declarar o contrato na chamada e consumir o resultado analisado.
Escolha entre resposta estruturada e chamada de função
Use o formato estruturado da resposta quando sua aplicação precisa receber dados do modelo, como uma classificação ou campos para compor uma interface. Na Responses API, um schema escrito diretamente vai em text.format, com type definido como json_schema, além de name, schema e strict: true. Os métodos parse dos SDKs permitem partir de um modelo Pydantic ou Zod em vez de montar esse objeto manualmente.
Use chamada de função quando o modelo precisa solicitar uma capacidade da aplicação, como consultar um cadastro. Nesse fluxo, o schema descreve os argumentos da ferramenta, e a solicitação aparece como um item function_call. Cabe à aplicação executar a função e, quando necessário, devolver seu resultado ao modelo. O formato dos argumentos não transforma essa chamada na resposta final que a automação deve consumir.
Ao migrar do JSON mode, identifique o destino do objeto. Se ele é a resposta que seu código vai ler, substitua json_object por um formato estruturado e obtenha o objeto analisado. Se ele contém parâmetros de uma operação, declare uma ferramenta estrita e trate a chamada como pedido de execução. Essa escolha determina onde procurar os dados na resposta.
Defina o tipo em Python com Pydantic
O guia do SDK Python documenta responses.parse() com uma classe Pydantic em text_format e o acesso ao resultado por output_parsed. No exemplo hipotético abaixo, categoria deve ser texto; resumo deve estar presente, mas pode valer null. Considere as linhas seguintes um único trecho de Python:
from pydantic import BaseModel
from openai import OpenAI
class Saida(BaseModel):
categoria: str
resumo: str | None
resposta = OpenAI().responses.parse(model='gpt-4o-mini', input='Classifique: entrega atrasada', text_format=Saida)
Depois de verificar o estado da resposta e a possibilidade de recusa, leia resposta.output_parsed. Se houver um objeto, resposta.output_parsed.categoria já pertence ao modelo declarado. No Pydantic usado nesse exemplo, a anotação str | None admite dois valores para resumo: uma string ou null. Ela não autoriza omitir a chave. Se o fluxo exige texto preenchido, declare resumo como str e trate conteúdo inadequado segundo as regras da aplicação.
Repita o contrato em TypeScript com Zod
A documentação do SDK para Node mostra que zodTextFormat() converte um schema Zod para o formato estrito enviado à Responses API e que responses.parse() devolve o resultado validado em output_parsed. O exemplo hipotético equivalente, dentro de uma função assíncrona, usa nullable() para permitir null sem tornar a propriedade opcional:
import OpenAI from 'openai';
import { zodTextFormat } from 'openai/helpers/zod';
import { z } from 'zod/v4';
const Saida = z.object({ categoria: z.string(), resumo: z.string().nullable() });
const resposta = await new OpenAI().responses.parse({ model: 'gpt-4o-mini', input: 'Classifique: entrega atrasada', text: { format: zodTextFormat(Saida, 'saida') } });
Verifique o estado e o conteúdo da resposta antes de usar resposta.output_parsed. Esse valor é null quando não há texto final analisado, por exemplo em uma resposta incompleta; isso é diferente de receber um objeto válido cujo campo resumo vale null. Use uma importação de Zod compatível com a versão instalada no projeto.
Para argumentos de ferramentas na Responses API, o helper é zodResponsesFunction(). Ele prepara parâmetros estritos e disponibiliza parsed_arguments no item function_call correspondente. A função da aplicação ainda precisa ser executada pelo seu código; gerar e analisar os argumentos não realiza a operação.
Monte um JSON Schema que a API aceite
A raiz do schema deve ser um objeto, e todas as propriedades declaradas precisam constar em required. Defina additionalProperties: false em cada objeto, inclusive nos aninhados, para impedir chaves extras. Um campo que pode ficar sem valor continua obrigatório: seu tipo pode aceitar tanto string quanto null. Assim, a aplicação distingue a presença da chave com valor null da ausência da chave.
O subconjunto aceito inclui string, number, integer, boolean, object, array, enum, anyOf dentro de uma estrutura válida e definições reutilizáveis em $defs. Há suporte a restrições como pattern e format para texto, limites numéricos e limites de itens em arrays nos modelos aos quais elas se aplicam. Uma união anyOf na raiz não é aceita; palavras de composição como allOf, not e if/then/else também ficam fora. Modelos ajustados por fine-tuning têm restrições adicionais para algumas validações de strings, números e arrays.
Com strict: true, um schema incompatível provoca erro na solicitação: corrija o contrato em vez de repetir a mesma chamada. Mesmo um objeto conforme ao schema pode contrariar uma regra própria do produto. Se categoria precisa corresponder a um registro existente no seu cadastro, faça essa verificação no código antes de disparar a próxima etapa.
Trate recusa, null e falha de validação separadamente
Uma recusa pode vir fora do schema solicitado. Também é possível a resposta terminar incompleta, sem um objeto analisado. Por isso, não encaminhe output_parsed à automação apenas porque a chamada à API retornou: inspecione o estado da resposta e seus itens de saída antes de consumir os campos.
- Se o status indicar resposta incompleta, examine incomplete_details. Um limite de saída e uma interrupção por filtro de conteúdo exigem tratamentos distintos; qualquer nova tentativa deve ter uma causa identificada.
- Procure conteúdo do tipo refusal nos itens de saída. Encaminhe-o como recusa, sem tratá-lo como erro de parsing nem repetir a mesma solicitação às cegas.
- Confirme que output_parsed contém um objeto. A ausência desse resultado indica que ainda não há dados tipados para a próxima etapa, mesmo que um campo anulável pudesse legitimamente valer null.
- Se o parser lançar um erro de validação, preserve o erro para diagnóstico e confira o schema, o SDK e o conteúdo recebido. Depois de obter um objeto válido, aplique também as regras de negócio aos seus campos.
Leia também:
Artigos relacionados


IA no failover: deixe o modelo escolher e o código executar

Google ADK ou OpenAI Agents SDK: estrutura pesa mais que o modelo

AWS aquece o SDK Java — a primeira chamada deixa de pagar o atraso

Chave exposta no SageMaker permite executar código — atualizar não basta

Seu RAG responde certo pelo motivo errado — meça contexto e fidelidade
Assine nossa newsletter
Receba as últimas notícias sobre Web3, IA e cripto diretamente no seu e-mail.