Memory

Memory lets an AI application persist useful information across interactions, instead of relying only on the current prompt.

The Big Question

We can now retrieve documents with RAG. We can call tools and APIs with function calling. But imagine this conversation with a personal assistant:

User: My favourite programming language is Rust.
Assistant: Got it.
...
200 messages later
User: What is my favourite programming language?

Can the assistant answer? Sometimes yes. Sometimes no. The reason is subtle but crucial: the model itself does not remember the earlier conversation. Every inference call starts from the tokens the application sends right now.

How can an AI application remember information across interactions?

Core Intuition

People do not remember everything equally. Some information stays in working memory: the sentence you are reading, the phone number you are about to type, the current step in a recipe. Some information becomes long-term memory: your city, your food preferences, your friend's name. Some information gets written down in notebooks, calendars, or databases. Some information is forgotten.

AI applications need the same kind of structure, but the mechanism is different. Human memory is biological. LLM memory is usually application code around a stateless model.

LLM inference
= model weights
+ current prompt
+ retrieved context
+ external memory inserted by the application

The common misconception is: the LLM remembers. Usually it does not. The application remembers, then writes relevant memories into the next prompt.

Interactive Demo

Memory and context lab

Context window

Visible now: 1200
Truncated: 2000

Memory retrieval

User asks

What is my favourite programming language?

Answer accuracy
94%
Latency
1.2s
Relative cost
2.0x

Memory database

SemanticI=0.94
The user's favourite programming language is Rust.
SemanticI=0.88
The user lives in Vancouver.
SemanticI=0.90
The user is vegetarian.
EpisodicI=0.76
The user's dog is called Luna.

Prompt builder

System instructions
+ recent visible conversation
+ retrieved memories
+ current user request
  • Retrieved semantic memory for favourite programming language.
  • Retrieved semantic memory for where the user lives.

Increase the conversation length until older messages fall out of the context window. Then turn external memory on and off. The model can only use what is in the current prompt, so persistent memory must be retrieved and inserted before inference.

Context Windows Are Not Memory

Suppose the model can receive at most NN tokens in its context window. The conversation has length LL tokens. If LNL \le N, the whole conversation can fit. If L>NL > N, some tokens must be omitted.

visible tokens=min(L,N)\text{visible tokens}=\min(L,N)
forgotten tokens=max(0,LN)\text{forgotten tokens}=\max(0,L-N)

The word forgotten here means forgotten by the current model call. The old messages may still exist in a database, transcript, or log, but the model cannot use them unless the application sends them again.

Memory storage can also be viewed as thresholding. A candidate memory receives an importance score II. The system stores it only if it crosses a threshold τ\tau:

store(m)={1I(m)>τ0I(m)τ\text{store}(m)=\begin{cases}1 & I(m)>\tau\\0 & I(m)\le\tau\end{cases}

A low threshold stores too much. A high threshold forgets useful facts. Good memory design is partly the art of choosing what deserves to persist.

The Three Places Information Can Live

The most important distinction in this lesson is:

Model
Weights
Current
Context
External
Memory
LocationWhat it isExampleHow it changes
Model weightsParameters learned during trainingGeneral knowledge about Rust, Vancouver, vegetarian foodOnly by training or fine-tuning
ContextTokens included in the current promptRecent messages, tool outputs, retrieved snippetsEvery model call
External memoryApplication state stored outside the modelUser preferences, stable facts, summaries, past decisionsBy application code

Model weights may contain general facts learned during training. Context contains the exact tokens provided right now. External memory is persistent application state, such as a user profile, vector database, conversation summary, or task record.

Human Memory Analogy

The human analogy is useful, but imperfect. It helps name different memory types, but an LLM does not literally have a hippocampus, lived experience, or conscious recall.

Human termAI analogueExample
Working memoryContext windowInformation currently available to the model
Episodic memoryConversation historySpecific events: yesterday the user debugged a login bug
Semantic memoryVector or profile storeStable facts: the user lives in Vancouver and is vegetarian
Procedural memoryModel weights or system codeSkills and routines: how to format code or call tools

Procedural memory is the most metaphorical row. A model can have learned routines in its weights, and an application can encode procedures in code. But updating those procedures during a normal chat is not the same thing as storing a user preference in a memory database.

Short-Term Memory

Short-term memory usually means conversation state included in the prompt. The application keeps a message list, then resends recent messages to the model.

User
-> Conversation history
-> Prompt builder
-> LLM
-> Assistant response

This is simple and powerful. It lets the model refer to earlier turns, resolve pronouns, follow corrections, and maintain a coherent local conversation. But it is bounded by the context window. A six-month relationship cannot be represented by resending every previous message forever.

Long-Term Memory

Long-term memory is information stored outside the prompt and retrieved later. For a personal assistant, useful memories might include:

  • The user's favourite programming language is Rust.
  • The user lives in Vancouver.
  • The user is vegetarian.
  • The user's dog is called Luna.
  • The user prefers concise morning summaries.

On a later request, the memory retriever searches for relevant records and inserts only those records into the prompt. That keeps the prompt smaller and makes memory selective rather than a giant transcript dump.

User request
-> Memory retriever
-> Relevant memories
-> Prompt builder
-> LLM
-> Memory updater

What Should Be Stored?

A memory system should not store every sentence. If it does, memory becomes noisy, expensive, and invasive. Store facts that are stable, useful later, and appropriate to remember.

DecisionExampleReason
StoreThe user says: My favourite programming language is RustStable preference
Do not storeThe user says: That joke was funnyTransient reaction
StoreThe user says: I am vegetarianFuture recommendations depend on it
Do not storeThe user asks: What is 17 times 23?One-time calculation
UpdateThe user says: I now live in TorontoConflicts with previous city memory

Practical systems often score candidate memories by importance, stability, sensitivity, recency, and usefulness. A medical detail, address, or identity attribute needs much stricter handling than a preference for short explanations.

Retrieving Memories

Memory retrieval often looks like RAG. The system embeds memories, embeds the current query, compares them with cosine similarity, and retrieves the most relevant records.

sim(q,m)=qmqm\operatorname{sim}(q,m)=\frac{q\cdot m}{\lVert q\rVert\lVert m\rVert}

If the user asks Can you suggest dinner?, the memory The user is vegetarian should rank highly. If the user asks What should I name this Rust crate?, the programming-language memory is more relevant.

Retrieval should also respect permissions and context. A memory may be relevant but inappropriate to use in a particular situation.

Updating Memories

Memory is not append-only. Suppose the user says:

I now live in Toronto.

If the store already contains I live in Vancouver, the system needs conflict resolution. It might replace the old memory, keep a version history, add a timestamp, lower confidence in the old record, or ask the user to confirm.

Good memory records often include fields like:

{
  "id": "city.current",
  "text": "The user lives in Toronto.",
  "type": "semantic",
  "source": "user stated directly",
  "created_at": "2026-07-10",
  "supersedes": "city.vancouver.2025",
  "confidence": 0.98
}

Summarisation And Compression

Long conversations can be compressed into summaries. Instead of sending 100 messages, the application sends a compact state summary: user goals, decisions, open questions, and preferences.

summary=C(conversation)\text{summary}=C(\text{conversation})

Summarisation is lossy compression. It reduces tokens, latency, and cost, but it can discard details. A good summary preserves information needed for future turns and leaves out local chatter.

Forgetting

Memory should not grow forever. Forgetting is a feature, not only a failure. Systems may delete or deprioritize memories using expiration times, recency, frequency, importance, manual deletion, or least-recently-used policies.

For example, the user is visiting Seattle this weekendmay expire after the trip. the user is vegetarianshould persist until changed. A user should also be able to inspect, edit, and delete stored memories.

Implementation From Scratch

Start with a simple in-memory store. This version is not production-ready, but it shows the core operations: add, retrieve, overwrite, and delete.

class MemoryStore:
    def __init__(self):
        self.memories = {}

    def add(self, key, text, importance=0.5):
        self.memories[key] = {
            "text": text,
            "importance": importance,
        }

    def get(self, key):
        return self.memories.get(key)

    def overwrite(self, key, text, importance=0.5):
        self.memories[key] = {
            "text": text,
            "importance": importance,
        }

    def delete(self, key):
        self.memories.pop(key, None)

store = MemoryStore()
store.add("favourite_language", "The user's favourite programming language is Rust.", 0.94)
store.add("diet", "The user is vegetarian.", 0.9)
store.overwrite("city", "The user lives in Toronto.", 0.88)
print(store.get("favourite_language"))

Semantic memory adds retrieval. A production system would use a vector database, but the shape is:

from sentence_transformers import SentenceTransformer
from numpy import dot
from numpy.linalg import norm

model = SentenceTransformer("all-MiniLM-L6-v2")

memories = [
    "The user's favourite programming language is Rust.",
    "The user lives in Vancouver.",
    "The user is vegetarian.",
    "The user's dog is called Luna.",
]

memory_vectors = model.encode(memories)

def cosine(a, b):
    return dot(a, b) / (norm(a) * norm(b))

def retrieve(query, k=2):
    query_vector = model.encode([query])[0]
    scored = [
        (cosine(query_vector, memory_vector), memory)
        for memory_vector, memory in zip(memory_vectors, memories)
    ]
    return [memory for score, memory in sorted(scored, reverse=True)[:k]]

print(retrieve("Can you suggest a vegetarian dinner place?"))

A tiny assistant combines extraction, retrieval, prompt building, and updating:

def extract_memory(user_message):
    if "favourite programming language is" in user_message:
        return ("favourite_language", user_message)
    if "I live in" in user_message or "I now live in" in user_message:
        return ("city", user_message)
    if "vegetarian" in user_message:
        return ("diet", "The user is vegetarian.")
    return None

def build_prompt(user_message, store):
    relevant = []
    if "favourite programming language" in user_message:
        relevant.append(store.get("favourite_language"))
    if "dinner" in user_message or "restaurant" in user_message:
        relevant.append(store.get("diet"))
    if "where do I live" in user_message:
        relevant.append(store.get("city"))

    memories = [item["text"] for item in relevant if item]
    return {
        "system": "Answer using relevant memories only when helpful.",
        "memories": memories,
        "user": user_message,
    }

message = "My favourite programming language is Rust."
memory = extract_memory(message)
if memory:
    key, text = memory
    store.overwrite(key, text, importance=0.9)

prompt = build_prompt("What is my favourite programming language?", store)

ChatGPT-Style Memory

Modern assistants can implement memory at the product layer. Conceptually, the system identifies potentially useful facts, stores them in a user-controlled memory layer, retrieves relevant memories for future conversations, and gives the user ways to view, update, or delete them.

The details vary by product, but the high-level idea is the same: the model is not quietly changing its weights after every chat. The application is maintaining state and deciding which state to include in future prompts.

How To Evaluate Memory

Memory should be evaluated like any other system component. Useful metrics include retrieval accuracy, false retrieval rate, memory precision, memory recall, storage growth, latency, cost, update correctness, deletion correctness, and privacy incidents.

PropertyWeightsContextMemory
Changes after trainingNoYesYes
Persists across chatsYesNoYes
User editableNoIndirectlyYes
Stores recent eventsNoYesYes
Stores long-term preferencesPoorlyLimitedYes

Interview Discussion

Why are LLMs usually described as stateless?

Each inference call only receives the model weights and the prompt provided for that call. Persistent state must be supplied by the application.

Is a context window the same thing as memory?

No. Context is temporary input to one model call. Memory persists outside a single call and can be retrieved later.

What is semantic memory in an AI assistant?

A store of stable facts and preferences that can be retrieved by meaning, often with embeddings and similarity search.

What happens when a user changes a fact?

The memory system should update, replace, version, or mark old records as superseded rather than blindly appending contradictory facts.

Why is forgetting important?

It controls noise, cost, privacy risk, and stale information. Memory should be useful, inspectable, editable, and deletable.

Active Recall

1. Why does the model not automatically remember a fact from 200 messages ago?

2. What is the difference between model weights, context, and external memory?

3. Why does a context window inevitably cause forgetting when conversations grow?

4. What is the difference between short-term and long-term memory?

5. Which facts should a personal assistant store?

6. How does semantic memory retrieval resemble RAG?

7. What should happen when a user says they now live in a different city?

8. Why can memory create privacy and safety risks?

Failure Modes

  • Wrong memory: The system stores Rust as the user's job title instead of language preference
  • Missed retrieval: The memory exists, but the retriever does not fetch it for a relevant query
  • Irrelevant retrieval: A dog-name memory is inserted into a restaurant recommendation prompt
  • Duplicate memories: The store contains five slightly different versions of the same preference
  • Contradictory memories: The user lives in Vancouver and the user lives in Toronto are both treated as current
  • Context poisoning: Untrusted text tells the memory updater to save false instructions
  • Outdated information: Old facts remain active after the user changes them
  • Privacy leak: A memory is revealed in a context where it should not be used

Connection To Agents

The application can now retrieve external knowledge, call tools, and remember useful information across turns.

The next step is to add a control loop. An agent combines prompting, retrieval, tools, and memory, then repeatedly decides what to do next until a task is complete.