Tokens e contexto na IA: planeje arquivos, limites e custo
Monte um orçamento de contexto, reserve espaço para a resposta, corte histórico antigo e selecione trechos relevantes com estimadores locais em Node.
Planejar contexto é decidir o que realmente precisa entrar, quanto espaço ficará para a resposta e o que será cortado quando a conversa crescer. Uma janela maior oferece capacidade; ela não transforma todo arquivo e todo histórico em material relevante.
Esta é uma oficina operacional. A explicação de como o modelo enxerga fragmentos está em o que é um LLM, pré-requisito recomendado. Aqui usaremos uma aproximação deliberadamente simples para revelar decisões. Os números publicados saíram de scripts no Node 26.3.0, sem modelo, tokenizador de provedor ou API. Portanto, são estimativas locais, nunca uma fatura prometida.
Orçamento começa reservando a resposta
Imagine uma mochila com limite de peso. Instruções, conversa, documentos, pergunta e resposta dividem o mesmo espaço. A analogia ajuda a visualizar a soma; o limite é que tokens não têm tamanho visual uniforme e cada família de modelos pode usar um tokenizador diferente.
Como sinal antecipado, podemos dividir a quantidade de caracteres por uma média. Isso não substitui a contagem oficial. Português, código, números e emoji podem se afastar bastante da regra de bolso.
const estimarTokens = (texto) => Math.ceil([...texto].length / 3.6);
const amostra = "Closures guardam acesso ao escopo em que foram criadas.";
console.log({
caracteres: [...amostra].length,
tokensEstimados: estimarTokens(amostra),
});O valor 16 não afirma que um modelo usará exatamente 16 tokens. Ele permite
comparar duas versões do mesmo material e perceber quando uma entrada dobrou sem
necessidade. Para medir produção, troque o estimador pelo tokenizador documentado
do provedor e confira o uso devolvido pela API.
Separe as partes antes de somar
Uma conversa parece um texto único na tela, mas a aplicação costuma montar partes com trabalhos diferentes. Instruções definem o comportamento; histórico mantém continuidade; documento traz evidência; pergunta declara a tarefa; e a resposta ainda precisa de espaço para existir.
const partes = {
instrucoes: "Explique apenas com base no documento e sinalize ausência.",
historico: [
"Pessoa: estou estudando closures.",
"Assistente: qual parte causou dúvida?",
].join("\n"),
documento: "x".repeat(7200),
pergunta: "Crie três perguntas de revisão com gabarito separado.",
};
const porParte = Object.fromEntries(
Object.entries(partes).map(([nome, texto]) => [nome, estimarTokens(texto)]),
);
console.log(porParte);O documento domina a entrada. Cortar “por favor” da pergunta não resolve um arquivo irrelevante de duas mil unidades estimadas. Nomear cada parte direciona o esforço para onde ele produz diferença.
Agora reserve saída e margem de protocolo antes de declarar que o material cabe.
const janela = 4096;
const reservaSaida = 700;
const margemProtocolo = 120;
const entradaEstimada = Object.values(porParte).reduce((soma, n) => soma + n, 0);
const tetoEntrada = janela - reservaSaida - margemProtocolo;
console.log({ janela, tetoEntrada, entradaEstimada, sobra: tetoEntrada - entradaEstimada });Reservar setecentas unidades não significa que a resposta necessariamente usará tudo. Significa que a entrada não pode consumir o lugar do resultado esperado. Escolha essa reserva a partir do formato: uma classificação curta pede menos que uma explicação com exemplos.
Corte histórico comum sem apagar o contrato
Quando a conversa ultrapassa o teto, remover mensagens antigas é uma política possível, mas instruções essenciais não podem desaparecer junto. Separe conteúdo fixo do histórico comum e mantenha as mensagens recentes que ainda cabem.
function manterRecentes(mensagens, limite) {
const mantidas = [];
let usados = 0;
for (const mensagem of [...mensagens].reverse()) {
const custo = estimarTokens(mensagem.texto);
if (usados + custo > limite) break;
mantidas.unshift({ ...mensagem, custo });
usados += custo;
}
return { mantidas, usados };
}
const mensagens = [
{ id: "m1", texto: "a".repeat(180) },
{ id: "m2", texto: "b".repeat(360) },
{ id: "m3", texto: "c".repeat(144) },
];
const recentes = manterRecentes(mensagens, 150);
console.log({
ids: recentes.mantidas.map((item) => item.id),
custos: recentes.mantidas.map((item) => item.custo),
usados: recentes.usados,
});O relatório imprime somente ids, custos e total, sem despejar 504 letras iguais.
m1 foi removida porque os dois itens mais recentes já consumiam 140 do limite
150. Usar break também preserva uma faixa contínua do histórico: o algoritmo não
pula uma mensagem grande para resgatar outra ainda mais antiga.
Uma instrução fixa entra por outro caminho e falha cedo se nem ela couber.
function montarContexto({ fixo, mensagens, limiteTotal }) {
const custoFixo = estimarTokens(fixo);
if (custoFixo >= limiteTotal) throw new Error("CONTEXTO_FIXO_EXCEDE_LIMITE");
const historico = manterRecentes(mensagens, limiteTotal - custoFixo);
return {
ids: historico.mantidas.map((item) => item.id),
custoFixo,
custoHistorico: historico.usados,
};
}
console.log(montarContexto({
fixo: "Não invente fatos; indique quando a fonte não responder.",
mensagens,
limiteTotal: 120,
}));O contrato permaneceu, e apenas m3 entrou no espaço restante. Em produto real,
histórico removido pode ser resumido, armazenado ou recuperado depois. Um resumo
também pode perder condição importante; ele precisa de revisão e versionamento.
Relevância vale mais que ordem de upload
Enviar cinco documentos na ordem em que chegaram não garante que a resposta veja o trecho necessário. Um seletor pode priorizar material com origem conhecida e relação com a pergunta. No exemplo didático, a relevância já foi atribuída por uma fixture local; não foi calculada por embeddings nem por um modelo.
const trechos = [
{ id: "politica", tokens: 380, relevancia: 0.95 },
{ id: "faq", tokens: 220, relevancia: 0.72 },
{ id: "historico-antigo", tokens: 600, relevancia: 0.20 },
{ id: "exemplo", tokens: 310, relevancia: 0.81 },
];
function selecionarTrechos(itens, limite) {
let usados = 0;
return [...itens]
.sort((a, b) => b.relevancia - a.relevancia)
.filter((item) => {
if (usados + item.tokens > limite) return false;
usados += item.tokens;
return true;
});
}
console.log(selecionarTrechos(trechos, 750).map(({ id, tokens }) => ({ id, tokens })));O algoritmo guloso escolheu 690 unidades e deixou a FAQ de fora. Isso expõe uma limitação: ordenar por relevância não encontra necessariamente a combinação ótima, e uma nota alta não prova que o trecho sustenta a resposta. A lição de RAG do zero separa recuperação e geração com mais cuidado.
Trate estouro como estado previsto
O pior corte é o silencioso: a aplicação remove o começo e a pessoa pensa que o modelo recebeu tudo. Registre o orçamento calculado e recuse a montagem quando a entrada ultrapassar o teto.
function validarOrcamento({ janela, entrada, saida, margem }) {
const total = entrada + saida + margem;
return {
cabe: total <= janela,
total,
excesso: Math.max(0, total - janela),
};
}
console.log(validarOrcamento({ janela: 4096, entrada: 3500, saida: 700, margem: 120 }));O próximo passo não é aumentar o número até o erro sumir. Remova repetição, reduza o documento ao trecho necessário, diminua a saída somente se o formato permitir ou escolha conscientemente outro modelo. Depois, use como verificar respostas da IA para conferir se o corte não retirou a evidência principal. O curso de engenharia de prompts organiza essas decisões numa prática sequencial.
Missão: faça o histórico caber sem perder a regra
Altere o limite de 120 para 70 no exercício de contexto fixo e observe quais ids restam. Depois reduza o texto fixo sem remover a obrigação de indicar ausência de fonte. O critério de sucesso é manter o contrato e produzir um total dentro do limite.
const missao = montarContexto({
fixo: "Indique ausência de fonte.",
mensagens,
limiteTotal: 70,
});
console.log(missao);
console.log(missao.custoFixo + missao.custoHistorico <= 70);Se você consegue justificar o que ficou, o que saiu, quanto reservou para a resposta e por que a fonte necessária continua presente, deixou de tratar a janela como um número mágico. A engenharia de prompt será mais previsível porque o material de entrada agora tem fronteiras explícitas.
Perguntas frequentes
Um token é sempre uma palavra?
A estimativa por caracteres mostra o custo exato?
Uma janela grande elimina a necessidade de selecionar contexto?
Devo apagar sempre as mensagens mais antigas?
Dúvidas e comentários
Travou em algum passo? Pergunte aqui — a equipe e outros alunos respondem.
Entrar para perguntarÉ o mesmo login gratuito dos cursos.
Nenhuma dúvida por aqui ainda — a primeira pode ser a sua.
Todo o código deste artigo foi executado em Node 26.3.0; estimadores e seletores locais executados sem chamada a modelo ou API, e as saídas exibidas são as reais — como produzimos este conteúdo.
Fontes consultadas
- Google AI for Developers — Long context — ai.google.dev
- Google AI for Developers — Prompt design strategies — ai.google.dev
- OpenAI Docs — Model guidance — developers.openai.com
- Anthropic Docs — Context windows — docs.anthropic.com


