Toda vez que vejo um diagrama de arquitetura de agente onde "memória" é uma caixa única apontando para um banco vetorial, sei que o autor nunca precisou operar um além da demo. Memória em um agente não é um sistema único. É uma stack de cinco camadas, cada uma resolvendo um problema diferente, e você escolhe quais camadas precisa com base no que o agente realmente faz.
Vou caminhar pelas cinco camadas, no que cada uma é boa e ruim, e a combinação que eu colocaria em produção se você me pedisse para subir um agente operacional esta semana. Spoiler: Pinecone quase nunca é a resposta certa quando você já roda Postgres.
As Cinco Camadas
Camada 1: Scratchpad In-Context
Este é o padrão. O LLM mantém seus pensamentos, ações e observações no próprio prompt. Zero infraestrutura. Funciona para demos e tarefas de um único passo. Falha no momento em que seu loop roda 15 iterações ou o agente precisa lembrar de algo depois que a sessão termina. Se o pitch que você está olhando tem apenas esta camada, é uma demo.
Camada 2: Cache
Redis com TTL de 24 a 72 horas é a resposta usual aqui. Esta camada guarda estado recente de sessão, resultados recentes de tool calls, preferências de usuário que ainda não pertencem ao store estruturado. O ganho é velocidade. A perda é que um cache chave-valor não é semântico, então você não pode perguntar "já vi um pedido parecido?", só "qual foi o pedido com ID X?". Se você ainda não roda Redis, não adicione por causa disso. Uma tabela unlogged do Postgres com uma coluna expires_at cobre o mesmo terreno sem nenhum serviço novo pra operar, e dá pra trocar no dia em que leituras de cache virarem de fato o seu gargalo.
Camada 3: Store Estruturado
Postgres. Chato, comprovado, e exatamente certo para os dados que têm colunas óbvias: ID do incidente, timestamp, versão do agente, tipo de trigger, tools chamadas, resultado, custo em tokens. Este é o seu audit log, a sua fonte de analytics, e a coisa que seu time de oncall de fato lê quando algo dá errado. Qualquer agente que você espera que passe numa auditoria precisa desta camada, porque ela é o único registro do que o agente de fato fez.
CREATE TABLE agent_runs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
agent_name TEXT NOT NULL,
agent_version TEXT NOT NULL,
trigger_type TEXT NOT NULL,
trigger_payload JSONB NOT NULL,
started_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
ended_at TIMESTAMPTZ,
status TEXT NOT NULL,
outcome JSONB,
tool_calls JSONB,
token_cost INTEGER,
escalated_to_human BOOLEAN DEFAULT FALSE,
confidence NUMERIC(3,2)
);
CREATE INDEX idx_agent_runs_agent_started
ON agent_runs (agent_name, started_at DESC);
CREATE INDEX idx_agent_runs_trigger
ON agent_runs USING GIN (trigger_payload);Camada 4: Vector Store
Esta é a camada que todo mundo fala e na qual a maioria dos times super-investe. O trabalho do vector store é recall semântico: "já tivemos um incidente que parece este?" Você embeda um resumo de incidentes passados, embeda a situação atual, e puxa os top K casos mais similares para dentro do prompt. Feito bem, isso transforma um agente reativo em um que aprende.
Minha opinião firme: se você já roda Postgres, use pgvector. É uma extensão do Postgres, não um serviço separado. Você tem busca semântica sem adicionar outro sistema pra operar, outra fronteira de auth, outro lugar sobre o qual seu oncall tem que saber às 2 da manhã. Pinecone, Weaviate, Qdrant são todos produtos bons. São exagero para a maioria dos times.
CREATE EXTENSION IF NOT EXISTS vector;
CREATE TABLE agent_memory (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
agent_name TEXT NOT NULL,
summary TEXT NOT NULL,
-- 384 dims matches all-MiniLM-L6-v2, which runs locally for free.
-- Bump this to your provider's dimension if you move to a hosted API.
embedding VECTOR(384) NOT NULL,
source_run_id UUID REFERENCES agent_runs(id),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_agent_memory_vector
ON agent_memory USING hnsw (embedding vector_cosine_ops);
-- Query: top 5 similar past incidents for a given embedding
SELECT id, summary, 1 - (embedding <=> $1) AS similarity
FROM agent_memory
WHERE agent_name = $2
ORDER BY embedding <=> $1
LIMIT 5;Camada 5: Sumarização
Esta não é storage. É compressão. Quando uma sessão roda longa, ou quando você puxa 20 incidentes passados do vector store e eles estourariam seu orçamento de contexto, você passa tudo por um LLM para produzir uma versão condensada. Esta é a camada que impede seus custos em tokens de explodir em agentes de longa duração. A maioria dos decks de introdução pula esta porque parece trivial até você ver a fatura.
Como as Camadas Realmente Interagem
Uma execução única de um agente DBA, de ponta a ponta:
- Trigger dispara. Agente acorda com um payload de alerta.
- Antes de chamar o planner do LLM, consulte o vector store em busca de incidentes passados similares. Puxe os top 5.
- Rode esses 5 pela camada de sumarização para comprimir em algumas centenas de tokens.
- Passe a memória comprimida mais o trigger mais o system prompt para o planner. Este é o estado inicial do scratchpad.
- Loop: planeja, chama tool, observa, repete. Scratchpad cresce.
- No fim, escreva o resultado estruturado no Postgres e um resumo semântico no pgvector. A próxima execução aprende com esta.
Nenhuma camada sozinha daria conta de tudo isso. Scratchpad te dá estado de sessão. Postgres te dá auditoria e analytics. pgvector te dá o "já vimos isso?". Sumarização impede o contexto de explodir. O cache cobre dados quentes que você não quer recalcular a cada execução.
A Stack Que Eu Realmente Colocaria em Produção
O Erro Que Mais Vejo
Times tratam memória como algo secundário. Constroem o loop, sobem em produção, e só depois parafusam memória três meses depois quando o agente começa a cometer o mesmo erro duas vezes. Nessa altura o log estruturado é um blob JSON no S3 sem schema, e você não consegue reconstruir o histórico porque nunca o capturou direito.
Desenhe o schema do Postgres antes de escrever a primeira tool call. Você não precisa construir a camada vetorial no dia um. Você precisa capturar cada execução com detalhe suficiente para que possa fazer backfill do vector store depois a partir dos mesmos dados.
O agente que lembra é um produto diferente do agente que reage. Escolha um de propósito.
Referências
- pgvector: https://github.com/pgvector/pgvector
- Anthropic, Building Effective Agents (padrões de design de agentes): https://www.anthropic.com/engineering/building-effective-agents
- Paper do MemGPT (memória hierárquica para LLMs): https://arxiv.org/abs/2310.08560