Como trabalho com agentes de IA (um guia prático sobre contexto e memória)

Como trabalho com agentes de IA (um guia prático sobre contexto e memória)

12 min de leitura

O que diferencia um agente que economiza horas de um que as faz perder não é o modelo subjacente, mas sim o contexto que você fornece e a memória que ele retém do que vocês dois já decidiram. Um tour prático pelas ferramentas de memória e gerenciamento de contexto que uso hoje em cada projeto: mise, Engram, context-mode e CodeGraph.

Quanto mais me aprofundo no universo das ferramentas de programação com IA, continuo encontrando modelos, benchmarks, “raciocínio” e todo tipo de marketing e “wishful thinking”, mas, antes de tudo, descobri que o que realmente diferencia um agente que economiza horas de um que as faz perder não é o modelo subjacente (embora ajude), mas sim o contexto que você fornece (juntamente com a memória que ele retém do que foi decidido a priori), e a maioria das análises e guias de ferramentas esquece essa parte. Compartilho isso a partir da minha experiência profissional, com as ferramentas que uso atualmente no dia a dia.

Para mim, é mais fácil pensar em um agente de IA como um parceiro rápido e capaz que acabou de chegar e ainda não viu sua base de código (codebase); a uma pessoa assim você não entregaria um ticket e esperaria que ela resolvesse às cegas. Você pediria para ela se sentar, mostraria o projeto, explicaria o que foi decidido na semana passada e por quê, e só então a deixaria trabalhar. Todo o desafio com essas ferramentas é conseguir esse comportamento, de forma sistemática, com gerenciamento de contexto e memória, em vez de apenas esperança. Pensando na minha experiência pessoal, o onboarding, dependendo da complexidade do projeto, poderia levar de 2 semanas a 3 meses (vivi isso na própria pele), então como poderíamos fazer um onboarding correto para uma IA?

Primeiro o contexto, depois o código

Atualmente, o erro mais comum que vejo é gente pedindo a um agente para “arrumar isso” sem dizer mais nada, e quase nunca é culpa do agente, é nossa. Queremos um parceiro inteligente e o tratamos como uma caixa de busca. Por isso, faço-o ler primeiro o projeto, a linguagem, o framework, as convenções existentes e adaptar-se ao que realmente existe, em vez de impor algum stack preferido que aprendeu em seus dados de treinamento. E digo a ele o mesmo que diria a um engenheiro novo: não redescubra a base de código (codebase) em cada sessão, sincronize-se com a documentação e com o que já foi decidido, porque um agente que adivinha sua arquitetura é exatamente tão perigoso quanto um engenheiro que a adivinha.

Para a parte estrutural desse contexto, apoio-me em CodeGraph, que constrói um grafo de conhecimento de cada símbolo, aresta e arquivo do workspace, analisado com tree-sitter, e responde às perguntas que o grep não consegue, como “quem chama isso?” ou “o que quebraria se eu mudasse aquilo?”, em submilissegundos (npmjs.com/package/@colbymchenry/codegraph). Eu o uso para a estrutura e deixo o grep para o texto literal, e ele converte um contexto que o agente teria que construir lendo arquivos completos em um contexto que já está ali.

O que ele basicamente faz é ter localmente um índice de funções, chamadas e estrutura em geral, o que torna a busca imediata e não um ciclo eterno de grep + find. Existem muitos projetos similares, mas este é um dos que possui uma comunidade bastante grande e estável.

A memória é a parte da qual ninguém fala

Qualquer modelo esquece tudo o que fizeram assim que a sessão termina. Para isso, utilizo 2 ferramentas: uma memória compartilhada e documentação “viva” com OpenWiki (que explico mais adiante). No meu caso, acabei tratando a memória persistente como o verdadeiro ativo, e há duas camadas que mantenho separadas propositalmente; existe a memória privada, que é como as notas que o agente guarda para si mesmo sobre suas decisões, bugs e convenções, armazenada por projeto para que trabalhar em um repositório nunca traga à tona as decisões de outro repositório, e existe a documentação do próprio repositório, a wiki que vive na base de código (codebase) e que a próxima pessoa, ou a próxima sessão, lê como fonte de verdade. A diferença é que a memória privada é o que a próxima sessão recorda, e a wiki é o que a próxima pessoa lê, e você precisa de ambas, não apenas uma.

Para a camada privada, uso Engram, um armazenamento local em SQLite + FTS5 que sobrevive entre sessões e até mesmo à compactação de contexto, onde você guarda observações tipadas e ele marca um conflito em vez de sobrescrever silenciosamente quando uma memória nova contradiz uma antiga. Assim, você termina com uma conversa que carrega sua própria história, em vez de um chat sem estado que começa do zero toda segunda-feira (github.com/Gentleman-Programming/engram). Eu o uso de forma proativa, não quando me pedem: contexto no início da sessão, uma busca antes de começar qualquer coisa que possa ter sido tocada antes, um salvamento imediatamente após qualquer decisão ou mudança de convenção, e um resumo antes de fechar. Isso soa como um overhead até você perceber que a alternativa é redescobrir e decidir novamente a mesma coisa toda semana.

O que isso gera?

Que quando você volta a trabalhar no projeto, em vez de ter que explicar novamente o que fez nas últimas sessões, você tem um histórico que pode ser pesquisado semanticamente, com decisões, ajustes e explicações que o agente pode encontrar facilmente. Inclusive, já aconteceu de eu pedir uma mudança e o agente me responder “Tem certeza? Isso vai contra o que fizemos há 2 semanas”, até me lembrando do que eu mesmo entreguei.

Engram

A wiki do repositório é a memória pública

E é aqui que entra a segunda camada de que eu falava, porque se Engram é o que o agente lembra em particular, OpenWiki é o que o repositório guarda em público. Uma wiki própria que vive dentro da base de código (codebase), novamente sob openwiki/, e que a próxima pessoa, ou a próxima sessão, lê como fonte de verdade do estado atual do projeto. Não um changelog que ninguém lê, mas sim a documentação real, enraizada nos arquivos, na história do Git e nas decisões que já foram tomadas. A ferramenta oficial se integra com o GitHub e pode ser acionada após um merge, no entanto, se você quiser fazer isso manualmente (funciona muito bem também), existe um plugin para Claude Code (facilmente adaptável como skill a qualquer outro agente que cumpra a mesma função).

A integração ao meu fluxo segue uma única regra: após qualquer mudança que afete a arquitetura, uma convenção ou um workflow, executo /openwiki:wiki update antes de dar o ticket por finalizado. O bom é que é idempotente, faz um snapshot da wiki antes e depois e só atualiza o que realmente mudou. Assim, executá-lo frequentemente é barato e executá-lo raramente é o que o torna caro. O padrão completo fica assim: Engram é o que a próxima sessão lembra, OpenWiki é o que a próxima pessoa lê, e você precisa de ambas, não apenas uma. Se você seguir a estrutura recomendada, isso ajuda o agente a encontrar respostas muito mais facilmente. No meu caso, inclusive, me ajudou a encontrar partes obsoletas da aplicação, seções que precisam de atualização, e mantém a ideia da engenharia básica de que a documentação deve estar sempre atualizada.

OpenWiki

A janela de contexto é um orçamento, não uma lata de lixo

Esta é a parte que mudou como trabalho ao reduzir incrivelmente o consumo de tokens, porque o movimento ingênuo é jogar cada log, cada diff, cada página web na conversa e deixar que o modelo nade nisso. Mas aprendi a dar a ele ferramentas que processam e indexam isso em seu lugar, de modo que a saída grande é buscada em vez de ser colada, com uma base de conhecimento consultável. Isso soa como um detalhe de implementação, mas na prática é a diferença entre um agente que permanece lúcido na segunda hora e um que se afoga em tokens que já não consegue raciocinar.

context-mode é minha ferramenta principal aqui: ela executa a saída das ferramentas em um sandbox e a indexa. Assim, um log enorme ou um diff grande é processado e buscado em vez de ser despejado diretamente na janela de contexto, e apenas a resposta que você precisa retorna à conversa (github.com/mksglu/context-mode). É uma daquelas ferramentas que você não percebe que funciona até removê-la e, de repente, o agente volta a ler arquivos de mil linhas em sua janela e se esquece do que estava fazendo.

Os testes são o instrumento, não a formalidade

E é aqui que entra a disciplina que dá sentido a tudo o anterior, porque um agente com contexto e memória, mas sem testes, é apenas um agente que soa seguro. Assim, o ciclo é red, green, refactor: escreva primeiro o teste que falha para a mudança, depois o mínimo de código para que ele passe, e por último, limpe o que sobra. E não subestimo o agente por isso; acostumo-o a que cada ticket real execute a suite completa e, acima de tudo, que execute o comando real e leia a saída real antes de afirmar que algo funciona. Porque eu posso prometer que um teste passou, mas se você não o executou e não viu sua saída, é apenas uma afirmação (evidência antes de afirmações).

Os olhos que o agente precisa: Chrome DevTools

E resta uma última peça que quase ninguém usa ao começar, porque uma suite de testes diz se o código é lógico, não se ele se parece bem em um navegador (browser). Então, para a pergunta “isso realmente funciona no navegador?” e não “compila?”, dei olhos ao agente com Chrome DevTools MCP, que lhe proporciona um Chrome real que ele pode controlar: navegar, clicar, preencher formulários, tirar snapshots do DOM e da árvore de acessibilidade, revisar a rede e o console, executar traces de performance e até auditorias de Lighthouse e screenshots. Na prática, é a diferença entre o agente dizer “o fix compila” para “abri a página, o fluxo de consentimento aparece assim, o console não mostra erros e o LCP caiu dois segundos”, e isso, juntamente com os testes, é o que transforma um assistente de terminal em algo em que você realmente pode se apoiar para entregar.

Superpowers: o processo como extensão

E se o processo é onde está o valor, a forma de não esquecê-lo é permitir que uma biblioteca de skills, Superpowers (há outras opções, como os Skills the Matt Pocock, mas, pelo menos no meu caso, achei muito mais prático para minhas necessidades usar Superpowers), faça o alinhamento por nós. Ela é carregada apenas no início da sessão e encaminha cada tarefa para sua skill correta (github.com/obra/superpowers). Os dois que mais uso são o brainstorming e o planning: o primeiro me obriga, e obriga o agente, a converter uma ideia difusa em um design acordado antes que exista uma única linha de código, a discutir os requisitos e a abordagem em vez de assumi-los. E o segundo divide esse design já aprovado em um plano de implementação menor, usando TDD, onde primeiro define os testes que falham, cria um SPEC, depois um plano e só então partimos para implementar. Assim, não estou delegando o ‘o quê’, mas sim o ‘como’ de um problema que já definimos juntos. E o que me parece importante é que ele usa o sistema de arquivos de forma que, mesmo que você feche a sessão, pode continuar a partir dos arquivos com um HANDOFF, o que depois pode se transformar em documentação dentro do OpenWiki.

Premortem: a skill que o ticket exige

E a esse processo adicionei à parte um que não pertence a Superpowers, mas que se instala sozinho, porque é a porta obrigatória antes que qualquer ticket finalizado retorne: o premortem. Nele, você assume que a mudança já falhou em produção e trabalha retroativamente, buscando modos de falha, regressões e casos de borda. Você corrige o que encontrar, executa novamente, e se algo deliberadamente não for corrigido, deixa por escrito na entrega (Premortem Skill).

Tudo isso eu integro no meu “system prompt” de base, que pode ser CLAUDE.md ou AGENTS.md e é lido no início (de forma global, não por projeto), para obrigar o agente a passar pelo processo de Pre-mortem antes de entregar algo. Estou pensando em convertê-lo em um subagente para que o faça com contexto limpo, mas por enquanto, como Skill, tem dado excelentes resultados.

Todo avanço é uma mudança de processo, não uma mudança de modelo

As ferramentas que mais me moveram não são os prompts mais engenhosos, mas sim as disciplinas em torno de todo o assunto: brainstorming antes de tocar no código, testes com refatoração e, sobretudo, um premortem antes que qualquer ticket finalizado retorne. Nele, você assume que a mudança já falhou em produção e trabalha retroativamente, buscando modos de falha, regressões e casos de borda, que é uma porta, não uma sugestão. E executo o build real e leio a saída real antes que eu ou o agente afirmemos que algo funciona, porque evidência vem antes de afirmações.

Por que todas essas ferramentas passam por um gerenciador de runtime

E aqui há um detalhe do qual ninguém te adverte: é que todas essas ferramentas são de linguagens e runtimes distintos, interligados entre si. Um binário em Go para a memória, um pacote npm para o grafo de conhecimento e o sandbox, e assim por diante. Na máquina média, isso significa que as ferramentas globais instaladas com um npm install -g simplesmente aterrissam sob a versão do Node que nvm ou fnm tiver ativa naquele momento. E assim que seu shell escolhe outro Node, em um terminal, em outro repositório dentro de outro projeto, esse path cai do seu PATH e a ferramenta desaparece em silêncio.

Assim, eu as gerencio com mise, que define um runtime explícito para as ferramentas globais e é proprietário de seus shims fora dos diretórios bin por versão do gerenciador de versões. Desse modo, o path se mantém estável em vez de depender da moda da semana no seu .nvmrc (mise.jdx.dev). A regra que mantenho em mente mapeia exatamente as ferramentas desta lista: mise para tudo o que for um pacote de linguagem com entrada de CLI, e um único proprietário por binário, porque dois gerenciadores de pacotes atualizando a mesma ferramenta em cronogramas distintos sempre acabarão brigando.

Talvez eu não seja o melhor nisso, mas depois de dois anos trabalhando com esses agentes em projetos reais, isso é o que aprendi, e o resumo honesto é: devemos tratar o agente como o parceiro que ele poderia ser, dar-lhe contexto, manter sua memória e aplicar as mesmas disciplinas que aplicaríamos a uma pessoa, porque o modelo é barato, o contexto é o que nós controlamos, e a diferença entre uma ferramenta que te impressiona em uma demo e uma que entrega o trabalho é, em todos os casos que vi, se você se deu ao trabalho de gerenciar o contexto e a memória.

SHARE_