Enviando Prompts — Guia de prompt() e promptStreaming()
O coração da Prompt API são os métodos session.prompt() e session.promptStreaming(). Ambos mandam conteúdo ao Gemini Nano pra inferência local, mas diferem em como a resposta chega até você. Vamos ver cada um em detalhe.
prompt() vs promptStreaming()
| Característica | prompt() | promptStreaming() |
|---|---|---|
| Retorno | Promise<string> | ReadableStream |
| Entrega | Resposta completa de uma vez | Chunks incrementais |
| Uso ideal | Respostas curtas, classificação, extração | Respostas longas, UX interativa |
| Cancelamento | Via signal (AbortController) | Via signal (AbortController) |
| Tempo até primeira resposta | Espera geração completa | Imediato (primeiro chunk) |
Quando usar prompt()
Use prompt() quando:
- A resposta esperada é curta (classificação, extração, sim/não)
- Você precisa do resultado completo antes de processar (parsing JSON)
- A latência total é aceitável pro caso de uso
- Você usa
responseConstraintcom JSON Schema
const session = await LanguageModel.create();
// Classificação binária — resposta curta
const resultado = await session.prompt(
'Is the following text spam? Answer only "yes" or "no": ' +
'"Buy now! Limited offer! Click here for free prizes!"'
);
console.log(resultado); // "yes"
Quando usar promptStreaming()
Use promptStreaming() quando:
- A resposta pode ser longa (textos, explicações)
- Você quer mostrar progresso ao usuário em tempo real
- A percepção de velocidade importa pra UX
- O usuário pode querer cancelar durante a geração
const session = await LanguageModel.create();
const stream = session.promptStreaming(
'Explain the differences between REST and GraphQL APIs.'
);
const outputEl = document.getElementById('output');
outputEl.textContent = '';
for await (const chunk of stream) {
outputEl.textContent += chunk;
}
Anatomia do content
O parâmetro content aceita dois formatos:
String simples
O formato mais direto — uma string é tratada como mensagem do role user:
const resposta = await session.prompt('What is machine learning?');
Array de mensagens
Pra conversas multi-turno ou quando você precisa de contexto adicional:
const resposta = await session.prompt([
{
role: 'user',
content: 'What is the weather like in São Paulo?'
},
{
role: 'assistant',
content: 'I don\'t have access to real-time weather data.'
},
{
role: 'user',
content: 'Then tell me what the typical climate is like.'
}
]);
Roles disponíveis
| Role | O que faz | Onde usar |
|---|---|---|
system | Define comportamento/persona do modelo | Apenas em initialPrompts |
user | Mensagem do usuário | Em prompt(), promptStreaming(), initialPrompts, append() |
assistant | Resposta anterior do modelo | Contexto de conversa, prefixing |
Content multimodal (array de partes)
Quando o content de uma mensagem mistura tipos (texto + imagem, por exemplo), use um array de objetos:
const resposta = await session.prompt([
{
role: 'user',
content: [
{ type: 'text', value: 'Describe this image in detail:' },
{ type: 'image', value: document.getElementById('minha-imagem') }
]
}
]);
Cada parte tem:
type:'text','image'ou'audio'value: O conteúdo correspondente (string pra texto, elemento/blob pra mídia)
Prefixing: guiando o formato de resposta
O recurso de prefix permite iniciar a resposta do modelo com um texto específico, guiando o formato de saída:
const resposta = await session.prompt([
{
role: 'user',
content: 'Create a JSON object with name, age, and city for a fictional person'
},
{
role: 'assistant',
content: '```json\n{',
prefix: true
}
]);
console.log('{' + resposta); // A resposta continua de onde o prefix parou
O prefix: true na última mensagem assistant diz pro modelo continuar a partir daquele ponto, não gerar uma nova resposta. Na prática é útil pra:
- Forçar formato de saída (JSON, TOML, Markdown)
- Garantir que a resposta começa com determinado texto
- Guiar o modelo pra respostas mais estruturadas
Cancelamento com AbortController
Ambos os métodos suportam cancelamento via AbortSignal:
const controller = new AbortController();
// Timeout de 5 segundos
setTimeout(() => controller.abort(), 5000);
try {
const resposta = await session.prompt('Write a detailed essay.', {
signal: controller.signal
});
} catch (error) {
if (error.name === 'AbortError') {
console.log('Prompt cancelado (timeout)');
}
}
Cancelamento interativo com streaming
const controller = new AbortController();
document.getElementById('btn-parar').addEventListener('click', () => {
controller.abort();
});
const stream = session.promptStreaming('Write a long story.', {
signal: controller.signal
});
try {
for await (const chunk of stream) {
document.getElementById('output').textContent += chunk;
}
} catch (error) {
if (error.name === 'AbortError') {
document.getElementById('output').textContent += '\n[Geração interrompida]';
}
}
Padrões práticos
Classificação com resposta booleana
const session = await LanguageModel.create({
initialPrompts: [
{ role: 'system', content: 'You are a content classifier. Answer only true or false.' }
]
});
async function classificar(texto, criterio) {
const resposta = await session.prompt(
`Does the following text match this criteria: "${criterio}"?\n\nText: ${texto}`
);
return resposta.trim().toLowerCase() === 'true';
}
const isSpam = await classificar(
'Buy cheap watches now!!!',
'spam or unsolicited commercial content'
);
// true
Extração de dados com prompt estruturado
const session = await LanguageModel.create({
initialPrompts: [
{
role: 'system',
content: 'Extract information and respond in the exact format requested. No additional text.'
}
]
});
const email = 'Hi, I\'m John Smith from Acme Corp. Call me at 555-0123.';
const resposta = await session.prompt(
`Extract name, company, and phone from this text. ` +
`Respond as JSON: {"name":"","company":"","phone":""}\n\n${email}`
);
const dados = JSON.parse(resposta);
// { name: "John Smith", company: "Acme Corp", phone: "555-0123" }
Streaming com renderização Markdown
async function streamComMarkdown(prompt) {
const session = await LanguageModel.create();
const stream = session.promptStreaming(prompt);
const container = document.getElementById('output');
let textoAcumulado = '';
for await (const chunk of stream) {
textoAcumulado += chunk;
container.innerHTML = marked.parse(textoAcumulado);
}
}
Retry com backoff
async function promptComRetry(session, texto, maxTentativas = 3) {
for (let tentativa = 1; tentativa <= maxTentativas; tentativa++) {
try {
return await session.prompt(texto);
} catch (error) {
if (error.name === 'AbortError') throw error; // Não retry em abort
if (tentativa === maxTentativas) throw error;
// Backoff exponencial
await new Promise(r => setTimeout(r, 1000 * Math.pow(2, tentativa)));
}
}
}
Múltiplos prompts em sequência
A sessão mantém contexto entre chamadas de prompt():
const session = await LanguageModel.create({
initialPrompts: [
{ role: 'system', content: 'You are a helpful tutor.' }
]
});
// Primeira pergunta
const r1 = await session.prompt('What is recursion in programming?');
console.log(r1);
// Segunda pergunta — o modelo lembra da conversa
const r2 = await session.prompt('Can you give me an example in JavaScript?');
console.log(r2); // Vai dar um exemplo de recursão, porque lembra do contexto
// Terceira pergunta
const r3 = await session.prompt('What are the risks of using it?');
console.log(r3); // Vai falar sobre stack overflow e riscos de recursão
Opções do segundo parâmetro
Tanto prompt() quanto promptStreaming() aceitam um segundo parâmetro com opções:
const resposta = await session.prompt(content, {
signal: controller.signal, // AbortSignal pra cancelamento
responseConstraint: jsonSchema, // JSON Schema ou regex
omitResponseConstraintInput: false // Se true, não inclui schema no contexto
});
| Opção | Tipo | O que faz |
|---|---|---|
signal | AbortSignal | Permite cancelar a operação |
responseConstraint | object ou RegExp | Força formato de resposta (JSON Schema) |
omitResponseConstraintInput | boolean | Não consome tokens de contexto com o schema |
Perguntas frequentes
O streaming retorna a resposta completa acumulada ou só os chunks novos?
O promptStreaming() retorna apenas os novos chunks a cada iteração. Você precisa acumular manualmente se quiser o texto completo.
Posso enviar múltiplos prompts ao mesmo tempo na mesma sessão?
Não é recomendado. Cada sessão processa um prompt por vez. Pra processamento paralelo, crie múltiplas sessões ou use session.clone().
Qual o tamanho máximo de um prompt?
Depende da contextWindow da sessão. Use session.contextWindow pra ver o máximo e session.contextUsage pra saber quanto já foi consumido. Se o prompt exceder o espaço disponível, um QuotaExceededError é lançado.
O prompt() pode retornar resposta vazia?
Sim, em casos raros o modelo pode não gerar conteúdo útil. Sempre valide a resposta antes de usar em produção.