Sessions, Memory & Skills
LLMs são stateless: cada chamada de API nasce sem lembrar de nada. Para que um agente lembre, aprenda e personalize, alguém precisa montar — turno a turno — a informação certa dentro da context window. Esse ofício é a Context Engineering. Este guia resume o paper "Context Engineering: Sessions, Memory" (Kimberly Milam & Antonio Gulli, Google) em formato interativo: diagramas clicáveis, simuladores, quiz e cheatsheets.
Pressupõe familiaridade com LLMs e desenvolvimento de software. Não pressupõe conhecimento prévio de frameworks de agentes — ADK e LangGraph são apresentados como exemplos, não como pré-requisito.
O que é Context Engineering
O ofício de montar, a cada turno, a informação certa dentro da janela de contexto — nem mais, nem menos.
LLMs são inerentemente stateless: todo o seu raciocínio acontece dentro da context window de uma única chamada de API. Nada do que veio antes existe para o modelo — a menos que alguém coloque lá. Context Engineering é o processo de montar e gerenciar dinamicamente a informação dentro da context window para habilitar agentes stateful e inteligentes.
É a evolução natural do Prompt Engineering: em vez de lapidar uma instrução estática, o engenheiro de contexto orquestra o payload inteiro — selecionando, resumindo e injetando estrategicamente diferentes tipos de informação a cada turno, com máxima relevância e mínimo ruído. Sistemas externos (RAG, session stores, memory managers) gerenciam o contexto; o framework orquestra tudo.
O chef não cozinha com a receita na mão — cozinha com a bancada pronta
Um chef que só tem a receita usa ingredientes aleatórios que encontra pela frente. O prato sai… ok. É o prompt estático: uma boa instrução, sem contexto preparado.
O chef reúne e prepara todos os ingredientes, organiza as ferramentas e define o estilo de apresentação antes de cozinhar. É o contexto completo: histórico, memórias, fatos, ferramentas — tudo no lugar, na hora certa.
Prompt = a receita
- diz o que fazer
- não sabe o que está na geladeira
- resultado imprevisível
Contexto = ingredientes preparados
- receita + ingredientes certos + ferramentas + apresentação
- montado a cada prato (a cada turno)
- nem mais, nem menos que o necessário
O objetivo não é encher a janela de contexto — é entregar a informação mais relevante para este turno. Nem mais, nem menos.
O payload do contexto
Três camadas de componentes — clique em cada uma para ver o que ela contém.
Tudo o que o modelo "vê" em um turno cabe em três categorias. A construção é dinâmica: memórias não são estáticas, few-shot examples devem ser relevantes à tarefa (não hardcoded) e o RAG responde à query imediata.
Contexto que guia o raciocínio
comportamentoFatos & evidências
sobre o que raciocinarConversação imediata
a tarefa atual🧭 Guia o raciocínio
…
Context rot & o ciclo contínuo
Por que o histórico precisa ser mutado a cada turno — e as quatro etapas que fazem isso acontecer.
O histórico de conversa cresce sem parar. Janelas maiores aguentam transcrições longas, mas: custo e latência aumentam a cada token e surge o context rot — a atenção do modelo à informação crítica diminui conforme o contexto cresce. A solução é mutar o histórico dinamicamente: sumarização, poda seletiva, compactação.
1 · Fetch Context
…
Session é a bancada de trabalho; Memory é o arquivo organizado
Ferramentas, notas e rascunhos espalhados: tudo acessível, mas temporário. No fim do dia, a bancada se esvazia — e a próxima conversa começa limpa.
Você revisa os materiais da bancada, descarta os rascunhos e arquiva só o essencial. Ninguém enfia a bancada bagunçada inteira no arquivo — é por isso que upload é consolidação, não cópia.
Sessions: fundamentos
O container cronológico de UMA conversa — events + state, ligado a um único usuário.
Uma session encapsula o histórico de diálogo e a working memory de uma conversa contínua: um registro auto-contido ligado a um usuário específico. Um usuário pode ter múltiplas sessions — logs distintos e desconectados entre si.
O agente anexa events e muta o state conforme a lógica do negócio. A estrutura ecoa a lista de Content objects da Gemini API — cada Content tem role (user/model) e parts (texto, imagens, tool calls): um turno = um Event.
# o histórico é uma lista de Content: role + parts response = client.models.generate_content( model="gemini-2.5-flash", contents=[ {"role": "user", "parts": [{"text": "Quero ir a Paris em novembro"}]}, {"role": "model", "parts": [{"text": "Direto ou com escala?"}]}, {"role": "user", "parts": [{"text": "Direto, por favor"}]}, ], )
Runtimes de produção são stateless — o histórico precisa ser persistido. Storage in-memory serve para desenvolvimento; produção exige databases robustos (ex.: Agent Engine Sessions).
Frameworks: o tradutor universal
ADK e LangGraph implementam sessions de formas distintas — mas as ideias centrais são as mesmas.
O framework é um tradutor universal entre o seu código e o LLM: mantém o histórico e o state, constrói as requests, parseia e armazena as respostas. Para o Gemini, a request é List[Content] — cada Content com role e parts. O framework mapeia seu objeto interno (ex.: um Event do ADK) para role/parts antes da chamada. Essa abstração desacopla a lógica do agente do LLM específico — e previne vendor lock-in.
Sua lógica
Eventos e state internos do agente
Framework
monta a request · parseia a resposta
Gemini API
List[Content] · role + parts
Session store
histórico + state persistidos
ADK — objeto Session explícito
Uma Session com lista de Events + um objeto state separado. Pense num arquivo com uma pasta para o histórico e outra para a working memory — cada coisa no seu lugar, claramente delimitada.
session = Session(
id="s_771",
events=[event_1, event_2, event_3], # histórico cronológico
state={"cart_items": [...]}, # working memory separada
)LangGraph — o state É a session
Não existe um objeto "session" formal: o estado abrangente e mutável (histórico como lista de Messages + dados de trabalho) é a session. E pode ser transformado — por exemplo, com history compaction — o que é valioso para conversas longas e limites de tokens.
class AgentState(TypedDict): messages: Annotated[list, add_messages] # histórico cart: dict # dados de trabalho # o grafo pode reescrever o state a cada passo (ex.: compactar)
Sessions multi-agente
Quando vários agentes colaboram, a arquitetura define quem vê o histórico de quem.
Session history é a transcrição permanente e integral. Contexto é o payload cuidadosamente construído para UM turno — pode ser um excerto relevante com formatação especial. Esta seção trata do que passa entre agentes, não necessariamente do que vai para o LLM.
Histórico compartilhado
- todos os agentes leem e escrevem no mesmo log cronológico
- ideal para tarefas acopladas: o output de um é o input do próximo
- mesmo assim, cada agente pode filtrar/rotular events antes de passá-los ao LLM
- ex.: delegação LLM-driven no ADK — events do sub-agente caem na session do root agent (com
output_key)
Históricos separados
- cada agente mantém histórico privado: raciocínio, tool use e passos intermediários ficam ocultos
- a comunicação acontece só por mensagens explícitas — o output final, não o processo
- via Agent-as-a-Tool (invoca outro agente como ferramenta e recebe um output auto-contido)
- ou via A2A Protocol (mensagens diretas e estruturadas)
Interoperabilidade & o protocolo A2A
A abstração que liberta o agente do LLM também o isola de outros frameworks — a memory layer é a ponte.
Há um trade-off crítico: a mesma abstração que desacopla o agente do LLM o isola de agentes de outros frameworks. O isolamento se solidifica na camada de persistência — o schema do banco fica acoplado aos objetos internos do framework, e o registro se torna não-portável. Um agente LangGraph não consegue interpretar nativamente os objetos Session/Event de um agente ADK: handoff seamless, impossível.
Session stores isolados
- A2A troca mensagens, mas não compartilha estado contextual rico
- o histórico vive no schema interno de cada framework
- enviar events de session via A2A exige uma camada de tradução customizada
Memory layer compartilhada
- conhecimento abstraído numa camada de dados framework-agnostic
- guarda informação processada e canônica: sumários, entidades, fatos como strings/dicts
- agentes heterogêneos alcançam inteligência colaborativa compartilhando um recurso cognitivo comum — sem tradutores
Session stores guardam objetos raw e framework-specific; a memory layer guarda informação processada e canônica. É ela a camada de dados universal.
Sessions em produção
Três áreas críticas que um session store gerenciado (ex.: Agent Engine Sessions) endereça.
🔐 Segurança & privacidade
- Strict isolation é o princípio mais crítico: uma session pertence a um usuário — nenhum outro pode acessá-la (ACLs; toda request autenticada contra o owner)
- PII: redact antes de escrever no storage — reduz o "blast radius" de um breach (ferramentas como Model Armor)
- simplifica compliance GDPR/CCPA e constrói confiança
🗂️ Integridade & lifecycle
- sessions não devem viver para sempre: políticas de TTL deletam sessions inativas (custo de storage + overhead)
- política de retenção clara: quanto tempo antes de arquivar ou deletar
- events anexados em ordem determinística — sequência cronológica correta = integridade do log
⚡ Performance & escala
- session data está no hot path de toda interação — leitura/escrita precisa ser muito rápida
- runtimes stateless buscam o histórico inteiro do banco central a cada turno (latência de rede)
- mitigação: reduzir o tamanho transferido — filtrar/compactar o histórico antes de enviar (ex.: remover function call outputs antigos e irrelevantes)
Compactação de conversas longas
Quatro pressões, uma mala de viagem e três estratégias — brinque com o simulador.
Numa arquitetura simples, a session é um log imutável. Conforme ela escala, o uso de tokens explode — e quatro limitações mordem aplicações latency-sensitive:
📏 Janela
exceder o máximo de texto processável = a chamada de API falha
💸 Custo
cobrança por tokens enviados/recebidos — histórico menor, conta menor
🐢 Latência
mais texto = mais tempo de processamento = resposta mais lenta
📉 Qualidade
mais tokens = pior performance: ruído + erros autorregressivos
A context window é uma mala com espaço limitado
Mala pesada e desorganizada: você paga excesso de bagagem (custo) e não encontra nada (lentidão). É o histórico sem compactação.
Você esquece o passaporte e o casaco — perde contexto crítico e responde errado. Compactar bem é levar só o necessário.
As três estratégias de compactação
🪟 Keep last N turnos
a mais simples: sliding window dos N turnos mais recentes — tudo que é mais antigo é descartado
✂️ Truncamento por tokens
conta tokens do mais recente para trás e inclui o máximo de mensagens possível sem exceder um limite predefinido (ex.: 4.000 tokens) — o resto é cortado
📜 Sumarização recursiva
mensagens antigas viram um sumário prefixado às recentes — melhor equilíbrio fidelidade/custo (operação LLM cara → roda em background)
# limita o contexto enviado ao LLM, sem modificar o log persistido plugin = ContextFilterPlugin(num_invocations_to_keep=10) # ou: compactação agendada de eventos config = EventsCompactionConfig(compaction_interval=5, overlap_size=1)
Mecanismos de trigger
🔢 Count-based
threshold de tokens ou de turnos — simples e "good enough"
⏰ Time-based
falta de atividade (ex.: 15–30 min sem interação) → compactação em background
🎯 Event-based
detecta tarefa, sub-objetivo ou tópico concluído — trigger semântico
Sumarização recursiva deve rodar assíncrona em background e persistir os resultados (o cliente não espera; a computação não se repete). O agente registra quais events já estão no sumário compactado — para não reenviar os originais verbosos. Memory generation é a capacidade ampla por trás disso: extrair conhecimento persistente de fontes ruidosas, descartando o filler.
Memory 101
A relação simbiótica entre sessions e memory — e as cinco camadas que colaboram em cada turno.
Sessions e memory vivem em simbiose: as sessions são a fonte primária para gerar memórias, e as memórias são a estratégia-chave para gerenciar o tamanho das sessions. Uma alimenta a outra, em ciclo contínuo.
Uma memória é um snapshot de informação extraída e significativa de uma conversa ou fonte: uma representação condensada que preserva o contexto importante, persistida entre sessões para uma experiência contínua e personalizada.
Alguns frameworks chamam a conversa verbatim de "short-term memory". Neste paper, memórias são informação extraída — não o diálogo raw.
Quatro capacidades que um sistema de memória habilita
🎯 Personalização
lembrar preferências, fatos e interações passadas — o time favorito, o assento preferido no avião
📦 Gestão da context window
compactar históricos longos em sumários e fatos-chave, preservando contexto sem enviar milhares de tokens por turno — menos custo, menos latência
📊 Data mining & insight
analisar memórias de muitos usuários de forma agregada e privacy-preserving — ex.: um chatbot de retail descobre que muitos perguntam sobre a política de devolução de um produto
🔁 Auto-aperfeiçoamento do agente
memórias procedurais sobre a própria performance — quais estratégias, tools e caminhos levaram ao sucesso — viram um playbook que o agente reutiliza e adapta
As cinco camadas que colaboram em cada turno
1 · User
fornece os dados raw — às vezes diretamente, via formulário
2 · Agent (developer logic)
decide o quê e quando lembrar, e orquestra o memory manager — do "sempre buscar/gerar" ao memory-as-a-tool, em que o LLM decide
3 · Agent framework (ADK, LangGraph)
o encanamento: estruturas e tools para interagir com a memória, acesso ao histórico, injeção na context window — não gerencia o storage de longo prazo
4 · Session storage (Agent Engine Sessions, Spanner, Redis)
armazena a conversa turno a turno; o diálogo raw é a matéria-prima ingerida pelo memory manager
5 · Memory manager (Agent Engine Memory Bank, Mem0, Zep)
storage, retrieval e compactação — o ciclo de vida completo: Extraction → Consolidation → Storage → Retrieval
Um memory manager não é um vector database passivo. Seu valor central é extrair, consolidar e curar memórias inteligentemente ao longo do tempo — não apenas fazer similarity search.
RAG × Memory
Papéis distintos e complementares: RAG torna o agente expert em fatos; Memory, expert no usuário.
O retrieval de memória é frequentemente comparado ao RAG, mas os princípios arquiteturais são diferentes: RAG lida com dados externos estáticos; Memory, com contexto dinâmico e específico do usuário. São complementares — e um agente verdadeiramente inteligente precisa dos dois.
RAG · o bibliotecário de pesquisa
- trabalha numa biblioteca pública vasta: enciclopédias, docs oficiais, base estática e compartilhada
- recupera fatos estabelecidos e autoritativos
- read-only, global — igual para todos os usuários
- não sabe nada pessoal sobre você
Memory · o assistente pessoal
- anda com um caderno privado, registrando detalhes de cada interação
- dinâmico e altamente isolado: preferências, conversas passadas, metas
- escreve a cada turno ou fim de sessão — event-based
- adapta-se conforme o relacionamento evolui
| Dimensão | RAG Engines | Memory Managers |
|---|---|---|
| Objetivo | injetar conhecimento factual externo | experiência personalizada e stateful: lembra fatos, adapta-se ao usuário, mantém contexto longo |
| Fonte de dados | base de conhecimento externa pré-indexada (PDFs, wikis, docs, APIs) | o diálogo usuário-agente |
| Isolamento | geralmente compartilhado (global, read-only) | altamente isolado (per-user, previne vazamentos) |
| Tipo de informação | estática, factual, autoritativa | dinâmica, user-specific, com incerteza inerente |
| Padrão de escrita | batch processing (ação administrativa offline) | event-based (a cada turno / fim de sessão) ou memory-as-a-tool |
| Padrão de leitura | quase sempre as-a-tool (o agente decide quando precisa) | memory-as-a-tool OU retrieval estático no início do turno |
| Formato | chunks em linguagem natural | snippets em linguagem natural OU perfil estruturado |
| Preparo dos dados | chunking + indexing (embeddings para busca rápida) | extraction + consolidation (sem duplicação nem contradição) |
Tipos de memória
Anatomia, taxonomia cognitiva, organização, storage, criação, escopo e multimodalidade.
Memórias são classificadas por como são armazenadas e capturadas — e trabalham juntas para um entendimento rico e contextual. Regra de ouro: memórias são descritivas, não preditivas.
Anatomia de uma memória
Uma "memória" é uma peça atômica de contexto retornada pelo memory manager e usada pelo agente como contexto. O schema exato pode variar, mas uma memória geralmente consiste em dois componentes: content e metadata.
📄 Content
a substância extraída dos dados-fonte, em formato framework-agnostic. Estruturada ({"seat_preference": "window"}) ou não-estruturada ("The user prefers a window seat").
🏷️ Metadata
o contexto sobre a memória: identificador único, owner e labels que descrevem conteúdo e fonte.
Declarative × Procedural (ciência cognitiva)
Declarative
- fatos, números, eventos
- inclui conhecimento geral (semantic) e fatos específicos do usuário (episodic)
- ex.: "o usuário prefere assento na janela"
Procedural
- habilidades e workflows
- guia ações demonstrando implicitamente como executar uma tarefa
- ex.: a sequência correta de tool calls para reservar uma viagem
Padrões de organização
🗃️ Collections
múltiplas memórias auto-contidas em linguagem natural por usuário — várias por tópico, buscadas num pool maior e menos estruturado
🪪 Structured user profile
um conjunto de fatos centrais, como um cartão de contato continuamente atualizado — lookup rápido do essencial (nomes, preferências, conta)
📜 Rolling summary
UMA memória única e evolutiva: o sumário de todo o relacionamento usuário-agente, atualizado continuamente — usado para compactar sessions longas
Arquiteturas de storage
🧮 Vector databases
retrieval por similaridade semântica (não keywords exatas): memórias viram embeddings e casam por conceito. Excelente para fatos não-estruturados
🕸️ Knowledge graphs
memórias como rede de entidades (nós) + relacionamentos (arestas); retrieval = traversar o grafo. Ideal para queries relacionais ("knowledge triples")
🔀 Hybrid
entidades do grafo enriquecidas com vector embeddings — busca relacional e semântica simultânea: o melhor dos dois mundos
Mecanismos de criação
🗣️ Explicit
comando direto do usuário: "lembre que meu aniversário é 26 de outubro"
🕵️ Implicit
o agente infere sem comando: "meu aniversário é semana que vem, me ajude com um presente" → memória criada
🏠 Internal
gerenciamento embutido no framework — conveniente, com menos recursos
☁️ External
serviço especializado (Memory Bank, Mem0, Zep): semantic search, entity extraction, summarization automática
Escopo: quem a memória descreve
👤 User-level
o mais comum: ligada ao user ID, persiste entre sessões — "o usuário prefere o assento do meio"
💬 Session-level
registro persistente de insights de UMA sessão — substitui a transcrição verbosa por fatos concisos, isolados àquela conversa
🌐 Application-level
contexto global acessível a todos os usuários — caso comum: memórias procedurais ("how-to" para o raciocínio do agente)
Memórias application-level devem ser sanitizadas de conteúdo sensível — senão viram vetor de vazamento entre usuários.
Memória multimodal: origem × conteúdo
Multimodal source
- o agente processa texto, imagem ou áudio — mas a memória criada é um insight textual
- ex.: voice memo → transcrição → "usuário expressou frustração com atraso na entrega" (o áudio não é armazenado)
Multimodal content
- a memória contém mídia não-textual diretamente
- ex.: "lembre deste design para o nosso logo" → a memória contém o arquivo de imagem
A maioria dos managers foca em fontes multimodais → conteúdo textual: converter tudo para texto é a forma mais simples de manter um formato buscável.
from google.genai import types client = vertexai.Client(project=..., location=...) response = client.agent_engines.memories.generate( name=agent_engine_name, direct_contents_source={ "events": [ { "content": types.Content( role="user", parts=[ types.Part.from_text("This is context about the multimodal input."), types.Part.from_bytes(data=CONTENT_AS_BYTES, mime_type=MIME_TYPE), types.Part.from_uri(file_uri="file/path/to/content", mime_type=MIME_TYPE) ] ) } ] }, scope={"user_id": user_id} )
Geração de memória: o pipeline ETL
Como dados conversacionais raw viram insights estruturados — um ETL dirigido por LLM.
A geração transforma autonomamente dados conversacionais raw em insights estruturados e significativos — um pipeline ETL dirigido por LLM (Extract, Transform, Load). É isso que distingue memory managers de RAG engines e databases tradicionais: em vez de o dev especificar operações de banco manualmente, o LLM decide quando adicionar, atualizar ou fundir memórias — abstraindo a complexidade de gerenciar conteúdo, encadear chamadas e rodar serviços em background.
Ingestion
o cliente fornece a fonte de dados raw — tipicamente o histórico de conversa
Extraction & filtering
o LLM extrai só o que se encaixa em definições de tópico pré-definidas — sem match, nenhuma memória é criada
Consolidation
o estágio mais sofisticado: resolução de conflitos + deduplicação — merge, delete ou create
Storage
a memória nova ou atualizada é persistida em storage durável (vector DB / knowledge graph)
memories.generate(
scope={"user_id": "u_8123"},
direct_contents_source=session_events, # matéria-prima raw
config={"wait_for_completion": False}, # assíncrono, em background
)Um jardim saudável não cresce sozinho — exige curadoria constante
Novas sementes e mudas chegam ao jardim: o LLM identifica o que merece ser plantado — e descarta o que não se encaixa nos canteiros (tópicos) definidos.
Arrancar ervas daninhas (deletar o redundante e conflitante), podar galhos (refinar e sumarizar o existente) e plantar cada muda no local ótimo. Sem curadoria, o jardim vira mato — processo contínuo, em background.
Um memory manager gerenciado (ex.: Agent Engine Memory Bank) automatiza o pipeline inteiro — extração, consolidação e storage — com uma única chamada de API assíncrona.
Deep-dive: Extraction
"Que informação aqui é significativa o suficiente para virar memória?" — filtragem inteligente, não sumarização.
A pergunta fundamental da extraction é: "que informação nesta conversa é significativa o suficiente para virar memória?" Não é sumarização simples — é filtragem inteligente e direcionada: separar o sinal (fatos, preferências, metas) do ruído (cortesias, filler).
"Significativo" não é universal — é definido pelo propósito do agente. Um agente de suporte ao cliente extrai números de pedido e problemas técnicos; um coach de bem-estar extrai metas de longo prazo e estados emocionais. Customizar essa definição é a chave para um agente eficaz.
Como o LLM sabe o que extrair
🧩 Schema / template-based
um JSON schema ou template pré-definido (structured output); o LLM constrói o JSON com a informação correspondente
📝 Definições em linguagem natural
o LLM é guiado por uma descrição simples, em linguagem natural, do que é cada tópico
🎓 Few-shot prompting
o LLM "vê" o que extrair por exemplos: input + memória ideal de alta fidelidade. Muito eficaz para tópicos nuançados e difíceis de descrever
A maioria dos managers funciona out-of-the-box com tópicos comuns (preferências, fatos-chave, metas) — e muitos permitem tópicos customizados. O exemplo do paper: uma conversa sobre uma cafeteria gera duas memórias de feedback — "o café coado estava morno" e "a música estava alta demais".
config = MemoryGenerationConfig(
memory_topics=[
ManagedTopicEnum.USER_PERSONAL_INFO, # tópico built-in
CustomMemoryTopic(
name="business_feedback",
description="feedback about the coffee shop",
),
],
generate_memories_examples=[...], # few-shot: conversa → fatos
)Embora não seja sumarização, o algoritmo pode incorporá-la: um rolling summary da conversa entra no prompt de extração, dando contexto condensado para extrair das interações recentes — sem reprocessar o diálogo completo a cada turno.
Deep-dive: Consolidation
O estágio que transforma uma coleção de fatos em entendimento curado — self-curation dirigida por LLM.
A consolidation integra nova informação numa base de conhecimento coerente, precisa e evolutiva. É o estágio mais sofisticado: sem ela, a memória vira um log ruidoso, contraditório e não-confiável. Essa "self-curation" gerenciada por LLM é o que eleva o memory manager além de um database simples.
Os quatro problemas que ela endereça
👯 Duplicação
o mesmo fato de várias formas: "preciso de um voo para NYC" + "estou planejando ir a New York" — extração simples criaria duas memórias redundantes
⚔️ Conflito
o estado do usuário muda com o tempo — sem consolidação, fatos contraditórios convivem na base
🌱 Evolução
um fato simples fica mais nuançado: "interessado em marketing" → "liderando projeto de aquisição de clientes no Q4"
⌛ Decaimento
nem toda memória permanece útil: o agente pratica forgetting — poda o velho, obsoleto e de baixa confiança (prioridade ao novo ou TTL)
O processo em três passos
1 · Buscar similares
memórias existentes similares às recém-extraídas viram candidatas à consolidação
2 · LLM analisa
memórias existentes + nova informação, juntas: o LLM identifica as operações necessárias
3 · Transação
o memory manager traduz a decisão do LLM numa transação que atualiza o store
UPDATE
modificar uma memória existente com informação nova ou corrigida
CREATE
insight totalmente novo e não-relacionado → criar uma memória nova
DELETE / INVALIDATE
a nova informação tornou a memória antiga irrelevante ou incorreta → deletar ou invalidar
Provenance: linhagem & confiança
"Garbage in, confident garbage out" — toda memória precisa de um registro de origem e histórico.
"Garbage in, garbage out" é ainda mais crítico para LLMs: aqui é "garbage in, confident garbage out". Para decisões confiáveis e consolidação eficaz, o agente deve avaliar criticamente a qualidade das próprias memórias — e a confiabilidade deriva da provenance: o registro detalhado de origem e histórico.
uma memória ← várias fontes
uma fonte → várias memórias
confiança = origem + idade
Linhagem durante o gerenciamento
⚔️ Conflict resolution
fontes conflitam — a provenance estabelece a hierarquia de confiança: priorizar a fonte mais confiável, favorecer a informação mais recente, buscar corroboração entre múltiplos dados.
🧹 Deleting derived data
se o usuário revoga acesso a uma fonte, os dados derivados devem ser removidos. Deletar toda memória "tocada" pode ser agressivo demais — a abordagem mais precisa (e cara) é regenerar as memórias afetadas do zero usando só as fontes válidas restantes.
A confiança evolui — e a poda é ativa
A confiança não é estática: aumenta por corroboração (múltiplas fontes confiáveis consistentes) e decai com a idade e o conflito. O memory pruning (esquecimento ativo) identifica e descarta memórias que deixaram de ser úteis — por time-based decay (uma reunião de 2 anos atrás vale menos que a da semana passada), low confidence (inferência fraca nunca corroborada) ou irrelevância (detalhes triviais antigos diante das metas atuais). Consolidação reativa + poda proativa = base de conhecimento curada, não um log crescente de tudo.
Memórias e seus confidence scores não são mostrados ao usuário — são injetados no system prompt para o LLM pesar as evidências, considerar a confiabilidade e tomar decisões mais nuançadas.
Disparando a geração & memory-as-a-tool
O agente decide QUANDO gerar — um balanço entre data freshness, custo e latência.
Memory managers automatizam extração e consolidação depois que a geração é disparada — mas quem decide quando tentar gerar é o agente. É uma escolha arquitetural crítica: balancear data freshness contra custo computacional e latência.
Estratégias de trigger
🏁 Session completion
no fim de uma sessão multi-turno — mais econômico, memórias de menor fidelidade
🔁 Turn cadence
após N turnos (ex.: a cada 5) — meio-termo entre frescor e custo
⚡ Real-time
após CADA turno — memórias detalhadas e frescas, maior custo de LLM/banco
🗣️ Explicit command
comando direto do usuário: "lembre disso" — fidelidade máxima, intenção clara
Geração frequente = memórias frescas e detalhadas, mas maior custo e latência potencial. Geração infrequente = econômica, mas o LLM sumariza blocos muito maiores (menor fidelidade). E cuidado: não reprocessar os mesmos events várias vezes — custo desnecessário.
Memory-as-a-tool: o agente decide
Na abordagem mais sofisticada, a geração é exposta como uma tool (ex.: create_memory) cuja definição descreve que tipos de informação são significativos. O agente analisa a conversa e chama a tool autonomamente quando identifica algo que vale persistir — transferindo a responsabilidade de identificar o "significativo" do memory manager para o agente/dev.
def generate_memories(tool_context): # opção 1: histórico completo da session memory_service.add_session_to_memory(tool_context.session) # opção 2: só o último turno, assíncrono memories.generate(..., config={"wait_for_completion": False}) runner = Runner(agent=agent, memory_service=VertexAiMemoryBankService())
# aqui o AGENTE extrai (extract_memories) e envia ao Memory Bank # apenas para CONSOLIDAR com as memórias existentes memories = extract_memories(direct_memories_source={"fact": query}) memory_bank.store(memories) # consolidação delegada ao serviço
Background, sempre
Memory Retrieval
Quais memórias buscar, quando buscá-las — e como pontuá-las em múltiplas dimensões.
A estratégia de retrieval depende da organização: um structured user profile é um lookup simples (o perfil inteiro ou um atributo); uma collection é um problema de busca complexo — descobrir a informação mais pertinente num pool grande e pouco estruturado.
Retrieval eficaz é crucial: memórias irrelevantes confundem o modelo e degradam a resposta; o contexto perfeito gera uma interação notavelmente inteligente. O desafio central é balancear utilidade com um budget de latência estrito.
As três dimensões do scoring
Relevance
quão conceitualmente relacionada à conversa atual?
Recency
quão recentemente a memória foi criada?
Importance
quão crítica ela é overall? (definida na geração — diferente de relevance)
Confiar só em relevance vetorial faz o retrieval surfar memórias conceitualmente similares — porém velhas ou triviais. A melhor estratégia é o blended approach: combinar as três dimensões.
Técnicas de precisão (e seu custo)
✍️ Query rewriting
o LLM melhora a própria query — reescreve input ambíguo em query precisa ou expande uma query em várias relacionadas. Melhora a qualidade, adiciona latência de uma chamada extra
🏆 Reranking
retrieval inicial amplo (ex.: top 50) por similaridade; depois o LLM re-avalia e re-rankeia o conjunto até a lista final, mais precisa
🔬 Specialized retriever
fine-tuning do retriever — requer dados rotulados e aumenta custos significativamente
1) Se essas técnicas forem necessárias e as memórias não ficarem obsoletas rápido, use uma caching layer — armazene resultados caros temporariamente e evite latência em requests idênticos. 2) A melhor abordagem começa antes do retrieval: uma geração de memória melhor (corpus de alta qualidade, livre de irrelevância) é a forma mais eficaz de garantir retrieval útil.
Timing: quando buscar
Proactive
- contexto sempre disponível — mas latência desnecessária em turnos que não precisam
- como memórias são estáticas durante um turno, podem ser cacheadas (mitiga o custo)
- ex.: ADK
PreloadMemoryToolou callbackbefore_model_callbackque anexa memórias ao system_instruction
Reactive · memory-as-a-tool
- mais eficiente e robusto — a chamada extra só acontece quando necessário
- risco: o agente pode não saber que existe informação relevante
- mitigação: descrever os tipos de memórias disponíveis na própria tool (ex.:
LoadMemoryToolouload_memory(query))
# Option 1: PreloadMemoryTool embutida — busca por similaridade em todo turno agent = LlmAgent( ..., tools=[adk.tools.preload_memory_tool.PreloadMemoryTool()] ) # Option 2: callback customizado — mais controle sobre como as memórias são buscadas def retrieve_memories_callback(callback_context, llm_request): user_id = callback_context._invocation_context.user_id app_name = callback_context._invocation_context.app_name response = client.agent_engines.memories.retrieve( name="projects/.../locations/.../reasoningEngines/...", scope={"user_id": user_id, "app_name": app_name} ) memories = [f"* {memory.memory.fact}" for memory in list(response)] if not memories: return # nenhuma memória para acrescentar às System Instructions # anexa as memórias formatadas às System Instructions llm_request.config.system_instruction += "\nHere is information that you have about the user:\n" llm_request.config.system_instruction += "\n".join(memories) agent = LlmAgent( ..., before_model_callback=retrieve_memories_callback, )
# Option 1: LoadMemoryTool embutida — o agente decide quando buscar agent = LlmAgent( ..., tools=[adk.tools.load_memory_tool.LoadMemoryTool()], ) # Option 2: tool customizada — descreva que tipos de informação podem estar disponíveis def load_memory(query: str, tool_context: ToolContext): """Retrieves memories for the user. The following types of information may be stored for the user: * User preferences, like the user's favorite foods. ...""" # busca memórias por similaridade response = tool_context.search_memory(query) return response.memories agent = LlmAgent( ..., tools=[load_memory], )
Inferência com memórias
O passo final: posicionar estrategicamente as memórias recuperadas na context window.
O posicionamento influencia o raciocínio do LLM, os custos operacionais e a qualidade da resposta. Na prática, a estratégia híbrida é a mais eficaz: system prompt para memórias estáveis/globais (perfil do usuário, sempre presentes); dialogue injection ou memory-as-a-tool para memórias transitórias/episódicas (relevantes só ao contexto imediato).
Memórias nas System Instructions
Anexar memórias ao system prompt com um preamble dá alta autoridade e separa o contexto do diálogo — ideal para informação estável e global. Tipicamente via template (ex.: Jinja) com um bloco <MEMORIES> iterando sobre retrieved_memory.memory.fact.
from jinja2 import Template template = Template(""" {{ system_instructions }} <MEMORIES> Here is some information about the user: {% for retrieved_memory in data %}* {{ retrieved_memory.memory.fact }} {% endfor %}</MEMORIES> """) prompt = template.render( system_instructions=system_instructions, data=retrieved_memories )
Over-influence: o agente tenta relacionar TODO tópico às memórias centrais, mesmo quando inapropriado. Além disso: requer framework que suporte system prompt dinâmico a cada chamada; é incompatível com memory-as-a-tool (o system prompt deve estar finalizado ANTES de o LLM decidir chamar a tool de retrieval); e lida mal com memórias não-textuais.
Memórias no Conversation History
Injetar diretamente no diálogo — antes do histórico completo ou logo antes da última query. Riscos: ruído (mais tokens, confusão se irrelevantes) e dialogue injection (o modelo trata a memória como algo realmente dito na conversa). Cuidado com a perspectiva: se usar role "user" com memórias user-level, escreva em primeira pessoa. Caso especial: retrieval via tool calls — as memórias chegam como tool output.
def load_memory(query: str, tool_context): """Search the user's long-term memories.""" response = tool_context.search_memory(query) return response.memories # entra no contexto como tool output
E as procedural memories?
O paper focou em declarative — reflexo do mercado comercial atual, cujas plataformas são arquitetadas para extrair/armazenar/recuperar o "what". Mas armazenar o "how" não é um problema de information retrieval — é um problema de reasoning augmentation, com lifecycle próprio:
⛏️ Extraction
prompts especializados destilam uma estratégia reutilizável — um "playbook" — de uma interação bem-sucedida, não apenas um fato
🧬 Consolidation
cura o WORKFLOW: integra novos métodos bem-sucedidos às best practices existentes, remenda passos falhos, poda procedimentos obsoletos
🔎 Retrieval
o objetivo não é recuperar dados para responder uma pergunta, mas recuperar um PLANO que guia a execução de uma tarefa complexa
Ambos visam melhorar o comportamento — mas os mecanismos são fundamentalmente diferentes. Fine-tuning é um processo lento e offline que altera os pesos do modelo. Procedural memory é adaptação rápida e online: injeta dinamicamente o "playbook" certo no prompt — in-context learning, sem fine-tuning.
Testing & evaluation de memória
Lembra as coisas certas? Encontra quando precisa? E usar memória ajuda de verdade?
Evaluation de memória é um processo em múltiplas camadas: verificar se o agente lembra as coisas certas (qualidade), encontra as memórias quando precisa (retrieval) e se usá-las realmente ajuda a cumprir objetivos (task success). Na academia, benchmarks reproduzíveis; na indústria, impacto direto no agente de produção.
🧪 Generation quality
🔎 Retrieval performance
🏁 End-to-end task success
Evaluation não é evento único: estabelecer baseline → analisar falhas → tunar o sistema (refinar prompts, ajustar algoritmos de retrieval) → re-avaliar para medir o impacto. E além de qualidade, production-readiness exige performance: retrieval sub-second no hot path, throughput suficiente na geração assíncrona. Sistema de memória bem-sucedido = inteligente + eficiente + robusto.
Memory em produção & segurança
Do protótipo à empresa: desacoplamento, concorrência, resiliência — e o arquivista corporativo.
Do protótipo à produção, o foco muda para concerns enterprise-grade: escalabilidade, resiliência e segurança. A regra número um: desacoplar o processamento de memória da lógica principal — a UX nunca pode ser bloqueada por geração cara.
1 · Agent pushes data
após um evento relevante (ex.: fim de sessão), chamada API não-bloqueante "empurra" os dados raw
2 · Process in background
o serviço reconhece, enfileira internamente e faz o trabalho pesado — LLM, extração, consolidação
3 · Memories persisted
memórias finais escritas em database durável dedicado (managed managers têm storage built-in)
4 · Agent retrieves
a aplicação busca direto no store quando precisa de contexto para uma nova interação
Falhas e latência no pipeline de memória não impactam a aplicação user-facing. O padrão também informa a escolha entre processamento online (real-time, frescor conversacional) e offline (batch, ideal para popular dados históricos).
Concorrência, falhas e escala global
🔀 Concorrência
eventos de alta frequência sem deadlocks/race conditions quando múltiplos eventos modificam a mesma memória: operações transacionais ou optimistic locking, com message queue robusta como buffer
🩹 Failure handling
resiliência a erros transitórios: chamada LLM falhou → retry com exponential backoff; falhas persistentes → dead-letter queue para análise
🌍 Global
multi-region replication built-in — replicação client-side não é viável (a consolidação exige visão única e transacionalmente consistente); o sistema replica internamente e apresenta um datastore lógico único
Privacidade & riscos de segurança
Memórias derivam de — e incluem — dados do usuário. Pense num arquivo corporativo seguro gerenciado por um arquivista profissional: ele preserva o conhecimento valioso protegendo a empresa.
🔐 Data isolation
a regra cardinal: como o arquivista nunca mistura arquivos confidenciais de departamentos, a memória é estritamente isolada por usuário/tenant (ACLs restritivas). Usuários têm controle programático: opt-out da geração ou deletar todos os seus arquivos
🖊️ PII redaction
antes de arquivar qualquer documento, o arquivista redacta informação pessoal sensível — o conhecimento é salvo sem criar liability
☠️ Memory poisoning
o arquivista é treinado para detectar falsificações: validar e sanitizar informação ANTES do commit à memória de longo prazo previne que um usuário malicioso corrompa o conhecimento persistente via prompt injection (safeguards como Model Armor)
📡 Exfiltration risk
memórias compartilhadas entre usuários (ex.: procedurais "how-to") são como um memo company-wide: se a memória de um usuário vira exemplo para outro, o arquivista faz anonimização rigorosa antes — prevenindo vazamento entre fronteiras de usuário
Conclusão
De um simples turno conversacional a inteligência persistente e acionável.
A jornada de um turno conversacional até inteligência persistente é governada pela Context Engineering — montar dinamicamente histórico, memórias e conhecimento externo na context window. Ela depende da interação de dois sistemas distintos e interconectados:
Session governa o "agora"
- desafio = performance + segurança: acesso low-latency e isolamento estrito
- compactação via token truncation e recursive summarization
- PII redaction ANTES de persistir — segurança paramount
Memory governa o "sempre"
- vai além do RAG (expert em fatos) para tornar o agente expert no USUÁRIO
- pipeline ETL dirigido por LLM: extraction → consolidation → retrieval
- geração assíncrona em background + provenance + safeguards contra poisoning = assistentes que aprendem e crescem com o usuário
Contexto é um recurso gerenciado, não um acidente
Cada token na janela tem custo, latência e peso atencional. Monte o payload dinamicamente: máxima relevância, mínimo ruído.
Sessions e memory são simbióticos, mas distintos
A session é o log cronológico de uma conversa; a memory é conhecimento extraído e curado entre conversas. Uma alimenta a outra — nunca se confunda as duas.
Confiança se rastreia, se pondera e se poda
Provenance diz de onde veio; confidence scores dizem quanto pesar; o forgetting ativo mantém a base curada. Memória sem curadoria é só um log com pretensões.
A memory governa o sempre."
Quiz
Oito perguntas para consolidar o ciclo, as sessions e o pipeline de memória.
Cheatsheets
Três artefatos copiáveis para levar para o seu próximo projeto de agente.
CONTEXT CYCLE — per-turn checklist ---------------------------------- [ ] FETCH - memories + RAG + recent events (query + metadata) [ ] PREPARE - full payload assembled (blocking, hot path) [ ] INVOKE - LLM + tools, append outputs as they arrive [ ] UPLOAD - persist events, trigger memory gen (background) COMPACTION decision tree history < 4k tokens - keep as-is 4k-16k tokens - keep-last-N / token truncation > 16k / long-running - recursive summarization (async + persist) TRIGGERS: count-based | time-based | event-based GOLDEN RULE: maximum relevance, minimum noise
MEMORY ETL — design recipe
--------------------------
INGEST - raw conversation events (from the session store)
EXTRACT - topic filter: define "meaningful" per agent purpose
(schema / natural-language defs / few-shot examples)
CONSOLIDATE - LLM decides: UPDATE | CREATE | DELETE-INVALIDATE
dedup + conflict resolution + active forgetting
STORE - vector DB / knowledge graph / hybrid
TRIGGERS : session-end | every-N-turns | real-time | explicit
SCOPE : user-level | session-level | application-level
TIMING : generation ALWAYS async in background
RULE : memories are descriptive, not predictive
RETRIEVAL — scoring and timing ------------------------------ SCORE = w1*relevance + w2*recency + w3*importance (never vector-similarity alone -> old/trivial memories resurface) TIMING proactive - preload each turn (cacheable, always available) reactive - memory-as-a-tool (agent decides, extra LLM call) PRECISION BOOSTERS (cost up, latency up) query rewriting -> reranking (top-50 -> top-K) -> specialized retriever + caching layer when memories are stable METRICS generation : precision / recall / F1 retrieval : recall@K / latency < 200ms (hot path) end-to-end : LLM judge vs golden answer
Checklists de implementação
Marque o que você já domina — seu progresso fica salvo neste navegador.
📦Colocar sessions em produção
🧠Construir um sistema de memória
🛡️Endurecer para produção
Glossário
Os termos essenciais do paper, em linguagem direta.
Continue a jornada
Os papers companions da série — cada guia segue o mesmo formato interativo e trilíngue.
Série Agents Whitepaper — hub
Todos os guias da série em um só lugar.
The New SDLC with Vibe Coding
O novo ciclo de vida de desenvolvimento de software: do código escrito à intenção orquestrada.
Agent Tools & Interoperability
Os 5 protocolos abertos que conectam agentes a ferramentas e entre si.
Vibe Coding Agent Security and Evaluation
Como avaliar e proteger agentes: quality gates, métricas e segurança em produção.
Spec-Driven Production Grade Development
Desenvolvimento guiado por specs para levar vibe coding a nível de produção.
Referências
As 30 endnotes do paper original, na ordem em que aparecem.
MILAM, Kimberly; GULLI, Antonio. "Context Engineering: Sessions, Memory" — Agents Whitepaper Series, Google, Novembro 2025.