Pular para o conteúdo

O efeito snowball: por que a mensagem 50 pesa 6x na janela de contexto

Cada mensagem pesa mais na janela de contexto. A fórmula do custo quadrático e um HUD de statusline pra ver a bola de neve crescer.

Avatar de DK
DKTrabalha com Linux e Unix a mais de 23 anos e possui as certificações LPI 3, RHCE, AIX e VIO.

29 jul, 2026
6 min de leitura

A mensagem 50 da sua sessão custa quase 6x mais tokens que a primeira. Mesmo texto, mesmo tamanho, e a janela de contexto explica o porquê.

Ninguém te avisa disso. A conversa cresce em silêncio enquanto você trabalha, e cada resposta do modelo vira peso morto no turno seguinte.

O efeito tem nome: snowball. Cada mensagem nova carrega a conversa inteira nas costas, e é essa bola de neve que vamos medir aqui, com fórmula e exemplo numérico.

No pacote: quanto o crescimento pesa no consumo de tokens e um HUD de statusline que torna o efeito visível. No final, o script completo pra instalar no seu Claude Code .

Screenshot_20260728_133148

A API não tem memória

Um LLM não “lembra” da conversa. A API é stateless: cada request chega sozinho, sem estado do lado do servidor.

Pra manter o contexto, o cliente reenvia tudo a cada turno. System prompt, definições de ferramentas, CLAUDE.md, e cada mensagem trocada desde o início da sessão. Sua pergunta nova é só a última linha de um pacote que cresce a cada turno.

Não é exclusividade do Claude Code: agentes construídos sobre APIs de chat costumam funcionar assim. A sensação de memória é uma releitura do histórico, paga em tokens de input, a cada mensagem.

E tem um detalhe que engorda a bola: a resposta do modelo no turno anterior vira histórico. Ou seja, o output de ontem é o input de hoje. Resultados de ferramentas, diffs, logs de teste: tudo entra na conta do turno seguinte.

A fórmula

Vamos dar nomes. P é o custo fixo que abre toda mensagem: system prompt, ferramentas, CLAUDE.md. t é o tamanho médio de um turno completo: sua mensagem, mais a resposta, mais os resultados de ferramentas.

O input da mensagem n é o custo fixo mais todos os turnos anteriores:

input(n) = P + (n - 1) * t          # grows linearly per message

total(N) = N * P + t * N * (N - 1) / 2   # grows quadratically per session

O custo por mensagem cresce linear. Mas o custo total da sessão soma essa escada inteira: 1 + 2 + … + (N – 1), a soma triangular. Por isso o total cresce quadrático.

Um exemplo ilustrativo, com P = 20k tokens e t = 2k tokens por turno:

Mensagem Input enviado % da janela de contexto (200k)
1 20k 10%
10 38k 19%
25 68k 34%
50 118k 59%

A mensagem 50 carrega quase 6x o peso da mensagem 1, com você digitando a mesma frase curta. E o total da sessão até ali passa de 3,4 milhões de tokens de input pra 50 mensagens.

É uma bola de neve descendo a montanha. Cada volta agrega o que encontrou no caminho, e nada sai por vontade própria. Só uma compactação enxuga a bola, e vamos chegar nela.

O cache paga a fatura, mas não esvazia a janela

Custo em dinheiro e custo em janela de contexto são coisas diferentes.

O prompt caching ataca o dinheiro. O prefixo repetido da conversa (system prompt, histórico antigo) é lido do cache por 10% do preço base de input na API da Anthropic. O Claude Code usa esse mecanismo: o payload do statusline expõe os campos cache_read_input_tokens e cache_creation_input_tokens de cada turno.

Mas o cache não muda a ocupação da janela de contexto. Token lido do cache é token dentro do contexto do mesmo jeito. A documentação do statusline define quais tokens contam pro percentual de janela usada:

used tokens = input_tokens
            + cache_creation_input_tokens
            + cache_read_input_tokens
# output_tokens do not count directly; they only enter
# the sum when they become history on the next turn

Cache barateia a releitura. A bola de neve continua crescendo, só desce a montanha com desconto. E quando a janela de contexto enche, nenhum desconto resolve: alguém precisa compactar o histórico.

O Claude Code faz isso sozinho perto do limite: limpa outputs antigos de ferramentas e, se preciso, resume a conversa. O resumo preserva seus pedidos, mas instruções do começo podem se perder. Compactar na sua hora, com /compact e um foco, preserva o que você escolher. Pra isso, você precisa ver a bola crescendo antes do limite.

O HUD: dando nome às fases da bola de neve

Percentual de contexto é um número abstrato. “62% usado” não diz o que fazer. Então criei um statusline que traduz o número em fases de uma bola de neve, cada uma com cor e recomendação:

Fase Faixa Cor Próxima mensagem
flake 0-14% cinza leve
rolling 15-39% verde média
steady 40-64% amarelo pesada
heavy 65-84% laranja cara
avalanche 85-94% vermelho rode /compact
frozen 95-100% vermelho fim da linha

No terminal, a linha fica assim (bar proporcional de 10 posições):

[Opus] ##........ rolling -> next ~ medium
[Opus] #######... heavy -> next ~ expensive
[Opus] #########. avalanche -> next ~ /compact

A versão que uso no dia a dia adiciona uma seta de aceleração. O script guarda amostras do percentual num arquivo por sessão e olha uma janela deslizante de 120 segundos:

  • ^^ subiu 15 pontos ou mais na janela: turno pesado em andamento, provavelmente leitura de arquivos grandes
  • ^ subiu 5 pontos ou mais: ritmo normal de trabalho
  • v caiu 10 pontos ou mais: um /compact acabou de acontecer

A aceleração importa porque a fase sozinha esconde o ritmo. Estar em steady subindo devagar é confortável. Estar em steady com ^^ significa que avalanche chega em poucos turnos.

Instalando no Claude Code

O Claude Code tem um mecanismo nativo de statusline: um script que recebe JSON da sessão via stdin e imprime uma linha. Ele roda dirigido por eventos da sessão, com debounce de 300ms.

Primeiro, salve o script em ~/.claude/snowball-statusline.sh. Esta é a versão mínima, com a fórmula das fases completa (depende só de jq):

#!/usr/bin/env bash
# Snowball statusline for Claude Code.
# Reads the /statusline JSON payload from stdin, prints one line.
set -euo pipefail

input="$(cat)"
model="$(jq -r '.model.display_name // "Claude"' <<<"$input")"
pct="$(jq -r '.context_window.used_percentage // 0' <<<"$input")"
pct="${pct%.*}"

# Map context usage to snowball phases.
if   (( pct < 15 )); then phase="flake";     next="light"
elif (( pct < 40 )); then phase="rolling";   next="medium"
elif (( pct < 65 )); then phase="steady";    next="heavy"
elif (( pct < 85 )); then phase="heavy";     next="expensive"
elif (( pct < 95 )); then phase="avalanche"; next="/compact"
else                      phase="frozen";    next="DEAD"
fi

# Proportional 10-slot bar, half-up rounding.
filled=$(( (pct * 10 + 50) / 100 ))
(( filled > 10 )) && filled=10
bar=""
for (( i = 0; i < 10; i++ )); do
  (( i < filled )) && bar+="#" || bar+="."
done

printf '[%s] %s %s -> next ~ %s\n' "$model" "$bar" "$phase" "$next"

Dê permissão de execução:

chmod +x ~/.claude/snowball-statusline.sh

Depois, registre no ~/.claude/settings.json:

{
  "statusLine": {
    "type": "command",
    "command": "~/.claude/snowball-statusline.sh"
  }
}

Pronto. A barra aparece no rodapé da sessão e atualiza sozinha.

Existe um atalho: o comando /statusline aceita instruções em linguagem natural, gera o script em ~/.claude/ e atualiza o settings pra você. Funciona bem pra começar. Escrever o script na mão dá controle fino sobre as fases e os limiares.

O payload de stdin traz mais do que percentual de contexto. Alguns campos úteis pra estender o HUD:

  • context_window.used_percentage: o combustível do snowball
  • rate_limits.seven_day.used_percentage: cota semanal do plano (presente só pra assinantes Pro/Max, depois da primeira resposta da API)
  • workspace.current_dir: diretório do projeto
  • cost.total_cost_usd: custo estimado da sessão, calculado no cliente (pode divergir da fatura)
  • session_id: chave pra guardar estado por sessão, como o log de aceleração

Minha versão completa compõe cinco segmentos com esses campos: modelo, snowball com aceleração, cota semanal, diretório e branch git com estado. Tudo numa linha:

[Opus] | #####..... steady ^ -> heavy | 7d 41% | ~/code/app | main *2 !1

https://github.com/dklima/claude-snowball-statusline

O que fazer em cada fase

O HUD só vale a pena se mudar comportamento. O que cada fase pede:

flake e rolling: trabalhe normal. É a zona barata da sessão, boa pra tarefas exploratórias que leem muitos arquivos.

steady: hora de intenção. Termine a tarefa atual antes de abrir outra frente. Cada tangente daqui pra frente custa caro.

heavy: feche o ciclo. Peça o resumo, o diff final, o commit. Evite colar logs grandes ou pedir leituras extensas.

avalanche: rode /compact agora, antes que o próximo turno pesado estoure a janela de contexto. Ou melhor: se a tarefa acabou, abra sessão nova.

frozen: o auto-compact vai agir por você, nos termos dele. Salve o que importa e recomece limpo.

E uma consequência direta da fórmula: o custo fixo P é pago em toda mensagem, da primeira à última. CLAUDE.md inchado, servidores MCP que você não usa, ferramentas demais: tudo isso é peso morto multiplicado por N. Enxugar o P é a otimização mais barata que existe, porque é paga uma vez e economiza sempre.

O ponto central

Conversa longa é um contrato de custo crescente. Cada mensagem relê o histórico acumulado desde a última compactação: linear por mensagem, quadrático por sessão.

O cache barateia a releitura, mas a janela de contexto enche do mesmo jeito. E decisão de contexto sem visibilidade é chute. Um statusline de 30 linhas transforma o número abstrato em fase com nome, cor e ação.


Fontes

Avatar de DK

Comentários

Deixe um comentário

Seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Ir para