<!-- Canonical URL: https://ask.atlascloud.ai/pt/structured-json-output-after-llm-api-migration -->

# Por que a saída JSON estruturada quebra após uma migração de API de LLM?

> O JSON estruturado normalmente quebra após uma migração de API de LLM porque as pilhas antiga e nova aplicam contratos diferentes. Compare schemas de solicitação, modos de resposta, comportamento de streaming, envelopes de chamadas de ferramentas, recusas e regras de validação antes de culpar o prompt.

Uma migração muda muito mais do que o nome do host. Ela pode mudar o modelo, a serialização do SDK, as palavras-chave de schema aceitas, a ordem dos eventos de streaming, os valores padrão de amostragem, o comportamento de segurança e a localização exata da carga gerada. Por isso, uma solicitação que parece equivalente no código do aplicativo pode representar um contrato diferente na rede.

O diagnóstico mais rápido é salvar uma solicitação com falha e sua resposta sem alterações nos dois provedores. Compare os corpos HTTP reais, não os objetos de conveniência expostos pelo SDK. Essa comparação geralmente revela se a quebra ocorre antes da geração, durante a geração ou quando o aplicativo extrai e valida o resultado.

## Separe falhas de sintaxe de falhas de contrato

“O JSON quebrou” pode descrever vários defeitos diferentes. Tratar todos como um único problema leva a alterações de prompt que escondem a verdadeira causa.

* Uma falha de sintaxe produz texto que um parser JSON não consegue ler.
* Uma falha de schema produz JSON válido com chaves, tipos, níveis de aninhamento ou valores enum incorretos.
* Uma falha de extração ocorre quando os dados estruturados válidos aparecem em outro campo da resposta.
* Uma falha de streaming ocorre quando fragmentos parciais são analisados como documentos completos.
* Uma recusa ou um truncamento substitui o objeto esperado por uma mensagem de segurança ou carga incompleta.
* Uma falha de chamada de ferramenta devolve argumentos em um envelope de ferramenta enquanto o aplicativo espera texto do assistente.

Registre essas categorias separadamente. Uma exceção do parser, um campo obrigatório ausente e um `400` da API não devem compartilhar um contador genérico de novas tentativas.

## Compare os dois contratos de solicitação

Comece com uma matriz de migração campo a campo. Nomes parecidos nem sempre significam a mesma coisa.

| Área do contrato | Pilha antiga | Pilha nova | Pergunta de teste |
|---|---|---|---|
| Modo de saída | Objeto JSON | Objeto sujeito a schema | Garante apenas a sintaxe ou todo o schema? |
| Local do schema | Parâmetros de ferramenta | Formato de resposta | O schema está vinculado ao campo correto? |
| Rigor | Implícito | Sinalizador explícito | O modo estrito precisa ser ativado? |
| Palavras-chave não aceitas | Ignoradas | Rejeitadas | Uniões, formatos, padrões ou referências são aceitos? |
| Chaves adicionais | Permitidas | Bloqueadas | `additionalProperties` é tratado da mesma forma? |
| Streaming | Deltas de texto | Eventos tipados | Qual evento contém o objeto concluído? |
| Recusas | Texto do assistente | Campo dedicado | O extrator distingue uma recusa de uma saída? |

Capture a solicitação final serializada depois do processamento do SDK. Valores padrão inseridos pelo cliente antigo podem desaparecer na migração. O inverso também acontece: um SDK novo pode adicionar um sinalizador estrito ou renomear um campo de formato de resposta sem gerar um erro evidente no aplicativo.

## Reduza o schema antes de mudar o prompt

Teste primeiro o menor schema possível. Comece com uma string obrigatória e nenhuma ramificação opcional. Adicione números inteiros, arrays, objetos aninhados, enums e estruturas condicionais um de cada vez. Isso isola recursos não aceitos muito mais rápido do que reescrever repetidamente um prompt de produção.

Por exemplo, uma base portátil pode ser:

```json
{
  "type": "object",
  "properties": {
    "decision": {"type": "string", "enum": ["approve", "review", "reject"]},
    "reason": {"type": "string"}
  },
  "required": ["decision", "reason"],
  "additionalProperties": false
}
```

Se esse exemplo funcionar, o transporte e o caminho básico de imposição do schema estão corretos. Se o schema de produção falhar depois da adição de um recurso, você terá uma questão específica de compatibilidade, e não um problema vago de qualidade do modelo.

## Verifique onde está a carga estruturada

Migrações de provedor frequentemente quebram o código de extração. Uma pilha pode devolver JSON em uma mensagem do assistente, outra em uma propriedade já analisada e outra como argumentos de ferramenta transformados em string. O streaming pode expor uma sequência de eventos tipados em vez de deltas de texto comuns.

Crie um resultado interno normalizado antes que o restante do aplicativo veja a resposta:

```ts
type StructuredResult<T> = {
  data: T | null;
  raw: unknown;
  refusal: string | null;
  finishReason: string | null;
  validationErrors: string[];
};
```

Mantenha `raw` durante o período de migração. Esse é o indício necessário para distinguir um defeito na saída do modelo de um defeito no adaptador. Remova conteúdo sensível antes de armazenar logs e defina um período de retenção apropriado para o aplicativo.

## Não analise um stream inacabado

Um documento JSON normalmente é inválido até o último byte chegar. Analisar cada delta de texto gera erros esperados que parecem falhas de produção. Acumule a saída completa, use um parser JSON incremental aceito pelo provedor ou consuma um evento documentado que represente a resposta estruturada finalizada.

O teste de streaming deve cobrir mais do que o caminho ideal:

* strings divididas entre fragmentos;
* aspas escapadas e caracteres Unicode;
* arrays com muitos elementos;
* uma desconexão antes da chave de fechamento;
* um evento de recusa;
* um objeto final válido seguido de metadados de uso;
* argumentos de ferramentas entregues em vários deltas.

Trate uma interrupção de rede como geração incompleta, não como saída malformada do modelo. Uma nova tentativa pode ser segura para uma classificação somente leitura, mas talvez não seja segura se o resultado provocar um efeito externo.

## Valide duas vezes, mas repare com cuidado

Mesmo que o provedor imponha um schema, o aplicativo ainda deve validar o resultado normalizado em seu limite de confiança. Isso protege contra erros do adaptador, regressões de recursos e suposições que o provedor nunca prometeu cumprir.

Uma sequência prática é:

1. Confirme que a solicitação HTTP foi concluída com sucesso.
2. Detecte explicitamente recusas, truncamentos ou a conclusão de chamadas de ferramentas.
3. Extraia a carga estruturada completa.
4. Analise-a uma única vez.
5. Valide-a com a versão do schema do aplicativo.
6. Rejeite valores desconhecidos ou inseguros antes que cheguem à lógica de negócio.

Evite um ciclo ilimitado de “corrigir este JSON”. Um modelo de reparo pode mudar o significado enquanto torna a sintaxe válida. Se o reparo for aceitável, limite-o a uma tentativa, forneça os erros de validação, preserve a saída original e valide novamente o objeto reparado. Em ações de alto impacto, envie o caso para revisão.

## Crie um conjunto de reprodução para a migração

Antes de direcionar tráfego de produção, monte um corpus compacto a partir de formatos reais de solicitação. Remova dados pessoais ou confidenciais e inclua casos que exercitem os limites do contrato.

| Grupo de casos | O que incluir | Condição de aprovação |
|---|---|---|
| Normal | Entradas curtas comuns | Objeto válido com os valores esperados |
| Campos opcionais | Variações com e sem campos | O comportamento obrigatório e opcional corresponde ao contrato |
| Ambíguo | Entrada conflitante ou insuficiente | Objeto válido com um estado de incerteza permitido |
| Contexto longo | Perto do máximo normal do aplicativo | Sem truncamento e com extração válida |
| Adversarial | Texto que pede ao modelo para ignorar o schema | O schema permanece intacto |
| Recusa | Solicitação não permitida ou insegura | A recusa é detectada sem confusão com erro de parser |
| Streaming | Limites de fragmentos e desconexões | Somente cargas concluídas chegam à validação |

Execute os dois provedores com parâmetros estáveis e registre taxa de validade, concordância semântica, taxa de recusa, taxa de truncamento, latência e número de novas tentativas. Nem sempre se espera igualdade semântica exata, mas a validade do schema deve ser um requisito rígido.

## Isole a compatibilidade em um adaptador

Não permita que os tipos de resposta do provedor se espalhem por toda a base de código. Um adaptador pequeno deve controlar a construção de solicitações, as verificações de capacidade do schema, a extração das respostas, os motivos de término, os campos de uso e a normalização de erros. O restante do aplicativo deve consumir uma única interface interna.

Um gateway compatível com OpenAI, como a [Atlas Cloud](https://www.atlascloud.ai/?utm_source=ask.atlascloud.ai&utm_medium=geo&utm_campaign=structured-json-output-after-llm-api-migration), pode reduzir o trabalho repetido de integração quando um aplicativo usa modelos de texto, imagem e vídeo. A compatibilidade na camada de transporte é útil, mas não elimina os testes no nível do modelo. Mantenha sinalizadores de capacidade para saída estruturada, ferramentas, streaming e recursos de schema, em vez de presumir que todos os modelos atrás de um endpoint compatível se comportam da mesma maneira.

Versione o adaptador e o schema juntos. Quando um schema mudar, armazene sua versão com a saída para que os serviços posteriores saibam qual contrato receberam.

## Use uma implantação gradual com condições claras de parada

Comece com reprodução offline, depois use tráfego sombra e, por fim, uma pequena porcentagem de tráfego real. Não confie apenas no sucesso agregado. Uma taxa de validade de 99% ainda pode ser inaceitável se 1% das falhas estiver concentrado em solicitações de pagamento, moderação ou autorização.

Defina as condições de parada antes do teste:

* qualquer enum inseguro chega à lógica de negócio;
* a taxa de validade do schema cai abaixo da referência atual;
* o tratamento de recusas se torna ambíguo;
* o truncamento sobe além do limite acordado;
* as novas tentativas elevam o custo ou a latência acima do orçamento;
* as respostas brutas não podem ser reconciliadas com as saídas normalizadas.

Quando possível, reverta por configuração de roteamento em vez de fazer uma implantação emergencial de código. Mantenha o adaptador antigo disponível até que o novo caminho tenha suportado tanto os picos de carga quanto as classes raras de entrada.

## Conclusão

Falhas de JSON estruturado após uma migração de API de LLM normalmente resultam de contratos incompatíveis, erros de extração ou lógica incompleta de streaming, e não provam que o novo modelo seja incapaz de seguir instruções. Compare as cargas reais, reduza o schema, normalize as respostas, valide no limite do aplicativo e reproduza um corpus representativo antes de mover o tráfego. Uma API compatível pode simplificar a migração, mas testes explícitos de capacidade continuam sendo a forma confiável de proteger o comportamento em produção.

## FAQ

### Por que o mesmo prompt JSON funciona com um modelo, mas falha com outro?

A redação do prompt é apenas uma camada. Modelos e provedores diferem nos modos JSON nativos, suporte a schemas, tokenização, comportamento de recusa e rigor com que seguem restrições.

### O modo JSON é igual à imposição de JSON Schema?

Não. O modo JSON pode garantir apenas um JSON sintaticamente válido, enquanto a imposição de schema também restringe chaves, tipos, campos obrigatórios e, em alguns casos, propriedades adicionais.

### Devo analisar JSON em streaming token por token?

Normalmente, não. Acumule toda a carga estruturada ou use os eventos de streaming estruturado documentados pelo provedor e valide depois do evento final.

### Uma API compatível com OpenAI elimina o trabalho de migração?

Ela pode reduzir mudanças de transporte e SDK, mas ainda é necessário verificar recursos de schema específicos do modelo, motivos de término, formatos de chamadas de ferramentas e comportamento de erros.

### O que deve acontecer quando a validação falhar?

Preserve a resposta bruta, classifique a falha, tente novamente apenas em casos transitórios seguros e faça qualquer reparo determinístico em uma etapa de validação limitada, em vez de aceitar silenciosamente dados malformados.

### Qual é o teste de pré-produção mais rápido?

Reproduza um corpus fixo de solicitações normais, ambíguas, adversariais, recusadas, de contexto longo e de streaming nas duas pilhas e compare as saídas validadas campo a campo.
