Conceitos · · 9 min de leitura · Time Catcher Agents

Memória de agentes em camadas:
verbatim, resumos e o ciclo de sono

Quase todo stack de agentes anuncia "memória", e quase sempre o mecanismo é um só: reenviar o histórico do chat inteiro a cada chamada. Isso não é memória — é um prompt cada vez mais caro. Mostramos o modelo em camadas da Catcher Agents: turnos verbatim, resumos de curto prazo e fatos duráveis, consolidados por um ciclo de sono e isolados por usuário final.

O volume diminui de camada em camada; o valor durável aumenta.

Memória seletiva

Menos volume, mais permanência

VerbatimTurnos recentes · literal · sessão
L3Observações diárias · dias
L4Fatos e preferências · meses+
  1. Sono leveDeduplica e reforça.
  2. ProfundoPromove e descarta.
  3. REMDecai, conecta e sintetiza.

A abordagem ingênua funciona na demo: a conversa tem dez turnos, tudo cabe no prompt, o modelo "lembra" de tudo. Em produto, quando a conversa vira semanas e os usuários viram milhares, ela degrada em silêncio. O problema não é detalhe de implementação — é estrutural. Reenviar tudo tem três custos que só crescem:

  • Custo por chamada. Cada turno antigo reenviado é tokenizado e cobrado de novo, em toda requisição. O gasto de uma conversa cresce com o quadrado do seu comprimento: o turno 200 paga pelos 199 anteriores.
  • Limite de contexto. A janela do modelo é finita, e um relacionamento de meses não cabe nela. Alguém decide o que cortar — e o corte ingênuo (descartar o mais antigo) joga fora exatamente os fatos duráveis: o nome, a preferência, a restrição dita uma vez, três meses atrás. A falha é silenciosa: nada retorna erro, o agente só passa a responder como se aquilo nunca tivesse sido dito.
  • Nenhuma persistência real. Histórico vive por sessão. O usuário fecha o chat, volta amanhã por outro canal, e o agente o trata como um estranho. O que parecia memória era só a sessão ainda aberta.

E mesmo dentro da janela, contexto longo não garante recuperação: modelos atendem pior ao que está enterrado no meio de um prompt gigante. Empilhar mais texto reduz — não aumenta — a chance de o fato certo pesar na resposta.

Contexto é RAM: rápido, caro e volátil. Memória é o que sobrevive quando a sessão fecha — e ela precisa viver fora do prompt.

O que memória precisa fazer, de verdade

Antes do "como", o contrato. Para merecer o nome, a memória de um agente precisa: persistir entre sessões e canais; ser seletiva, retendo o que importa em vez de tudo; caber num orçamento de tokens que não cresce com a idade do relacionamento; ser isolada por usuário final; e ser inspecionável por quem opera o agente. O histórico de chat cru não cumpre nenhum desses cinco pontos. O modelo em camadas cumpre todos.

O modelo em camadas

Em vez de um blob único que só cresce, a memória é dividida em camadas com granularidade e tempo de vida diferentes — cada uma responde por um tipo de lembrança.

Verbatim: os turnos recentes, palavra por palavra

A camada mais rasa é o histórico recente cru — os últimos turnos, sem compressão. É o que resolve pronomes ("e nesse caso?"), correções imediatas e o fio da conversa atual. É uma janela pequena e deslizante: barata porque é curta, fiel porque é literal.

Vive só a sessão — e os turnos crus não sobem de camada em bloco: a cada troca, um extrator anota observações tipadas (fato, preferência, evento, habilidade, estilo) na camada seguinte. Quando a sessão fecha, o que tinha valor durável já virou registro datado em L3.

L3: resumos de curto prazo

Acima dela, resumos diários condensam o que aconteceu nos últimos dias: "pediu reagendamento da consulta de quinta, ficou de confirmar o horário". A L3 é a ponte entre o turno cru e o fato durável — carrega o contexto recente por uma fração dos tokens que os turnos originais custariam.

Cada entrada é datada e tipada, e vive dias, por design: a L3 é matéria-prima do ciclo de sono, não arquivo — entradas já consolidadas são podadas em cerca de uma semana. Repetição não é ruído: a mesma preferência dita em três conversas vira sinal de reforço, não três registros.

L4: fatos duráveis, preferências e estilo

No fundo, a camada de longo prazo guarda o que define a pessoa ao longo de meses: "prefere ser chamada de Dra. Marina", "alérgico a dipirona", "responde melhor a mensagens curtas e diretas". São declarações pequenas e de alto valor — o tipo de coisa dita uma vez que precisa valer para sempre.

Cada memória de L4 carrega um score de importância (0–100); fatos imutáveis de identidade — nome, língua nativa — levam uma marca de permanência e nunca decaem. A camada também guarda duas peças sintetizadas: um perfil de estilo único e evolutivo (como a pessoa se comunica — atualizado a cada consolidação, não N linhas repetidas) e sínteses que conectam duas ou mais memórias. Vida de meses ou anos, condicionada a uso — o decaimento é parte do contrato.

No modo padrão, o Brain consulta L3 e L4 sob demanda: o modelo escolhe qual informação procurar, enquanto o backend sela empresa, agente e usuário final. A janela da conversa atual continua no contexto, mas o conjunto inteiro de memórias não é despejado automaticamente em todo turno. A injeção de um bloco compacto com perfil, fatos L4 e observações L3 pertence ao legacy_mode, um opt-out depreciado mantido por compatibilidade. Nos dois caminhos, a curadoria em camadas evita que o histórico vire um blob que só cresce.

O ciclo de sono: consolidar em vez de acumular

Camadas sozinhas ainda acumulariam ruído. O que fecha o sistema é o ciclo de sono (dream cycle): um processo que roda entre as conversas, relê o material bruto e decide o que sobe, o que se funde e o que morre. Um fato que se repete em três conversas é promovido para a L4. Dois registros sobre a mesma preferência viram um. Small talk e logística resolvida ("chego 10 minutos atrasado") são descartados.

A metáfora vai até o fim — são três fases: o sono leve deduplica a L3 (repetição vira reforço); o sono profundo faz a curadoria — promove o que sobreviveu para a L4 com score de importância e descarta o que fica abaixo do corte, fundindo paráfrases do mesmo assunto sem nunca fundir assuntos diferentes; e o REM trabalha sobre a própria L4 — aplica o decaimento, esquece o que caiu abaixo do piso, escreve sínteses conectando duas ou mais memórias e atualiza o perfil de estilo.

turnos verbatim da sessão                     [vida: a sessão]
   |
   |  extrator por turno: observações tipadas
   |  (fato, preferência, evento, habilidade, estilo)
   v
L3 — observações diárias, datadas             [vida: dias]
   |
   |  ciclo de sono ("Sonhar")
   |    1. sono leve     -> dedup: repetição vira reforço
   |    2. sono profundo -> cura e promove (importância >= corte);
   |                        o que fica abaixo é descartado
   |    3. REM           -> decai, esquece (piso), sintetiza,
   |                        atualiza o perfil de estilo
   v
L4 — fatos duráveis, preferências,            [vida: meses+,
     perfil de estilo, sínteses (0-100)        com decaimento]
   |
   +-- Brain padrão: recall sob demanda, com escopo selado
   +-- legacy_mode: bloco compacto injetado por compatibilidade

O esquecimento tem mecânica explícita, não é efeito colateral de corte de janela: a importância decai exponencialmente com o tempo desde a última recorrência do tópico. Quando o extrator encontra de novo um fato que a L4 já guarda, a deduplicação reforça a memória existente e atualiza esse marco; abaixo de um piso, ela é removida. Ler uma memória pelo Brain não incrementa esse contador. O que volta a aparecer permanece; o que nunca mais apareceu vai embora.

A analogia com o sono biológico é honesta: consolidar, durante a folga, o que o dia produziu — e esquecer o resto. Em termos de engenharia, é uma troca deliberada: um passe offline que custa tokens uma vez, em vez de reenviar o ruído em toda chamada, para sempre. E o esquecimento é recurso, não falha. Memória que retém tudo é só um log; o valor está na seleção.

A memória tem endpoints

Nada disso é caixa-preta. Cada camada é legível e apagável pela mesma API que o Console usa — estes são os endpoints que um desenvolvedor ou operador toca:

  • POST /v1/agents/{id}/dream — roda o ciclo completo (leve → profundo → REM) para o agente.
  • POST /v1/agents/{id}/memory/consolidate — passe único que reprocessa a pilha inteira de L3, incluindo o que já foi promovido; útil para migrar um agente que acumulou backlog.
  • GET /v1/agents/{id}/daily e DELETE /v1/agents/{id}/daily — listam e limpam a L3 (dá para apagar uma entrada específica também).
  • GET /v1/agents/{id}/memories e DELETE /v1/agents/{id}/memories/{docID} — listam a L4 e removem uma memória pontual.
  • GET /v1/agents/{id}/conversation-memory — histórico verbatim opcional para o Console. Quando habilitado, cada troca é arquivada de forma assíncrona (fire-and-forget), pesquisável e separada do prompt e do ciclo de sonho; falhas de armazenamento não bloqueiam a resposta do agente.

Disparar um sonho é uma chamada:

curl -X POST https://agents-api.catcher.one/v1/agents/AGENT_ID/dream \
  -H "Authorization: Bearer $TOKEN"

A resposta devolve os contadores do ciclo — quantas entradas foram consideradas, quantas duplicatas caíram no sono leve, quantas memórias foram promovidas, quantas decaíram ou foram esquecidas no REM e quantas sínteses nasceram:

{ "considered": 42, "duplicates": 9, "promoted": 6, "decayed": 3,
  "forgotten": 2, "synthesized": 1, "rem_before": 31, "rem_after": 30 }

Uma consolidação completa faz dezenas de chamadas ao modelo e pode levar minutos, então existe a variante POST /v1/agents/{id}/dream/stream, que emite o progresso por SSE, fase a fase — é ela que o botão "Sonhar" do Console usa para mostrar o andamento em vez de um spinner cego.

Isolada por usuário final: a parte que vira produto

Agora a propriedade mais importante. Toda leitura e escrita de memória é chaveada pelo end_user_external_id — o identificador que o seu sistema usa para o usuário final. A memória do cliente A nunca entra no prompt do cliente B. Não por uma instrução educada no system prompt, mas por construção: a consulta ao armazenamento já sai filtrada pela chave.

É isso que torna a memória segura para o caso embedded. Pense numa software house que atende dezenas de clínicas: cada paciente conversa com um agente que lembra dele — do tratamento, da preferência de horário — e nada vaza entre pacientes. O isolamento opera em dois níveis: cada tenant (cada clínica, no exemplo) vive num schema de banco dedicado, e dentro dele a memória é particionada por pessoa via end_user_external_id. A partição vale até para o passe offline: o ciclo de sono agrupa as observações por usuário final antes de consolidar, então nem o processo que roda entre as conversas mistura as pessoas. Não é hipótese: um SaaS de gestão de clínicas roda agentes nossos em produção exatamente nesse desenho, com memória por paciente.

Na integração, você não escreve uma linha de lógica de memória: ao embutir o agente via runtime tokens, o end_user_external_id vai na criação da sessão e o resto acontece sozinho. São três chamadas — token, sessão, mensagem — e cada usuário do seu app passa a ter a própria memória.

Inspecionável e removível no Console

Memória que ninguém consegue inspecionar é passivo. No Console da Catcher Agents, você enxerga o que o agente lembra de cada usuário final, camada por camada, e remove o que não deveria ter sido retido. A curadoria mapeia direto para os endpoints da seção anterior — apagar uma memória de L4 é um DELETE, remover uma entrada ou limpar a L3 são outros — e o botão "Sonhar" dispara a consolidação com progresso ao vivo. A superfície atual não edita o texto de uma memória no lugar: para corrigir um fato, o operador remove o registro incorreto e deixa a informação correta ser aprendida novamente.

Memória não é conhecimento

Vale separar dois sistemas que costumam ser confundidos. Memória é por pessoa: aprendida da conversa, diferente para cada usuário final, mutável ao longo do relacionamento. Conhecimento é compartilhado: os seus documentos, os mesmos para todos, recuperados por pergunta e citados na resposta — é o RAG híbrido que levamos a 100% de hit@5. Um agente útil precisa dos dois: conhecimento para responder certo, memória para responder certo para aquela pessoa.

Perguntas frequentes

Qual a diferença entre contexto e memória?

A janela de contexto é a memória de trabalho do modelo: existe só durante a chamada e custa tokens a cada requisição. Memória é o que persiste fora do prompt — fatos, preferências e resumos armazenados por usuário final — e volta em forma compacta na conversa seguinte, em outra sessão ou em outro canal.

Como a memória de um cliente fica isolada da de outro?

Toda leitura e escrita de memória é chaveada pelo end_user_external_id, o identificador do usuário final no seu sistema. O agente que atende o cliente A só enxerga as camadas do cliente A; nada do que o cliente B disse entra no prompt. É isso que torna a memória segura para produtos multi-tenant, como uma software house atendendo dezenas de clínicas.

O agente esquece coisas de propósito?

Sim — esquecer é parte do design, não falha. Na consolidação, duplicatas são fundidas e observações abaixo do corte de importância são descartadas. Depois, com o tempo, a importância de cada memória decai; o que não volta a aparecer cai abaixo de um piso e é removido, enquanto a recorrência de um tópico reforça a memória correspondente. Memória que retém tudo é só um log — a seleção mantém o recall relevante.

Posso ver e editar o que o agente lembra?

Você pode ver as camadas no Console, remover uma memória específica de longo prazo, apagar uma observação diária ou limpar uma camada. A superfície atual não oferece edição direta do texto de uma memória; para corrigir um fato, remova o registro incorreto e deixe a informação correta ser aprendida novamente.

Dê memória ao seu agente

A memória em camadas já vem ligada em cada agente da Catcher Agents. Crie um agente, converse, feche a sessão e volte amanhã: ele lembra — e você inspeciona ou remove cada registro no Console.

Continue lendo

Engenharia

De 71% a 100% de hit@5

Recuperação híbrida (denso + léxico com RRF) e re-ranking, medidos num benchmark determinístico.

Guias

Embuta um agente em 3 chamadas

Runtime token, sessão e mensagem com SSE — o caminho mais curto para um agente dentro do seu produto.