Postagens anteriores desta série abordadaspor que os agentes precisam de JSON(Chamada de ferramenta para fluxo de dados MCP),por que JSON Schema⟧ se tornou infraestrutura(Esquema, Chamada de Função e evolução MCP), eConfiguração Structured Output específica do Gemini(Guia Gêmeos API).
Este artigo diminui o zoom:independentemente de qual modelo API você usa, como você passa de “responda em JSON” para “a saída deve corresponder a este JSON esquema⟧”? Os fornecedores convergiram para isso em 2024-2026 sob nomes como Structured Outputs⟧ / JSON Schema⟧ mode - mesma ideia, nomes de campo ligeiramente diferentes, subconjuntos de esquema e limites com Tool Calling.
Quatro níveis, cada um estritoer que o anterior
As equipes normalmente usam quatro abordagens para obter JSON de um modelo – a confiabilidade difere em uma ordem de grandeza:
| Nível | Abordagem | O que você controla | Falha típica |
|---|---|---|---|
| L0 | Somente prompt: “saída JSON” | Restrição suave | ```json fences, prose, single quotes, trailing commas |
| L1 | Prompt + exemplos JSON de algumas fotos | Molde pelo exemplo, sem regras rígidas | Desvio de nome de campo, campos ausentes, tipos mistos |
| L2 | JSON Mode⟧ (response_format: json_object, etc.) | A saída deve ser válida JSON | Parses, but price may be a string |
| L3 | Saída Estruturada+ JSON Esquema⟧ | Campos, tipos, enum, obrigatórios | Alucinação semântica, truncamento, palavras-chave ignoradas |
For production extraction, classification, or form filling, aim for L3. L0–L1 suit exploration; L2 when shape varies and you only need JSON.parse. L3 is the contract programs can consume directly.
O que o JSON Schema⟧ controla — e o que não controla
JSON Esquema⟧descreve a estrutura do documento: campos, tipos, chaves obrigatórias, enumerações, intervalos, formato do item da matriz. As Structured Outputs do fornecedor compilam esse esquema na geração - não apenas cola-o no prompt.
Schema can enforce: syntax shape (object / array / string / integer), required, enum, minimum / maximum, additionalProperties: false, nested objects and arrays.
Schema cannot enforce business correctness. Example: “total_cents must equal sum of line items” — assert that in code after Schema validation. Schema also does not fact-check: a well-typed fabricated invoice number is still hallucination.
Tool inputSchema uses the same language; Structured Output constrains the final reply, Tool Calling constrains tool arguments. See guia de fluxo de dados.
Decodificação restrita: por que o Schema supera o Prompt
As solicitações apenas aumentam as chances de conformidade. Saída Estruturada usadecodificação restrita: em cada token, o decodificador suprime tokens que quebrariam a sintaxe JSON ou violariam o esquema.
Você geralmente obtém JSON analisável e com formato correto, sem barreiras de marcação de remoção de regex. As implementações diferem (FSM, gramática, máscaras logit), mas o contrato do desenvolvedor é o mesmo:passe o esquema para a API, não apenas para o prompt.
Garantias de decodificação restritasestrutura, nãosemântica. Sempre revalide com o mesmo esquema e adicione regras de negócio em produção.
Comparação OpenAI, Gemini, Anthropic
Mesmo conceito, nomes de campo diferentes. Exemplo: extrair um objeto de fatura.
| Fornecedor | JSON Modo⟧ | Saída Estruturada / Esquema | Notas |
|---|---|---|---|
| OpenAI | response_format: { type: "json_object" } | response_format: { type: "json_schema", json_schema: { name, schema, strict: true } } | strict: true rejects undeclared fields; works with Pydantic model_json_schema() |
| Google Gêmeos | responseMimeType: "application/json" | Above + responseJsonSchema or SDK response_schema | Verartigo dedicado Gemini API |
| Antrópico | Solicitar + analisar | output_format (Claude structured output) or schema in Messages API | Os campos evoluem com o SDK; manter o esquema plano |
When migrating vendors, keep the Schema itself standard JSON Schema⟧ (type, properties, required, enum); SDKs only wrap the request. Do not mix OpenAPI 3.0 uppercase types (OBJECT) with JSON Schema⟧ lowercase (object).
Escrevendo um bom esquema: do Pydantic à produção
Recommended flow: define types in Pydantic / Zod → export JSON Schema⟧ → tune → send to API. Put semantics in description — it enters model context and disambiguates “qty = pieces vs boxes”; type: integer alone cannot.
from pydantic import BaseModel, Field
class LineItem(BaseModel):
name: str = Field(description="Product name")
qty: int = Field(description="Quantity, positive integer", ge=1)
unit_price_cents: int = Field(description="Unit price in cents", ge=0)
class Invoice(BaseModel):
vendor: str
currency: str = Field(description="ISO 4217, e.g. CNY")
items: list[LineItem]
total_cents: int
schema = Invoice.model_json_schema()
# In production add additionalProperties: false
Regras práticas:
- Prefer object root over root-level array;
{ "items": [...] }is more stable on some APIs. - Start with type / properties / required / enum, then add
additionalProperties, min/max; do not dump full Draft 2020-12 — some keywords are ignored. - Continue aninhando superficialmente; referências circulares são rejeitadas - nivelar o esquema.
- Esquema dividido vs prompt: Esquema = forma; Prompt = semântica (“extrair fatura do texto abaixo…”).
OpenAI Saída Estruturadas⟧ exemplo
Chat Completions supports json_schema response format since 2024. With strict: true, output should only contain Schema fields:
from openai import OpenAI
from pydantic import BaseModel
client = OpenAI()
class Invoice(BaseModel):
vendor: str
total_cents: int
response = client.chat.completions.create(
model="gpt-4o-2024-08-06",
messages=[
{"role": "user", "content": "Extract invoice: Acme sold 2 keyboards for 398 CNY."}
],
response_format={
"type": "json_schema",
"json_schema": {
"name": "invoice",
"strict": True,
"schema": Invoice.model_json_schema(),
},
},
)
data = response.choices[0].message.content # JSON string
import json
invoice = json.loads(data)
Gemini uses response_mime_type + response_json_schema — see the dedicated Gemini API article. For Anthropic, check current SDK structured output docs — same idea, official field names.
Pipeline de produção: gerar → analisar → validar → tentar novamente
Saída Estruturada não é “uma chamada de API e pronto”. Corrija estas quatro etapas:
- Generate: call model with Schema; log prompt, Schema version, raw
content. - Parse:
JSON.parse(or SDKparsed); on failure, retry whole response — no half-parse. - Schema validate: run same JSON Schema⟧ via AJV /
jsonschema/ Pydantic; retry or degrade on failure. - Validação de negócios: declarações personalizadas (totais, chaves estrangeiras); mecanismo humano ou de regras em caso de falha.
No desenvolvimento, armazene o Schema mais 2–3 amostras positivas/negativas no repositório; use JSON Toolbox⟧ localmente para estrutura e Diff - mesma mentalidade dos testes de contrato REST, o consumidor é o LLM.
Armadilhas comuns: pedir “explique então JSON” enquanto o JSON Mode⟧ está ativado; truncamento (aumentar o máximo de tokens ou dividir tarefas); Chaves API em demonstrações de frontend; Desvio da versão do esquema no prompt.
Como isso difere de Tool Calling
| Saída Estruturada | Chamada de ferramenta / MCP | |
|---|---|---|
| Restrições | Resposta final JSON ao usuário | Tool argument JSON (inputSchema) |
| Efeitos colaterais | Nenhum – apenas dados | Host / MCP Servidor é executado |
| Uso típico | Extrair, classificar, preencher formulários, transferir agentes | Inventário, arquivos, APIs externas |
| Em caso de falha | Tente novamente ou humano | Erro na mensagem da ferramenta → perguntar novamente ao modelo |
Um loop de agente completo geralmente se parece com:Saída Estruturada extrai intenção → Chamada de Ferramenta atos → Saída Estruturada ou resumos em prosa para o usuário. Não use Structured Output para fingir que “o API de pagamento foi chamado” – o modelo não o chamou.
Perguntas frequentes
“Por favor, envie JSON” no prompt é suficiente?
Não. Os prompts apenas aumentam as chances de conformidade – barreiras de redução, vírgulas finais e desvios de campo ainda acontecem. Na produção, habilite pelo menos JSON Mode⟧; idealmente, passe JSON Schema⟧ através do canal API Structured Output para que a decodificação exclua tokens ilegais.
Qual é a diferença entre JSON Mode⟧ e Structured Output?
O modo JSON garante apenas texto JSON válido, não nomes de campos, tipos ou chaves obrigatórias. Structured Output adiciona JSON Schema⟧ e filtra tokens durante a geração - a forma se estabiliza para que você possa armazenar ou passar diretamente para o próximo salto.
Os campos de configuração OpenAI, Gemini e Anthropic são iguais?
Mesmo conceito, nomes diferentes. OpenAI: formato_de_resposta com json_schema e strict; Gemini: responseMimeType + responseJsonSchema; Anthropic: output_format ou saída estruturada em ferramentas. Mantenha o padrão do Schema; Os SDKs agrupam solicitações.
A Saída Estruturada pode substituir a Chamada de Ferramenta?
Não. Saída Estruturada restringe a resposta JSON final; Tool Calling restringe o argumento da ferramenta JSON e requer que o host execute ferramentas. Use o primeiro para extrair/classificar/preencher; o último para inventário, arquivos, MCP. Cadeias completas de agentes geralmente usam ambos.
Ainda preciso validar a saída do modelo?
Sim. A decodificação restrita elimina erros de sintaxe e desvio de tipo, mas não a correção semântica (tipos válidos, valores fabricados). Execute novamente o mesmo JSON Schema⟧ em produção; tentar novamente, degradar ou revisar em caso de falha.
Como valido o esquema e a amostra de saída localmente?
Salve JSON Schema⟧ e alguns exemplos de saída do modelo como arquivos JSON; use JSON Toolbox⟧ no navegador para verificações de sintaxe e estrutura - nada é carregado.
Resumo
Para obter JSON que corresponda ao JSON Schema⟧ da IA, o pedido é importante:defina o esquema primeiro, habilite JSON Mode⟧ / Structured Output e, em seguida, escreva o prompt. Prompt = semântica; Esquema = forma; Pydantic / Zod são frentes amigas do autor; APIs do fornecedor expõem canais de esquema.
Execute uma fatura real ou transcrição de suporte de ponta a ponta: Esquema → chamada API → cole a saída em um validador. Quando corresponder, conecte o banco de dados ou o próximo agente. Os argumentos da ferramenta ainda passam por Tool Calling / MCP - não se fundem em um API.