Exercises — Memory systems for agents
Before we start, we define the one tool used again and again on this page: cosine similarity, written . When two pieces of text are turned into lists of numbers (embeddings — see Vector Databases), measures how "close in meaning" they are. Picture two arrows starting at the same point:

Level 1 — Recognition
L1.1
Name the three memory layers of the standard agent architecture and, in one word each, what time-scale they cover.
Recall Solution
- Working memory — short-term (the current task/turn).
- Episodic memory — mid-term (past interactions, "what happened last Tuesday").
- Semantic memory — long-term (timeless facts and world knowledge).
L1.2
List the four memory primitives (operations) every memory system implements.
Recall Solution
Write (store), Read (retrieve), Update (modify), Forget (delete). Read as flashcards: Store new info under a key ::: Write Get info matching a query ::: Read Change an existing entry's value ::: Update Remove an entry (decay/privacy/capacity) ::: Forget
L1.3
Which memory layer would each of these live in? (a) "User Alice prefers 9–11 am meetings." (b) "Two turns ago the user pasted this stack trace." (c) "On June 26 we issued a refund to user_123."
Recall Solution
(a) Semantic — a timeless preference/fact. (b) Working — immediate context for the current task. (c) Episodic — a specific dated event.
Level 2 — Application
L2.1 — Working-memory budget
A model has an 8000-token context window. The system prompt costs 1200 tokens and you reserve 600 tokens as an output buffer. How many tokens are left for working memory?
Recall Solution
Working memory is whatever is left of the window after the fixed costs: What we did: subtracted the non-negotiable pieces (system prompt + output room) from the total window. Why: those tokens are spoken for before any conversation content can go in — see LM Context Window Management.
L2.2 — Cosine similarity by hand
An episode embedding is and the incoming query embedding is . Compute their cosine similarity.
Recall Solution
Step 1 — dot product (multiply matching entries, add): Step 2 — lengths: Step 3 — divide: What it looks like: two arrows almost overlapping (angle ). See figure s01 — a score this high means "nearly the same meaning".
L2.3 — Recency forgetting
Retention window is days and "now" is day 100. Apply the keep-rule to episodes stamped at days . Which survive?
Recall Solution
Compute the age and compare with 30:
- day 95: age → keep
- day 71: age → keep
- day 70: age → this is the boundary case. The rule uses a strict , so age exactly is not less than → forget. (Had the rule been , this episode would survive — the choice of strict-vs-inclusive is a design decision you must make explicit, because it flips exactly the episode sitting on the fence.)
- day 40: age → forget Survivors: days 95 and 71.
Level 3 — Analysis
L3.1 — Redundancy pruning threshold
Your merge rule: if a new episode's embedding has with an existing one, delete the older near-duplicate. New embedding . Three stored episodes have embeddings , , . Which get merged/deleted?
Recall Solution
First, why the formula simplifies here. For a stored embedding against :
- dot product: — the -term is multiplied by and vanishes, so only the first coordinate survives.
- length of : , so dividing by it changes nothing.
- length of : .
Putting these together, . That is why the whole thing collapses to "first coordinate over length".
Now evaluate each:
- : → delete.
- : → keep (that's a angle — genuinely different).
- : → delete. So two are pruned, one survives.
L3.2 — Importance ranking
Importance score is with weights . You may keep only the top 2 of three episodes:
| Episode | Access | Recency | Feedback |
|---|---|---|---|
| A | 10 | 0.2 | 0 |
| B | 2 | 0.9 | 1 |
| C | 4 | 0.5 | 1 |
Which two survive?
Recall Solution
Plug each row into the weighted sum:
- Ranking: . Keep A and C. Analysis: Access dominates because is largest and Access values are on a scale of tens while Recency/Feedback sit in . That scale mismatch is itself a design smell (see next mistake).
Level 4 — Synthesis
L4.1 — Retrieval budget under a token cap
Each retrieved episode summary costs 300 tokens. After the system prompt and output buffer you have 6200 tokens of working memory (from L2.1), but you must also leave 2000 tokens for the live user turn and reasoning. How many past episodes can you inject into context?
Recall Solution
Step 1 — room for retrieval: subtract the reserved live-turn budget: Step 2 — divide by cost per episode and floor: Why floor? You cannot inject a fraction of an episode; overshooting the budget truncates the prompt. Exactly fit ().
L4.2 — Design a memory-routing rule
Sketch how an agent decides which layer to consult when a new user message arrives. Cover the case where nothing relevant is found. The rendered decision diagram is shown below.
Recall Solution
The agent tries the cheapest, most-current source first and falls back outward:
- Working memory — is the answer in the current turn's context already? If yes, respond.
- Semantic memory — is this a general fact question ("how do I read a CSV")? Query the knowledge store (Knowledge Graphs).
- Episodic memory — does this refer to a past interaction ("is my refund done")? Embed the query, similarity-search past episodes (Vector Databases), load the best match into working memory.
- Nothing found — either ask the user a clarifying question or call an external tool; then Write the result back so next time it's remembered.

Why this order? Working memory is free (already loaded); semantic lookups are cheap key/graph hits; episodic search costs an embedding + vector query; external tools are slowest and priciest. Try cheap-and-fresh before expensive-and-stale.
Level 5 — Mastery
L5.1 — End-to-end trace
A support agent stores this Day-1 episode:
{ "timestamp": "day1", "user_id": "u42",
"summary": "charged twice for June subscription; refund issued",
"outcome": "resolved" }On Day 6 the user asks: "Did my refund go through?" The query embeds to ; the Day-1 episode embeds to ; an unrelated "weather" episode embeds to . (a) Which episode is retrieved? (b) Walk the full memory pipeline that produces the answer.
Recall Solution
(a) Rank by cosine similarity.
- (identical direction — is just doubled).
- The Day-1 billing episode wins ().
(b) Pipeline.
- Read (working): query not answerable from current turn alone.
- Read (episodic): embed query → similarity search → retrieve Day-1 episode (score ).
- Update (working): load "user had double-charge; refund issued Day 1" into working memory — no need to re-ask the user.
- Tool call: check live refund-status API.
- Respond with the status.
- Write: append this Day-6 follow-up as a new episode so future queries have it. What it looks like: and lie on the same ray from the origin (angle ), while points off to the side — cosine vs makes the billing episode the clear winner.
L5.2 — Contradiction handling in semantic memory
Semantic memory holds ("u42", "prefers_time", "09:00-11:00", confidence=0.85). The user now says, twice, "actually I prefer afternoons." Describe the correct Write/Update/Forget behaviour and why you would not just append a second fact.
Recall Solution
Why not append a second fact. Appending a new row ("u42","prefers_time","afternoon",...) alongside the old one leaves two facts sharing the same (entity, relation) key ("u42","prefers_time") but with contradictory values ("09:00-11:00" vs "afternoon"). Future retrievals would surface morning or afternoon at random, and the prompt you build (Prompt Engineering) would contain a self-contradiction. Semantic memory must answer "what is true now", so it can hold at most one live value per key.
The correct sequence, in the four primitives:
- Read the existing fact by its key
("u42","prefers_time")→ find value"09:00-11:00", confidence . - Update that same entry's value to
"afternoon"— because the key already exists, this is an in-place Update, not a new Write. The old value is overwritten. - Adjust confidence upward. The user stated the new preference twice, so the evidence is stronger than a single mention. Raise confidence, e.g. from toward . (A repeated, consistent claim earns more trust.)
- Forget the stale morning value completely — it is now contradicted by newer evidence, which is exactly the semantic-memory pruning rule "remove facts contradicted by newer evidence." After the Update overwrites the value there is nothing left to keep; if your store versions values, explicitly delete the old version.
Result: semantic memory now holds the single fact ("u42","prefers_time","afternoon",confidence≈0.90).
What still gets appended — but elsewhere. You do keep a record that the preference changed, but that record belongs in episodic memory (an audit trail of "on Day N the user changed their preferred time"), not in semantic memory. Episodic memory remembers what happened; semantic memory remembers what is currently true. Splitting them this way keeps retrieval unambiguous while losing no history.
Recall Quick self-check
Cosine of two identical-direction arrows ::: 1.0 Cosine of two perpendicular arrows ::: 0 Cosine when one arrow has length zero ::: undefined (division by zero) — guard and return 0 Which primitive fixes a contradicted fact ::: Update the value (then Forget the old one) Why divide the dot product by the two lengths ::: to remove magnitude and leave only angle/direction