Conteúdo da trilha
8 minNarração em inglês, legenda em portuguêsPodcast (RSS)
Capítulos
  1. 0:00Abertura
  2. 1:01A ideia
  3. 1:59Como funciona
  4. 2:28Um caso real
  5. 3:43Um desafio
  6. 4:31Quando não usar
  7. 6:05Em produção
  8. 7:45Fechamento
Transcrição

Abertura

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.

A ideia

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.

Como funciona

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.

Um caso real

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.

Um desafio

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.

Quando não usar

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.

Em produção

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.

Fechamento

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á.

PadrãoContexto e conhecimento

Compactação de Contexto

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.

Elemento
18/70
Nível
Avançado
Leitura
8 min
Atualizado
Nesta página 18
  1. 01Intenção
  2. 02Problema
  3. 03Solução
  4. 04Estrutura
  5. 05Pseudocódigo
  6. 06Cenários reais
  7. 07Aplicabilidade
  8. 08Quando não usar
  9. 09Como implementar
  10. 10Variações
  11. 11Custo, latência e falhas
  12. 12Como avaliar
  13. 13Em produção
  14. 14Segurança
  15. 15Prós e contras
  16. 16Relações
  17. 17Código
  18. 18Teste seu entendimento
  19. ··Perguntas rápidas

Intenção

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.

Em uma frase
A ata de uma reunião longa: ninguém relê a gravação inteira, todo mundo lê as decisões.

Problema

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?

Solução

Trate o contexto como memória de trabalho, com manutenção contínua. Três operações, em ordem de custo:

  • Podar: apagar resultados de ferramenta antigos que já foram usados (o conteúdo de um arquivo lido 80 voltas atrás). A chamada fica registrada; o conteúdo sai.
  • Resumir: quando o contexto passa de um limite, trocar a parte antiga por um resumo que guarda objetivo, decisões, estado atual e próximos passos.
  • Externalizar: fatos que precisam sobreviver a qualquer resumo (plano, restrições, lista de arquivos alterados) vão para um arquivo ou estado fora do contexto, e o agente consulta quando precisa.

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.

Exemplo trabalhado

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.

Checagem +20 XP de primeiraDepois da compactação, o agente da Renata altera uma assinatura pública. O resumo tinha goal, done e next_steps, mas nenhum campo de restrição. Qual é o conserto?

Estrutura

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
  1. O agente trabalha normalmente.
  2. Antes de cada volta, o código mede o contexto.
  3. A primeira medida é barata: apagar conteúdo de resultados de ferramenta antigos.
  4. Se a poda bastou, o loop segue.
  5. Senão, um modelo resume tudo que veio antes dos últimos turnos.
  6. Fatos críticos ficam fora do contexto, num arquivo de notas ou estado, e o resumo aponta para eles.

Pseudocódigo

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

Cenários reais

  • Agente de código. Tarefas longas com muita leitura de arquivo. A poda de resultados antigos resolve a maior parte; o resumo entra só nas tarefas mais longas, e o plano fica num arquivo de notas.
  • Automação de back-office com execução durável. Processos que duram dias, com pausas para aprovação. Cada retomada começa do estado compactado, não do histórico de três dias.
  • Tutor educacional. Sessões que viram semanas. O que a aluna domina e as regras combinadas (“só dicas, sem a resolução”) ficam como fatos; o resto vira resumo de aula.

Aplicabilidade

  • Tarefas ou conversas que passam com frequência de algumas dezenas de milhares de tokens.
  • Agentes que leem muito (arquivos, páginas, logs) e usam pouco do que leram depois.
  • Custo ou latência por volta crescendo ao longo da execução.
  • Qualidade que cai no fim das tarefas longas e é boa no começo.

Quando não usar

  • Tarefas curtas. O passo de compactação custa mais do que economiza.
  • O problema é leitura pesada numa subtarefa bem definida. Isole num subagente: veja Isolamento de Contexto. Às vezes os dois padrões andam juntos.
  • Conteúdo que precisa ser lido inteiro para a resposta (um contrato revisado cláusula por cláusula). Resumir ali perde o que importa.
  • Conversa de atendimento curta em que o problema é guardar dois ou três fatos. Guarde esses fatos em estado explícito, fora do texto bruto, em vez de resumir o chat.
Checagem +20 XP de primeiraUm chat de suporte termina em 8 turnos. Um colega quer compactar a cada 4 turnos para 'economizar'. O que você responde?

Como implementar

  1. Meça o tamanho do contexto por volta nos traces atuais e ache onde ele cresce.
  2. Comece pela poda de resultados de ferramenta antigos. Muitas vezes ela sozinha resolve.
  3. Defina o schema do resumo: objetivo, decisões, feito, estado atual, próximos passos, restrições.
  4. Dê ao agente um arquivo de notas (ou ferramenta de memória) para registrar plano e decisões ao longo do caminho.
  5. Escolha limites: um suave para podar e um forte para resumir.
  6. Verifique se o provedor oferece compactação no servidor ou edição de contexto, e prefira usar essa opção quando ela cobrir o seu caso.
  7. Monte um eval com tarefas longas que dependem de algo do começo e rode antes e depois.

Armadilhas comuns

  • Resumir cedo demais. Compactar a cada poucas voltas gasta chamada e apaga detalhe que ainda seria usado. Meça primeiro; corte quando a curva de tokens doer.
  • Schema sem restrições. Objetivo e próximos passos não guardam um “não faça”. O eval de retenção precisa de um caso desses.
  • Cortar no meio de uma chamada de ferramenta. Separar o tool_use do tool_result deixa o próximo request inválido. O corte começa num turno do usuário.
  • Jogar o histórico bruto fora. Você vai precisar dele para depurar um resumo que inventou uma decisão. Compactação muda o que o modelo vê, não o que você guarda.

Variações

  • Compactação no servidor. A API resume o contexto antigo sozinha quando ele passa de um limite. Menos código; você precisa devolver os blocos de compactação que ela gera.
  • Edição de contexto. A API apaga resultados de ferramenta antigos antes de o modelo ver o contexto. É a poda, sem código seu.
  • Janela deslizante. Só os últimos N turnos. Simples, mas perde tudo que saiu da janela; serve quando o passado realmente não importa.
  • Nota escrita pelo próprio agente. O agente mantém um arquivo de progresso que sobrevive a qualquer corte. Combina com as outras variações.

Custo, latência e falhas

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

Como avaliar

  • Retenção: perguntas de eval sobre fatos do começo da tarefa, feitas depois da compactação.
  • Taxa de conclusão e retrabalho (arquivos editados duas vezes pela mesma razão) em tarefas longas.
  • Custo por tarefa e tokens por volta no fim da execução.
{ "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.

Checagem +20 XP de primeiraDepois da poda, o agente relê billing/api.py, que ele já tinha lido 80 voltas atrás. O trace mostra o resultado antigo trocado pelo placeholder. Isso é bug?

Em produção

  • Span compaction com tokens antes e depois e o resumo gerado.
  • Painel de tokens por volta ao longo da execução: a curva deve ter dentes, não subir sem parar.
  • Alerta para execuções que compactam muitas vezes. Talvez a tarefa devesse ser dividida.
  • Guarde o histórico bruto fora do contexto para depurar resumos ruins.
  • Se tokens_before e tokens_after quase não mudam, o splice não substituiu as mensagens antigas.

Segurança

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 e contras

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

Relações

Código

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}"}] + recent

O 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.

Teste seu entendimento

Checagem +20 XP de primeiraUma tarefa de 150 voltas fica ruim no fim, com uns 180 mil tokens no contexto. Qual é o primeiro passo?

Checagem +20 XP de primeiraO span compaction mostra tokens_before=120000 e tokens_after=118000. O que isso indica?

Checagem +20 XP de primeiraUm processo de back-office pausou dois dias para um humano aprovar. Na retomada, o sistema envia as 48 horas de histórico ao modelo. Qual é o desenho certo?

Perguntas rápidas

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.

Quais smells o padrão Compactação de Contexto ajuda a curar?

Contexto Podre.

Onde Compactação de Contexto aparece na prática?

Nos cenários reais Agente de código, Automação de back-office com execução durável e Tutor educacional.

Para ir além

Relações

Smells que ajuda a curar 1
Refatorações que chegam aqui 1
Aparece nas trilhas 1
Buscar