Structured Outputs (JSON mode)
Structured Outputs permite forçar o modelo a responder em JSON válido, seguindo um schema que você define. Essencial para pipelines de dados, classificação, extração de entidades e qualquer caso onde você precisa parsear a resposta programaticamente.
JSON mode (básico)
O modo mais simples: o modelo retorna JSON válido, mas sem schema fixo. Use response_format: { "type": "json_object" }:
python
from openai import OpenAI
client = OpenAI(
api_key="sk-...",
base_url="https://api.usetokia.com/v1",
)
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{
"role": "system",
"content": "Extraia os dados do texto em JSON com campos: nome, idade, cidade"
},
{
"role": "user",
"content": "João tem 32 anos e mora em Belo Horizonte"
}
],
response_format={"type": "json_object"},
)
import json
data = json.loads(response.choices[0].message.content)
print(data)
# {"nome": "João", "idade": 32, "cidade": "Belo Horizonte"}JSON Schema (avançado)
Para garantir que a resposta siga um schema específico, use json_schema. O modelo é forçado a gerar JSON que valida contra o schema:
python
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{
"role": "system",
"content": "Extraia as entidades do texto"
},
{
"role": "user",
"content": "A reunião da Tokia com a IT Booster será em 15/10 às 14h em Brasília"
}
],
response_format={
"type": "json_schema",
"json_schema": {
"name": "entidades_extraidas",
"strict": True,
"schema": {
"type": "object",
"properties": {
"empresas": {
"type": "array",
"items": {"type": "string"},
"description": "Nomes de empresas mencionadas"
},
"data": {
"type": "string",
"description": "Data do evento em formato ISO (YYYY-MM-DD)"
},
"hora": {
"type": "string",
"description": "Horário no formato HH:MM"
},
"local": {
"type": "string",
"description": "Cidade ou local mencionado"
}
},
"required": ["empresas", "data", "hora", "local"],
"additionalProperties": False
}
}
},
)
data = json.loads(response.choices[0].message.content)
# {
# "empresas": ["Tokia", "IT Booster"],
# "data": "2026-10-15",
# "hora": "14:00",
# "local": "Brasília"
# }TypeScript
typescript
import OpenAI from "openai";
const client = new OpenAI({
apiKey: process.env.TOKIA_KEY,
baseURL: "https://api.usetokia.com/v1",
});
const res = await client.chat.completions.create({
model: "gpt-4o-mini",
messages: [
{ role: "system", content: "Classifique o sentimento do texto" },
{ role: "user", content: "O produto é excelente, adorei a entrega rápida!" },
],
response_format: {
type: "json_schema",
json_schema: {
name: "analise_sentimento",
strict: true,
schema: {
type: "object",
properties: {
sentimento: {
type: "string",
enum: ["positivo", "negativo", "neutro"],
},
confianca: {
type: "number",
description: "Score de confiança de 0 a 1",
},
palavras_chave: {
type: "array",
items: { type: "string" },
},
},
required: ["sentimento", "confianca", "palavras_chave"],
additionalProperties: false,
},
},
},
});
const data = JSON.parse(res.choices[0].message.content!);
console.log(data.sentimento); // "positivo"
console.log(data.confianca); // 0.95Modelos com suporte
| Modo | Modelos |
|---|---|
json_object | GPT-4o, GPT-4o-mini, GPT-4-turbo, Claude (todos), Gemini, DeepSeek, Mistral, Llama 3.1+ |
json_schema (strict) | GPT-4o, GPT-4o-mini (suporte nativo); outros modelos podem ter suporte parcial |
Fallback para modelos sem suporte
Se o modelo não suporta response_format, use o prompt para instruir o formato:
python
response = client.chat.completions.create(
model="claude-3-haiku-20240307",
messages=[
{
"role": "system",
"content": """Responda APENAS com JSON válido, sem texto antes ou depois.
Use exatamente este formato:
{
"sentimento": "positivo" | "negativo" | "neutro",
"resumo": "frase curta"
}"""
},
{
"role": "user",
"content": "O atendimento foi péssimo, esperei 2 horas"
}
],
)
import json
try:
data = json.loads(response.choices[0].message.content)
except json.JSONDecodeError:
# Fallback: extrair JSON do texto
text = response.choices[0].message.content
start = text.find("{")
end = text.rfind("}") + 1
data = json.loads(text[start:end])Casos de uso comuns
- Extração de entidades: extrair nomes, datas, valores de textos não estruturados
- Classificação: categorizar textos (sentimento, tópico, urgência) com labels fixos
- Geração de dados: criar registros estruturados a partir de descrições em linguagem natural
- Parsing de documentos: converter faturas, contratos, currículos em JSON
- Pipeline de dados: cada etapa recebe e retorna JSON, sem parsing de texto livre
Boas práticas
- Sempre use
strict: truequando disponível — garante que o schema é respeitado - Use
enumpara campos com valores fixos (evita variações como “Positivo” vs “positivo”) - Defina
additionalProperties: falsepara evitar campos extras - Valide o JSON no seu código mesmo com strict mode — defesa em profundidade
- Use descriptions nos campos do schema para guiar o modelo
Próximos passos
- Tool Calling — quando o modelo precisa executar ações, não só retornar dados
- Streaming — respostas em tempo real (funciona com JSON mode)
- /v1/chat/completions — referência completa do endpoint