Gerenciamento de Sessões na Prompt API — Contexto e Tokens
Na Prompt API, toda interação com o Gemini Nano acontece dentro de uma sessão. Sessões mantêm o contexto da conversa, controlam o uso de tokens e gerenciam o ciclo de vida da inferência. Se você não entender como elas funcionam, vai acabar criando sessões à toa, estourando contexto e desperdiçando recursos.
O que é uma sessão
Uma sessão é o objeto retornado por LanguageModel.create(). Ela encapsula:
- O contexto conversacional (histórico de prompts e respostas)
- A janela de contexto (limite máximo de tokens)
- Os prompts iniciais (system prompt e contexto prévio)
- As configurações de modalidade (texto, imagem, áudio)
const session = await LanguageModel.create({
initialPrompts: [
{ role: 'system', content: 'You are a helpful assistant.' }
],
expectedInputs: [{ type: 'text', languages: ['en'] }],
expectedOutputs: [{ type: 'text', languages: ['en'] }]
});
Context Window: contextUsage e contextWindow
Cada sessão tem um limite de tokens que consegue processar. Monitore o uso com duas propriedades:
// Total de tokens disponíveis na sessão
console.log(session.contextWindow); // ex: 4096
// Tokens já consumidos (prompts + respostas anteriores)
console.log(session.contextUsage); // ex: 512
// Tokens restantes
const disponivel = session.contextWindow - session.contextUsage;
console.log(`Disponível: ${disponivel} tokens`);
| Propriedade | Tipo | Descrição |
|---|---|---|
session.contextWindow | number | Capacidade total da janela de contexto |
session.contextUsage | number | Tokens consumidos até o momento |
Monitorando uso em tempo real
async function promptComMonitoramento(session, texto) {
const antes = session.contextUsage;
const resposta = await session.prompt(texto);
const depois = session.contextUsage;
console.log(`Tokens usados neste turno: ${depois - antes}`);
console.log(`Capacidade restante: ${session.contextWindow - depois}`);
return resposta;
}
Context Overflow
Quando a janela de contexto fica cheia e um novo prompt chega, o Chrome remove automaticamente pares de prompt+resposta antigos (do início da conversa) pra liberar espaço. A exceção é o system prompt — esse nunca é removido.
Detectando overflow
Use o evento contextoverflow para reagir quando tokens antigos são descartados:
session.addEventListener('contextoverflow', () => {
console.warn('Context overflow! Mensagens antigas foram removidas.');
// Opções de reação:
// 1. Avisar o usuário
mostrarAviso('Parte do histórico foi descartada para continuar a conversa.');
// 2. Criar nova sessão com resumo
criarNovaSessaoComResumo();
// 3. Simplesmente continuar (comportamento padrão)
});
QuotaExceededError
Se não for possível liberar tokens suficientes (por exemplo, um único prompt é maior que a janela), um QuotaExceededError é lançado:
try {
const resposta = await session.prompt(textoMuitoLongo);
} catch (error) {
if (error.name === 'QuotaExceededError') {
console.error(`Prompt muito longo!`);
console.error(`Tokens do input: ${error.requested}`);
console.error(`Tokens disponíveis: ${error.contextWindow}`);
// Dividir o texto ou usar resumo
const textoCurto = textoMuitoLongo.substring(0, 2000);
const resposta = await session.prompt(textoCurto);
}
}
initialPrompts: configurando o contexto inicial
O initialPrompts define o contexto da sessão no momento da criação. Aceita um array de mensagens com roles system, user e assistant:
const session = await LanguageModel.create({
initialPrompts: [
// System prompt: define comportamento (nunca é removido por overflow)
{
role: 'system',
content: 'You are a senior JavaScript developer. Answer concisely with code examples.'
},
// Contexto de conversa prévia (opcional)
{ role: 'user', content: 'What is a closure?' },
{
role: 'assistant',
content: 'A closure is a function that captures variables from its lexical scope...'
},
// O próximo prompt continuará a partir deste contexto
{ role: 'user', content: 'Can you show a practical example?' }
]
});
// O modelo já tem todo o contexto e responderá sobre closures
const resposta = await session.prompt('What about memory leaks with closures?');
Caso de uso: Restaurar sessão após reinício do navegador
// Salvar contexto antes de fechar
function salvarContexto(historico) {
localStorage.setItem('chat_historico', JSON.stringify(historico));
}
// Restaurar ao reabrir
async function restaurarSessao() {
const historico = JSON.parse(localStorage.getItem('chat_historico') || '[]');
const session = await LanguageModel.create({
initialPrompts: [
{ role: 'system', content: 'You are a helpful assistant.' },
...historico
]
});
return session;
}
append(): adicionando contexto depois da criação
O método append() permite adicionar mensagens ao contexto da sessão após a criação, sem solicitar uma resposta do modelo. Isso é útil pra:
- Pré-processar inputs multimodais enquanto o usuário interage
- Adicionar contexto incremental antes de pedir inferência
- Preparar o modelo com dados que chegam aos poucos
const session = await LanguageModel.create({
initialPrompts: [
{
role: 'system',
content: 'You are an image analyst. Compare images when asked.'
}
],
expectedInputs: [{ type: 'image' }, { type: 'text', languages: ['en'] }]
});
// Usuário faz upload da primeira imagem
fileInput1.onchange = async () => {
await session.append([
{
role: 'user',
content: [
{ type: 'text', value: 'Here is the first image:' },
{ type: 'image', value: fileInput1.files[0] }
]
}
]);
console.log('Primeira imagem processada');
};
// Usuário faz upload da segunda imagem
fileInput2.onchange = async () => {
await session.append([
{
role: 'user',
content: [
{ type: 'text', value: 'Here is the second image:' },
{ type: 'image', value: fileInput2.files[0] }
]
}
]);
console.log('Segunda imagem processada');
};
// Quando pronto, solicita a comparação
btnComparar.onclick = async () => {
const analise = await session.prompt('Compare both images in detail.');
document.getElementById('resultado').textContent = analise;
};
A Promise retornada por append() resolve quando a mensagem foi validada e processada. Ela rejeita se a mensagem não puder ser adicionada.
clone(): bifurcando uma sessão
O clone() cria uma cópia da sessão com todo o contexto e configurações preservados. Na minha experiência, os melhores usos são:
- Testar continuações diferentes de uma conversa
- Preservar um “checkpoint” antes de uma interação pesada
- Criar ramificações de conversa
const session = await LanguageModel.create({
initialPrompts: [
{ role: 'system', content: 'You are a creative writing assistant.' }
]
});
// Desenvolver uma história
await session.prompt('Start a mystery story set in a library.');
// Clonar antes de continuar — preserva o ponto atual
const sessaoAlternativa = await session.clone();
// Caminho A: continua na sessão original
const caminhoA = await session.prompt('The detective finds a hidden door.');
// Caminho B: continua na sessão clonada
const caminhoB = await sessaoAlternativa.prompt('The lights suddenly go out.');
Clone com AbortSignal
const controller = new AbortController();
const clonada = await session.clone({
signal: controller.signal
});
// Pode cancelar a sessão clonada independentemente
controller.abort();
destroy(): liberando recursos
Quando uma sessão não é mais necessária, destrua pra liberar memória e recursos de GPU:
const session = await LanguageModel.create();
const resposta = await session.prompt('Quick question: what is 2+2?');
// Liberar recursos
session.destroy();
// Qualquer uso posterior lança erro
try {
await session.prompt('Another question'); // ERRO!
} catch (error) {
console.error('Sessão destruída:', error.message);
}
Quando destruir
- Quando o componente/página que usa a sessão é desmontado
- Após completar uma tarefa isolada (classificação batch, por exemplo)
- Quando o usuário navega para outra seção da aplicação
- Em caso de erro irrecuperável
Quando NÃO destruir
- Se o usuário pode voltar e continuar a conversa
- Se você pretende reutilizar a sessão em breve (criar sessão tem custo)
- Em componentes persistentes (sidebar de chat, por exemplo)
Estratégias de gerenciamento
Estratégia 1: sessão por feature
Crie uma sessão dedicada pra cada funcionalidade da aplicação:
class AIFeatures {
constructor() {
this.sessions = {};
}
async getSessao(feature) {
if (!this.sessions[feature]) {
const configs = {
classificador: {
initialPrompts: [
{ role: 'system', content: 'Classify content. Answer: positive, negative, or neutral.' }
]
},
resumidor: {
initialPrompts: [
{ role: 'system', content: 'Summarize text in 2-3 sentences.' }
]
},
extrator: {
initialPrompts: [
{ role: 'system', content: 'Extract structured data from text.' }
]
}
};
this.sessions[feature] = await LanguageModel.create(configs[feature]);
}
return this.sessions[feature];
}
destruirTodas() {
Object.values(this.sessions).forEach(s => s.destroy());
this.sessions = {};
}
}
Estratégia 2: rotação de sessão por contexto
Quando o contexto fica cheio, crie uma nova sessão com resumo do que veio antes:
async function promptComRotacao(session, texto, historico) {
try {
return await session.prompt(texto);
} catch (error) {
if (error.name === 'QuotaExceededError') {
// Criar nova sessão com resumo do contexto
const resumo = historico.slice(-5).map(h =>
`${h.role}: ${h.content.substring(0, 100)}`
).join('\n');
session.destroy();
const novaSessao = await LanguageModel.create({
initialPrompts: [
{ role: 'system', content: 'You are a helpful assistant.' },
{ role: 'user', content: `Previous context summary:\n${resumo}` },
{ role: 'assistant', content: 'Understood. I have the context. How can I help?' }
]
});
return { sessao: novaSessao, resposta: await novaSessao.prompt(texto) };
}
throw error;
}
}
Estratégia 3: pool de sessões
Pra aplicações com uso intensivo, manter um pool funciona bem:
class SessionPool {
constructor(maxSessions = 3) {
this.max = maxSessions;
this.available = [];
this.inUse = new Set();
}
async acquire() {
if (this.available.length > 0) {
const session = this.available.pop();
this.inUse.add(session);
return session;
}
if (this.inUse.size < this.max) {
const session = await LanguageModel.create();
this.inUse.add(session);
return session;
}
// Esperar uma sessão ficar disponível
return new Promise(resolve => {
const check = setInterval(() => {
if (this.available.length > 0) {
clearInterval(check);
resolve(this.acquire());
}
}, 100);
});
}
release(session) {
this.inUse.delete(session);
this.available.push(session);
}
}
measureContextUsage: medindo antes de enviar
Use session.measureContextUsage() pra saber quanto um prompt vai consumir antes de mandá-lo:
const uso = await session.measureContextUsage('A very long prompt...');
console.log(`Este prompt consumirá: ${uso} tokens`);
if (session.contextUsage + uso > session.contextWindow) {
console.warn('Prompt não cabe no contexto atual');
}
Perguntas frequentes
Quantas sessões posso criar ao mesmo tempo?
Não tem um limite documentado, mas cada sessão consome memória. Na prática, mantenha o mínimo necessário e destrua as que não estão em uso.
O system prompt é contado na contextWindow?
Sim. O system prompt consome tokens da janela de contexto. Mantenha-o conciso. A diferença é que ele nunca é removido durante overflow — tudo mais é removido antes dele.
Posso alterar o system prompt depois de criar a sessão?
Não. O initialPrompts é imutável após a criação. Pra mudar o system prompt, destrua a sessão e crie uma nova.
O que acontece se eu chamar prompt() numa sessão destruída?
A Promise é rejeitada com um erro. Sempre verifique se a sessão tá ativa antes de usar.
clone() consome memória adicional?
Sim. Uma sessão clonada é independente e consome recursos próprios. Destrua clones que não são mais necessários.