AI Infra
0%
Part VI · Chapter 39

Memory Systems

AuthorChangkun Ou
Reading time~21 min

The agent loop in Chapter 38 is transient unless its state survives the process that runs it. A model response may schedule work, a tool may change a workspace, and a later turn may need evidence from an earlier one. Calling all of that state memory hides the most important engineering fact: different state has different owners, recovery rules, and authority.

This chapter separates four things that are often collapsed into one store: execution history, the mutable workspace, long-term memory, and external systems. A checkpoint can reconnect them, but it cannot make an external side effect happen exactly once. A retrieval index can help find an old record, but it does not decide whether that record was safe to write, authorized to read, still valid, or complete enough to act on. Reliable memory begins by naming those boundaries.

One word, four owners

At turn tt, the agent's operational state can be written as

St=(Jt,Wt,Mt,Et).S_t = (J_t, W_t, M_t, E_t).

Here, StS_t is the complete state relevant to turn tt; JtJ_t is the durable execution history; WtW_t is the workspace version or snapshot visible to the agent; MtM_t is the long-term memory store; and EtE_t is the agent's recorded view of external systems. The last component is only a view. The payment service, ticket tracker, Git remote, or production database remains the system of record for its own state.

State What it is for Authoritative owner Characteristic recovery question
Execution history JtJ_t Inputs, scheduled steps, results, errors, timers, approvals, and workflow version Durable orchestration store Which decisions and results were accepted?
Workspace WtW_t Files, repositories, generated artifacts, and local tool state Workspace storage layer Which mutually consistent filesystem version should be restored?
Long-term memory MtM_t Selected observations, facts, lessons, summaries, and artifact references Memory service and its write policy What should be retained, revised, retrieved, or deleted?
External state EtE_t Receipts and references to effects outside the agent boundary Each external system Did an attempted effect commit, and how can that be proved?

An audit transcript is not automatically a replay log. Replay also needs stable step identities, recorded non-deterministic results, compatible workflow code, and durable references to any workspace or artifact the workflow expects. Likewise, a workspace snapshot is not a record of which API calls succeeded. Each store should make its guarantees explicit instead of borrowing guarantees from its neighbors.

C Checkpoint bundle E External systems independent systems of record C->E receipts / references J Execution history accepted decisions and results J->C W Workspace version files and artifacts W->C M Long-term memory selected records M->C
Figure 39.1. Four state owners meet at a checkpoint. The journal, workspace, and memory store are controlled state; external systems remain separate systems of record.

Durable execution preserves progress, not exactly-once effects

Consider a step that creates a support ticket. The journal durably records the scheduled call, the provider creates ticket 8421, and the worker crashes before the provider's response reaches the journal. Recovery sees a scheduled step with no completed result. Two histories now look identical from inside the journal:

  1. the request never reached the provider; or
  2. the request committed, but its reply was lost.

The outcome is unknown. Recording intent before the call narrows the uncertainty to one named step, but it does not close the gap. AWS Lambda durable steps therefore have at-least-once execution semantics by default, and its documentation still requires idempotent business logic for interrupted attempts (Amazon Web Services 2026). Temporal states the same boundary: completed activities are not rerun during replay, but an activity that did not report completion may be retried and execute more than once (Temporal Technologies 2026).

S Persist Scheduled(step, key, input hash) D Dispatch effect with stable key S->D X External system commits D->X C Persist Completed(step, result) X->C U Crash window: outcome unknown X->U R Recover: lookup, retry same key, reconcile, compensate, or escalate U->R
Figure 39.2. A durable journal distinguishes scheduled from completed work, but a crash after an external commit and before outcome persistence leaves an unknown result.

What deterministic replay records

A minimal history for step ii contains the following entries, where every symbol is defined below:

Scheduled(i,k,H(x),v),Completed(i,r),\operatorname{Scheduled}(i,k,H(x),v), \qquad \operatorname{Completed}(i,r),

The next formula represents replay as a deterministic reducer:

(σt,ct)=Fv(Jt).(\sigma_t, c_t) = F_v(J_{\leq t}).

Here, ii is a stable step identifier; kk is the effect's idempotency key; xx is the requested input; H(x)H(x) is an input fingerprint; vv is the workflow version; rr is the accepted result; JtJ_{\leq t} is the history through turn tt; FvF_v is the reducer implemented by workflow version vv; σt\sigma_t is the reconstructed workflow state; and ctc_t is the next command or command set.

On replay, FvF_v must emit commands compatible with the recorded history. A recorded result is substituted instead of calling the model, clock, random-number generator, or external API again. Those non-deterministic operations belong inside durable steps whose accepted outputs enter the history. If workflow code changes its branching or command order, old histories may no longer replay. Long-running systems therefore pin or explicitly migrate the workflow version rather than silently running every old execution under new code (Microsoft 2026; Microsoft 2026).

Durability and effect delivery are separate guarantees:

Guarantee What recovery does Cost or risk
At-most-once attempt Never retry an ambiguous attempt The effect may never happen
At-least-once attempt Retry until completion is observed The effect may run more than once
Keyed, effectively-once mutation Retry the same key; receiver atomically returns the first mutation's result Requires receiver-side deduplication and sufficient key retention
Transactionally coupled mutation Commit journal state and effect in one transaction or transactional outbox Only works inside a shared transactional boundary

Unqualified “exactly once” is misleading when the journal and effect owner are independent systems. The practical choices are idempotency, reconciliation, compensation, or an explicit operator decision.

A key is a protocol, not a random string

The following sketch is safe only because the provider accepts the key, binds it to the input fingerprint, and returns the prior result on a retry:

def run_effect(journal, provider, step_id, tenant, request):
    key = journal.stable_key(step_id, tenant, request)  # stable across retries
    if completed := journal.completed(key):
        return completed.result

    fingerprint = sha256(canonical_json(request)).hexdigest()
    journal.schedule(step_id, key, fingerprint)

    known = provider.lookup(tenant=tenant, idempotency_key=key)
    if known is None:
        known = provider.apply(
            request,
            tenant=tenant,
            idempotency_key=key,
            input_fingerprint=fingerprint,
        )

    journal.complete(step_id, key, known.receipt)
    return known.result

The key must be generated and persisted before the first attempt, remain stable across retries, be scoped to the tenant and operation, and be bound to an input fingerprint so that the same key with different input is rejected. Its retention period must exceed the maximum replay and retry lifetime. The provider's lookup and mutation must share the same deduplication record; otherwise the lookup followed by the mutation creates another check-then-act race.

When the receiver has no keyed interface, recovery needs evidence from its own system of record: search for the expected ticket, compare a Git reference, reconcile an account ledger, or ask an operator. Compensation can undo some committed effects, but compensation is a new effect with its own failure modes. A transactional outbox can atomically bind a database mutation to an event destined for another service, although downstream delivery still needs deduplication. Step boundaries make these protocols observable; they do not replace them.

Step granularity also matters. A coarse step that reads a database, calls a service, and writes a file may repeat a partially completed sequence. Finer steps isolate retries and store more intermediate results, but increase history size and coordination. Choose a boundary at the smallest unit whose retry semantics can be stated and tested.

A useful checkpoint is not merely “turn 27.” It is a bundle of compatible identities:

Ck=(jk,wk,mk,vk,pk).C_k = (j_k, w_k, m_k, v_k, p_k).

Here, CkC_k is checkpoint kk; jkj_k is the execution-history head; wkw_k is an immutable workspace snapshot or version; mkm_k is the memory version or read timestamp; vkv_k is the workflow version; and pkp_k is the policy and tool catalog version. Recovery restores this bundle, then reconciles any scheduled step whose outcome is unknown.

Replay, rewind, and fork are different operations:

Operation History Workspace and memory External side effects
Replay Recompute state from the same checkpoint; reuse recorded results Restore the versions named by the checkpoint Do not repeat completed effects; reconcile unknown ones
Rewind Move the active head to an earlier checkpoint Restore an earlier owned-state bundle Cannot automatically undo later external effects
Fork Create a child from a shared ancestor Give the child isolated writable state or an explicit shared-state policy External systems remain shared unless separately cloned or namespaced

Immutable histories make a conversation fork cheap because both branches can reference a shared ancestor. The workspace is different: concurrently writable branches need isolated namespaces if their writes must not leak. A full copy, copy-on-write clone, Git worktree, database branch, or remote sandbox can provide that isolation. Non-versioned external state is not automatically forked.

Two branches do have a merge base: their shared checkpoint. Files can use a three-way merge when the storage model preserves that ancestry. The harder problem is semantic merge: deciding which divergent plans, approvals, tool results, and external effects should survive. That is a product policy and sometimes a human decision, not an absence of shared history. LangGraph's documented time-travel surface illustrates the distinction: replay re-executes work after a checkpoint, whereas a fork creates a new checkpoint branch without modifying the original history (LangChain 2026).

C Shared checkpoint ancestor A Branch A history head + workspace A C->A B Branch B history head + workspace B C->B E External systems shared by default A->E M Merge or select with explicit policy A->M B->E B->M
Figure 39.3. A fork shares an immutable checkpoint ancestor while giving each branch isolated writable state. External systems stay shared unless explicitly cloned or namespaced.

Workspace durability is a stack of guarantees

The container filesystem, a persistent volume, a snapshot, and a backup answer different questions. A container filesystem normally follows the container or Pod lifetime. A Kubernetes persistent volume exists beyond an individual Pod, while an ephemeral volume follows the Pod (Kubernetes Authors 2026). Neither fact says where the volume can attach, whether two nodes may write it, what happens when its claim is deleted, or whether it can be restored after corruption.

Those properties must be checked separately:

Property Question to answer
Volume lifetime Does data survive container, Pod, node, and cluster replacement?
Access mode Which nodes or Pods may mount the volume, and with what write access?
Topology In which zones, regions, or hosts is the backing storage reachable?
Reclaim policy What happens to the backing volume when its claim is deleted?
Snapshot consistency Is the image crash-consistent or application-consistent?
Backup independence Does a failure or deletion in the primary system also remove the backup?
Restore objective What recovery point objective and recovery time objective have been tested?

ReadWriteOnce is an access mode, not a statement that every volume is a zonal block device. Topology depends on the storage backend and its provisioning policy. Likewise, deleting a Pod does not normally delete an ordinary persistent volume; generic ephemeral claims and explicit retention or reclaim policies behave differently. A design review should name the actual CSI driver, StorageClass, topology constraints, retention policy, and restore path rather than reasoning from the PVC label alone.

Snapshot cadence gives an RPO bound, not a backup

Suppose instantaneous snapshots occur every Δ\Delta minutes and a crash is equally likely at any phase between them. If LL is the amount of work since the latest snapshot, then

LUniform(0,Δ),E[L]=Δ2,Lmax<Δ,f=60Δ.L \sim \operatorname{Uniform}(0,\Delta), \qquad \mathbb{E}[L] = \frac{\Delta}{2}, \qquad L_{\max} < \Delta, \qquad f = \frac{60}{\Delta}.

Here, Δ\Delta is the snapshot interval in minutes; LL is recoverable work loss; E[L]\mathbb{E}[L] is expected loss under the uniform-crash assumption; LmaxL_{\max} is the worst loss before the next snapshot; and ff is the number of snapshot requests per hour. The interval is therefore a simple recovery point objective (RPO) bound. It says nothing about bytes written, snapshot duration, deduplication, retention, recovery time objective (RTO), or whether a restore succeeds.

Snapshots also need a consistency contract. An application-consistent snapshot may need to pause writers, flush a journal, or record a database position. Kubernetes VolumeSnapshot provides a standard API only when the CSI driver and storage backend support it (Kubernetes Authors 2024). A restore drill must verify the workspace, the execution head, and any database or memory version together; a green “snapshot created” event is not proof of recoverability.

Cloning cost also depends on the storage backend. Kubernetes supports PVC cloning through compatible CSI drivers, but the API does not promise a particular copy algorithm or latency (Kubernetes Authors 2023). Btrfs snapshots initially share a root and isolate later changes through copy-on-write (Btrfs Maintainers 2026). File-level overlay systems, block-level copy-on-write filesystems, content-addressed manifests, and full copies have different copy-up and retention costs; “copy-on-write” alone is not a complete performance model.

MicroVM snapshots illustrate why inclusion lists matter. Firecracker serializes guest memory and emulated hardware state, while disk files remain separately managed; network continuity is not guaranteed and restore compatibility depends on the host and snapshot version (Firecracker Maintainers 2026). Cloned VM state can also duplicate random generator state and identifiers, so a restore path may need to rekey secrets, regenerate identities, and reconnect services (Brooker et al. 2021). A snapshot is only as complete as the state it explicitly includes.

Lower-layer constraint

The storage backend determines whether checkpointing and branching are metadata operations or full copies. The harness can request a fork, but the CSI driver, filesystem, database, object store, or microVM layer determines its isolation, latency, changed-byte cost, and restore limits. Expose those lower-layer facts in the checkpoint contract instead of presenting every branch as equally cheap.

Long-term memory is a governed write–manage–read loop

Execution history answers what the runtime accepted. Long-term memory answers what selected information should influence later decisions. The selection is the point: raw history may be an input to memory, but retaining every event is logging, not a memory policy.

Two influential systems illustrate different mechanisms. Generative Agents stored a natural-language stream of experiences, synthesized higher-level reflections, and retrieved records for later planning (Park et al. 2023). MemGPT treated a bounded context window and external storage as tiers managed through explicit movement between them (Packer et al. 2023). Neither establishes one mandatory store. Logs, tables, files, summaries, graphs, lexical indexes, vector indexes, and hybrids can all implement parts of the loop.

The familiar labels episodic, semantic, and procedural are useful analogies for events, facts, and learned ways of acting, but they are not mutually exclusive database classes (Squire 2004). An engineering design is clearer when it keeps orthogonal choices separate:

Axis Examples
Content Event, fact, preference, procedure, lesson, artifact reference
Scope Agent, user, project, tenant, organization, or shared
Representation Log, record, file, graph, lexical index, vector index, or hybrid
Lifecycle Append, revise, supersede, expire, quarantine, delete
Provenance Quoted observation, tool result, user-confirmed statement, derived summary
Retrieval control Harness preload, rule-triggered lookup, model-invoked tool, or hybrid

Retrieval-augmented generation (RAG) is a retrieval pattern, not an ownership class. A RAG corpus can be private and mutable; a memory store can be shared and read-only. The useful distinction is lifecycle: memory is normally updated as the agent interacts, while an external corpus may have a separate ingestion owner. Chapter 44 (Chapter 44) treats retrieval itself in depth.

Records need provenance and time

A durable memory record should carry more than text or an embedding:

MemoryRecord {
  id, scope, subject, kind, payload,
  source, derivation, recorded_at, valid_from, valid_until,
  version, confidence, sensitivity, purpose, retention_until,
  status, supersedes
}

scope names the authorized audience, while subject names the person or entity the record concerns; those are not the same. source links to the observation or tool result, and derivation explains how a summary or inference was produced. recorded_at is system time; valid_from and valid_until describe when the claim is true. status distinguishes active, superseded, quarantined, and tombstoned records. supersedes links a correction to the version it replaces. The remaining fields make retention, sensitivity, purpose, and confidence testable policy inputs.

The complete loop is:

  1. Propose a write. Extract a candidate from an observation or outcome.
  2. Authorize and classify. Establish writer, scope, subject, purpose, provenance, sensitivity, and validity.
  3. Manage. Deduplicate, detect contradictions, insert a new version, supersede stale records, quarantine suspicious content, or decline the write.
  4. Retrieve. Restrict the candidate set by trusted identity and purpose, then search and rerank within a context budget.
  5. Use as evidence. Preserve attribution and keep retrieved content below trusted instructions; memory never grants authority by itself.
  6. Revise or delete. Apply corrections, expiry, retention, and deletion to the source and every derived representation.
O Observation or outcome W Write policy authorize, classify, deduplicate O->W M Versioned memory records W->M R Retrieval policy authorize, search, rerank M->R C Attributed evidence in context R->C C->O later outcome U Revision, expiry, deletion U->M
Figure 39.4. A long-term memory system governs both the write and read paths. Provenance, authorization, revision, and deletion surround retrieval rather than being delegated to the index.

Authorization must constrain retrieval

For query qtq_t, the following formula defines the authorized candidate set before retrieved records reach the model:

Ct={mMt:allow(at,pt,m)live(m,t)status(m)=active},\mathcal{C}_t = \{m \in M_t : \operatorname{allow}(a_t,p_t,m) \land \operatorname{live}(m,t) \land \operatorname{status}(m)=\text{active}\},

then retrieve within a budget:

Rt=TopBudget(rerank(qt,retrieve(qt,Ct)),Bt).R_t = \operatorname{TopBudget} \left(\operatorname{rerank}(q_t, \operatorname{retrieve}(q_t,\mathcal{C}_t)), B_t\right).

Here, MtM_t is memory at time tt; mm is one record; ata_t is the authenticated principal; ptp_t is the authorized purpose; allow checks scope and sensitivity; live checks validity and retention; Ct\mathcal{C}_t is the allowed candidate set; qtq_t is the query; BtB_t is the token or byte budget; and RtR_t is the final retrieved set. retrieve may be lexical, vector, graph, keyed, or hybrid search; rerank orders candidates; and TopBudget admits records until the budget is reached.

This invariant can be enforced by a trusted retrieval service, physical partitioning, database policies, or defense in depth across them. A user-supplied tenant label is not an authenticated principal. PostgreSQL row-level security, for example, can restrict normal reads and writes, but table owners, superusers, and roles with BYPASSRLS require deliberate treatment and tests (PostgreSQL Global Development Group 2026). The security property is zero unauthorized candidates, not merely a high relevance score.

Persistent memory also extends the lifetime of poisoned content. A malicious or mistaken statement can be extracted, summarized, and retrieved in later sessions; AgentPoison demonstrates this class of attack against agent memory and knowledge bases (Chen et al. 2024). Store writer and source, distinguish quoted evidence from derived inference, quarantine suspicious writes, and never interpret retrieved records as privileged instructions. Session logs and RAG corpora can carry the same attack; memory makes later reuse part of the default path.

Deletion must follow lineage. Removing a source row while leaving its embedding, summary, graph edge, cache entry, or export does not remove the information from the online system. A deletion manifest should enumerate derivatives, record completion, prevent a backup restore from resurrecting tombstoned records, and document when backups age out. The precise legal obligation depends on jurisdiction and purpose; the engineering contract is discoverability, attributable lineage, and verifiable deletion within the stated policy.

Evaluate the stages, not only the final answer

Memory benchmarks stress different abilities. LoCoMo uses long, multi-session conversations for question answering, event summarization, and multimodal dialogue generation (Maharana et al. 2024). LongMemEval targets information extraction, multi-session and temporal reasoning, knowledge updates, and abstention, and analyzes indexing, retrieval, and reading separately (Wu et al. 2025). MemoryAgentBench adds incremental interaction and tests accurate retrieval, test-time learning, long-range understanding, and selective forgetting (Hu et al. 2026). None of them proves tenancy isolation, poisoning resistance, or deletion completeness.

An evaluation should localize failure:

Stage Measures
Write and maintenance Worthwhile-write precision and recall, duplicate rate, provenance accuracy, conflict resolution, poison admission, stale-record survival
Retrieval Recall@kk, precision@kk, authorized recall, stale or conflicting retrieval, no-evidence abstention, p50/p95 latency, retrieved tokens
Use Grounded answer or task success, evidence attribution, appropriate abstention, downstream action success
Governance Cross-tenant negative tests, export and correction, deletion latency and completeness, backup-restore resurrection tests
Operations Index and storage growth, write amplification, model calls, token cost, cache behavior, and recovery time

Compare systems with the same model checkpoint, prompt and policy versions, task split, write budget, retrieval budget, tool access, judge and rubric, hardware and cache state, and repeated-run policy. Include no-memory, full-history, lexical, vector, and hybrid baselines when they fit the task. Otherwise a better model, larger context budget, or looser authorization boundary can masquerade as a better memory system.

What's contested

There is no universally best memory representation or benchmark. Conversational QA rewards recall but may miss whether memory improves later action. Full history can be accurate yet expensive; summaries can be cheap yet erase provenance; vector retrieval can find paraphrases yet miss exact identifiers; graphs can preserve relationships yet depend on fallible extraction. Vendor-reported scores are not comparable unless model, data split, budgets, judge, and operating envelope match. Treat memory quality as a measured system property, not a ranking of storage brands.

The operational contract

Before shipping persistent agent state, write down the following contract:

Area Required statement
Replay Which events are durable, which code version replays them, and where non-determinism is recorded
Effects Delivery semantics, key scope and retention, reconciliation evidence, compensation, and escalation
Checkpoint Bound history head, workspace version, memory version, policy version, and restore order
Workspace Volume lifetime, access mode, topology, snapshot consistency, RPO, RTO, retention, and tested restore
Fork Owned state that is cloned, state that remains shared, namespace isolation, merge policy, and TTL
Memory write Provenance, scope, validity, contradiction, sensitivity, and confirmation rules
Memory read Trusted principal and purpose, authorization boundary, retrieval budget, and evidence formatting
Lifecycle Inspection, correction, expiry, deletion lineage, backup handling, and verification
Evaluation Stage-level quality, cost, recovery, poisoning, cross-tenant, and deletion tests

This contract keeps runtime recovery separate from remembered knowledge while making their coupling explicit. The next chapter narrows the memory problem to a particular owner: persistent user state used for personalization across sessions.

Further reading

  • Amazon Web Services, “Idempotency for AWS Lambda Durable Functions,” 2026. docs.aws.amazon.com
    Lambda durable steps use at-least-once execution by default; interrupted work can repeat, so effectful business logic still needs idempotency keys or another deduplication protocol.
  • Temporal Technologies, “Activity Definition,” 2026. docs.temporal.io
    Temporal records completed activities for replay, but an activity that fails to report completion may be retried and execute more than once.
  • LangChain, “Use Time Travel,” 2026. docs.langchain.com
    LangGraph distinguishes replay from fork: replay re-executes nodes after a checkpoint, while a fork creates a new checkpoint branch without modifying the original history.
  • Kubernetes Authors, “Volumes,” 2026. kubernetes.io
    Kubernetes distinguishes Pod-scoped ephemeral volumes from persistent volumes that outlive an individual Pod; topology, access, reclaim, and backup remain separate properties.
  • Firecracker Maintainers, “Snapshotting Support,” 2026. github.com
    Firecracker snapshots serialize guest memory and emulated hardware state, while disk files, connectivity, compatibility, and omitted runtime data require separate handling.
  • Park et al., “Generative Agents: Interactive Simulacra of Human Behavior,” 2023. arXiv:2304.03442
    The memory stream with retrieval scored by recency, importance, and relevance, plus periodic reflection that synthesizes higher-level memories: the conceptual template every later memory system echoes.
  • Packer et al., “MemGPT: Towards LLMs as Operating Systems,” 2023. arXiv:2310.08560
    MemGPT introduces virtual context management for LLMs, using an OS-inspired hierarchical memory system to page data between a fixed context window and external storage, enabling unbounded context for document analysis and multi-session chat.
  • Chen et al., “AgentPoison: Red-Teaming LLM Agents via Poisoning Memory or Knowledge Bases,” 2024. proceedings.neurips.cc
    AgentPoison evaluates targeted backdoor attacks that poison an agent's long-term memory or retrieval knowledge base.
  • Maharana et al., “Evaluating Very Long-Term Conversational Memory of LLM Agents,” 2024. aclanthology.org
    Very-long-term dialogues spanning hundreds of turns across many sessions, with question answering and event summarization: the benchmark at the center of the memory-system disputes.
  • Wu et al., “LongMemEval: Benchmarking Chat Assistants on Long-Term Interactive Memory” (Evaluates information extraction, multi-session reasoning, temporal reasoning, knowledge updates, and abstention), 2025. proceedings.iclr.cc
    LongMemEval uses scalable chat histories and 500 questions to test five memory abilities while separating indexing, retrieval, and reading.
  • Hu et al., “Evaluating Memory in LLM Agents via Incremental Multi-Turn Interactions” (Introduces MemoryAgentBench), 2026. arXiv:2507.05257
    MemoryAgentBench evaluates accurate retrieval, test-time learning, long-range understanding, and selective forgetting under incremental interaction.

Comments

Log in to comment