O que é Compactação de Contexto?
Compactação de Contexto (Context Compaction) é um padrão de projeto de IA para apps com LLM e agentes, do grupo Contexto e conhecimento. Resumir ou podar o contexto quando ele cresce, mantendo o que importa.
O agente de código da Renata cuida de tarefas longas. Duas ou três horas. Migrar um módulo, atualizar dependências, consertar um lote de testes.
No começo de uma tarefa, ele é preciso. Depois de cento e cinquenta turnos, o contexto carrega centenas de resultados de ferramentas. Arquivos inteiros, saídas de teste com milhares de linhas, buscas que não deram em nada.
Perto do fim, o agente começa a editar arquivos que já tinha consertado.
Reaplicando mudanças que tinham sido revertidas.
E esquecendo a restrição combinada no começo. Não mexa na API pública. Em algumas tarefas, a janela estoura, e a execução falha.
Começar uma sessão nova não ajuda. O agente perderia o plano, as decisões e o que já foi feito. Nesta aula, você vai aprender a manter um agente lúcido numa tarefa mais longa do que a janela de contexto dele comporta.
Trate o contexto como memória de trabalho, com manutenção contínua. Três operações, em ordem de custo.
Podar. Apague o conteúdo de resultados antigos de ferramenta que já foram usados, como um arquivo lido oitenta turnos atrás. A chamada fica registrada. O conteúdo sai.
Resumir. Quando o contexto passa de um limite, troque a parte antiga por um resumo que guarda o objetivo, as decisões, o estado atual e os próximos passos.
E externalizar. Fatos que precisam sobreviver a qualquer resumo, como o plano, as restrições e a lista de arquivos alterados, vão para um arquivo ou estado fora do contexto. O agente lê quando precisa.
O gatilho é um limite de tokens, conferido antes de cada turno. Os turnos mais recentes sempre ficam inteiros. E a divisão de trabalho é esta. O código decide quando cortar. O modelo só escreve o resumo.
O agente trabalha normalmente.
Antes de cada turno, o código mede o contexto.
A primeira medida é barata. Apagar o conteúdo dos resultados antigos de ferramenta.
Se a poda bastou, o loop segue.
Se não, um modelo resume tudo o que vem antes dos últimos turnos.
E os fatos críticos moram fora do contexto, num arquivo de notas ou no estado. O resumo aponta para eles.
De volta à Renata. No turno três, ela combinou: não mude a API pública do módulo de cobrança. No turno oitenta, o agente leu o arquivo da API de cobrança, uns dois mil e quatrocentos tokens, e rodou os testes, uns mil e oitocentos tokens de log. No turno cento e cinquenta, esses resultados ainda vão em toda chamada, junto com dezenas de outros.
Com números ilustrativos, no turno cento e cinquenta, a entrada já passa de sessenta mil tokens por chamada. Sem poda, os próximos cinquenta turnos reenviam esse volume. Uns três milhões de tokens de entrada, só para terminar a tarefa.
A poda troca o conteúdo antigo por uma linha. O histórico ainda diz que a leitura aconteceu. Os dois mil e quatrocentos tokens saem. E se o agente precisar do arquivo de novo, ele lê de novo. Isso é mais barato que carregar o arquivo por cinquenta turnos.
Quando a poda não basta, entra o resumo. Aqui está um schema que se sustenta no eval da Renata. O objetivo. As decisões. O que está feito. O estado atual. Os próximos passos.
E esta linha. Restrições. Não mudar a API pública.
Uma pergunta para você. Depois de uma compactação, o agente da Renata muda uma assinatura pública. O resumo tinha o objetivo, o que estava feito e os próximos passos. Mas nenhum campo de restrições. Qual é a correção?
Colocar restrições no schema do resumo, e num arquivo de notas fora do contexto. Tudo o que precisa sobreviver a todo corte precisa de um lugar no resumo, e de uma cópia fora dele. Objetivo e próximos passos não guardam um não faça.
Subir o limite para a compactação nunca rodar só adia o apodrecimento. E um modelo maior não lembra do que você tirou do contexto. Sem aquele campo, o compactador te ajuda a esquecer justamente a única coisa que não pode ser esquecida.
Tarefas curtas. A etapa de compactação custa mais do que economiza.
Leitura pesada numa subtarefa bem delimitada. Isole num subagente. Às vezes os dois padrões andam juntos. O isolamento mantém o material pesado fora. A compactação limpa o que já entrou.
Conteúdo que precisa ser lido inteiro para a resposta, como um contrato revisado cláusula por cláusula. Resumir ali perde o que importa.
E um chat de atendimento curto. Digamos que ele termina em oito turnos, e um colega quer compactar a cada quatro, para economizar. Não faça. O histórico cabe, e um resumo só arrisca perder o pedido original, como o número do pedido na primeira mensagem. Guarde esses fatos como estado explícito.
Agora as armadilhas comuns. Resumir cedo demais. Compactar a cada poucos turnos gasta uma chamada e apaga detalhe que ainda seria usado. Meça primeiro. Corte quando a curva de tokens doer.
Um schema sem restrições. Esse a gente acabou de ver. O seu eval de retenção precisa de um caso assim.
Cortar no meio de uma chamada de ferramenta. Separe o pedido de ferramenta do resultado dele, e a próxima requisição à API fica inválida. O corte começa num turno do usuário.
E jogar o histórico bruto fora. Você vai precisar dele para depurar um resumo que inventou uma decisão. A compactação muda o que o modelo vê, não o que você guarda.
Uma pergunta que os times sempre fazem. Depois da poda, o agente relê um arquivo que já tinha lido oitenta turnos atrás. Isso é bug? Não. O conteúdo podado sumiu de propósito. Se o arquivo ainda importa, a ferramenta é chamada de novo. E o resumo também não deve copiar arquivos inteiros. Ele guarda decisões e estado, não código.
Como avaliar? Retenção, primeiro. Faça perguntas sobre fatos do começo da tarefa, depois da compactação. É o eval que a maioria pula. Sem ele, a compactação funciona no custo e falha no produto.
Depois, a taxa de conclusão, e o retrabalho. Arquivos editados duas vezes, pelo mesmo motivo.
Depois, tokens por turno, ao longo da execução. A curva deve ter dentes, não subir para sempre. E se os tokens antes e depois de uma compactação quase não mudam, as mensagens antigas nunca foram substituídas de verdade.
E o cache de prompt. Mudar o começo do contexto pode zerar ele. Acompanhe os tokens de cache depois de cada compactação.
Alguns provedores já fazem parte disso por você. Compactação no servidor, em que a API resume o contexto antigo sozinha. Ou edição de contexto, em que a API limpa os resultados antigos de ferramenta antes de o modelo ver. Prefira esses quando cobrirem o seu caso. E uma nota de privacidade. O resumo e o arquivo de notas costumam ir para os logs. Se a conversa tem dados pessoais, a compactação cria mais uma cópia. Restrinja quem pode ler esses logs.
Então, a ideia para levar. Uma tarefa longa precisa de uma memória com manutenção, não de uma pilha que cresce. Pode o que já foi usado, resuma o resto num schema que tenha lugar para todo não faça, e guarde os fatos críticos num arquivo que nenhum resumo apaga. Aí a terceira hora parece o terceiro minuto.
Na próxima aula, um smell sobre o formato do próprio agente: um agente tentando fazer tudo. O mega agent. Até lá.
Context Compaction
Compactação de Contexto (Context Compaction) é um padrão de projeto de IA para apps com LLM e agentes, do grupo Contexto e conhecimento. Resumir ou podar o contexto quando ele cresce, mantendo o que importa.
Resumir ou podar o contexto à medida que ele cresce, mantendo o que importa para os próximos passos. Serve para agentes e conversas longas que, sem isso, enchem a janela e pioram a cada volta.
A ata de uma reunião longa: ninguém relê a gravação inteira, todo mundo lê as decisões.
O agente de código de Renata resolve tarefas de duas a três horas: migrar um módulo, atualizar dependências, corrigir uma bateria de testes. No começo da tarefa ele é preciso. Depois de 150 voltas, o contexto tem centenas de resultados de ferramenta: arquivos inteiros, saídas de teste com milhares de linhas, buscas que não deram em nada.
Perto do fim, o agente começa a editar arquivos que já tinha consertado, a reaplicar mudanças que foram revertidas e a esquecer a restrição combinada no começo (“não mexa na API pública”). Em algumas tarefas, a janela estoura e a execução falha.
Isso é o smell Contexto Podre: o histórico ainda está lá, mas já não é memória útil. O paper “Lost in the Middle” (Liu et al., 2023) ajuda a explicar o sintoma. Com a janela cheia, o modelo usa mal o que ficou no meio, exatamente onde está a restrição da volta 3.
Começar uma sessão nova não resolve: o agente perde o plano, as decisões e o que já foi feito. O que Renata precisa é de um jeito de o contexto continuar útil depois de horas.
A pergunta que este padrão responde: como manter um agente lúcido numa tarefa mais longa do que a janela de contexto aguenta?
Trate o contexto como memória de trabalho, com manutenção contínua. Três operações, em ordem de custo:
O gatilho é um limite de tokens, conferido antes de cada volta. Os turnos mais recentes ficam sempre inteiros.
O guia “Building effective agents” da Anthropic (dezembro de 2024) trata compactação como manutenção de contexto, não como truque de prompt. O código decide quando cortar. O modelo só escreve o resumo.
Na volta 3, Renata combinou: “não altere a API pública do módulo billing”. Na volta 80, o agente leu billing/api.py (2.400 tokens) e rodou os testes (1.800 tokens de log). Na volta 150, esses resultados ainda viajam em toda chamada, junto com dezenas de outros.
Suponha, para a conta, um system prompt de 4.000 tokens e 400 tokens acrescentados por volta. Na volta 150, a entrada já passa de 60 mil tokens. Sem poda, as 50 voltas seguintes reenviam esse volume: uns 3 milhões de tokens de entrada só para terminar a tarefa.
A poda troca o conteúdo antigo por uma linha:
tool_result read_file billing/api.py
[conteúdo removido; chame a ferramenta de novo se precisar]
O histórico ainda diz que a leitura aconteceu. Os 2.400 tokens saem. Se o agente precisar do arquivo de novo, ele lê de novo. Isso é mais barato do que carregar o arquivo em 50 voltas.
Quando a poda não basta, o resumo entra. O schema que funciona no eval da Renata é este:
{
"goal": "Migrar billing para a API v2",
"constraints": ["não alterar a API pública"],
"decisions": ["manter os nomes dos endpoints", "adaptar só o cliente interno"],
"done": ["cliente interno atualizado", "testes de unidade passando"],
"current_state": "falha o teste de contrato em test_public_api.py:41",
"next_steps": ["ler o teste de contrato", "ajustar o adapter, não a assinatura pública"]
}
A restrição da volta 3 só sobrevive se o schema tiver um campo para ela, e se a mesma restrição estiver num arquivo de notas que o resumo não pode apagar. Sem isso, o compactador “ajuda” a esquecer exatamente o que não podia ser esquecido.
flowchart TD
L(["1. Volta do agente"]):::llm --> C{"2. Contexto passou do limite?"}
C -->|não| L
C -->|sim| P["3. Podar resultados antigos"]:::tool
P --> C2{"4. Ainda acima?"}
C2 -->|não| L
C2 -->|sim| S(["5. Resumir a parte antiga"]):::llm
S --> N[("6. Notas e estado externos")]:::store
N --> L
schema Compaction { goal: string, decisions: list[string], done: list[string],
current_state: string, next_steps: list[string] }
function step(state):
if tokens(state.messages) > SOFT_LIMIT:
# 3. podar: manter a chamada, apagar o conteúdo antigo
for r in old_tool_results(state.messages, older_than=20):
r.content = "[conteúdo removido; chame a ferramenta de novo se precisar]"
if tokens(state.messages) > HARD_LIMIT:
# 5. resumir a parte antiga, manter os últimos turnos
old, recent = split(state.messages, keep_last=10)
summary = llm(COMPACT_PROMPT, old + read(state.notes_file)) -> Compaction
write(state.notes_file, summary) # 6. externalizar
state.messages = [as_message(summary)] + recent
trace.span("compaction", tokens_before, tokens(state.messages))
return llm_with_tools(SYSTEM, TOOLS, state) # 1
tool_use do tool_result deixa o próximo request inválido. O corte começa num turno do usuário.| Aspecto | O que acontece | Como aparece no trace |
|---|---|---|
| Chamadas | Uma extra a cada compactação, nenhuma na poda | span compaction ocasional |
| Custo | O resumo custa uma chamada; as voltas seguintes ficam muito mais baratas | tokens de entrada caindo depois de cada compaction |
| Latência | A volta que compacta fica mais lenta | pico de duração na volta da compactação |
| Cache | Mudar o início do contexto pode zerar o cache de prompt | cache_read_input_tokens caindo depois da compactação |
| Falha: fato perdido | O agente refaz trabalho ou viola uma restrição antiga | ação repetida depois de um compaction |
| Falha: resumo que inventa | O agente age sobre algo que não aconteceu | decisão no resumo sem origem no histórico |
{ "task": "Migre o módulo billing para a nova API", "constraint_turn": 3, "constraint": "não alterar a API pública", "check": "nenhuma assinatura pública mudou" }
O caso de retenção é o eval que mais gente esquece. Sem ele, a compactação “funciona” no custo e falha no produto.
compaction com tokens antes e depois e o resumo gerado.tokens_before e tokens_after quase não mudam, o splice não substituiu as mensagens antigas.O resumo e o arquivo de notas costumam ir para log. Se a conversa tem dados pessoais (CPF, saldo, número de pedido com nome), a compactação cria mais uma cópia. Na LGPD, isso é tratamento. Restrinja quem lê esses logs e não mande o histórico bruto para um modelo de compactação fora da política da empresa.
| Prós | Contras |
|---|---|
| Tarefas longas cabem na janela | Resumos perdem detalhes |
| Custo e latência por volta estáveis | Uma chamada extra a cada compactação |
| O agente foca no que é relevante agora | Pode invalidar o cache de prompt |
| Notas externas sobrevivem a qualquer corte | Mais um prompt para escrever, versionar e avaliar |
A aba Python faz poda e resumo à mão. A aba TypeScript usa a compactação no servidor da API.
Python. Use quando você quer controlar o que é podado e o formato do resumo.
import json
import anthropic
client = anthropic.Anthropic()
SOFT, HARD, KEEP_LAST = 60_000, 120_000, 10
COMPACT_PROMPT = """Resuma o trabalho do agente até aqui em JSON com as chaves:
goal, constraints, decisions, done, current_state, next_steps.
Mantenha toda restrição combinada com o usuário. Não invente nada."""
def count(messages: list) -> int:
return client.messages.count_tokens(model="claude-opus-5-5", messages=messages).input_tokens
def prune(messages: list, older_than: int = 20) -> None: # 3. poda
for msg in messages[:-older_than]:
if msg["role"] == "user" and isinstance(msg["content"], list):
for block in msg["content"]:
if block.get("type") == "tool_result":
block["content"] = "[removido; chame a ferramenta de novo se precisar]"
def compact(messages: list, notes_path: str) -> list:
if count(messages) > SOFT:
prune(messages)
if count(messages) <= HARD:
return messages
old, recent = messages[:-KEEP_LAST], messages[-KEEP_LAST:]
while recent and recent[0]["role"] != "user": # o corte começa num turno do usuário
old.append(recent.pop(0))
reply = client.messages.create( # 5. resumo
model="claude-opus-5-5", max_tokens=4000, system=COMPACT_PROMPT,
messages=[{"role": "user", "content": json.dumps(old, default=str)[:400_000]}],
)
summary = reply.content[-1].text
open(notes_path, "w", encoding="utf-8").write(summary) # 6. externalizar
return [{"role": "user", "content": f"Resumo do trabalho anterior:\n{summary}"}] + recentO que você ganhou: você decide o que sai, o formato do resumo e onde ele fica. O que você perdeu: cortar no lugar certo (sem separar um tool_use do seu tool_result) é responsabilidade sua.
TypeScript. Use quando você prefere que a API resuma sozinha e não quer manter o código de compactação.
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
const messages: Anthropic.Beta.BetaMessageParam[] = [];
export async function turn(userMessage: string, tools: Anthropic.Beta.BetaTool[]) {
messages.push({ role: "user", content: userMessage });
const response = await client.beta.messages.create({
betas: ["compact-2026-01-12"],
model: "claude-opus-5-5",
max_tokens: 16000,
tools,
messages,
// 2 a 5. a API resume o contexto antigo quando ele passa do limite
context_management: { edits: [{ type: "compact_20260112" }] },
});
// devolva o conteúdo inteiro: os blocos de compactação precisam voltar na próxima chamada
messages.push({ role: "assistant", content: response.content });
return response;
}O que você ganhou: nenhum código de resumo para manter. O que você perdeu: controle do formato do resumo; guarde as notas críticas num arquivo próprio mesmo assim.
Responda as 6 perguntas para concluir a aula. Só assistir não conclui: a checagem é o que conta para a trilha e para o certificado.
Compactação de Contexto (Context Compaction) é um padrão de projeto de IA para apps com LLM e agentes, do grupo Contexto e conhecimento. Resumir ou podar o contexto quando ele cresce, mantendo o que importa.
Nos cenários reais Agente de código, Automação de back-office com execução durável e Tutor educacional.