Crie agentes que nunca esquecem

@akshay_pachaar
INGLÊShá 3 meses · 13/04/2026
625K
1.9K
305
46
4.1K

TL;DR

Uma análise técnica aprofundada sobre sistemas de memória para agentes de IA, evoluindo de listas simples para o motor de grafo-vetorial de código aberto da Cognee, focado em raciocínio relacional e persistente.

Uma análise fundamentada sobre memória de agentes: de listas em Python a arquivos markdown, busca vetorial, híbridos de grafos e vetores, e, por fim, uma solução limpa e open-source para tudo isso.

Akshay 🚀 - inline image

Um LLM é inerentemente stateless. Cada chamada de API começa do zero. A "memória" que você sente ao conversar com o ChatGPT é uma ilusão criada ao reenviar todo o histórico da conversa a cada requisição.

Esse truque funciona para conversas casuais. Ele desmorona no momento em que você tenta construir um agente real.

Aqui estão 7 modos de falha que aparecem assim que você ignora a memória:

  1. Amnésia de contexto: o agente pergunta por informações que você já forneceu
  2. Zero personalização: toda interação parece genérica
  3. Falha em tarefas de múltiplas etapas: o estado intermediário desaparece silenciosamente no meio da tarefa
  4. Erros repetidos: sem recordação episódica, os mesmos erros acontecem para sempre
  5. Nenhum acúmulo de conhecimento: cada sessão começa do zero
  6. Alucinação por lacunas: quando o contexto transborda, o modelo inventa
  7. Colapso de identidade: sem continuidade, não há confiança

A resposta óbvia é "jogar mais contexto nisso". É por isso que janelas de 128K e 200K tokens parecem que deveriam resolver tudo.

Não resolvem.

A precisão cai mais de 30% quando informações relevantes estão no meio de um contexto longo. Este é o bem documentado efeito "perdido no meio".

Contexto é um orçamento compartilhado: prompts de sistema, documentos recuperados, histórico de conversas e saída competem pelos mesmos tokens.

Mesmo com 100K tokens, a ausência de persistência, priorização e saliência torna o comprimento do contexto bruto insuficiente.

Akshay 🚀 - inline image

Memória não é sobre enfiar mais texto no prompt. É sobre estruturar o que o agente lembra para que ele possa encontrar o que importa.

O framework da ciência cognitiva que realmente ajuda

A formulação de Lilian Weng em 2023 tornou-se o framework padrão:

Agente = LLM + Memória + Planejamento + Uso de Ferramentas.

Os quatro pilares de igual importância.

Sua taxonomia empresta da ciência cognitiva, onde a memória humana se divide em três sistemas:

  • Memória sensorial captura a entrada perceptual bruta e a mantém por uma fração de segundo. Apenas as partes às quais você presta atenção são passadas adiante.
  • Memória de trabalho é onde o pensamento ativo acontece. Ela mantém aproximadamente 7±2 itens por vez (descoberta de Miller em 1956). Perde o foco, e o conteúdo desaparece.
  • Memória de longo prazo é um armazenamento durável sem limite prático de capacidade. A recuperação é o gargalo: você pode armazenar milhões de coisas e ainda assim falhar em lembrar a que precisa.

Cada uma mapeia diretamente para um componente nas arquiteturas modernas de agentes:

Akshay 🚀 - inline image

A memória de longo prazo se divide ainda mais:

  • Episódica: eventos passados específicos ("na terça-feira, o cluster PostgreSQL caiu")
  • Semântica: fatos e conceitos ("PostgreSQL é um banco de dados relacional")
  • Procedural: habilidades e fluxos de trabalho ("quando um usuário pede um reembolso, primeiro verifique a data da compra")

A ponte entre o episódico e o semântico é a consolidação da memória: eventos específicos repetidos se destilando em conhecimento geral. Um agente que percebe "usuários consistentemente preferem resumos executivos" em dezenas de interações deve transformar isso em uma regra reutilizável. Sem consolidação, seu agente reproduz eventos individuais em vez de aprender com eles.

Akshay 🚀 - inline image

O agente mínimo, e o que quebra primeiro

Tirando os frameworks, um agente é um loop: perceber, pensar, agir.

python
1class Agent:
2 """Agente de IA mínimo: perceber, pensar, agir"""
3 def __init__(self):
4 self.client = anthropic.Anthropic()
5 self.model = "claude-sonnet-4-20250514"
6
7 def run(self, user_input: str) -> str:
8 response = self.client.messages.create(
9 model=self.model,
10 max_tokens=1024,
11 messages=[{"role": "user", "content": user_input}],
12 )
13 return response.content[0].text

Diga a ele "Tenho 4 maçãs", então pergunte "Comi uma, quantas sobraram?" e ele não tem ideia de quais maçãs você está falando. Cada chamada existe isoladamente.

Camada 1: A lista em Python

A primeira correção que todos tentam:

python
1class Agent:
2 def __init__(self):
3 self.client = anthropic.Anthropic()
4 self.messages = [] # Toda a "memória" é uma lista
5
6 def chat(self, user_input: str) -> str:
7 self.messages.append({"role": "user", "content": user_input})
8 response = self.client.messages.create(
9 model="claude-sonnet-4-20250514",
10 max_tokens=1024,
11 messages=self.messages, # Histórico completo enviado a cada vez
12 )
13 reply = response.content[0].text
14 self.messages.append({"role": "assistant", "content": reply})
15 return reply

Múltiplas voltas funcionam agora. A pergunta das maçãs é respondida corretamente porque a conversa completa é reenviada a cada chamada.

Dois problemas aparecem rapidamente:

  • A lista cresce sem limites. Por volta da volta 200, você atinge o teto de contexto e as mensagens mais antigas são descartadas silenciosamente. O nome do usuário da volta 1 desaparece muito antes de uma piada descartável de ontem. Sem priorização, apenas ordem cronológica estrita.
  • Tudo vive na RAM. No momento em que o processo Python termina, seu agente não faz ideia de quem você é.

Camada 2: Arquivos Markdown para persistência

O próximo passo é escrever a memória no disco. Markdown é uma escolha natural: legível por humanos, amigável ao Git, e o agente pode lê-lo de volta como texto simples. O Claude Code usa exatamente este padrão com arquivos CLAUDE.md e MEMORY.md.

python
1class MarkdownMemoryAgent:
2 def __init__(self):
3 self.client = anthropic.Anthropic()
4 self.history_file = Path("memory/conversation_history.md")
5 self.facts_file = Path("memory/known_facts.md")
6
7 def save_to_disk(self, role: str, content: str) -> None:
8 with open(self.history_file, "a") as f:
9 f.write(f"### {role} at {datetime.now().isoformat()}\n{content}\n\n")
10
11 def load_history(self) -> str:
12 if self.history_file.exists():
13 return self.history_file.read_text()
14 return ""
15
16 def chat(self, user_input: str) -> str:
17 self.save_to_disk("user", user_input)
18 history = self.load_history()
19 response = self.client.messages.create(
20 model="claude-sonnet-4-20250514",
21 max_tokens=1024,
22 system=f"Conversa anterior:\n{history}",
23 messages=[{"role": "user", "content": user_input}],
24 )
25 reply = response.content[0].text
26 self.save_to_disk("assistant", reply)
27 return reply

A persistência está resolvida. Reinicie o script, e a conversa ainda está no disco. Você também pode manter um arquivo de fatos separado que o agente extrai ao longo do tempo:

text
1- O nome do usuário é Sarah
2- Sarah gerencia o time de backend na Acme Corp
3- Acme Corp é uma empresa de SaaS B2B
4- Atualmente migrando o banco de dados de produção para uma nova região da AWS

Você pode abrir o arquivo em qualquer editor, ver exatamente o que o agente sabe e corrigi-lo manualmente. Genuinamente útil para prototipagem.

Com 4 fatos, isso funciona perfeitamente. Carregue o arquivo inteiro no contexto e o LLM lida com qualquer pergunta sobre Sarah, sua empresa ou seu setor.

Agora avance três meses. Seu agente tem 2.000 fatos extraídos e 200 registros de conversas. Isso são 500K+ tokens de markdown no disco, e sua janela de contexto é de 128K.

Você não pode mais carregar tudo. Você precisa recuperar seletivamente apenas os fatos relevantes para a consulta atual. Com arquivos planos, sua única opção é a busca por palavra-chave:

python
1# Usuário pergunta: "Qual é o status da nossa migração para a nuvem?"
2grep("migração para a nuvem", facts_file)
3# Retorna: []
4# O fato no disco diz "migrando banco de dados de produção para uma nova região da AWS."
5# As palavras "migração para a nuvem" não aparecem em lugar nenhum.
6
7# Usuário pergunta: "Qual time está cuidando do trabalho com o banco de dados?"
8grep("time do banco de dados", facts_file)
9# Retorna: []
10# Um fato diz que Sarah "gerencia o time de backend." Outro diz que o time
11# está "migrando o banco de dados de produção." Mas nenhuma linha contém
12# "banco de dados" e "time" juntos.

Em pequena escala, arquivos markdown funcionam. Em escala real, eles forçam a recuperação por palavra-chave, e palavras-chave não conseguem lidar com sinônimos, paráfrases ou conexões entre fatos.

A informação está no disco. Mas você não pode carregar tudo, e a busca por palavra-chave é frágil demais para encontrar as peças certas.

Se você já usou o OpenClaw, já viu isso acontecer. Ele armazena a memória como arquivos de checkpoint em markdown e, após semanas de uso diário, fatos anteriores desaparecem silenciosamente à medida que o contexto se acumula e é compactado. O armazenamento está lá. A recuperação não está.

Armazenamento sem recuperação inteligente é uma biblioteca sem catálogo.

Camada 3: Busca vetorial e o muro que ela encontra

Adicione embeddings. Divida seu markdown em chunks, incorpore os chunks, busque por similaridade de cosseno. Agora "banco de dados" corresponde a "PostgreSQL" porque seus vetores vivem próximos no espaço de embedding. O problema do sinônimo se dissolve.

Então você encontra um novo muro. Considere estes três fatos em seu banco de dados vetorial:

text
1- "Alice é a líder técnica do Projeto Atlas"
2- "Projeto Atlas usa PostgreSQL como armazenamento de dados principal"
3- "O cluster PostgreSQL teve uma interrupção na terça-feira"

Usuário pergunta: "O projeto da Alice foi afetado pela interrupção de terça?"

A consulta menciona Alice e a interrupção de terça, então a busca vetorial classifica o primeiro e o terceiro fatos como altos. Mas a ponte crítica, "Projeto Atlas usa PostgreSQL", não menciona nem Alice nem terça-feira. É a peça de conexão, e é a que não vai aparecer.

Cada fato é um ponto isolado no espaço de embedding. O tecido conjuntivo que os liga é invisível para os vetores.

Akshay 🚀 - inline image

Isso não é um caso extremo. É a forma normal das perguntas do mundo real. O conhecimento empresarial é inerentemente relacional: pessoas pertencem a equipes, equipes possuem projetos, projetos dependem de sistemas, sistemas têm incidentes. Qualquer pergunta que cruze dois ou mais saltos excede o que a recuperação vetorial plana pode responder.

A matriz de capacidades

Cada camada corrige a dor anterior, mas revela uma mais profunda:

Akshay 🚀 - inline image

Você precisa de persistência, compreensão semântica e raciocínio relacional em uma única camada de memória.

Construir isso sozinho significa colar um banco de dados vetorial, um banco de dados de grafo, um armazenamento relacional, um extrator de entidades, um pipeline de desduplicação e um sistema de ponderação de arestas. São semanas de trabalho de infraestrutura antes de escrever uma única linha de lógica de agente.

Eu tenho usado uma solução que preenche essa lacuna de forma limpa. É totalmente open-source, lida com todos os três paradigmas de armazenamento sob o mesmo teto, e você pode colocá-la para funcionar em minutos. Vamos falar sobre Cognee.

Cognee: três armazenamentos, um mecanismo, quatro chamadas

Cognee é um mecanismo de conhecimento open-source construído para memória de agentes. Ele combina busca vetorial com grafos de conhecimento e uma camada de proveniência relacional em um único sistema.

Toda a superfície da API são quatro chamadas assíncronas:

python
1import cognee
2
3await cognee.add("Seu documento aqui") # Ingerir qualquer coisa
4await cognee.cognify() # Construir grafo de conhecimento + embeddings
5await cognee.memify() # Automelhorar a memória
6await cognee.search("Sua consulta") # Recuperar com raciocínio

Por trás dessas quatro chamadas, há uma arquitetura de três armazenamentos.

Akshay 🚀 - inline image

Por que três armazenamentos e não um?

Cada armazenamento captura uma dimensão do conhecimento que os outros não conseguem:

  • Armazenamento relacional → proveniência: de onde os dados vieram, quando foram ingeridos, quem tem acesso
  • Armazenamento vetorial → semântica: o que o conteúdo significa, ao que é semelhante
  • Armazenamento de grafo → relacionamentos: como as entidades se conectam, o que causa o quê, quem se reporta a quem

Achate qualquer um deles e você perde informações que importam para a precisão da recuperação.

A pilha padrão é SQLite + LanceDB + Kuzu, totalmente embarcada e baseada em arquivos. pip install cognee mais uma chave de API de LLM e você está rodando.

Sem Docker, sem serviços externos.

Para produção, troque o SQLite por Postgres, o LanceDB por Qdrant/Pinecone/pgvector e o Kuzu por Neo4j/FalkorDB/Neptune.

A mesma API de quatro chamadas de qualquer forma.

O que o cognify realmente faz?

cognee.cognify() executa um pipeline de múltiplos estágios que converte texto bruto em conhecimento estruturado e interconectado:

  1. Classificação de documentos por tipo e domínio
  2. Verificação de permissões para controle de acesso multi-tenant
  3. Extração de chunks que respeita a estrutura de parágrafos (não cortes de tamanho fixo)
  4. Extração de entidades e relacionamentos via LLM, com desduplicação automática através de hashing de conteúdo
  5. Geração de resumos para recuperação eficiente
  6. Indexação dupla no armazenamento vetorial (embeddings) e no armazenamento de grafo (arestas)

A etapa de desduplicação é mais importante do que parece. Se a mesma entidade aparecer em 50 documentos, o Cognee a mescla em um único nó do grafo com 50 arestas de entrada. Seu agente não vê mais "Alice" como 50 estranhos diferentes. E o pipeline é incremental por padrão: apenas arquivos novos ou atualizados são reprocessados.

Akshay 🚀 - inline image

Cada nó do grafo tem um embedding correspondente. Esta representação dupla é o truque central: entre pelos vetores (encontre conteúdo semanticamente semelhante) e saia pelo grafo (siga relacionamentos para entidades conectadas), ou o inverso. É isso que torna as consultas de múltiplos saltos possíveis sem sacrificar a busca semântica.

Memify: memória que aprende

memify() é o que diferencia o Cognee de toda ferramenta de "ingerir e pesquisar". Ele executa uma passagem de otimização inspirada em RL sobre o grafo:

  • Fortalecendo caminhos úteis que levaram a uma boa recuperação
  • Podando nós obsoletos que não foram tocados
  • Autoajustando pesos de arestas com base no uso real
  • Adicionando fatos derivados identificando relacionamentos implícitos

O grafo de um agente de suporte ao cliente naturalmente fortalece caminhos através de documentos de produto e políticas de reembolso, enquanto permite que arestas de RH raramente consultadas decaiam. O grafo desenvolve seu próprio senso de relevância ao longo do tempo.

Akshay 🚀 - inline image

Quatorze modos de recuperação

O Cognee oferece 14 modos de busca. Os que você realmente usará:

Akshay 🚀 - inline image

Construindo um agente real com a memória do Cognee

Aqui está o padrão completo conectando o Cognee ao loop perceber-pensar-agir:

python
1import cognee
2from cognee import SearchType
3
4class CogneeMemoryAgent:
5 """Agente com memória persistente híbrida de grafo e vetor."""
6
7 def __init__(self, session_id: str = "default"):
8 self.llm_client = OpenAI()
9 self.session_id = session_id
10
11 async def ingest(self, text: str, dataset: str = "main"):
12 await cognee.add(text, dataset)
13 await cognee.cognify([dataset])
14
15 async def recall(self, query: str) -> str:
16 results = await cognee.search(
17 query_text=query,
18 query_type=SearchType.GRAPH_COMPLETION,
19 session_id=self.session_id,
20 )
21 return results[0] if results else ""
22
23 async def chat(self, user_input: str) -> str:
24 context = await self.recall(user_input)
25 messages = [
26 {"role": "system", "content": "Você é útil. Use o contexto da memória."},
27 {"role": "system", "content": f"Contexto da memória:\n{context}"},
28 {"role": "user", "content": user_input},
29 ]
30 response = self.llm_client.chat.completions.create(
31 model="gpt-4o-mini", messages=messages
32 )
33 reply = response.choices[0].message.content
34 await cognee.add(
35 f"Usuário: {user_input}\nAssistente: {reply}",
36 "conversas"
37 )
38 await cognee.cognify(["conversas"])
39 return reply

O ciclo da memória: ingerir, extrair, armazenar, recuperar, responder, armazenar novamente. Cada turno enriquece o grafo de conhecimento, e o processamento incremental significa que você só paga para indexar novo conteúdo.

A memória de sessão lida com a resolução de pronomes automaticamente:

python
1await cognee.search(query_text="Onde a Alice mora?", session_id="conv_1")
2await cognee.search(query_text="O que ela faz para trabalhar?", session_id="conv_1")
3# "ela" resolve para Alice a partir do contexto da sessão

O multi-tenancy é incorporado no nível do grafo com permissões por conjunto de dados (ler, escrever, deletar, compartilhar). Não é separação de namespace, é isolamento real no nível do grafo.

O caminho prático a seguir

Se você está construindo um agente hoje, a verdadeira pergunta inicial é: "o que meu agente precisa lembrar e que tipo de perguntas ele vai responder?"

Se suas consultas só precisam de busca por similaridade ("encontre conversas como esta"), a memória apenas com vetores funciona. No momento em que as consultas cruzam limites de entidades ("O projeto da Alice foi afetado pela interrupção de terça-feira?"), você precisa de travessia de grafo.

Você pode conectar armazenamentos separados de vetor, grafo e relacional por conta própria. Equipes que seguem esse caminho tipicamente perdem semanas em infraestrutura para uma camada de memória que ainda não aprende com seu próprio uso.

O Cognee reduz isso a quatro chamadas de API. Os padrões embarcados fazem você rodar em minutos. Backends substituíveis (Postgres, Qdrant, Neo4j) levam você à produção sem alterar o código do seu agente.

Inteligência requer estrutura, não apenas armazenamento. Os três paradigmas de armazenamento (relacional, vetorial, grafo) não são opções concorrentes. São camadas complementares do mesmo sistema de memória. Tratá-los dessa forma é o que transforma um invólucro de LLM sem estado em algo que realmente aprende.

Qual é a próxima coisa que você gostaria que seu agente se lembrasse amanhã e que ele esqueceu hoje? Comece por aí.

👉 [ Confira o Cognee no GitHub →https://github.com/topoteretes/cognee)**, dê uma estrela e tente conectá-lo ao seu próximo agente.**

Quatro chamadas assíncronas, um pip install, e você está rodando.

É isso aí!

Se você gostou de ler isso:

Me encontre → @akshay_pachaar ✔️

Todos os dias, compartilho tutoriais e insights sobre IA, Machine Learning e as melhores práticas de vibe coding.

Guardar com um clique

Faça leitura aprofundada de artigos virais com IA no YouMind

Guarde a fonte, faça perguntas específicas, resuma o argumento e transforme um artigo viral em notas reutilizáveis num único espaço de trabalho com IA.

Explorar o YouMind
Para criadores

Transforme o seu Markdown num artigo 𝕏 impecável

Quando publica os seus próprios textos longos, formatar imagens, tabelas e blocos de código para o 𝕏 é uma dor de cabeça. O YouMind transforma um rascunho completo em Markdown num artigo 𝕏 impecável e pronto a publicar.

Experimente Markdown para 𝕏

Mais padrões para decifrar

Artigos virais recentes

Explorar mais artigos virais