segunda-feira, 2 de novembro de 2026 IA e tecnologia por Denis Ribeiro
Código Aberto

IA e tecnologia sem enrolação — por Denis Ribeiro

Agentes

RAG vs memória de agentes de IA: 4 testes em 2026

Comparação entre RAG e memória de agentes de IA em um diagrama de arquitetura sobre a mesa de trabalho de um desenvolvedor
Foto: Daniil Komov / Pexels

RAG vs memória de agentes de IA vira bug report no instante em que o agente chega na terceira mensagem da conversa e pergunta de novo o número do pedido. O cenário é ilustrativo, mas se repete em quase todo time que monta agente de suporte: Chroma ou pgvector em produção, embedding de todo o histórico de conversa, chunk fixo com overlap pequeno, top-k baixo. Mesmo assim o bot se comporta como quem tem amnésia anterógrada, e só lembra quando o usuário repete a maldita palavra-chave.

Minha tese é impopular. Na maioria dos casos isso não se resolve trocando de vector DB nem afinando chunk size. O problema mora uma camada acima. O que o time tem é um índice de recuperação, e índice não é memória. A diferença é de arquitetura, não de semântica. Vou tentar mostrar onde ela fica, mito por mito.

Mito 1: quem tem banco vetorial acha que tem memória de agente

A confusão vem de berço. O LangChain popularizou o módulo ConversationBufferMemory e, logo depois, o VectorStoreRetrieverMemory, e pronto: “memória” virou nome de classe que qualquer coisa podia implementar. Só que o que existia ali dentro era isto: pegue a última pergunta, gere um embedding, busque os k chunks mais próximos, cole no prompt. Retrieval com outro rótulo. A doc do LangChain é razoavelmente explícita hoje. A distinção entre curto prazo (estado da thread) e longo prazo (armazenamento externo) existe, mas aparece no meio de uma página longa de leitura, e o nome “memory” continua no caminho.

O efeito sobrevive até em time sênior. Já vi gente tentando “resolver” a ausência de memória só subindo o valor de top_k. Isso não cria memória, só aumenta a chance de o chunk certo cair no prompt quando a pergunta atual se parece com ele. Se a pergunta não se parece, k nenhum salva.

O que fazer no lugar: pare de chamar de memória o que é índice. Depois separe as duas coisas em código, mesmo que morem no mesmo Postgres. Um nome de tabela, um namespace, um serviço. O vocabulário do time determina o que o time enxerga.

Mito 2: se o agente não lembra, é chunk size ou modelo de embedding

Esse é o mito mais caro, porque consome sprint. A crença é que existe um parâmetro mágico (chunk_size, top_k, embedding_model) capaz de fazer o agente lembrar. Não existe, porque a pergunta que o RAG responde é uma só: o que no meu corpus se parece semanticamente com este texto agora?

Ele não responde “o que é verdade sobre este usuário”. Não responde “desde quando”. Também não responde “o que deixou de ser verdade”. A similaridade de cosseno entre “qual meu endereço de entrega?” e o chunk “o cliente pediu entrega expressa em São Paulo” costuma vir alta. Parece plausível, mas não é afirmação sobre o mundo. É proximidade vetorial, e proximidade não carrega temporalidade, contradição nem identidade.

Repare no sintoma que denuncia isso na hora: o agente só acerta quando o usuário usa a palavra que estava no texto original. “Preciso do pedido” funciona, “e aquele negócio lá?” não funciona. Não é alucinação, é a assinatura de um índice fazendo o trabalho que a arquitetura não faz.

Mito 3: dá para jogar histórico de conversa e base de conhecimento no mesmo índice

Aqui o mito deixa de ser inofensivo e passa a produzir resposta errada. Se histórico de sessão e documentação interna caem na mesma coleção vetorial, sem filtro por tipo na leitura, o retrieval traz conversa antiga com a mesma confiança com que traz política da empresa. O sintoma clássico é o agente cuspir algo como “conforme alinhamos no chat de ontem, o SLA é de 4 horas” no meio de uma resposta para outro cliente. Pior: tratar o desabafo de um usuário como se fosse conhecimento oficial.

Isso tem nome, context pollution. E não é problema de embedding, é falta de rota de escrita e leitura separadas. Um filtro de metadado (source_type = "conversation") resolve a maior parte do estrago em duas linhas de query. O que não resolve é confiar que o modelo vai “entender o contexto” e ignorar o que não interessa.

RAG vs memória de agentes de IA: três camadas, três ciclos de vida

Aqui entra a referência que mudou como eu leio esse problema. O MemGPT, hoje Letta, parte da premissa de que página gerenciada não é a mesma coisa que índice de busca. A hierarquia dele (main context, o que está na janela agora; recall storage, o que aconteceu na conversa; archival storage, o que é documento) existe porque essas três coisas têm tempos de vida diferentes.

Traduzindo para o dia a dia:

Camada O que guarda Quem escreve Quem lê Expira?
Contexto ativo turnos recentes + estado da tarefa runtime o modelo, sempre a cada turno
Episódica o que aconteceu naquela sessão o próprio agente na retomada da sessão com TTL, dias
Semântica / perfil fatos sobre a entidade (“prefere entrega em Curitiba”, “é cliente antigo”) pipeline de extração todas as sessões daquele usuário quando o fato é invalidado

A terceira linha é a que quase ninguém tem, e é a única que responde “o que eu já sei sobre esta entidade”. O Graphiti, do time do Zep, ataca exatamente esse ponto com grafo temporal. Quando o usuário diz em janeiro que quer entrega em São Paulo e em março diz que mudou para Curitiba, a aresta antiga não é apagada, ganha um invalid_at. O fato novo invalida o velho, e o histórico continua auditável. É uma operação que busca vetorial por similaridade não expressa.

O teste de quatro perguntas

Antes de comprar mais um banco, rode isto no agente que já existe. São quatro verificações que não pedem infraestrutura nova, só coragem para olhar o resultado:

  1. Teste da palavra-chave. Substitua a última mensagem do usuário por “e aí, como fica?”. Se o agente perde o fio da meada, ele nunca teve memória. Teve matching léxico-semântico com a mensagem anterior.
  2. Teste da contradição. Informe um endereço novo depois de um antigo. Pergunte “onde eu recebo?”. Se o agente devolve as duas versões como igualmente verdadeiras, você tem índice, não memória.
  3. Teste da sessão nova. Abra uma thread nova, sem repetir nada, e pergunte sobre um fato dito na sessão anterior. Sessão nova sem contexto é o mesmo que reiniciar o processo, e é o que expõe memória presa à thread. Checkpointers como o do LangGraph salvam estado por thread, o que é ótimo para retomar e inútil para reconhecer o usuário.
  4. Teste do “desde quando”. Peça a data da informação. Sem metadado temporal (valid_at, timestamp de aquisição, origem), o que você tem é chunk. E chunk sem procedência não sustenta decisão de negócio.

E tem a métrica que engana. recall@k do seu índice de retrieval não mede memória. Mede se o trecho certo apareceu entre os k primeiros para queries construídas a partir do próprio corpus. O LongMemEval, benchmark que o time do Zep usa para avaliar o Graphiti, existe porque essa lacuna ficou evidente: pergunta de longo prazo em conversa raramente compartilha vocabulário com o texto que a responde. Seu dashboard pode estar verde com o agente perguntando o número do pedido três vezes.

Quando RAG é a resposta certa (e onde a briga RAG vs memória de agentes de IA começa)

RAG continua sendo a peça correta para base estática, versionada e auditável: documentação, contrato, catálogo de produto, política interna. Conteúdo que muda por deploy, não por conversa. Nesse caso o índice faz o trabalho e faz bem.

A confusão aparece quando o time usa a mesma peça para estado dinâmico. O desenho que eu defendo é prosaico: duas rotas, dois namespaces, dois ciclos de escrita. O índice é alimentado por pipeline de ingestão (documento entra, chunk entra, versão registrada). A memória é alimentada pelo runtime (o agente decide o que vale virar fato e grava com timestamp e entidade). Na leitura, o prompt recebe contexto ativo sempre, perfil da entidade quando existe usuário identificado, e chunks do índice só quando a pergunta é sobre conhecimento. Se for montar isso, a categoria de ferramenta que resolve é orquestração com estado persistente (LangGraph com PostgresSaver, Letta ou equivalente), um banco relacional com pgvector para o índice, e observabilidade (Langfuse e afins) para conseguir ver qual camada respondeu o quê.

O outro extremo existe e é igualmente burro: colocar camada de memória em agente single-turn que só responde dúvida de manual. Overengineering de memória gera o mesmo custo de manutenção que overengineering de índice, só com mais tabelas.

Meu posicionamento: a pergunta “qual vector DB usar para memória de agente” está mal formulada desde o início. O que define se seu agente lembra não é o banco. É se existe uma camada que trata fato como fato, com entidade, validade e contradição. Se o seu time precisa que o usuário repita a palavra-chave para o agente acertar, o problema não está no índice. Está na camada que você ainda não escreveu.

Fontes consultadas

  • MemGPT: Towards LLMs as Operating Systems (arXiv 2310.08560) link
Publicidade