Structured Output na Prompt API — JSON Schema e Regex
A Prompt API suporta structured output — a capacidade de forçar o modelo a responder num formato específico usando JSON Schema ou expressões regulares. Com o campo responseConstraint, você garante que a resposta vai ser parseável e consistente. Chega de parsing frágil de texto livre.
Disponível desde o Chrome 137, o structured output é passado como opção nos métodos prompt() e promptStreaming().
O que é responseConstraint
O responseConstraint é um campo do segundo parâmetro de prompt() e promptStreaming() que aceita um JSON Schema ou uma RegExp. Quando você passa isso, o modelo é obrigado a gerar uma resposta que valida contra o schema.
const session = await LanguageModel.create();
const schema = {
type: 'object',
properties: {
name: { type: 'string' },
age: { type: 'number' },
city: { type: 'string' }
},
required: ['name', 'age', 'city']
};
const resultado = await session.prompt(
'Generate a fictional person with name, age, and city.',
{ responseConstraint: schema }
);
const pessoa = JSON.parse(resultado);
console.log(pessoa.name); // "Alice Johnson"
console.log(pessoa.age); // 34
console.log(pessoa.city); // "Portland"
Tipos de JSON Schema suportados
Boolean
Força uma resposta true ou false:
const schema = { type: 'boolean' };
const resultado = await session.prompt(
'Is the following text about pottery?\n\n' +
'Mugs and ramen bowls, both a bit smaller than intended.',
{ responseConstraint: schema }
);
console.log(JSON.parse(resultado)); // true
String
Força uma resposta em formato string:
const schema = { type: 'string' };
const resultado = await session.prompt(
'What is the capital of France? Answer with just the city name.',
{ responseConstraint: schema }
);
console.log(JSON.parse(resultado)); // "Paris"
Number
Força uma resposta numérica:
const schema = { type: 'number' };
const resultado = await session.prompt(
'Rate this review from 1 to 5: "Excellent product, fast delivery!"',
{ responseConstraint: schema }
);
console.log(JSON.parse(resultado)); // 5
Object
Força uma resposta como objeto JSON com propriedades específicas:
const schema = {
type: 'object',
properties: {
sentiment: { type: 'string', enum: ['positive', 'negative', 'neutral'] },
confidence: { type: 'number' },
keywords: {
type: 'array',
items: { type: 'string' }
}
},
required: ['sentiment', 'confidence', 'keywords']
};
const resultado = await session.prompt(
'Analyze the sentiment of: "I love this product but the shipping was slow."',
{ responseConstraint: schema }
);
const analise = JSON.parse(resultado);
// { sentiment: "positive", confidence: 0.7, keywords: ["love", "slow shipping"] }
Array
Força uma resposta como array:
const schema = {
type: 'array',
items: {
type: 'object',
properties: {
task: { type: 'string' },
priority: { type: 'string', enum: ['high', 'medium', 'low'] }
},
required: ['task', 'priority']
}
};
const resultado = await session.prompt(
'Extract action items from: "We need to fix the login bug urgently, ' +
'update the docs when possible, and consider redesigning the dashboard."',
{ responseConstraint: schema }
);
const tarefas = JSON.parse(resultado);
// [
// { task: "Fix the login bug", priority: "high" },
// { task: "Update the docs", priority: "medium" },
// { task: "Redesign the dashboard", priority: "low" }
// ]
Enum
Restringe a resposta a valores específicos:
const schema = {
type: 'string',
enum: ['bug', 'feature', 'question', 'documentation']
};
const resultado = await session.prompt(
'Classify this GitHub issue title: "Add dark mode support"',
{ responseConstraint: schema }
);
console.log(JSON.parse(resultado)); // "feature"
Combinações complexas
const schema = {
type: 'object',
properties: {
valid: { type: 'boolean' },
errors: {
type: 'array',
items: {
type: 'object',
properties: {
field: { type: 'string' },
message: { type: 'string' },
severity: { type: 'string', enum: ['error', 'warning'] }
},
required: ['field', 'message', 'severity']
}
},
suggestion: { type: 'string' }
},
required: ['valid', 'errors']
};
const resultado = await session.prompt(
'Validate this email form data: { name: "", email: "notanemail", age: -5 }',
{ responseConstraint: schema }
);
const validacao = JSON.parse(resultado);
// {
// valid: false,
// errors: [
// { field: "name", message: "Name is required", severity: "error" },
// { field: "email", message: "Invalid email format", severity: "error" },
// { field: "age", message: "Age must be positive", severity: "error" }
// ],
// suggestion: "Please fill in all required fields with valid data."
// }
responseConstraint com RegExp
Além de JSON Schema, você pode usar expressões regulares para restringir o formato:
// Forçar resposta no formato de data ISO
const regexData = /^\d{4}-\d{2}-\d{2}$/;
const resultado = await session.prompt(
'What is today\'s date? Respond in YYYY-MM-DD format only.',
{ responseConstraint: regexData }
);
console.log(resultado); // "2026-06-06"
// Forçar resposta como hex color
const regexHex = /^#[0-9A-Fa-f]{6}$/;
const resultado = await session.prompt(
'What color best represents "ocean"? Respond as a hex color code.',
{ responseConstraint: regexHex }
);
console.log(resultado); // "#1E90FF"
omitResponseConstraintInput
Por padrão, o JSON Schema ou regex é incluído na mensagem enviada ao modelo, consumindo tokens da context window. Para economizar tokens, use omitResponseConstraintInput: true:
const schema = {
type: 'object',
properties: {
rating: { type: 'number' }
},
required: ['rating']
};
// Schema incluído no contexto (padrão) — consome tokens
const r1 = await session.prompt('Rate this: "Great product!"', {
responseConstraint: schema
});
// Schema NÃO incluído no contexto — economiza tokens
const r2 = await session.prompt(
'Rate this from 1-5 as JSON {"rating": <number>}: "Great product!"',
{
responseConstraint: schema,
omitResponseConstraintInput: true
}
);
Quando usar omitResponseConstraintInput
| Cenário | omitResponseConstraintInput | Motivo |
|---|---|---|
| Schema simples, contexto amplo | false (padrão) | Modelo entende melhor o formato esperado |
| Schema complexo, contexto limitado | true | Economiza tokens significativos |
| Prompt já descreve o formato | true | Evita duplicação de instruções |
| Muitas chamadas na mesma sessão | true | Preserva contexto para histórico |
⚠️ Cuidado: Com omitResponseConstraintInput: true, inclua instruções claras sobre o formato no próprio prompt, pois o modelo não verá o schema automaticamente.
measureContextUsage com responseConstraint
Use session.measureContextUsage() para verificar quantos tokens o responseConstraint consumirá:
const schemaGrande = {
type: 'object',
properties: {
// ... muitas propriedades
}
};
const uso = await session.measureContextUsage({
responseConstraint: schemaGrande
});
console.log(`O schema consumirá ${uso} tokens do contexto`);
// Se for muito, considere omitResponseConstraintInput: true
if (uso > session.contextWindow * 0.2) {
console.warn('Schema consome >20% do contexto. Considere omitir.');
}
Structured output com streaming
O responseConstraint funciona tanto com prompt() quanto com promptStreaming():
const schema = {
type: 'object',
properties: {
title: { type: 'string' },
summary: { type: 'string' },
tags: { type: 'array', items: { type: 'string' } }
},
required: ['title', 'summary', 'tags']
};
const stream = session.promptStreaming(
'Analyze this article and extract metadata: [article text...]',
{ responseConstraint: schema }
);
let jsonAcumulado = '';
for await (const chunk of stream) {
jsonAcumulado += chunk;
// Mostrar progresso parcial (JSON incompleto durante streaming)
document.getElementById('output').textContent = jsonAcumulado;
}
// Ao final, o JSON completo está disponível
const metadata = JSON.parse(jsonAcumulado);
Exemplos práticos
Classificador de e-mail
const session = await LanguageModel.create({
initialPrompts: [
{ role: 'system', content: 'You are an email classifier.' }
]
});
const schema = {
type: 'object',
properties: {
category: {
type: 'string',
enum: ['work', 'personal', 'marketing', 'spam', 'newsletter']
},
priority: {
type: 'string',
enum: ['urgent', 'normal', 'low']
},
requiresReply: { type: 'boolean' },
summary: { type: 'string' }
},
required: ['category', 'priority', 'requiresReply', 'summary']
};
async function classificarEmail(assunto, corpo) {
const resultado = await session.prompt(
`Classify this email:\nSubject: ${assunto}\nBody: ${corpo}`,
{ responseConstraint: schema }
);
return JSON.parse(resultado);
}
Extrator de eventos de calendário
const schema = {
type: 'object',
properties: {
events: {
type: 'array',
items: {
type: 'object',
properties: {
title: { type: 'string' },
date: { type: 'string' },
time: { type: 'string' },
location: { type: 'string' },
duration: { type: 'string' }
},
required: ['title', 'date']
}
}
},
required: ['events']
};
async function extrairEventos(texto) {
const resultado = await session.prompt(
`Extract calendar events from this text:\n\n${texto}`,
{ responseConstraint: schema }
);
return JSON.parse(resultado).events;
}
const eventos = await extrairEventos(
'Meeting with John tomorrow at 3pm in Room 201 for about 1 hour. ' +
'Also, dentist appointment on Friday at 10am.'
);
// [
// { title: "Meeting with John", date: "tomorrow", time: "3pm", location: "Room 201", duration: "1 hour" },
// { title: "Dentist appointment", date: "Friday", time: "10am" }
// ]
Validador de formulário inteligente
const schema = {
type: 'object',
properties: {
isValid: { type: 'boolean' },
issues: {
type: 'array',
items: {
type: 'object',
properties: {
field: { type: 'string' },
issue: { type: 'string' },
suggestion: { type: 'string' }
},
required: ['field', 'issue']
}
}
},
required: ['isValid', 'issues']
};
async function validarFormulario(dados) {
const resultado = await session.prompt(
`Validate this form data for a job application:\n${JSON.stringify(dados)}`,
{ responseConstraint: schema }
);
return JSON.parse(resultado);
}
Perguntas frequentes
O responseConstraint garante 100% que o JSON será válido?
Na grande maioria dos casos, sim. O modelo é forçado a gerar output que valida contra o schema. Porém, em edge cases com schemas muito complexos, é prudente envolver o JSON.parse() em try/catch.
Posso usar JSON Schema com $ref ou definitions?
A implementação atual suporta schemas inline simples. Schemas com referências externas ($ref) podem não funcionar como esperado. Prefira schemas auto-contidos.
O responseConstraint funciona com todos os idiomas de output?
Sim. O constraint se aplica ao formato da resposta, não ao idioma. Você pode combinar expectedOutputs em qualquer idioma suportado com um JSON Schema.
Regex ou JSON Schema — qual devo usar?
Use JSON Schema quando precisa de dados estruturados (objetos, arrays, tipos específicos). Use regex quando precisa apenas de um formato de string específico (datas, códigos, identificadores).
O structured output consome mais tokens?
Sim, quando omitResponseConstraintInput é false (padrão), o schema é incluído no contexto. Schemas complexos podem consumir dezenas ou centenas de tokens. Use measureContextUsage() para avaliar o impacto.