Structured Outputs em APIs OpenAI-compatible: guia JSON Schema

Guia prático de JSON Schema estrito com Responses e Chat Completions, validação em camadas, falhas e testes de compatibilidade da rota.

Structured Outputs permite solicitar JSON conforme a um Schema definido, em vez de apenas pedir ao modelo para “retornar JSON”. Em uma API OpenAI-compatible, o mesmo JSON Schema pode ser usado com Responses ou Chat Completions, mas o wrapper muda e o suporte deve ser verificado no modelo e na rota exatos.

O padrão seguro de production tem três camadas: usar Schema strict quando suportado, fazer parse e validação novamente na aplicação e, só então, aplicar regras de negócio determinísticas. Conformidade estrutural reduz erros de formato; não prova correção semântica ou factual.

Structured Outputs não é JSON mode

Método JSON válido Impõe o Schema Uso típico
Somente Prompt Não garantido Não Protótipos que toleram falha de parsing
JSON mode Sim, quando suportado e concluído Não JSON flexível validado pela aplicação
Structured Outputs com strict: true Sim, com tratamento de conclusão e refusal Sim, no subset suportado Extração tipada e workflows de aplicação

O guia OpenAI Structured Outputs recomenda essa opção em vez de JSON mode quando modelo e endpoint suportam. Formato estruturado serve para devolver um objeto previsível; Function Calling serve para solicitar uma ação da aplicação. Os Schemas podem ser semelhantes, mas Call IDs e mensagens de resultado pertencem a outro contrato.

Defina o Schema antes de escolher o endpoint

Uma triagem de suporte precisa de quatro campos:

{
  "type": "object",
  "properties": {
    "category": { "type": "string", "enum": ["billing", "technical", "account"] },
    "priority": { "type": "integer", "minimum": 1, "maximum": 3 },
    "requires_human": { "type": "boolean" },
    "summary": { "type": "string" }
  },
  "required": ["category", "priority", "requires_human", "summary"],
  "additionalProperties": false
}

Tornar tudo required e usar additionalProperties: false cria um objeto estável. Isso não torna todo keyword de JSON Schema portátil. OpenAI documenta um subset, enquanto outro provedor pode implementar um subset diferente ou não oferecer Strict Schema Mode.

Envie o Schema com Responses API

Responses coloca o Schema em text.format:

{
  "model": "<MODEL_WITH_VERIFIED_STRUCTURED_OUTPUT_SUPPORT>",
  "input": "The customer was charged twice and wants a refund.",
  "text": {
    "format": {
      "type": "json_schema",
      "name": "support_ticket",
      "schema": {
        "type": "object",
        "properties": {
          "category": { "type": "string", "enum": ["billing", "technical", "account"] },
          "priority": { "type": "integer", "minimum": 1, "maximum": 3 },
          "requires_human": { "type": "boolean" },
          "summary": { "type": "string" }
        },
        "required": ["category", "priority", "requires_human", "summary"],
        "additionalProperties": false
      },
      "strict": true
    }
  }
}

Envie para POST https://modelflare.dev/v1/responses com Authorization: Bearer <YOUR_API_KEY>. O conteúdo aparece em typed output items. SDKs podem oferecer helpers, mas um cliente HTTP deve localizar o texto completo e fazer parse; não assuma um objeto tipado no top level.

Envie o mesmo Schema com Chat Completions

Chat Completions usa response_format.json_schema:

{
  "model": "<MODEL_WITH_VERIFIED_STRUCTURED_OUTPUT_SUPPORT>",
  "messages": [
    { "role": "user", "content": "The customer was charged twice and wants a refund." }
  ],
  "response_format": {
    "type": "json_schema",
    "json_schema": {
      "name": "support_ticket",
      "schema": {
        "type": "object",
        "properties": {
          "category": { "type": "string", "enum": ["billing", "technical", "account"] },
          "priority": { "type": "integer", "minimum": 1, "maximum": 3 },
          "requires_human": { "type": "boolean" },
          "summary": { "type": "string" }
        },
        "required": ["category", "priority", "requires_human", "summary"],
        "additionalProperties": false
      },
      "strict": true
    }
  }
}

O JSON normalmente é uma string em choices[0].message.content e ainda precisa de parse.

Objetivo Responses API Chat Completions
Container text.format response_format.json_schema
Tipo text.format.type response_format.type
Nome text.format.name response_format.json_schema.name
Schema text.format.schema response_format.json_schema.schema
Strict text.format.strict response_format.json_schema.strict
Resultado Output items / helper choices[0].message.content

A camada de compatibilidade do Modelflare converte os wrappers em rotas OpenAI/Codex suportadas, mas não cria Structured Outputs em um modelo upstream sem o recurso. Em famílias Raw Chat Completions Pass-through, o contrato do provedor continua sendo a fonte de verdade.

Valide estrutura e significado separadamente

{
  "category": "billing",
  "priority": 2,
  "requires_human": true,
  "summary": "Customer reports a duplicate charge and requests a refund."
}

Validação estrutural

Um JSON Schema validator confirma properties required, ausência de extras, tipos, enum e limites. Mesmo com Strict Adherence, a validação protege contra rota incompatível, erro de integração, truncation e mudança futura.

Validação semântica e de negócio

O Schema não sabe se a cobrança duplicada existiu, se priority: 2 está correto ou quem pode aprovar reembolso. Trate o objeto como classificação proposta, compare com dados autoritativos e imponha permissão e limite financeiro em código determinístico. JSON válido nunca deve contornar autorização, billing ou segurança.

Trate saídas incompletas e excepcionais

Refusals

Verifique Status e representação do refusal antes de procurar JSON. Recusa de segurança não é erro de parsing.

Truncation e Output Limits

Se a geração para antes do fechamento, o Schema não recupera o sufixo. Confira Completion Status e Stop Reason e use Output Limit suficiente, porém limitado.

Keywords não suportados

Comece com Objects, Arrays, Primitive Types, Enums, Required e Additional Properties explícitos. Consulte a documentação antes de References, recursion, Unions complexas ou validação avançada.

Latência do primeiro Schema

Alguns provedores preprocessam e armazenam um Schema novo em cache. Reutilize Schemas estáveis e versionados e meça First Use separadamente do Steady State.

Modelo ou rota incompatível

Um endpoint pode aceitar Chat Completions, rejeitar json_schema ou ignorar strict. Um 200 com JSON não prova Strict Adherence. Inclua inputs inválidos e casos-limite.

Execute uma matriz de compatibilidade

Teste Evidência
Objeto required mínimo Status, modelo, rota, objeto e validação
Cada enum Produção e parse de todos os valores
Informação ausente Valor limitado ou pedido de esclarecimento
Input de segurança Formato de refusal e tratamento
Output Limit baixo Completion Status e truncation
Feature não suportada Erro explícito ou constraint ignorada
Wrappers Responses e Chat Objetos equivalentes na aplicação
Schema estável repetido First Use contra Steady State

Mantenha Schema, Prompt, Region, Streaming Mode e Output Limit constantes e registre a data.

Escolha o endpoint após testar o workflow

Responses é adequado para output items tipados, streaming events e workflows maiores de Tools. Chat Completions é adequado para integração por messages quando a rota suporta response_format. Veja Responses API vs Chat Completions.

Em qualquer opção:

  1. mantenha uma Source of Truth versionada para JSON Schema;
  2. altere apenas o wrapper, não o significado;
  3. valide a resposta completa;
  4. aplique regras determinísticas depois da estrutura;
  5. monitore parsing, refusal, truncation e compatibilidade separadamente.

Para migração, use o guia OpenAI-Compatible API; para streams incompletos, o guia AI API Streaming. Consulte Models & Pricing e teste Structured Outputs na rota exata da API Key.

Structured Outputs torna a resposta uma interface mais confiável, mas não substitui verificação factual, autorização ou lógica de billing. “OpenAI-compatible” continua sendo uma afirmação a testar recurso por recurso.