Como fazer o GPT-6 Astra devolver JSON confiável na sua integração

resposta JSON confiável do GPT-6 Astra validada por JSON Schema antes de integrar
Resposta rápida

Pedir JSON no texto do prompt não garante nada. Para o GPT-6 Astra devolver JSON confiável na sua integração, o caminho é Structured Outputs com JSON Schema e strict: true, que faz a saída corresponder ao schema, e não o JSON mode, que só melhora a chance de JSON sintaticamente válido. No Chat Completions o schema vai em response_format; no Responses API vai em text.format. Antes de gravar no banco, cheque programaticamente o campo refusal e o status incomplete, porque a geração pode parar no limite de tokens e devolver conteúdo pela metade

O que derruba integração quase nunca é o modelo errar o conteúdo, é ele mandar um "Claro, aqui está o JSON que você pediu:" antes da primeira chave

Aí o parser estoura, o worker morre e o registro nem chega no banco 😀

Fala aí, beleza? O GPT-6 Astra chegou dia 3 de setembro de 2026, atende pelo identificador gpt-6-astra na API e está disponível pela API da OpenAI, pela Microsoft Azure e pela AWS Bedrock

E ele tem recurso próprio de saída estruturada, o que muda o jogo: escrever "responda apenas em JSON" no prompt é, de longe, a parte mais frágil do seu pipeline

Este post é pra quem consome a resposta em código e grava em banco, não pra quem só conversa no chat…

Pedir JSON no prompt, JSON mode ou Structured Outputs: qual usar

Abordagem O que garante O que NÃO garante Quando usar
Instrução em texto no prompt ("responda só em JSON") Nada, é só uma pedida educada ao modelo Não garante nem JSON sintaticamente válido, nem os campos que você espera Rascunho, teste rápido no console, nada que rode sozinho
JSON mode (json_object) Melhora a chance da resposta ser JSON sintaticamente válido Não garante que a resposta siga um schema específico Quando você só precisa de um objeto JSON qualquer e valida os campos depois
Structured Outputs (JSON Schema + strict: true) A saída corresponde ao schema fornecido Não protege de recusa nem de geração cortada no meio Integração que grava em banco, fila, worker, qualquer coisa automatizada
Formação Claude Code
Formação Recomendada

Formação Claude Code

Domine Claude Code do absoluto zero até o avançado

  • 120 aulas
  • 4 projetos
  • 9h 45min

Repara na diferença entre as duas últimas linhas, porque é aqui que muita gente se enrola

O JSON mode cuida da sintaxe, o Structured Outputs cuida do contrato

E a primeira linha da tabela é a que mais quebra integração por um motivo simples: você não tem NENHUM mecanismo do lado da API te ajudando, a única coisa segurando seu banco é a boa vontade do modelo naquela requisição específica

Funciona um monte de vezes seguidas, aí numa delas vem um texto de cortesia grudado no objeto e o seu try/except vira o dono do produto

O que você precisa antes de começar

Acesso ao modelo:

Você precisa chamar o modelo pelo identificador gpt-6-astra, seja pela API da OpenAI, pela Azure ou pela AWS Bedrock

Mesmo nome, mesmo recurso de saída estruturada com JSON Schema, além de streaming e function calling

Chat Completions ou Responses API?

Essa decisão vem antes do código, porque o schema não mora no mesmo lugar nas duas

A OpenAI recomenda o Responses API para aplicações novas que precisam de saída estruturada, busca, funções customizadas ou estado multi-turno

Se o seu projeto já está inteiro em Chat Completions, dá pra fazer structured outputs nele também, só não copie payload de um pro outro (mais sobre isso no passo 3)

Os limites do schema aceito:

Aqui mora a maior parte dos erros de integração, e é bom saber antes de desenhar sua entidade

O Structured Outputs aceita apenas um subconjunto do JSON Schema

  • palavras-chave como minLength, maxLength e format não são suportadas
  • o aninhamento é limitado a 5 níveis
  • existe limite de tamanho total pros nomes de propriedades e pros valores de enum

Ou seja: validação de formato de e-mail, tamanho mínimo de string e afins continuam sendo trabalho SEU, do lado da aplicação

O schema garante a forma, não a regra de negócio

O teto operacional (e a conta no fim do mês):

O GPT-6 Astra trabalha com 1.050.000 tokens de contexto e até 128.000 tokens de completion

O preço de API é de US$ 10,00 por milhão de tokens de entrada e US$ 50,00 por milhão de tokens de saída, com leitura de cache a US$ 1,00 por milhão e escrita de cache a US$ 12,50 por milhão

Tome cuidado com um detalhe: prompts acima de 272 mil tokens de entrada entram numa faixa mais cara, US$ 20 de entrada e US$ 75 de saída por milhão

Se o seu fluxo empurra documento gigante pra dentro do prompt, esse degrau aparece na fatura sem avisar

Passo a passo: ligando Structured Outputs no GPT-6 Astra

  1. Escreva o schema já no formato que o modo strict exige

O modo strict tem duas exigências que pegam todo mundo de primeira: additionalProperties: false em CADA objeto e todos os campos de properties listados em required

Sim, todos. Inclusive os que você considera opcionais

{
  "name": "pedido",
  "schema": {
    "type": "object",
    "properties": {
      "cliente": { "type": "string" },
      "total_centavos": { "type": "integer" },
      "cupom": { "type": ["string", "null"] },
      "itens": {
        "type": "array",
        "items": {
          "type": "object",
          "properties": {
            "sku": { "type": "string" },
            "quantidade": { "type": "integer" }
          },
          "required": ["sku", "quantidade"],
          "additionalProperties": false
        }
      }
    },
    "required": ["cliente", "total_centavos", "cupom", "itens"],
    "additionalProperties": false
  }
}

Repara no cupom: campo opcional se resolve com um tipo que também aceita null, e não tirando ele de required

O erro comum deste passo: remover o campo de required achando que assim ele vira opcional. O schema é rejeitado e você fica caçando bug no lugar errado

  1. Mande o schema no Chat Completions com response_format

No Chat Completions, o schema entra em response_format com {"type": "json_schema"}, e é isso que faz a saída seguir o schema fornecido

from openai import OpenAI

client = OpenAI()

resposta = client.chat.completions.create(
    model="gpt-6-astra",
    messages=[
        {"role": "system", "content": "Extraia o pedido do texto do cliente"},
        {"role": "user", "content": texto_do_cliente},
    ],
    response_format={
        "type": "json_schema",
        "json_schema": {
            "name": "pedido",
            "strict": True,
            "schema": SCHEMA_PEDIDO,
        },
    },
)

O erro comum deste passo: esquecer o strict: True e sair contando pra equipe que o schema está garantido

É o strict que ativa a garantia real de aderência ao schema. Sem ele, aquele JSON Schema lindo que você escreveu volta a ser só uma sugestão pro modelo

  1. No Responses API, o schema muda de lugar

Aqui não tem response_format. O schema sai de lá e vai pra text.format

resposta = client.responses.create(
    model="gpt-6-astra",
    input=[
        {"role": "system", "content": "Extraia o pedido do texto do cliente"},
        {"role": "user", "content": texto_do_cliente},
    ],
    text={
        "format": {
            "type": "json_schema",
            "name": "pedido",
            "schema": SCHEMA_PEDIDO,
        }
    },
)

O erro comum deste passo: copiar o payload do Chat Completions e colar no Responses

O corpo é parecido o bastante pra parecer certo e diferente o bastante pra não funcionar, e o sintoma costuma ser aquele texto solto voltando sem estrutura nenhuma

  1. Use os helpers do SDK em vez de escrever schema na mão

Os SDKs oficiais convertem os seus tipos pra um schema suportado e já tratam recusa pra você

No Python, é classe Pydantic + responses.parse()

from pydantic import BaseModel

class ItemPedido(BaseModel):
    sku: str
    quantidade: int

class Pedido(BaseModel):
    cliente: str
    total_centavos: int
    cupom: str | None
    itens: list[ItemPedido]

resposta = client.responses.parse(
    model="gpt-6-astra",
    input=[{"role": "user", "content": texto_do_cliente}],
    text_format=Pedido,
)

No JavaScript, o caminho é o helper zodTextFormat com um schema Zod

import OpenAI from "openai";
import { zodTextFormat } from "openai/helpers/zod";
import { z } from "zod";

const Pedido = z.object({
  cliente: z.string(),
  total_centavos: z.number().int(),
  cupom: z.string().nullable(),
  itens: z.array(z.object({ sku: z.string(), quantidade: z.number().int() })),
});

const resposta = await client.responses.parse({
  model: "gpt-6-astra",
  input: [{ role: "user", content: textoDoCliente }],
  text: { format: zodTextFormat(Pedido, "pedido") },
});

Se você conhece serializer de framework web, é a mesma ideia: você declara o tipo uma vez e a ferramenta gera o contrato

O erro comum deste passo: manter dois schemas em paralelo, o do modelo e o da sua aplicação, e deixar eles divergirem com o tempo

  1. Valide ANTES de gravar no banco

Essa é a parte que separa demo de integração de verdade

A checagem tem que ser programática, nunca no olho: cheque o campo refusal e cheque se o conteúdo parseado voltou nulo

resultado = resposta.output_parsed

if resultado is None:
    # recusa ou resposta fora do schema: NÃO persiste
    registrar_para_revisao(resposta)
else:
    salvar_pedido(resultado)

Quando o modelo recusa um pedido, o conteúdo parseado vem nulo e a propriedade refusal vem preenchida

O erro comum deste passo: tratar recusa como erro de parsing e jogar num retry infinito. O modelo não vai mudar de ideia na terceira tentativa, você só vai queimar token de saída a US$ 50,00 por milhão

Quando o JSON vem quebrado no meio do fluxo automatizado

Structured Outputs resolve o formato, não resolve a vida

Se liga nos três casos que aparecem quando o pipeline já está rodando sozinho

A saída não segue o schema mesmo com Structured Outputs ligado:

Sintoma: a chamada volta 200, mas o objeto que você esperava não está lá, e o parse falha

Causa: recusa do modelo. A versão liberada aos usuários pagos recusa certos prompts, por exemplo em áreas como cibersegurança, e nesse caso a mensagem volta com refusal preenchido e a saída não segue o schema

Solução: checagem programática do refusal antes de qualquer parse, com caminho alternativo no pipeline (fila de revisão humana, fallback, o que fizer sentido no seu produto)

Como prevenir: trate recusa como um estado esperado do fluxo, com log próprio. Ela não é exceção de rede, é resposta legítima da API

O JSON vem cortado no meio:

Sintoma: objeto começa bonito e termina no meio de uma string, sem fechar a chave

Causa: mesmo com Structured Outputs, a saída pode falhar em seguir o schema se a geração atingir max_tokens ou outra condição de parada antes de terminar

No Responses API isso é sinalizado: vem "status": "incomplete" com incomplete_details.reason indicando max_output_tokens ou content_filter

E tem um caso que confunde bastante: com reason igual a max_output_tokens, a saída às vezes traz só itens do tipo reasoning e o output_text vem vazio

Solução: olhar o status ANTES de tentar parsear, e ajustar o teto de saída (lembrando que o modelo vai até 128.000 tokens de completion)

if resposta.status == "incomplete":
    motivo = resposta.incomplete_details.reason
    # max_output_tokens ou content_filter: não tente parsear
    reprocessar(resposta, motivo)

Como prevenir: peça só os campos que você vai gravar. Schema enxuto gera menos token de saída, corta menos e ainda sai mais barato

E se o incômodo for tempo de resposta e não formato, o Astra demorando pra responder é um problema separado, com outras causas

A function calling volta fora do schema:

Sintoma: os argumentos da ferramenta chegam com campo faltando ou tipo diferente do declarado

Causa: o padrão do strict é diferente nas duas APIs. No Chat Completions, as funções são não estritas por padrão. No Responses, omitir o strict tenta o modo estrito e, se o schema não for compatível, cai pra best-effort e retorna a ferramenta com strict: false

Ou seja: você acha que está no modo garantido e está no modo torcida

Solução: declarar strict explicitamente em toda ferramenta e conferir o que voltou na resposta, não o que você mandou

Como prevenir: manter o schema da função dentro do subconjunto suportado, senão o fallback silencioso te pega. A lógica é a mesma que vale pra tool calling no DeepSeek V4 Pro: argumento de ferramenta é contrato, não texto livre

Prevenção que vale pros três casos: schema dentro do subconjunto suportado, retry com limite e uma fila morta pro que falhar

O que cair na fila morta não precisa voltar em tempo real. Existe modo batch com preço próprio, listado separadamente como gpt-6-astra:batch, e reprocessamento em lote é exatamente o tipo de trabalho que cabe ali

JSON no dia a dia do dev: vídeo para contextualizar

Pra começar do zero com o assunto, este vídeo do canal mostra um dev front-end montando o backend só com JSON server e discute se isso é válido

Conclusão

A regra prática cabe em quatro linhas 🙂

Schema escrito no formato do modo strict, com additionalProperties: false e tudo em required

API certa pro seu caso, lembrando que o schema vive em response_format no Chat Completions e em text.format no Responses

Validação programática de refusal e de resposta incompleta antes de qualquer INSERT

E nada de tratar recusa como erro de rede

Próximo passo: monte o schema mínimo da sua entidade (só os campos que você grava mesmo), rode no Responses API com strict e adicione o tratamento de status incomplete no seu worker

Depois disso o deploy fica bem menos assustador…

até o próximo post!

Perguntas frequentes

Como saber se o GPT-6 Astra recusou o pedido em vez de gerar o JSON esperado?

A resposta traz um campo refusal justamente pra isso. Quando o modelo recusa um pedido inseguro, esse campo vem preenchido e a saída não segue o schema. Por isso a checagem tem que ser programática, checando refusal antes de tentar parsear o conteúdo.

Qual a diferença entre configurar Structured Outputs no Chat Completions e no Responses API?

No Chat Completions o schema entra em response_format com type json_schema. No Responses API o schema sai de response_format e vai pra text.format, no formato text: { format: { type: json_schema, name, schema } }. A OpenAI recomenda o Responses API pra apps novos que precisam de structured output, busca, funções customizadas ou estado multi-turno.

O JSON pode vir cortado no meio mesmo com Structured Outputs ligado?

Pode sim. O GPT-6 Astra aceita até 128.000 tokens de completion, mas se a geração bater em max_tokens ou outra condição de parada antes de terminar, a saída pode falhar em seguir o schema. No Responses API isso aparece como status incomplete, com incomplete_details.reason indicando max_output_tokens ou content_filter.

Dá pra usar Structured Outputs com Pydantic ou Zod no GPT-6 Astra?

Dá, os SDKs oficiais já têm helper pra isso. No Python usa uma classe Pydantic BaseModel com o método responses.parse(), no SDK JavaScript usa o helper zodTextFormat com schema Zod. Em caso de recusa, o conteúdo parseado vem nulo e a propriedade refusal é preenchida.

Quanto custa rodar Structured Outputs no GPT-6 Astra em volume alto?

Se o volume for grande e não precisar de resposta imediata, existe o modo batch com preço próprio, listado separadamente como gpt-6-astra:batch. Fora do batch, o preço padrão é US$ 10,00 por milhão de tokens de entrada e US$ 50,00 por milhão de saída, subindo pra US$ 20 de entrada e US$ 75 de saída quando o prompt passa de 272 mil tokens de entrada.

Function calling no GPT-6 Astra também usa strict, igual o Structured Outputs?

Usa, mas o comportamento padrão muda conforme a API. No Chat Completions as funções são não estritas por padrão, e no Responses, se você omitir o strict, ele tenta o modo estrito primeiro e, se o schema não for compatível, cai pra best-effort retornando a ferramenta com strict: false.




Escrito por | Matheus Battisti

Matheus Battisti
Fundador da Hora de Codar

Programador apaixonado pelo mundo das tecnologias, sempre buscando em aprender e se aprofundar em linguagens, frameworks e o que mais for necessário para executar um bom trabalho. Agora tem uma nova missão que é de passar seu conhecimento adiante para formar novos programadores e especializar mais os que já são.

Subscribe
Notify of
guest

0 Comentários
Oldest
Newest Most Voted

Formações

Formação Vibe Coding

Formação Vibe Coding

Do Prompt ao Produto: Crie Software Real com IA

  • 474 aulas
  • 20 projetos
  • 39h 27min

Blog | Mais populares