RAG vs memória de agentes de IA: 4 testes em 2026
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:
- 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.
- 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.
- 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.
- 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