Skip to content
AI360XpertBeta

Agent Memory Systems That Persist State

Model calls forget everything between sessions. Agent memory systems file distilled facts outside the window and pull back only the top match for the task at hand.

Agent memory files 20 facts at 240 tokens and pulls back the top 2 at 24 tokens, so a 4100 token paste becomes an 1124 token request inside a 4000 window.
Agent memory files 20 facts at 240 tokens and pulls back the top 2 at 24 tokens, so a 4100 token paste becomes an 1124 token request inside a 4000 window.

Why Does This Exist?

A model call is stateless. It reads exactly the tokens in its window and keeps none afterward. For one question that hardly matters. For an agent serving the same user for weeks, it breaks everything: preferences restated every Monday, fixes relearned every sprint, addresses re-asked after a move.

The naive fix pastes old chats into every prompt until the window bursts. Six past sessions at 500 tokens each plus 400 of system and 700 of task want 400+700+3000=4100400 + 700 + 3000 = 4100 tokens against a 4000 window, over by 100. Memory systems replace that paste with a file and a pull: write distilled facts to durable storage once, retrieve the top match per task, and leave the rest filed.

This page covers the stores, the write decision, and the retrieve step. What each type is for lives in agent memory types. The loop that spends the assembled prompt lives in agent architectures, and the plans that survive across sessions live in long-horizon planning. The general short versus long-term split lives in memory systems, while the episode-to-fact distillation lives in episodic and semantic memory.

Basics first: the context window is the maximum tokens one call can read, prompt plus reply together. Retrieval usually ranks by similarity over embeddings. If windows are new, the worked example shows the token arithmetic before any jargon arrives.

Think of It Like This

A contractor with a tool belt, a site diary, and a materials catalog

A contractor arrives each morning with three holders. The tool belt carries today's tools: hammer, tape, pencil. Small, fast, emptied nightly. That is short-term memory. A site diary on the truck holds dated notes: the north wall ran damp last March, the fix that held in June. That is episodic recall. A materials catalog in the office holds undated facts: load ratings, drying times, part numbers. That is semantic storage.

The day works because the contractor consults all three without confusing them. The belt answers what is in hand now. The diary answers what happened on this site before. The catalog answers what is true everywhere. Filing every coffee chat into the diary would bury the damp-wall note, and carrying the whole catalog on the belt would stop all work.

Where it stops: paper never contradicts itself, but stored agent facts do. The client moves, tastes change, and two filed notes disagree with equal confidence. A catalog never charges rent per page, while every retrieved line costs window space, so pulling the whole drawer each morning buries the task it meant to help.

How It Actually Works

Call WW the window: the most tokens one request may hold. Call SS the live contents: system instructions, recent turns, and whatever retrieval just added. Call MM the durable pile: one row per saved fact with its source. A write moves a fact from SS into MM. A retrieve moves a few rows from MM back into SS for one request. Saved and used are two steps, and skipping the second builds a store nobody reads.

The write is a durability judgment

A one-off detail, like renaming one variable today, belongs in SS and dies there. A repeated preference, like pytest over unittest stated twice and confirmed by edits, earns a row in MM with its source episode. When in doubt, do not write. Every extra row taxes every future search. The step loop that produces these facts lives in ReAct, and the milestone state it must survive lives in long-horizon planning.

Retrieval ranks facts against today

Call the current task qq: the query for what you need right now. Call each stored fact mim_i: fact number ii as a vector. Call sis_i its score against qq. Call kk how many you pull back: usually one or two. You rank by sis_i and copy only the top kk rows into SS.

Worked example: three facts ranked, one budget checked

Take three stored facts as two-dimensional vectors so you can check the math. Real stores use hundreds of dimensions. The arithmetic is the same. Here q=[2,1]q = [2, 1] stands in for writing a pytest fixture, m1=[2,1]m_1 = [2, 1] is prefers pytest, m2=[1,2]m_2 = [1, 2] is deploys on Fridays, and m3=[0,2]m_3 = [0, 2] is likes demo GIFs.

Score with cosine similarity, which is alignment divided by lengths. The length of [a,b][a, b] is a2+b2\sqrt{a^2 + b^2}. Lengths: ∥q∥=4+1=5≈2.2361\lVert q \rVert = \sqrt{4 + 1} = \sqrt{5} \approx 2.2361, same for m1m_1 and m2m_2. ∥m3∥=0+4=2\lVert m_3 \rVert = \sqrt{0 + 4} = 2. Dots: q⋅m1=4+1=5q \cdot m_1 = 4 + 1 = 5. q⋅m2=2+2=4q \cdot m_2 = 2 + 2 = 4. q⋅m3=0+2=2q \cdot m_3 = 0 + 2 = 2. Divide: s1=5/(2.2361×2.2361)=5/5=1.0s_1 = 5 / (2.2361 \times 2.2361) = 5 / 5 = 1.0. s2=4/5=0.8s_2 = 4 / 5 = 0.8. s3=2/(2.2361×2)=2/4.4721≈0.4472s_3 = 2 / (2.2361 \times 2) = 2 / 4.4721 \approx 0.4472. Ranked, 1.01.0 beats 0.80.8 beats 0.44720.4472. With k=2k = 2 you pull back the first two. The diagram shows these three scores and the two returning arrows.

Now the token reason this matters. Name W=4000W = 4000. System needs 400 tokens and today's task needs 700. Pasting six old sessions at 500 tokens each costs 6×500=30006 \times 500 = 3000, so the request wants 400+700+3000=4100400 + 700 + 3000 = 4100. Overflow is 4100−4000=1004100 - 4000 = 100. The store instead holds 20 facts at 12 tokens each: 20×12=24020 \times 12 = 240 tokens total. Pulling the top 2 costs 24. The request becomes 400+700+24=1124400 + 700 + 24 = 1124, leaving 4000−1124=28764000 - 1124 = 2876 spare. Same history, two shapes: one never fits, one barely registers.

That trade assumes past choices predict future ones. When the user switches runners or moves cities, old rows lie until a new episode overwrites them.

Code

The snippet reruns the ranking and the token fit, so you can check both numbers yourself:

import math

def cosine(u: list[float], v: list[float]) -> float:    dot = sum(x * y for x, y in zip(u, v))    nu = math.sqrt(sum(x * x for x in u))    nv = math.sqrt(sum(x * x for x in v))    return dot / (nu * nv)

query = [2.0, 1.0]mems = [[2.0, 1.0], [1.0, 2.0], [0.0, 2.0]]print([round(cosine(query, m), 4) for m in mems])  # -> [1.0, 0.8, 0.4472]print(400 + 700 + 6 * 500 - 4000)  # -> 100print(20 * 12)  # -> 240print(400 + 700 + 24)  # -> 1124

Four outputs match the worked example: the three scores, the 100-token overflow, the 240-token store, and the 1124-token request.

Watch Out For

Filing every turn as a permanent fact

The symptom is a store that grows by hundreds of rows a week while retrieval starts returning one-off details with the same confidence as real preferences. A query about tests pulls back a renamed variable from March alongside the pytest preference, and the model treats both as instructions.

Fix it by writing distilled facts, not transcript lines. Require a second confirmation before a write, keep the source episode on every row, and overwrite rivals instead of appending beside them.

Pulling the whole store into every prompt

The symptom is session twelve opening with all forty stored facts pasted in just to be safe. The prompt costs more, answers slower, and the one fact today needed now competes with thirty-nine it did not.

Fix it by retrieving top kk only, usually one or two, ranked against today's task. Leave the rest filed until some query actually calls for them.

The Quick Version

  • Short-term memory is the live window. It costs nothing to read and it vanishes when the session ends.
  • Long-term memory is facts filed on purpose outside the window. Filed facts do nothing until retrieval copies them back.
  • Three facts scoring 1.0, 0.8, and 0.4472 retrieve the top two, turning a 3000-token paste into a 24-token pull.
  • A 4100-token paste overflows a 4000 window by 100, while an 1124-token memory request fits with 2876 spare.
  • Twenty 12-token facts cost 240 tokens total, a fraction of one pasted session.
  • Writes should record repeated preferences, not one-off details, and old rows must be overwritten when the world changes.