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ísticaprompt()promptStreaming()
RetornoPromise<string>ReadableStream
EntregaResposta completa de uma vezChunks incrementais
Uso idealRespostas curtas, classificação, extraçãoRespostas longas, UX interativa
CancelamentoVia signal (AbortController)Via signal (AbortController)
Tempo até primeira respostaEspera geração completaImediato (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 responseConstraint com 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

RoleO que fazOnde usar
systemDefine comportamento/persona do modeloApenas em initialPrompts
userMensagem do usuárioEm prompt(), promptStreaming(), initialPrompts, append()
assistantResposta anterior do modeloContexto 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çãoTipoO que faz
signalAbortSignalPermite cancelar a operação
responseConstraintobject ou RegExpForça formato de resposta (JSON Schema)
omitResponseConstraintInputbooleanNã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.


Referências