What is AI agent memory, and why isn't a context window enough?
An AI agent runs a loop — perceive, plan, act, observe — and every one of those steps needs to know what happened before. The context window is where that information lives during a single call, but it is bounded, and it is not memory in any durable sense: close the session, or push enough new turns through it, and anything not actively re-sent is gone. That's the problem agent memory solves — giving an agent a way to keep and recall information that outlives any single context window.
The useful split, used across the tools in this guide, is short-term memory (how you manage what's inside the current context window) versus long-term memory (what's persisted outside it and pulled back in only when relevant). A big context window makes the short-term side more forgiving, but it doesn't replace the long-term side — an agent with a 1M-token window still has no way to recall a fact from a session that ended yesterday unless something wrote that fact down somewhere it can search later.
Short-term memory: managing the context window
Short-term memory is about keeping the current conversation inside the model's context limit without losing what matters. Three patterns do most of the work:
- • Sliding window. Keep only the most recent N turns and drop the rest. Simple and cheap, but anything outside the window is simply gone — no recall, no summary.
- • Summarization / compression. Periodically ask an LLM to compress older turns into a shorter summary, then keep the summary plus recent raw turns. This is how LangGraph's checkpointing and most production chat agents handle long sessions — it trades detail for token budget.
- • Structured scratchpad / tiered blocks. Letta's "core memory" is the sharpest version of this: a small set of named, size-limited blocks (e.g.
human,persona) that stay in the prompt at all times, which the agent itself edits with tool calls rather than a background process deciding for it.
All three are still working inside the context window — they decide what's in it, not where information goes once it falls out. That's where long-term memory comes in.
Long-term memory: vector retrieval, knowledge graphs, and hybrids
Long-term memory persists facts outside the context window and retrieves only what's relevant to the current turn, the same retrieve-then-inject shape as RAG. Two storage approaches dominate:
- • Vector-based retrieval. Facts (often extracted from raw conversation by an LLM call, as Mem0 does) are embedded and stored; at query time the agent embeds its question and retrieves the nearest facts by similarity. Good at "what does this remind me of," weak at representing how facts relate to each other or when they changed.
- • Knowledge graphs. Facts are stored as entities and relationships — an edge, not a blob of text. Zep's open-source engine, Graphiti, adds a temporal layer: each edge carries a validity window, so when a new fact contradicts an old one, the old edge is invalidated rather than silently overwritten, and the agent can query "what was true on date X" as well as "what's true now" (Rasmussen et al., "Zep: A Temporal Knowledge Graph Architecture for Agent Memory," arXiv 2025).
- • Hybrid retrieval. Several of these tools don't pick one mechanism — Mem0's newer releases fuse semantic (vector), keyword (BM25), and entity-match scoring, and Graphiti combines vector similarity, full-text search, and graph traversal into one ranked result, because no single signal catches everything a query might need.
The common thread across all of them: write happens continuously as the agent runs (not as a one-time ingest like a RAG corpus), and read happens selectively — only the facts relevant to the current turn get pulled back into the context window.
Mem0 vs Letta vs Zep vs LangMem: how they compare
These four show up constantly in agent-memory discussions, and they take genuinely different bets on who decides what gets remembered.
| Tool | Architecture | Open source? | Best-fit use case |
|---|---|---|---|
| Mem0 | Extraction pipeline: an LLM call pulls facts out of each conversation turn and stores them with embeddings; retrieval fuses semantic, keyword (BM25), and entity matching | Open source (Apache-2.0 library/server) plus a managed cloud platform | Drop-in user/session/agent memory for assistants and chatbots — add a search+write call around any existing LLM call |
| Letta (MemGPT) | Agent self-edits its own memory via tool calls: fixed "core memory" blocks stay in the prompt, "archival" memory is a vector store the agent queries, "recall" memory is the full message log | Open source (Apache-2.0), runs as a self-hosted FastAPI+Postgres server with a hosted cloud option | Long-running assistants that need to decide for themselves what to keep in context vs. page out to storage |
| Zep (Graphiti) | Builds a temporal knowledge graph from conversation and business data: entities and relationships as graph edges, each with a validity window, so contradicted facts are invalidated rather than overwritten | Graphiti (the graph engine) is open source; Zep itself is a managed/enterprise memory service built on it | Agents where relationships and how facts changed over time matter — not just "what is true now" |
| LangMem | A library of memory primitives (semantic, episodic, procedural) on top of LangGraph's long-term memory store; memories are JSON documents under a namespace, written either inline ("hot path") or by a background extractor | Open source, part of the LangChain/LangGraph ecosystem | Teams already building on LangGraph who want memory tools and a store wired into the same framework, not a separate service |
Mem0 is a library/server you call around an existing LLM app — install it, call add() after a turn and search() before the next response, and an extraction pipeline decides what's worth keeping (Mem0 GitHub README). Letta, the productized successor to the MemGPT research project, instead gives the agent itself the tools to edit its own memory blocks and decide what stays in context vs. gets paged to an archival store (Letta GitHub repository). Zep's differentiator is time: its open-source Graphiti engine builds a bi-temporal knowledge graph so facts that change don't just get overwritten — the history is queryable (Graphiti documentation). LangMem is the lightest-weight of the four if you're already in the LangChain/LangGraph ecosystem: it's a set of memory primitives and tools (create_manage_memory_tool, create_search_memory_tool) wired into LangGraph's existing long-term memory store rather than a separate service (LangMem GitHub repository; LangChain docs — long-term memory).
Get the weekly AI engineering brief
Agent memory, RAG, agents, and the tools worth using — one practical email a week. Plus the free roadmap PDF.
By subscribing you agree to receive emails from AI Engineer Insights. Unsubscribe anytime. See our Privacy Policy.
How to implement a basic memory layer
You don't need any of the tools above to get the core pattern working. A minimal long-term memory layer is three functions: extract facts from a turn, store them with embeddings, and retrieve the relevant ones before the next response. Here it is with Chroma, the same way our vector database for RAG guide builds the retrieval side:
# A minimal long-term memory layer: embed, store, retrieve.
# Swap chromadb for Mem0/Letta/Zep's SDK and the shape is the same.
import chromadb
from openai import OpenAI
client = chromadb.PersistentClient(path="./agent_memory")
memory = client.get_or_create_collection(name="user_facts")
llm = OpenAI()
def extract_facts(conversation_turn: str) -> list[str]:
# One LLM call: pull out durable facts worth remembering.
# ("User prefers concise answers", "User's timezone is IST", ...)
resp = llm.chat.completions.create(
model="gpt-4o-mini",
messages=[{
"role": "user",
"content": f"Extract durable facts worth remembering, one per line:\n{conversation_turn}",
}],
)
return [f.strip("- ") for f in resp.choices[0].message.content.splitlines() if f.strip()]
def remember(conversation_turn: str, user_id: str):
for fact in extract_facts(conversation_turn):
memory.add(
ids=[f"{user_id}-{hash(fact)}"],
documents=[fact],
metadatas=[{"user_id": user_id}],
)
def recall(query: str, user_id: str, k: int = 3) -> list[str]:
results = memory.query(query_texts=[query], n_results=k, where={"user_id": user_id})
return results["documents"][0]
# At response time: pull relevant facts into the system prompt before calling the LLM.
relevant = recall("What does this user prefer?", user_id="u1")
system_prompt = "Known facts about the user:\n" + "\n".join(relevant)Three things worth noting. Extraction is its own LLM call — you're not embedding the raw conversation, you're asking a model to decide what's durable first, which is exactly what Mem0's pipeline does under the hood. Writes are scoped — every fact carries a user_id in its metadata, the same pattern pgvector or any filtered vector search uses, so one user's facts never leak into another's retrieval. Retrieval happens before generation, not during it — the facts get folded into the system prompt, not fetched by the model mid-answer, which keeps the pattern simple to reason about and test.
Moving from this to Mem0, Letta, or Zep mainly swaps who does the extraction and what the store looks like underneath — a graph instead of flat vectors for Zep, agent-driven tool calls instead of a background pipeline for Letta — but the write → embed/structure → retrieve → inject loop stays the same.
When do you actually need long-term memory vs RAG/context alone?
- • Context/RAG alone is enough when the task is single-session — a research assistant answering questions about a fixed document set doesn't need to remember you personally, it needs good retrieval over that corpus.
- • Reach for long-term memory when the agent needs to persist across sessions: a personal assistant that should remember your preferences next week, a support bot that shouldn't make the customer re-explain their issue, or any agent whose facts genuinely change over time (a user's role, a project's status).
- • Reach specifically for a knowledge graph over flat vector memory when relationships between entities matter to the answer, or when you need to reason about when something became true, not just whether it's similar to the query.
- • Most production agents end up hybrid: RAG for static domain knowledge, short-term context management for the live conversation, and a long-term memory layer for anything that should outlive the session.
See our RAG vs fine-tuning guide for the adjacent decision of whether to retrieve knowledge at all versus bake it into model weights — memory is a third axis on top of that, about what persists from the agent's own interactions rather than from a static corpus.
Go deeper on AI agent memory with AI
Ask your next question with this article as context. Opens in a new tab; you can edit the question before sending.
Frequently Asked Questions
What is agent memory in AI?
Agent memory is how an AI agent keeps and reuses information beyond what fits in a single prompt. Short-term memory is the context window for the current session — managed with sliding windows and summarization — and long-term memory persists across sessions, usually in a vector store, a knowledge graph, or both, so the agent can recall relevant facts about a user or task without re-reading its entire history.
What is the difference between short-term and long-term memory in AI agents?
Short-term memory is the model's context window for the current conversation: it holds recent turns and disappears when the session ends or the window fills up, so it's managed with sliding windows and summarization/compression. Long-term memory is stored outside the context window — typically as embeddings in a vector database or facts in a knowledge graph — and is retrieved and injected back into the prompt only when relevant, which is what lets an agent remember a user across days or sessions.
Do AI agents need long-term memory, or is a big context window enough?
A bigger context window helps but doesn't substitute for memory: cramming everything into the prompt is expensive, slow, and research on long-context models (e.g. the "lost in the middle" findings) shows retrieval quality over a huge context degrades, it doesn't just get free. Long-term memory earns its place when an agent needs to recall facts across sessions, personalize to a specific user, or keep straight which facts changed over time — things a stateless context window can't do no matter how large it is.
What is the difference between RAG and agent memory?
RAG retrieves from a mostly static external knowledge corpus — docs, a wiki, a codebase — that the agent didn't create. Agent memory is built from the agent's own interactions: facts extracted from conversations, user preferences, and task history, which get written as the agent runs, not pre-indexed ahead of time. Mechanically they often look the same (embed, store, retrieve by similarity), and a production agent typically uses RAG for domain knowledge and a memory layer for personalization and continuity, side by side.
What is Mem0 used for?
Mem0 is an open-source memory layer you drop into an existing LLM application: it extracts facts from conversation turns with an LLM call, stores them with embeddings, and exposes a search call you run before generating a response so the model sees relevant prior facts. It is aimed at adding user/session memory to assistants and chatbots without building a memory pipeline from scratch.
What is Letta (MemGPT) and how is it different from Mem0?
Letta is the productized successor to the MemGPT research project. Its defining idea is that the agent itself edits its memory through tool calls — it decides what stays in a fixed "core memory" block in the prompt versus what gets paged out to an "archival" vector store it can query. That's a different bet from Mem0, where an extraction pipeline (not the agent) decides what to remember; Letta runs as a self-hostable server rather than a library you call.
What is a knowledge graph for agent memory, and when do I need one?
A knowledge-graph memory stores facts as entities and relationships (e.g. "Alice — works at — Acme") instead of unstructured text chunks, and a temporal implementation like Graphiti timestamps each relationship so a later contradicting fact invalidates the old one instead of silently overwriting it. Reach for it when relationships between entities matter and you need to answer "what was true then" as well as "what's true now" — a vector store alone can tell you a fact is similar to your query, but not whether it's still valid.
References
- • Mem0 — GitHub repository and README
- • Letta (formerly MemGPT) — GitHub repository
- • Rasmussen et al. — "Zep: A Temporal Knowledge Graph Architecture for Agent Memory" (arXiv, 2025)
- • Graphiti — official documentation
- • LangMem — GitHub repository
- • LangChain docs — long-term memory
- • LangChain — LangMem SDK launch post (memory types)
- • Chroma — documentation