You've told ChatGPT your name ten times. It keeps asking.
You've explained your project setup in excruciating detail. Next conversation β blank slate. Gone. Like the last session never happened.
This isn't a bug. It's architecture. LLMs have no persistent memory by default. Every conversation starts from zero. The model doesn't remember you, your preferences, your projects, or the brilliant idea you shared yesterday at 2 AM.
AI agents need memory to be useful. Without it, they're brilliant amnesics β smart enough to solve hard problems, but can't remember solving the same problem for you last week. Let's fix that.
The Two Types of Memory
Short-Term Memory: The Context Window
The context window IS the LLM's short-term memory. Everything the model can "remember" lives inside the current conversation β the system prompt, chat history, tool results, all of it.
βββββββββββββββββββββββββββββββββββββββββββ
β Context Window (128K) β
β β
β System prompt (~500 tokens) β
β Tool definitions (~2,000 tokens) β
β Chat history (~10,000 tokens) β
β Tool results (~5,000 tokens) β
β Current message (~100 tokens) β
β β
β Free space: ~110,400 tokens β
βββββββββββββββββββββββββββββββββββββββββββ
This is fast, reliable, and built-in. The model can see everything in the context window and reason about it naturally. No extra infrastructure needed.
But it has limits:
Limitation Impact
| Fixed size | 128K tokens max (GPT-4o), ~200 pages of text |
|---|---|
| Per-session | Resets completely between conversations |
| Gets expensive | More context = more tokens = higher cost per call |
| Degradation | Models perform worse with very long contexts ("lost in the middle" problem) |
| No prioritization | Can't mark some memories as more important than others |
Short-term memory is like a whiteboard. Useful during the meeting, erased afterward.
Long-Term Memory: External Storage
For an agent to truly remember things, it needs external storage that persists across sessions. This is long-term memory β data stored outside the model and retrieved when relevant.
User: "Remember, I prefer Python over JavaScript"
βAgent stores: {"fact": "User prefers Python over JS", "timestamp": "2025-01-15"}
β[Two weeks later]
User: "Set up a new project for me"
βAgent retrieves: "User prefers Python over JS"
βAgent: "I'll set this up as a Python project since you prefer Python."
Long-term memory requires infrastructure β databases, embeddings, retrieval systems. But it's what separates a tool from an assistant.
How Long-Term Memory Works
The architecture is essentially RAG (Retrieval-Augmented Generation) applied to personal context:
- STORE
User says something important
β Extract the fact
β Generate an embedding (vector)
β Store in vector database
- RETRIEVE
User starts a new conversation
β Embed the current query
β Search vector DB for relevant memories
β Inject top memories into context window
- USE
LLM sees memories in its context
β Incorporates them naturally into its response
python
Simplified memory system
import chromadb
from openai import OpenAI
client = OpenAI()
db = chromadb.Client()
collection = db.create_collection("agent_memory")
def store_memory(text, metadata=None):
"""Store a fact in long-term memory"""
embedding = client.embeddings.create(
model="text-embedding-3-small",
input=text
).data[0].embedding
collection.add(
documents=[text],
embeddings=[embedding],
ids=[str(uuid4())],
metadatas=[metadata or {}]
)
def recall(query, n=5):
"""Retrieve relevant memories"""
embedding = client.embeddings.create(
model="text-embedding-3-small",
input=query
).data[0].embedding
results = collection.query(
query_embeddings=[embedding],
n_results=n
)
return results["documents"][0]Usage
store_memory("User prefers Python over JavaScript")
store_memory("User's project is called 'HappenAI'")
store_memory("User is in IST timezone (GMT+5:30)")Later, in a new conversation:
memories = recall("Set up a new web project")Returns: ["User prefers Python over JavaScript", "User's project is called 'HappenAI'"]
π§
Episodic vs Semantic Memory
Cognitive science gives us a useful framework for thinking about agent memory:
Episodic Memory β What Happened
Specific events, conversations, experiences. "The user asked me to fix a bug in auth.py on Tuesday, and the fix was adding a null check on line 47."
python
episodic_memory = {
"event": "Bug fix in auth.py",
"date": "2025-01-14",
"context": "User reported login failures",
"action": "Added null check on line 47",
"result": "Fixed β auth flow works now",
"conversation_id": "conv_abc123"}
Semantic Memory β What Is True
General facts, preferences, knowledge. "The user prefers Python. The project uses PostgreSQL. The deployment is on AWS."
python
semantic_memory = {
"fact": "User prefers Python over JavaScript",
"confidence": 0.95,
"source": "Stated directly in conversation",
"last_confirmed": "2025-01-14"}
Working Memory β What Matters Right Now
The subset of memories relevant to the current task. This is what gets injected into the context window.
Memory Type What It Stores Persistence Example
| Episodic | Events, conversations | Long-term | "Last time we deployed, the DB migration failed" |
|---|---|---|---|
| Semantic | Facts, preferences | Long-term | "User uses PostgreSQL on AWS" |
| Working | Current task context | Session only | "We're fixing bug #234 in auth.py" |
π
Memory in Practice: Architecture Patterns
Pattern 1: File-Based Memory (Simple)
Store memories as files. Read them at the start of each session.
~/.agent/memory/
βββ MEMORY.md # Curated long-term facts
βββ 2025-01-14.md # Daily log
βββ 2025-01-15.md # Daily log
βββ preferences.json # Structured preferences
python
At session start, read memory files
memory_context = read_file("~/.agent/memory/MEMORY.md")
today_log = read_file(f"~/.agent/memory/{today}.md")
system_prompt = f"""You are a personal assistant.Things you know about the user:
{memory_context}
Recent activity:
{today_log}
"""
Pros: Dead simple, human-readable, editable.
Cons: Doesn't scale, no semantic search, reads everything every time.
Pattern 2: Vector Store Memory (Scalable)
Use embeddings and a vector database for semantic retrieval.
python
At session start, retrieve relevant memories
user_message = "Help me with the HappenAI deployment"
relevant_memories = vector_store.search(
query=user_message,
n_results=10,
filter={"user_id": "abhi"})
Inject into context
system_prompt = f"""Relevant context from previous conversations:
{format_memories(relevant_memories)}
"""
Pros: Scales to thousands of memories, retrieves only relevant ones.
Cons: Requires embedding infrastructure, retrieval can miss things.
Pattern 3: Hybrid (Production)
Combine both β files for critical always-loaded context, vectors for searchable history.
python
Always loaded
core_context = read_file("MEMORY.md") # User preferences, key facts
tools_context = read_file("TOOLS.md") # Environment detailsDynamically retrieved
relevant = vector_search(user_message) # Semantic search
recent = get_recent_conversations(n=3) # Last 3 conversations
system_prompt = f"""{core_context}
{tools_context}
Relevant past context:
{relevant}
Recent conversations:
{recent}
"""
This is what most production agents actually do. OpenClaw uses this pattern β MEMORY.md for core facts, daily files for logs, and Qdrant for semantic search.
The Memory Lifecycle
Memory isn't just store-and-retrieve. Good memory systems have a lifecycle:
- CAPTURE β Detect important information in conversation
- EXTRACT β Parse into structured facts
- STORE β Save with embedding + metadata
- RETRIEVE β Find relevant memories for current context
- USE β Inject into context window
- UPDATE β Modify memories when facts change
- FORGET β Remove outdated or contradicted memories
The Forgetting Problem
Humans forget naturally. AI agents don't β unless you build it in. This causes problems:
Memory from January: "User is working on Project Alpha"
Memory from March: "User is working on Project Beta"
Without forgetting: Agent mentions both projects, confusing itself
With forgetting: Old memory is superseded, only Beta matters
Solutions:
Time decay: Reduce relevance score of older memories
Contradiction detection: When a new fact contradicts an old one, mark the old one as outdated
Explicit deletion: Let users say "forget that" and actually remove it
Periodic review: Agent reviews its own memories and cleans house
Memory and Cost
Every memory you inject costs tokens:
Memories Retrieved Extra Tokens Extra Cost (GPT-4o)
| 5 short facts | ~200 | $0.0005 |
|---|---|---|
| 10 detailed memories | ~1,000 | $0.0025 |
| 20 conversation excerpts | ~5,000 | $0.0125 |
| 50 full conversations | ~25,000 | $0.0625 |
Per call, it's cheap. But agents make many calls per task, and tasks happen all day. A memory system that retrieves 5,000 extra tokens per call, across 100 calls per day, adds $1.25/day β or $37.50/month.
Optimization: Only retrieve memories when the conversation actually needs them. Don't load your entire memory into every single API call.
π¬
Building Memory That Works
python
Complete memory system skeleton
class AgentMemory:
def __init__(self):
self.vector_store = ChromaDB("agent_memories")
self.core_file = "MEMORY.md"def remember(self, text, type="semantic", metadata=None):
"""Store a new memory"""
# Check for contradictions
existing = self.recall(text, n=3)
for mem in existing:
if self.contradicts(text, mem):
self.forget(mem.id)self.vector_store.add(text, metadata={
"type": type,
"timestamp": now(),
**(metadata or {})
})def recall(self, query, n=5, type=None):
"""Retrieve relevant memories"""
filters = {"type": type} if type else None
return self.vector_store.search(query, n=n, filter=filters)def forget(self, memory_id):
"""Remove a specific memory"""
self.vector_store.delete(memory_id)def get_context(self, user_message):
"""Build context for current conversation"""
core = read_file(self.core_file)
relevant = self.recall(user_message, n=10)
return f"{core}\n\nRelevant memories:\n{format(relevant)}"def review(self):
"""Periodic maintenance β consolidate and clean"""
all_memories = self.vector_store.list_all()
# Remove duplicates, merge related facts, decay old ones
...π‘οΈ
Practical Takeaways
Short-term memory = context window β built-in, reliable, but per-session only
Long-term memory = external storage β requires infrastructure but enables persistence
Use hybrid: files + vectors β core facts in files, searchable history in vector DB
Build a forgetting mechanism β outdated memories cause more harm than no memory
Memory costs tokens β retrieve selectively, not everything every time
Episodic + semantic is the winning combo β what happened AND what is true
π¦
What's Next?
Episode 34: Agent Frameworks β LangChain, CrewAI, AutoGen, Smolagents β every framework promises to make agents easy. Which ones actually deliver? We'll look at the internals of each, when to use them, and when to just build from scratch.
β Previous
Ep 32: Multi-Agent Systems
Next β
Ep 34: Agent Frameworks
Next: Episode 34 β Agent Frameworks
Everyone has an opinion on agent frameworks. 'LangChain is bloated.' 'CrewAI is magical.' Here's what actually matters.
This is part of a 98-episode series covering AI engineering from tokens to production deployment.