O artigo anteriorPor que Agentess de IA não conseguem viver sem JSONrastreou Tool Calling e MCP salto a salto. Este olha para oresposta finalo modelo fornece a um usuário ou programa downstream: como fazer com que Gemini emita JSON você pode analisar, validar e armazenar - não uma prosa que apenas se parece com JSON.
Isso são Produtos Estruturados (geração controlada) nos documentos do Gemini. Ele compartilha ideias de esquema com Function Calling, mas um alvo diferente: o primeiro restringe ocarga útil final; o último restringeferramenta argumentos. Mantenha-os separados para que um Agente não trate “extrair uma fatura” e “ligar para a API de pagamento” como o mesmo tipo de ligação.
Três abordagens, cada uma mais rigorosa
As equipes geralmente tentam três maneiras de “fazer com que Gemini produza JSON”. A confiabilidade difere em uma ordem de magnitude:
| Abordagem | O que você controla | Quando é o suficiente |
|---|---|---|
| Somente prompt: “por favor, produza JSON” | Restrição suave; cercas de remarcação e comentários finais ainda aparecem | Exploração, scripts únicos |
responseMimeType: application/json | A saída deve ser um texto JSON válido | A forma varia; você só precisa de parse() para ter sucesso |
MIME + responseSchema / responseJsonSchema | Campos, tipos, enums e chaves obrigatórias são restritos | Extração de produção, formulários, cargas úteis entre agentes |
Everyone has seen the first failure mode: a ```json fence, an extra paragraph, single quotes, a trailing comma. The second layer parses, but price may be a string and items may be missing. The third layer is this tutorial: hand JSON Schema to the API so the decoder avoids illegal paths at each token.
Decodificação restrita: por que o Schema supera um prompt
A prompt only raises the odds that the model wants to comply. Structured Output compiles the Schema into generation: if the next token would break JSON syntax or leave the Schema (for example starting an undeclared field), its probability is suppressed. So response.text is usually a parseable object — no regex to strip fences.
Since 2025 the Gemini API complements the OpenAPI 3.0-style responseSchema with standard JSON Schema (often responseJsonSchema on the wire). Pydantic model_json_schema() and Zod exports can be sent almost as-is. Gemini 2.5 and later also tend to preserve property order from the Schema, which helps CSV columns and tables downstream.
Classification has a side path: responseMimeType: text/x.enum emits only the enum string (for example Keyboard), with no braces. Use application/json when you need an object; use the enum MIME when you need a single label.
Python: um exemplo completo de google-genai
Prefer the current SDK google-genai (from google import genai). Do not mix it with the legacy google-generativeai package. With GEMINI_API_KEY set:
from google import genai
from pydantic import BaseModel, Field
class LineItem(BaseModel):
name: str = Field(description="Product name")
qty: int = Field(description="Quantity, positive integer")
unit_price_cents: int = Field(description="Unit price in cents")
class Invoice(BaseModel):
vendor: str
currency: str = Field(description="ISO 4217, e.g. CNY")
items: list[LineItem]
total_cents: int
client = genai.Client()
response = client.models.generate_content(
model="gemini-2.5-flash",
contents="Extract an invoice from: Acme sold 2 keyboards at 199 CNY each.",
config={
"response_mime_type": "application/json",
"response_schema": Invoice,
},
)
print(response.text) # JSON string
invoice = response.parsed # Invoice instance (Pydantic path)
print(invoice.total_cents)
response.parsed is meaningful when response_schema is a Pydantic or SDK type. If you pass a raw JSON Schema dict (next section), json.loads(response.text) and validate yourself.
For many records use list[Invoice] or wrap invoices: list[Invoice] in an object. An array at the root is less stable on some models than always returning an object; production code usually does the latter.
response_schema vs JSON Esquema
Não adivinhe qual chave de configuração usar:
- response_schema: um modelo Pydantic, Python Enum ou objeto SDK Schema. O SDK o mapeia para o subconjunto OpenAPI on-wire.
- response_json_schema: a JSON Schema object (dict). Use it for
Invoice.model_json_schema(), ZodtoJSONSchema(), and richer keywords such asadditionalProperties,minimum/maximum, andprefixItems.
schema = {
"type": "object",
"properties": {
"vendor": { "type": "string" },
"currency": { "type": "string", "enum": ["CNY", "USD", "EUR"] },
"items": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": { "type": "string" },
"qty": { "type": "integer", "minimum": 1 },
"unit_price_cents": { "type": "integer", "minimum": 0 }
},
"required": ["name", "qty", "unit_price_cents"],
"additionalProperties": False
}
},
"total_cents": { "type": "integer" }
},
"required": ["vendor", "currency", "items", "total_cents"],
"additionalProperties": False
}
response = client.models.generate_content(
model="gemini-2.5-flash",
contents="Extract the invoice: …",
config={
"response_mime_type": "application/json",
"response_json_schema": schema,
},
)
Older REST docs use uppercase types in responseSchema (OBJECT, STRING, ARRAY, INTEGER). The JSON Schema path uses lowercase object / string. Do not mix the two keyword sets. Put field meaning in description: it enters the model context and decides whether qty is pieces or cases. Types alone cannot.
Qual é a aparência da solicitação REST
On the Gemini Developer API, generateContent puts structured output under generationConfig. The key goes in x-goog-api-key or a query param — never in a frontend repo.
POST https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent
{
"contents": [
{
"role": "user",
"parts": [{ "text": "Extract an invoice from the text: …" }]
}
],
"generationConfig": {
"responseMimeType": "application/json",
"responseJsonSchema": {
"type": "object",
"properties": {
"vendor": { "type": "string" },
"total_cents": { "type": "integer" }
},
"required": ["vendor", "total_cents"]
}
}
}
On success the candidate text is candidates[0].content.parts[0].text — a JSON string. Vertex AI uses the same field names; only the endpoint and GCP auth change. Images and PDFs can be inputs: the Schema constrains output, not multimodal input.
Como dividir o trabalho com Function Calling
Ambos usam Schema para governar JSON, mas ficam em saltos diferentes:
| Saída Estruturada | Chamada de Função / Chamada de Ferramenta | |
|---|---|---|
| O que é restrito | Resposta final JSON | Argumento da ferramenta JSON |
| Quem executa efeitos colaterais | Ninguém; são apenas dados | Host / MCP Servidor |
| Configuração típica | responseMimeType + Esquema | ferramentas[].parâmetros / inputSchema |
| Em caso de falha | Tente novamente ou volte para um humano | Escreva o erro como uma mensagem da ferramenta e pergunte novamente |
Extração de faturas, rótulos de moderação, transformação de notas em lista de tarefas: Saída Estruturada. Consulta de inventário, criação de ticket, leitura de arquivo repo: ferramentas — consulteo artigo sobre fluxo de dadoseJSON Esquema e evolução MCP. Não use Saída Estruturada para fingir que um pagamento API já foi executado - o modelo não o chamou.
Validação de tempo de execução e armadilhas comuns
A decodificação restrita não é correção comercial. Mantenha dois portões:
- Syntax and Schema: after
json.loads, validate again with the same JSON Schema (required, enum, minimum). - Business invariants: for example
sum(item.qty * item.unit_price_cents) == total_cents. Schema cannot express that; you write it.
Armadilhas comuns:
- Palavras-chave não suportadas: despejar um esboço completo do esquema 2020-12 pode ignorar silenciosamente algumas palavras-chave. Comece com tipo / propriedades / obrigatório / enum / itens e adicione additionalProperties e min/max.
- Array at the root:
{ "items": [ ... ] }as an object root is often more reliable. - Misturando comentários Markdown com JSON: quando JSON MIME estiver ativado, não peça também “explicar primeiro, depois JSON”.
- Truncamento: aumente maxOutputTokens ou divida “liste primeiro e depois preencha cada linha”.
- Chaves no frontend: demonstrações de saída estruturada no navegador vazam chaves API. O Esquema pode ser público; a chave permanece no servidor.
Durante o desenvolvimento, mantenha o esquema e duas ou três amostras positivas/negativas no git. Inspecione a estrutura e o Diff localmente em JSON Toolbox — o mesmo hábito de teste de contrato que REST, com Gemini como consumidor.
Perguntas frequentes
Qual é a diferença entre o tipo MIME JSON sozinho e também enviar um esquema?
Com apenas responseMimeType application/json, o modelo tenta emitir JSON válido, mas nomes de campos, tipos e chaves obrigatórias são irrestritos. Adicionar responseSchema ou responseJsonSchema restringe os tokens durante a decodificação, para que a forma seja estável o suficiente para persistir ou passar para o próximo agente.
Como escolho response_schema vs response_json_schema?
Use response_schema com um modelo Pydantic ou esquema SDK; o SDK pode expor response.parsed. Use response_json_schema para um objeto JSON Schema completo (additionalProperties, min/max, prefixItems) ou ao enviar Pydantic/Zod model_json_schema() como está. Ambos requerem response_mime_type=application/json.
A saída estruturada pode substituir Chamada de Função?
A saída estruturada restringe o JSON final que o usuário ou o código downstream vê. Chamada de Função / Chamada de Ferramenta restringe o argumento da ferramenta JSON e ainda requer que o host execute a ferramenta. Use saída estruturada para extração, classificação e preenchimento de formulários; use ferramentas para clima, arquivos e MCP. Os pipelines Agent geralmente usam ambos.
O modelo garante 100% de conformidade com o esquema?
A decodificação restrita elimina erros de sintaxe e desvios de tipo, mas alucinações semânticas, truncamento e palavras-chave ignoradas e não suportadas ainda acontecem. Na produção, execute o mesmo esquema por meio de um validador e tente novamente ou degrade em caso de falha.
São suportados objetos aninhados, matrizes e enumerações?
Sim. Objetos, matrizes e enums de string são a combinação usual. Para classificação, você pode definir MIME como text/x.enum para que o modelo emita apenas o valor enum, não um objeto JSON. Aninhamentos muito profundos ou referências cíclicas podem ser rejeitados - nivelar o esquema.
Como valido o esquema e a amostra de saída localmente?
Salve responseJsonSchema e alguns exemplos de saída do modelo como arquivos JSON. Verifique a sintaxe e a estrutura localmente em JSON Toolbox no navegador - nada é carregado. Use o mesmo esquema novamente em tempo de execução após o envio.
Resumo
To get structured JSON from Gemini, the order is: Schema first, JSON MIME second, prompt last. The prompt owns meaning (what to extract); the Schema owns shape (what fields look like). Pydantic / Zod are author-friendly fronts; on the wire you send response_schema or response_json_schema.
Run one real invoice or a support transcript: write the Schema → call generateContent once → paste response.text into a validator. Only then wire a database or the next agent. Tool arguments still go through Function Calling / MCP — do not collapse them into one API.