Interactive guide · Day 3

Sessions, Memory & Skills

LLMs are stateless: every API call is born remembering nothing. For an agent to remember, learn and personalize, someone must assemble — turn by turn — the right information inside the context window. That craft is Context Engineering. This guide summarizes the paper "Context Engineering: Sessions, Memory" (Kimberly Milam & Antonio Gulli, Google) in interactive form: clickable diagrams, simulators, a quiz and cheatsheets.

📄 Paper: Day 3 ⏱ ~25 min of study 🎮 interactive simulators ✅ 8-question quiz 🌐 EN · ES · PT-BR
👥 Who this guide is for
🤖 Agent engineers 🏛 System architects 👩‍💻 Production devs 🧠 Product & personalization

It assumes familiarity with LLMs and software development. It does not assume prior knowledge of agent frameworks — ADK and LangGraph are presented as examples, not prerequisites.

agent@production — turn 47 · the context cycle in action
user$ "book my November trip, like last time" ▸ fetch memories.retrieve(user=u_8123)… 3 memories · 96ms   · "prefers direct flight and middle seat" · "travels NYC→PAR in Nov" ▸ prepare payload assembled: 4,210 tokens (compacted history) ▸ invoke gemini → tool:search_flights → final answer ok ▸ upload memories.generate(events[45..47])… background ✓ user$
0
stages in the continuous context-management cycle: Fetch → Prepare → Invoke → Upload
0
layers collaborating on every turn: user, agent, framework, session storage, memory manager
0
endnotes in the original paper — all listed in the references section
01

What is Context Engineering

The craft of assembling, every turn, the right information inside the context window — no more, no less.

LLMs are inherently stateless: all their reasoning happens inside the context window of a single API call. Nothing that came before exists for the model — unless someone puts it there. Context Engineering is the process of dynamically assembling and managing the information inside the context window to enable stateful, intelligent agents.

It is the natural evolution of Prompt Engineering: instead of polishing a static instruction, the context engineer orchestrates the entire payload — selecting, summarizing and strategically injecting different types of information on every turn, with maximum relevance and minimum noise. External systems (RAG, session stores, memory managers) manage the context; the framework orchestrates it all.

👨‍🍳Analogy · Mise en place

The chef doesn't cook holding the recipe — the chef cooks with a ready station

Prompt only · the recipe

A chef who only has the recipe uses whatever random ingredients happen to be around. The dish turns out… okay. That's the static prompt: a good instruction, with no prepared context.

Full context · the ready station

The chef gathers and prepares all the ingredients, arranges the tools and defines the plating style before cooking. That's the full context: history, memories, facts, tools — everything in place, at the right time.

📜

Prompt = the recipe

static instruction
  • says what to do
  • doesn't know what's in the fridge
  • unpredictable result
🍳 an okay meal, with luck
vs
🥘

Context = prepared ingredients

dynamic, complete payload
  • recipe + right ingredients + tools + plating
  • assembled per dish (per turn)
  • no more, no less than what's needed
⭐ excellent, consistent results
Golden rule

The goal is not to fill the context window — it is to deliver the most relevant information for this turn. No more, no less.

02

The context payload

Three layers of components — click each one to see what it contains.

Everything the model "sees" in a turn fits into three categories. Assembly is dynamic: memories aren't static, few-shot examples must be relevant to the task (not hardcoded), and RAG responds to the immediate query.

🧭

Context that guides reasoning

behavior
System InstructionsTool DefinitionsFew-Shot Examples
📚

Facts & evidence

what to reason about
Long-Term MemoryExternal Knowledge (RAG)Tool OutputsSub-Agent OutputsArtifacts
💬

Immediate conversation

the current task
Conversation HistoryState / ScratchpadUser's Prompt

🧭 Guia o raciocínio

03

Context rot & the continuous cycle

Why the history must be mutated on every turn — and the four stages that make it happen.

The conversation history grows without stopping. Bigger windows survive long transcripts, but: cost and latency rise with every token, and context rot appears — the model's attention to critical information decreases as the context grows. The solution is to mutate the history dynamically: summarization, selective pruning, compaction.

Sessionsturn-by-turn stateMemorypersistence across sessions🔍FETCH🧩PREPAREINVOKE📤UPLOAD
FETCH

1 · Fetch Context

🪑Analogy · Workbench × Filing cabinet

The Session is the workbench; Memory is the organized filing cabinet

Session · the workbench

Tools, notes and drafts scattered around: everything accessible, but temporary. At the end of the day the bench is cleared — and the next conversation starts clean.

Memory · the filing cabinet

You review the materials from the bench, discard the drafts and file only the essentials. Nobody shoves the whole messy bench into the cabinet — that's why upload is consolidation, not copying.

04

Sessions: fundamentals

The chronological container of ONE conversation — events + state, bound to a single user.

A session encapsulates the dialogue history and working memory of one continuous conversation: a self-contained record bound to a specific user. A user can have multiple sessions — separate, disconnected logs.

📦 session s_771 · user u_8123 · 2 components
Events — chronological history
userinput (text / audio / image)
agentagent response
tooltool call
tooltool output
State — mutable scratchpad
cart.items[NYC→PAR, 2 pax]
cart.seat"middle"
trip.datesNov 7–14

The agent appends events and mutates the state according to business logic. The structure echoes the list of Content objects in the Gemini API — each Content has a role (user/model) and parts (text, images, tool calls): one turn = one Event.

pythonmulti-turn call · Gemini API
# o histórico é uma lista de Content: role + partsresponse = 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"}]}, ], )
Production ≠ development

Production runtimes are stateless — the history must be persisted. In-memory storage is fine for development; production demands robust databases (e.g. Agent Engine Sessions).

05

Frameworks: the universal translator

ADK and LangGraph implement sessions differently — but the core ideas are the same.

The framework is a universal translator between your code and the LLM: it keeps the history and state, builds the requests, parses and stores the responses. For Gemini, the request is List[Content] — each Content with a role and parts. The framework maps your internal object (e.g. an ADK Event) to role/parts before the call. This abstraction decouples the agent's logic from the specific LLM — and prevents vendor lock-in.

🧠

Your logic

Agent's internal events and state

🔁

Framework

builds the request · parses the response

📡

Gemini API

List[Content] · role + parts

💾

Session store

history + state persisted

ADK — explicit Session object

A Session with a list of Events + a separate state object. Think of a folder with one file for the history and another for the working memory — everything in its place, clearly delimited.

pythonstructure of an ADK Session
session = Session( id="s_771", events=[event_1, event_2, event_3],  # histórico cronológicostate={"cart_items": [...]},          # working memory separada)

LangGraph — the state IS the session

There is no formal "session" object: the comprehensive, mutable state (history as a list of Messages + working data) is the session. And it can be transformed — for example with history compaction — which is valuable for long conversations and token limits.

pythonthe state as session in LangGraph
class AgentState(TypedDict): messages: Annotated[list, add_messages]  # históricocart: dict                                 # dados de trabalho# o grafo pode reescrever o state a cada passo (ex.: compactar)
06

Multi-agent sessions

When several agents collaborate, the architecture defines who sees whose history.

Don't confuse them

Session history is the permanent, complete transcript. Context is the carefully built payload for ONE turn — it may be a relevant excerpt with special formatting. This section is about what passes between agents, not necessarily what goes to the LLM.

📜

Shared history

single central log · single source of truth
  • all agents read and write the same chronological log
  • ideal for coupled tasks: one's output is the next one's input
  • even so, each agent can filter/label events before passing them to the LLM
  • e.g. LLM-driven delegation in ADK — sub-agent events land in the root agent's session (with output_key)
📦

Separate histories

black boxes · message-based communication
  • each agent keeps a private history: reasoning, tool use and intermediate steps stay hidden
  • communication happens only through explicit messages — the final output, not the process
  • via Agent-as-a-Tool (invoke another agent as a tool and receive a self-contained output)
  • or via the A2A Protocol (direct, structured messages)
07

Interoperability & the A2A protocol

The abstraction that frees the agent from the LLM also isolates it from other frameworks — the memory layer is the bridge.

There is a critical trade-off: the same abstraction that decouples the agent from the LLM isolates it from agents of other frameworks. The isolation hardens at the persistence layer — the database schema gets coupled to the framework's internal objects, and the record becomes non-portable. A LangGraph agent cannot natively interpret the Session/Event objects of an ADK agent: seamless handoff, impossible.

🔒

Isolated session stores

the problem
  • A2A exchanges messages, but doesn't share rich contextual state
  • the history lives in each framework's internal schema
  • sending session events via A2A requires a custom translation layer
🧠

Shared memory layer

the most robust pattern
  • knowledge abstracted into a framework-agnostic data layer
  • stores processed, canonical information: summaries, entities, facts as strings/dicts
  • heterogeneous agents achieve collaborative intelligence by sharing a common cognitive resource — no translators needed
In one sentence

Session stores keep raw, framework-specific objects; the memory layer keeps processed, canonical information. It is the universal data layer.

08

Sessions in production

Three critical areas a managed session store (e.g. Agent Engine Sessions) addresses.

🔐 Security & privacy

  • Strict isolation is the most critical principle: a session belongs to one user — no one else can access it (ACLs; every request authenticated against the owner)
  • PII: redact before writing to storage — shrinks the "blast radius" of a breach (tools like Model Armor)
  • simplifies GDPR/CCPA compliance and builds trust

🗂️ Integrity & lifecycle

  • sessions shouldn't live forever: TTL policies delete inactive sessions (storage cost + overhead)
  • clear retention policy: how long before archiving or deleting
  • events appended in deterministic order — correct chronological sequence = log integrity

⚡ Performance & scale

  • session data sits on the hot path of every interaction — reads/writes must be very fast
  • stateless runtimes fetch the entire history from the central database on every turn (network latency)
  • mitigation: shrink what's transferred — filter/compact the history before sending (e.g. drop old, irrelevant function call outputs)
09

Compacting long conversations

Four pressures, one suitcase and three strategies — play with the simulator.

In a simple architecture, the session is an immutable log. As it scales, token usage explodes — and four limitations bite latency-sensitive applications:

📏 Window

exceeding the maximum processable text = the API call fails

💸 Cost

you pay per token sent/received — smaller history, smaller bill

🐢 Latency

more text = more processing time = slower response

📉 Quality

more tokens = worse performance: noise + autoregressive errors

🧳Analogy · The suitcase

The context window is a suitcase with limited space

Overpacking

A heavy, disorganized suitcase: you pay excess baggage (cost) and can't find anything (slowness). That's uncompacted history.

Underpacking

You forget your passport and coat — you lose critical context and answer wrong. Compacting well means packing only what's needed.

The three compaction strategies

🪟 Keep last N turns

the simplest: a sliding window over the most recent N turns — everything older is discarded

✂️ Token-based truncation

counts tokens from the most recent backward and includes as many messages as possible without exceeding a predefined limit (e.g. 4,000 tokens) — the rest is cut off

📜 Recursive summarization

older messages become a summary prefixed to the recent ones — best fidelity/cost balance (expensive LLM operation → runs in background)

tokens (kept / total)
estimated cost / turn
context-loss risk
pythonADK — compaction without altering the stored events
# limita o contexto enviado ao LLM, sem modificar o log persistidoplugin = ContextFilterPlugin(num_invocations_to_keep=10)# ou: compactação agendada de eventosconfig = EventsCompactionConfig(compaction_interval=5, overlap_size=1)

Trigger mechanisms

🔢 Count-based

token or turn-count threshold — simple and "good enough"

⏰ Time-based

lack of activity (e.g. 15–30 min without interaction) → background compaction

🎯 Event-based

detects a completed task, sub-goal or topic — semantic trigger

Expensive operations → background

Recursive summarization must run asynchronously in the background and persist its results (the client doesn't wait; the computation isn't repeated). The agent records which events are already in the compacted summary — so it doesn't re-send the verbose originals. Memory generation is the broad capability behind this: extracting persistent knowledge from noisy sources, discarding the filler.

10

Memory 101

The symbiotic relationship between sessions and memory — and the five layers that collaborate on every turn.

Sessions and memory live in symbiosis: sessions are the primary source for generating memories, and memories are the key strategy for managing the size of sessions. Each one feeds the other, in a continuous cycle.

A memory is a snapshot of extracted, meaningful information from a conversation or source: a condensed representation that preserves the important context, persisted across sessions for a continuous, personalized experience.

Terminology note

Some frameworks call the verbatim conversation "short-term memory". In this paper, memories are extracted information — not the raw dialogue.

Four capabilities a memory system enables

🎯 Personalization

remembering preferences, facts and past interactions — the favorite team, the preferred airplane seat

📦 Context window management

compacting long histories into summaries and key facts, preserving context without sending thousands of tokens per turn — less cost, less latency

📊 Data mining & insight

analyzing memories from many users in an aggregated, privacy-preserving way — e.g. a retail chatbot discovers many people asking about a product's return policy

🔁 Agent self-improvement

procedural memories about its own performance — which strategies, tools and paths led to success — become a playbook the agent reuses and adapts

The five layers collaborating on every turn

🧑

1 · User

provides the raw data — sometimes directly, via a form

input direto
🤖

2 · Agent (developer logic)

decides what and when to remember, and orchestrates the memory manager — from "always fetch/generate" to memory-as-a-tool, where the LLM decides

orquestração
🔧

3 · Agent framework (ADK, LangGraph)

the plumbing: structures and tools to interact with memory, access the history, inject into the context window — it does not manage long-term storage

plumbing
🗄️

4 · Session storage (Agent Engine Sessions, Spanner, Redis)

stores the conversation turn by turn; the raw dialogue is the raw material ingested by the memory manager

turno a turno
🧠

5 · Memory manager (Agent Engine Memory Bank, Mem0, Zep)

storage, retrieval and compaction — the complete lifecycle: Extraction → Consolidation → Storage → Retrieval

ciclo completo
An active system, not a passive database

A memory manager is not a passive vector database. Its core value is to extract, consolidate and curate memories intelligently over time — not just do similarity search.

11

RAG × Memory

Distinct, complementary roles: RAG makes the agent an expert in facts; Memory, an expert in the user.

Memory retrieval is often compared to RAG, but the architectural principles are different: RAG deals with static external data; Memory, with dynamic, user-specific context. They are complementary — and a truly intelligent agent needs both.

📚

RAG · the research librarian

expert in world facts
  • works in a vast public library: encyclopedias, official docs, a static and shared base
  • retrieves established, authoritative facts
  • read-only, global — the same for every user
  • knows nothing personal about you
🗒️

Memory · the personal assistant

expert in you
  • carries a private notebook, recording details of every interaction
  • dynamic and highly isolated: preferences, past conversations, goals
  • writes on every turn or at session end — event-based
  • adapts as the relationship evolves
DimensionRAG EnginesMemory Managers
Primary goalinject external factual knowledgepersonalized, stateful experience: remembers facts, adapts to the user, maintains long context
Data sourcepre-indexed external knowledge base (PDFs, wikis, docs, APIs)the user-agent dialogue
Isolationusually shared (global, read-only)highly isolated (per-user, prevents leaks)
Information typestatic, factual, authoritativedynamic, user-specific, with inherent uncertainty
Write patternbatch processing (offline administrative action)event-based (every turn / session end) or memory-as-a-tool
Read patternalmost always as-a-tool (the agent decides when it's needed)memory-as-a-tool OR static retrieval at the start of the turn
Formatnatural-language chunksnatural-language snippets OR structured profile
Data preparationchunking + indexing (embeddings for fast search)extraction + consolidation (no duplication or contradiction)
12

Memory types

Anatomy, cognitive taxonomy, organization, storage, creation, scope and multimodality.

Memories are classified by how they are stored and captured — and they work together for a rich, contextual understanding. Golden rule: memories are descriptive, not predictive.

Anatomy of a memory

A 'memory' is an atomic piece of context that is returned by the memory manager and used by the agent as context. While the exact schema can vary, a single memory generally consists of two components: content and metadata.

📄 Content

the substance extracted from the source data, in a framework-agnostic format. Structured ({"seat_preference": "window"}) or unstructured ("The user prefers a window seat").

🏷️ Metadata

the context about the memory: unique identifier, owner and labels describing content and source.

Declarative × Procedural (cognitive science)

🧾

Declarative

"knowing what" · answers WHAT
  • facts, numbers, events
  • includes general knowledge (semantic) and user-specific facts (episodic)
  • e.g. "the user prefers a window seat"
🛠️

Procedural

"knowing how" · answers HOW
  • skills and workflows
  • guides actions by implicitly demonstrating how to execute a task
  • e.g. the correct sequence of tool calls to book a trip

Organization patterns

🗃️ Collections

multiple self-contained natural-language memories per user — several per topic, searched in a larger, less structured pool

🪪 Structured user profile

a set of core facts, like a continuously updated contact card — fast lookup of the essentials (names, preferences, account)

📜 Rolling summary

ONE single, evolving memory: the summary of the entire user-agent relationship, continuously updated — used to compact long sessions

Storage architectures

🧮 Vector databases

retrieval by semantic similarity (not exact keywords): memories become embeddings and match by concept. Excellent for unstructured facts

🕸️ Knowledge graphs

memories as a network of entities (nodes) + relationships (edges); retrieval = traversing the graph. Ideal for relational queries ("knowledge triples")

🔀 Hybrid

graph entities enriched with vector embeddings — relational and semantic search at once: the best of both worlds

Creation mechanisms

🗣️ Explicit

direct command from the user: "remember my anniversary is October 26th"

🕵️ Implicit

the agent infers without a command: "my anniversary is next week, help me find a gift" → memory created

🏠 Internal

management embedded in the framework — convenient, with fewer features

☁️ External

specialized service (Memory Bank, Mem0, Zep): semantic search, entity extraction, automatic summarization

Scope: who the memory describes

👤 User-level

the most common: bound to the user ID, persists across sessions — "the user prefers the middle seat"

💬 Session-level

persistent record of insights from ONE session — replaces the verbose transcript with concise facts, isolated to that conversation

🌐 Application-level

global context accessible to all users — common case: procedural memories ("how-to" for the agent's reasoning)

Critical

Application-level memories must be sanitized of sensitive content — otherwise they become a leak vector between users.

Multimodal memory: source × content

🎙️

Multimodal source

the most common
  • the agent processes text, image or audio — but the memory created is a textual insight
  • e.g. voice memo → transcription → "user expressed frustration about shipping delay" (the audio is not stored)
🖼️

Multimodal content

advanced
  • the memory contains non-textual media directly
  • e.g. "remember this design for our logo" → the memory contains the image file
In practice

Most managers focus on multimodal sources → textual content: converting everything to text is the simplest way to keep a searchable format.

pythonSnippet 5 — generating memories from multimodal input (Gemini API)
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})
13

Memory generation: the ETL pipeline

How raw conversational data becomes structured insights — an LLM-directed ETL.

Generation autonomously transforms raw conversational data into structured, meaningful insights — an LLM-directed ETL pipeline (Extract, Transform, Load). That's what distinguishes memory managers from RAG engines and traditional databases: instead of the dev specifying database operations manually, the LLM decides when to add, update or merge memories — abstracting the complexity of managing content, chaining calls and running background services.

📥

Ingestion

the client provides the raw data source — typically the conversation history

⛏️

Extraction & filtering

the LLM extracts only what fits predefined topic definitions — no match, no memory created

🧬

Consolidation

the most sophisticated stage: conflict resolution + deduplication — merge, delete or create

💾

Storage

the new or updated memory is persisted in durable storage (vector DB / knowledge graph)

pythonMemory Bank — one call orchestrates the entire pipeline
memories.generate( scope={"user_id": "u_8123"}, direct_contents_source=session_events,   # matéria-prima rawconfig={"wait_for_completion": False},   # assíncrono, em background)
🌱Analogy · The gardener

A healthy garden doesn't grow by itself — it demands constant curation

Extraction · receiving the seedlings

New seeds and seedlings arrive at the garden: the LLM identifies what deserves to be planted — and discards what doesn't fit the defined beds (topics).

Consolidation · weeding and pruning

Pull out the weeds (delete the redundant and conflicting), prune branches (refine and summarize the existing) and plant each seedling in the optimal spot. Without curation, the garden turns to weeds — a continuous, background process.

Managed = complete pipeline

A managed memory manager (e.g. Agent Engine Memory Bank) automates the entire pipeline — extraction, consolidation and storage — with a single asynchronous API call.

14

Deep-dive: Extraction

"What information here is meaningful enough to become a memory?" — intelligent filtering, not summarization.

The fundamental question of extraction is: "what information in this conversation is meaningful enough to become a memory?" It's not simple summarization — it's intelligent, targeted filtering: separating signal (facts, preferences, goals) from noise (pleasantries, filler).

"Meaningful" is not universal — it's defined by the agent's purpose. A customer-support agent extracts order numbers and technical issues; a wellness coach extracts long-term goals and emotional states. Customizing that definition is the key to an effective agent.

💬 Full conversation
turns, pleasantries, filler, hesitations — everything that was said
🎛️ Topic filter
programmatic guardrails: only what fits the defined topics
⛏️ Extraction LLM
signal separated from noise, according to the topic definitions
🧠 Memories
high-fidelity facts and insights, ready for consolidation

How the LLM knows what to extract

🧩 Schema / template-based

a predefined JSON schema or template (structured output); the LLM builds the JSON with the matching information

📝 Natural-language definitions

the LLM is guided by a simple natural-language description of what each topic is

🎓 Few-shot prompting

the LLM "sees" what to extract through examples: input + ideal high-fidelity memory. Very effective for nuanced topics that are hard to describe

Most managers work out-of-the-box with common topics (preferences, key facts, goals) — and many allow custom topics. The paper's example: a conversation about a coffee shop generates two feedback memories — "the drip coffee was lukewarm" and "the music was too loud".

pythonMemory Bank — managed + custom topics + examples
config = MemoryGenerationConfig( memory_topics=[ ManagedTopicEnum.USER_PERSONAL_INFO,          # tópico built-inCustomMemoryTopic( name="business_feedback", description="feedback about the coffee shop", ), ], generate_memories_examples=[...],                  # few-shot: conversa → fatos)
Summarization in service of extraction

Although it isn't summarization, the algorithm can incorporate it: a rolling summary of the conversation enters the extraction prompt, giving condensed context to extract from recent interactions — without reprocessing the full dialogue every turn.

15

Deep-dive: Consolidation

The stage that turns a collection of facts into curated understanding — LLM-directed self-curation.

Consolidation integrates new information into a coherent, accurate, evolving knowledge base. It's the most sophisticated stage: without it, memory becomes a noisy, contradictory, unreliable log. This LLM-managed "self-curation" is what elevates the memory manager beyond a simple database.

The four problems it addresses

👯 Duplication

the same fact in several forms: "I need a flight to NYC" + "I'm planning a trip to New York" — naive extraction would create two redundant memories

⚔️ Conflict

the user's state changes over time — without consolidation, contradictory facts coexist in the base

🌱 Evolution

a simple fact becomes more nuanced: "interested in marketing" → "leading a Q4 customer-acquisition project"

⌛ Decay

not every memory stays useful: the agent practices forgetting — pruning the old, obsolete and low-confidence (prioritize the new, or TTL)

The three-step process

🔎

1 · Find similar

existing memories similar to the freshly extracted ones become consolidation candidates

⚖️

2 · LLM analyzes

existing memories + new information, together: the LLM identifies the required operations

📝

3 · Transaction

the memory manager translates the LLM's decision into a transaction that updates the store

✏️

UPDATE

modify an existing memory with new or corrected information

CREATE

a wholly new, unrelated insight → create a new memory

🗑️

DELETE / INVALIDATE

the new information made the old memory irrelevant or incorrect → delete or invalidate

16

Provenance: lineage & trust

"Garbage in, confident garbage out" — every memory needs a record of origin and history.

"Garbage in, garbage out" is even more critical for LLMs: here it's "garbage in, confident garbage out". For trustworthy decisions and effective consolidation, the agent must critically evaluate the quality of its own memories — and reliability derives from provenance: the detailed record of origin and history.

🏢 Bootstrapped data
pre-loaded from internal systems (CRM) — high confidence; solves the cold-start problem: personalization before any interaction
🙋 User input
provided explicitly (form = high confidence) or implicitly extracted from conversation (less reliable)
🔧 Tool output
returned by external tools — generating memories from here is discouraged (fragile and stale); it serves for short-term caching
many ↔ many
one memory ← several sources
one source → several memories

trust = origin + age
🧠 m_1 · "prefers direct flights"
sources: conversation t_12 + conversation t_40 · corroborated 2×
🧠 m_2 · "middle seat"
source: profile form · high confidence
🧠 m_3 · "travels in Nov"
source: conversation t_40 · single, implicit · decayed with age

Lineage during management

⚔️ Conflict resolution

sources conflict — provenance establishes the trust hierarchy: prioritize the most reliable source, favor the most recent information, seek corroboration across multiple data points.

🧹 Deleting derived data

if the user revokes access to a source, derived data must be removed. Deleting every memory "touched" can be too aggressive — the most precise (and expensive) approach is to regenerate the affected memories from scratch using only the remaining valid sources.

Trust evolves — and pruning is active

Trust is not static: it grows with corroboration (multiple consistent reliable sources) and decays with age and conflict. Memory pruning (active forgetting) identifies and discards memories that are no longer useful — by time-based decay (a meeting from 2 years ago is worth less than last week's), low confidence (a weak inference never corroborated) or irrelevance (old trivial details in the face of current goals). Reactive consolidation + proactive pruning = a curated knowledge base, not an ever-growing log of everything.

At inference time

Memories and their confidence scores are not shown to the user — they're injected into the system prompt so the LLM can weigh the evidence, consider reliability and make more nuanced decisions.

17

Triggering generation & memory-as-a-tool

The agent decides WHEN to generate — a balance between data freshness, cost and latency.

Memory managers automate extraction and consolidation after generation is triggered — but who decides when to attempt generation is the agent. It's a critical architectural choice: balancing data freshness against computational cost and latency.

Trigger strategies

🏁 Session completion

at the end of a multi-turn session — most economical, lower-fidelity memories

🔁 Turn cadence

after N turns (e.g. every 5) — a middle ground between freshness and cost

⚡ Real-time

after EVERY turn — detailed, fresh memories, higher LLM/database cost

🗣️ Explicit command

direct command from the user: "remember this" — maximum fidelity, clear intent

Cost × fidelity trade-off

Frequent generation = fresh, detailed memories, but higher cost and potential latency. Infrequent generation = economical, but the LLM summarizes much larger blocks (lower fidelity). And beware: don't reprocess the same events multiple times — unnecessary cost.

Memory-as-a-tool: the agent decides

In the most sophisticated approach, generation is exposed as a tool (e.g. create_memory) whose definition describes which types of information are meaningful. The agent analyzes the conversation and calls the tool autonomously when it identifies something worth persisting — shifting the responsibility of identifying the "meaningful" from the memory manager to the agent/dev.

pythonADK — generation as an agent tool
def generate_memories(tool_context):# opção 1: histórico completo da sessionmemory_service.add_session_to_memory(tool_context.session)# opção 2: só o último turno, assíncronomemories.generate(..., config={"wait_for_completion": False}) runner = Runner(agent=agent, memory_service=VertexAiMemoryBankService())
pythonVariant — the agent extracts, the Memory Bank only consolidates
# aqui o AGENTE extrai (extract_memories) e envia ao Memory Bank# apenas para CONSOLIDAR com as memórias existentesmemories = extract_memories(direct_memories_source={"fact": query}) memory_bank.store(memories)  # consolidação delegada ao serviço

Background, always

🌙
Generation is expensive — never block the UX
LLM calls + database writes. In production, almost always asynchronous in the background: after the agent sends its response, the pipeline runs in parallel. Waiting for the memory to be written before responding = unacceptably slow UX. That's why the service is architecturally separate from the agent's core runtime.
18

Memory Retrieval

Which memories to fetch, when to fetch them — and how to score them across multiple dimensions.

The retrieval strategy depends on the organization: a structured user profile is a simple lookup (the whole profile or one attribute); a collection is a complex search problem — finding the most pertinent information in a large, loosely structured pool.

Effective retrieval is crucial: irrelevant memories confuse the model and degrade the response; perfect context produces a remarkably intelligent interaction. The central challenge is balancing utility against a strict latency budget.

The three scoring dimensions

🎯

Relevance

semantic similarity

how conceptually related to the current conversation?

🕐

Recency

time-based

how recently was the memory created?

💎

Importance

significance

how critical is it overall? (set at generation — different from relevance)

Classic pitfall

Relying only on vector relevance makes retrieval surface conceptually similar memories — but old or trivial ones. The best strategy is a blended approach: combining all three dimensions.

Precision techniques (and their cost)

✍️ Query rewriting

the LLM improves its own query — rewriting ambiguous input into a precise query or expanding one query into several related ones. Improves quality, adds the latency of an extra call

🏆 Reranking

broad initial retrieval (e.g. top 50) by similarity; then the LLM re-evaluates and re-ranks the set into a more precise final list

🔬 Specialized retriever

fine-tuning the retriever — requires labeled data and significantly raises costs

Two practical truths

1) If these techniques are needed and memories don't go stale quickly, use a caching layer — store expensive results temporarily and avoid latency on identical requests. 2) The best approach starts before retrieval: better memory generation (a high-quality corpus, free of irrelevance) is the most effective way to guarantee useful retrieval.

Timing: when to fetch

🌅

Proactive

loaded at the start of every turn
  • context always available — but unnecessary latency on turns that don't need it
  • since memories are static during a turn, they can be cached (mitigates the cost)
  • e.g. ADK PreloadMemoryTool or a before_model_callback that appends memories to the system_instruction
🎯

Reactive · memory-as-a-tool

the agent decides when to fetch
  • more efficient and robust — the extra call only happens when needed
  • risk: the agent may not know relevant information exists
  • mitigation: describe the types of memories available in the tool itself (e.g. LoadMemoryTool or load_memory(query))
pythonSnippet 10 — proactive retrieval: PreloadMemoryTool or custom callback (ADK)
# Option 1: PreloadMemoryTool embutida — busca por similaridade em todo turnoagent = LlmAgent( ..., tools=[adk.tools.preload_memory_tool.PreloadMemoryTool()] )# Option 2: callback customizado — mais controle sobre como as memórias são buscadasdef 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 Instructionsllm_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, )
pythonSnippet 11 — reactive retrieval: built-in LoadMemoryTool or custom tool (ADK)
# Option 1: LoadMemoryTool embutida — o agente decide quando buscaragent = LlmAgent( ..., tools=[adk.tools.load_memory_tool.LoadMemoryTool()], )# Option 2: tool customizada — descreva que tipos de informação podem estar disponíveisdef 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 similaridaderesponse = tool_context.search_memory(query)return response.memories agent = LlmAgent( ..., tools=[load_memory], )
19

Inference with memories

The final step: strategically positioning the retrieved memories in the context window.

Positioning influences the LLM's reasoning, operational costs and response quality. In practice, a hybrid strategy works best: system prompt for stable/global memories (the user profile, always present); dialogue injection or memory-as-a-tool for transient/episodic memories (relevant only to the immediate context).

Memories in the System Instructions

Appending memories to the system prompt with a preamble gives them high authority and separates the context from the dialogue — ideal for stable, global information. Typically via a template (e.g. Jinja) with a <MEMORIES> block iterating over retrieved_memory.memory.fact.

pythonSnippet 12 — Jinja template appending memories to the system instructions
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 )
Risks & constraints

Over-influence: the agent tries to relate EVERY topic to the core memories, even when inappropriate. Also: it requires a framework that supports a dynamic system prompt on every call; it is incompatible with memory-as-a-tool (the system prompt must be finalized BEFORE the LLM decides to call the retrieval tool); and it handles non-textual memories poorly.

Memories in the Conversation History

Injecting directly into the dialogue — before the full history or right before the user's last query. Risks: noise (more tokens, confusion if irrelevant) and dialogue injection (the model treats the memory as something actually said in the conversation). Mind the perspective: if you use role "user" with user-level memories, write in first person. Special case: retrieval via tool calls — memories arrive as tool output.

pythonmemories returned as 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

And what about procedural memories?

The paper focused on declarative — a reflection of today's commercial market, whose platforms are architected to extract/store/retrieve the "what". But storing the "how" is not an information-retrieval problem — it's a reasoning-augmentation problem, with its own lifecycle:

⛏️ Extraction

specialized prompts distill a reusable strategy — a "playbook" — from a successful interaction, not just a fact

🧬 Consolidation

curates the WORKFLOW: integrates new successful methods with existing best practices, patches failing steps, prunes obsolete procedures

🔎 Retrieval

the goal isn't retrieving data to answer a question, but retrieving a PLAN that guides the execution of a complex task

Procedural memory × fine-tuning (RLHF)

Both aim to improve behavior — but the mechanisms are fundamentally different. Fine-tuning is a slow, offline process that alters the model's weights. Procedural memory is fast, online adaptation: dynamically injecting the right "playbook" into the prompt — in-context learning, no fine-tuning.

20

Testing & evaluation of memory

Does it remember the right things? Does it find them when needed? And does using memory actually help?

Memory evaluation is a multi-layered process: verifying the agent remembers the right things (quality), finds memories when needed (retrieval), and that using them actually helps achieve goals (task success). In academia, reproducible benchmarks; in industry, direct impact on the production agent.

🧪 Generation quality

Precisionof the memories created, % accurate and relevant — protects against an "over-eager" system that pollutes the base
Recallof the facts it should have remembered, % captured — guarantees nothing critical slips through
F1-Scoreharmonic mean of precision and recall — a single balanced measure vs. a manual golden set

🔎 Retrieval performance

Recall@Kwhen the memory is needed, is the right one in the top K results? — the primary measure of precision
Latencyretrieval sits on the response hot path — strict budget (e.g. <200ms) so UX doesn't degrade

🏁 End-to-end task success

LLM judgean LLM compares the final output with the golden answer and determines whether the response was accurate
Impactomeasures how much the memory system contributed to the downstream outcome
Continuous-improvement engine

Evaluation is not a one-time event: establish a baseline → analyze failures → tune the system (refine prompts, adjust retrieval algorithms) → re-evaluate to measure impact. And beyond quality, production-readiness demands performance: sub-second retrieval on the hot path, sufficient throughput for asynchronous generation. A successful memory system = intelligent + efficient + robust.

21

Memory in production & security

From prototype to enterprise: decoupling, concurrency, resilience — and the corporate archivist.

From prototype to production, the focus shifts to enterprise-grade concerns: scalability, resilience and security. Rule number one: decouple memory processing from the main logic — the UX can never be blocked by expensive generation.

📤

1 · Agent pushes data

after a relevant event (e.g. session end), a non-blocking API call "pushes" the raw data

🌙

2 · Process in background

the service acknowledges, queues internally and does the heavy lifting — LLM, extraction, consolidation

💾

3 · Memories persisted

final memories written to a dedicated durable database (managed managers have built-in storage)

🔍

4 · Agent retrieves

the application queries the store directly when it needs context for a new interaction

Why non-blocking service-based

Failures and latency in the memory pipeline don't impact the user-facing application. The pattern also informs the choice between online processing (real-time, conversational freshness) and offline (batch, ideal for backfilling historical data).

Concurrency, failures and global scale

🔀 Concurrency

high-frequency events without deadlocks/race conditions when multiple events modify the same memory: transactional operations or optimistic locking, with a robust message queue as buffer

🩹 Failure handling

resilience to transient errors: LLM call failed → retry with exponential backoff; persistent failures → dead-letter queue for analysis

🌍 Global

multi-region replication built-in — client-side replication isn't viable (consolidation requires a single, transactionally consistent view); the system replicates internally and presents a single logical datastore

Privacy & security risks

Memories derive from — and include — user data. Think of a secure corporate archive managed by a professional archivist: it preserves valuable knowledge while protecting the company.

🔐 Data isolation

the cardinal rule: just as the archivist never mixes confidential files from different departments, memory is strictly isolated per user/tenant (restrictive ACLs). Users have programmatic control: opt out of generation or delete all their files

🖊️ PII redaction

before filing any document, the archivist redacts sensitive personal information — knowledge is saved without creating liability

☠️ Memory poisoning

the archivist is trained to spot forgeries: validating and sanitizing information BEFORE committing to long-term memory prevents a malicious user from corrupting persistent knowledge via prompt injection (safeguards like Model Armor)

📡 Exfiltration risk

memories shared across users (e.g. procedural "how-to") are like a company-wide memo: if one user's memory becomes an example for another, the archivist performs rigorous anonymization first — preventing leaks across user boundaries

22

Conclusion

From a single conversational turn to persistent, actionable intelligence.

The journey from a conversational turn to persistent intelligence is governed by Context Engineering — dynamically assembling history, memories and external knowledge into the context window. It depends on the interplay of two distinct, interconnected systems:

⏱️

The Session governs the "now"

low-latency chronological container
  • challenge = performance + security: low-latency access and strict isolation
  • compaction via token truncation and recursive summarization
  • PII redaction BEFORE persisting — security paramount
🧠

Memory governs the "always"

long-term personalization engine
  • goes beyond RAG (expert in facts) to make the agent an expert in the USER
  • LLM-directed ETL pipeline: extraction → consolidation → retrieval
  • asynchronous background generation + provenance + poisoning safeguards = assistants that learn and grow with the user
1

Context is a managed resource, not an accident

Every token in the window has cost, latency and attentional weight. Assemble the payload dynamically: maximum relevance, minimum noise.

2

Sessions and memory are symbiotic, but distinct

The session is the chronological log of one conversation; memory is knowledge extracted and curated across conversations. One feeds the other — never confuse the two.

3

Trust is tracked, weighed and pruned

Provenance says where it came from; confidence scores say how much to weigh it; active forgetting keeps the base curated. Memory without curation is just a log with pretensions.

"The session governs the now.
Memory governs the always."
Context Engineering · Sessions, Memory & Skills — Google, November 2025
23

Quiz

Eight questions to consolidate the cycle, sessions and the memory pipeline.

24

Cheatsheets

Three copyable artifacts to take to your next agent project.

📋 context-cycle-checklist.txt
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-recipe.txt
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.txt
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
25

Implementation checklists

Check off what you already master — your progress is saved in this browser.

📦Ship sessions to production

Model the session as Events (history) + State (scratchpad)
Persist the history — in-memory is only valid in development
Enforce strict isolation with per-user ACLs
Redact PII before writing to storage
Define TTL and a retention policy
Compact the history (keep-last-N / tokens / summarization)
Measure hot-path latency on every turn

🧠Build a memory system

Choose the organization (collections / profile / rolling summary)
Define extraction topics — separate signal from noise
Enable consolidation (UPDATE / CREATE / DELETE-INVALIDATE)
Generate memories in the background, without blocking the UX
Track provenance and score confidence
Blend relevance + recency + importance in retrieval
Evaluate with precision / recall / recall@K

🛡️Harden for production

Decouple the memory service from the agent runtime
Handle concurrency (transactions / optimistic locking)
Retry with exponential backoff + dead-letter queue
Protect against memory poisoning (e.g. Model Armor)
Anonymize shared application-level memories
Replicate globally with a consistent view of the data
26

Glossary

The paper's essential terms, in plain language.

Context window
the window of information the LLM sees in a single call — everything that exists for the model on that turn.
Context rot
the degradation of the model's attention to critical information as the context grows.
Session
the chronological container of ONE conversation: events + state, bound to a single user.
Event
a unit of the history: user input, agent response, tool call or tool output.
State / scratchpad
temporary, mutable structured data of the conversation (e.g. cart items).
Long-term memory
information extracted and persisted across sessions — the foundation of personalization.
RAG
retrieval of static, shared external knowledge — makes the agent an expert in facts.
Consolidation
LLM-directed merging, updating and invalidation of memories (UPDATE / CREATE / DELETE).
Provenance
the record of a memory's origin and history — the foundation of trust.
Retrieval
searching for the memories most pertinent to the current conversation, scored across multiple dimensions.
Compaction
shrinking the history while preserving the important context (keep-last-N, truncation, summarization).
Rolling summary
a single evolving memory that summarizes the entire user-agent relationship.
Memory-as-a-tool
memory generation/retrieval exposed as a tool — the LLM itself decides when to use it.
Cold start
the problem of personalizing for a user with no prior interactions — solved with bootstrapped data.
27

Continue the journey

The companion papers in the series — each guide follows the same interactive, trilingual format.

HUBstarting point

Agents Whitepaper Series — hub

All series guides in one place.

indexnavigation
D1fundamentals

The New SDLC with Vibe Coding

The new software development lifecycle: from written code to orchestrated intent.

vibe codingautonomy spectrumagent harness
D2tools

Agent Tools & Interoperability

The 5 open protocols that connect agents to tools and to each other.

MCPA2AA2UI
D4security & evaluation

Vibe Coding Agent Security and Evaluation

How to evaluate and protect agents: quality gates, metrics and production security.

evaluationquality gatesagent security
D5production

Spec-Driven Production Grade Development

Spec-driven development to take vibe coding to production grade.

spec-drivenproduction gradeworkflow
28

References

All 30 endnotes from the original paper, in order of appearance.

Paper citation

MILAM, Kimberly; GULLI, Antonio. "Context Engineering: Sessions, Memory" — Agents Whitepaper Series, Google, November 2025.