# How to Add Memory to an AI Agent

- Tool: Any LLM or framework
- Difficulty: Intermediate
- Time required: 30-45 min
- Compatibility: Python 3.10+, langchain 1.4+, langgraph 1.2+, mem0ai, an Anthropic API key, any OS
- Last updated: November 2026

## TL;DR

AI agent memory comes in two layers that solve different problems: short-term memory for what happened earlier in the current conversation, and long-term memory for facts that should survive after the session ends. This guide builds a personal finance coaching agent with LangChain's checkpointer for thread-scoped recall and Mem0 for persistent user facts like income and savings goals. Budget 30-45 minutes and an Anthropic API key.

## What you'll build

You'll build a personal finance coaching agent a user talks to over several sessions, days apart. Within one session, it needs to remember what you said three messages ago ('what about that second scenario I mentioned') without you repeating it; that's short-term memory, scoped to the current thread. Across sessions, it needs to remember that you're saving for a house down payment and have told it your rough monthly income before, without you re-explaining your situation every time you open a new chat; that's long-term memory, scoped to you as a user, not to any one conversation.

These are genuinely different systems, and conflating them is the most common memory mistake. Short-term memory in this guide comes from LangGraph's checkpointer, which snapshots the full message history under a thread_id and restores it automatically. Long-term memory comes from Mem0, which extracts durable facts from conversations and lets you search them later with a user_id, independent of which thread they came from.

Use a checkpointer alone when the agent only needs to function within one sitting, like a support chat that resets between visitors. Add Mem0 or a similar long-term store once the same user is expected to come back and the agent should feel like it remembers them, not just the current exchange.

## Before you start

- Python 3.10+ and a terminal
- An Anthropic API key (ANTHROPIC_API_KEY)
- pip install langchain langgraph mem0ai
- An OpenAI API key if you keep Mem0's default extraction model, or a Mem0 config pointed at Claude

## Step-by-step guide

### 1. Install the packages and set up Mem0

Install langchain, langgraph, and mem0ai. Mem0 needs its own small LLM for fact extraction; the default uses an OpenAI model, so either keep an OpenAI key around for that one internal call or configure Mem0 to use Claude instead. Initialize a single Memory instance your whole app shares.

```
pip install langchain langgraph mem0ai
export ANTHROPIC_API_KEY="sk-ant-..."
export OPENAI_API_KEY="sk-..."  # used internally by Mem0 for fact extraction

from mem0 import Memory

long_term_memory = Memory()
```

**Expected result:** Memory() initializes with no errors; it uses a local vector store by default, no external memory service needed for this guide.

### 2. Build the agent with a checkpointer for short-term memory

create_agent takes a checkpointer directly, which is all short-term memory requires: every invoke() call under the same thread_id reads and appends to the same message history automatically. No manual message-list management needed.

```
from langchain.agents import create_agent
from langgraph.checkpoint.memory import InMemorySaver

agent = create_agent(
    model="anthropic:claude-sonnet-5-5",
    tools=[],
    checkpointer=InMemorySaver(),
)

config = {"configurable": {"thread_id": "session-2026-11-04-alex"}}
agent.invoke({"messages": [{"role": "user", "content": "I'm trying to save $20k for a down payment"}]}, config=config)
result = agent.invoke({"messages": [{"role": "user", "content": "How much should I save monthly for that in 2 years?"}]}, config=config)
```

**Expected result:** The second response correctly references the $20k goal from the first message, within the same thread_id, with no manual history passing.

### 3. Write long-term facts to Mem0 after each session

At the end of a session, hand Mem0 the exchange and a user_id (not a thread_id, since this should outlive any one thread). Mem0's extraction step pulls out durable facts, not the raw transcript, so 'I'm trying to save $20k for a down payment' becomes a stored fact tied to that user, independent of which conversation it came from.

```
def save_long_term_facts(user_id: str, messages: list[dict]):
    long_term_memory.add(messages, user_id=user_id)

save_long_term_facts(
    "alex",
    [
        {"role": "user", "content": "I'm trying to save $20k for a down payment"},
        {"role": "assistant", "content": "Got it, saving for a $20k down payment."},
    ],
)
```

**Expected result:** long_term_memory.search('down payment', filters={'user_id': 'alex'}) now returns a stored memory even in a brand new Python process.

### 4. Retrieve long-term facts at the start of a new session

Before the agent's first turn in a new session, search Mem0 for relevant facts about this user and fold the results into the system prompt as a short block, not the raw search payload. This is the step that makes the agent feel like it remembers you: by the time it answers, it already knows the down-payment goal from a session days ago.

```
def build_system_prompt(user_id: str, current_message: str) -> str:
    hits = long_term_memory.search(current_message, filters={"user_id": user_id})
    facts = "\n".join(f"- {m['memory']}" for m in hits.get("results", [])[:5])
    base = "You are a personal finance coach. Be specific with numbers."
    if facts:
        return f"{base}\n\nKnown facts about this user:\n{facts}"
    return base
```

**Expected result:** A new thread's system prompt includes 'Known facts about this user: - Saving for a $20k down payment' pulled from a prior session.

### 5. Wire both memory layers into one call

On every new session, build the system prompt from Mem0 first, then run the agent with a fresh thread_id and that prompt. Within the session, the checkpointer handles turn-to-turn recall; across sessions, the system prompt built from Mem0 search carries the context forward.

```
import uuid

agent = create_agent(
    model="anthropic:claude-sonnet-5-5",
    tools=[],
    system_prompt=build_system_prompt("alex", "How's my savings plan looking?"),
    checkpointer=InMemorySaver(),
)
config = {"configurable": {"thread_id": str(uuid.uuid4())}}
result = agent.invoke({"messages": [{"role": "user", "content": "How's my savings plan looking?"}]}, config=config)
print(result["messages"][-1].content)
```

**Expected result:** A brand new thread with no prior turns still answers with awareness of the down-payment goal from a previous session.

### 6. Harden it: bound what gets stored and retrieved

Two failure modes show up fast in production. First, Mem0 can accumulate contradictory facts over time ('saving $20k' then later 'saving $30k'); periodically review or let newer facts naturally outrank older ones in search ranking rather than storing every raw message. Second, cap how many search results you fold into the prompt (five is a reasonable default) so a user with months of history doesn't blow out your context window on every turn.

```
def build_system_prompt(user_id: str, current_message: str, max_facts: int = 5) -> str:
    hits = long_term_memory.search(current_message, filters={"user_id": user_id})
    results = sorted(hits.get("results", []), key=lambda m: m.get("score", 0), reverse=True)[:max_facts]
    facts = "\n".join(f"- {m['memory']}" for m in results)
    return f"You are a personal finance coach.\n\nKnown facts:\n{facts}" if facts else "You are a personal finance coach."
```

**Expected result:** Even a user with 50+ stored memories only ever contributes at most 5 facts to any single prompt.

## Complete code example

File: `finance_coach_memory.py`

```python
"""Personal finance coach with two memory layers: a checkpointer for
within-session recall and Mem0 for facts that persist across sessions.
Run: python finance_coach_memory.py
(pip install langchain langgraph mem0ai; set ANTHROPIC_API_KEY and OPENAI_API_KEY)
"""
import uuid

from langchain.agents import create_agent
from langgraph.checkpoint.memory import InMemorySaver
from mem0 import Memory

long_term_memory = Memory()


def save_long_term_facts(user_id: str, messages: list[dict]) -> None:
    long_term_memory.add(messages, user_id=user_id)


def build_system_prompt(user_id: str, current_message: str, max_facts: int = 5) -> str:
    hits = long_term_memory.search(current_message, filters={"user_id": user_id})
    results = sorted(
        hits.get("results", []), key=lambda m: m.get("score", 0), reverse=True
    )[:max_facts]
    facts = "\n".join(f"- {m['memory']}" for m in results)
    base = "You are a personal finance coach. Be specific with numbers."
    return f"{base}\n\nKnown facts about this user:\n{facts}" if facts else base


def run_turn(user_id: str, thread_id: str, user_message: str) -> str:
    agent = create_agent(
        model="anthropic:claude-sonnet-5-5",
        tools=[],
        system_prompt=build_system_prompt(user_id, user_message),
        checkpointer=InMemorySaver(),
    )
    config = {"configurable": {"thread_id": thread_id}}
    result = agent.invoke({"messages": [{"role": "user", "content": user_message}]}, config=config)
    return result["messages"][-1].content


if __name__ == "__main__":
    user_id = "alex"

    # Session 1: establish a goal, then ask a follow-up in the same thread
    thread_1 = str(uuid.uuid4())
    run_turn(user_id, thread_1, "I'm trying to save $20k for a down payment")
    print(run_turn(user_id, thread_1, "How much should I save monthly for that in 2 years?"))

    # Persist what was learned for future sessions
    save_long_term_facts(
        user_id,
        [
            {"role": "user", "content": "I'm trying to save $20k for a down payment"},
            {"role": "assistant", "content": "Got it, saving for a $20k down payment."},
        ],
    )

    # Session 2: a brand new thread, days later, still knows the goal
    thread_2 = str(uuid.uuid4())
    print(run_turn(user_id, thread_2, "How's my savings plan looking?"))
```

## Common mistakes

- **Using only a checkpointer and expecting the agent to remember the user in a new session** — undefined Fix: A checkpointer is scoped to a thread_id, not a user. A new thread starts with zero history, no matter how many prior sessions that user had.
- **Storing the raw conversation transcript as 'long-term memory' instead of extracted facts** — undefined Fix: Raw transcripts grow unbounded and resurface stale or irrelevant detail. Let Mem0's extraction step distill durable facts, and search instead of replaying everything.
- **Folding every search result into the system prompt with no limit** — undefined Fix: Cap retrieved facts (5 is reasonable) and rank by relevance or recency. An unbounded fact list burns tokens and can bury the one fact that actually matters for this turn.
- **Reusing the same thread_id across unrelated sessions to fake long-term memory** — undefined Fix: This works until the transcript gets too long for the context window, and it mixes unrelated conversations together. Use a real long-term store keyed by user_id instead.
- **Never updating or expiring long-term facts, so contradictions pile up over months** — undefined Fix: Review stored facts periodically or lean on Mem0's relevance scoring to let newer facts outrank stale ones in search results.

## Best practices

- Treat short-term memory (thread_id, checkpointer) and long-term memory (user_id, Mem0 or similar) as two separate systems with two separate keys.
- Extract and store facts, not full transcripts, for anything meant to survive past the current session.
- Cap how many long-term facts get injected into any one system prompt; rank by relevance to the current message, not just recency.
- Save long-term facts at natural checkpoints (end of session, after a goal is confirmed) rather than after every single message.
- Let users see and correct what the agent remembers about them; wrong persisted facts are worse than no memory at all.
- Use InMemorySaver for development and a persistent checkpointer (Postgres, Redis) before you rely on short-term memory surviving a process restart in production.

## Use cases

### undefined



### undefined



### undefined



## Frequently asked questions

### Do I need both short-term and long-term memory, or just one?

It depends on whether the same user returns. A single-session support chat only needs short-term memory from a checkpointer. Any agent meant to recognize a returning user, like this finance coach, needs long-term memory too.

### Why does Mem0 need an OpenAI key if I'm building with Claude?

By default, Mem0 uses an OpenAI model internally for its own fact-extraction step, separate from whatever model powers your agent. You can configure Mem0 to use a different provider for extraction if you want to avoid the second API key.

### Can I use a Postgres checkpointer instead of InMemorySaver?

Yes, and you should before production. InMemorySaver loses all short-term memory on process restart. LangGraph ships Postgres and other persistent checkpointer backends that work as a drop-in replacement in the same checkpointer= argument.

### How is this different from just putting the whole chat history in the prompt every time?

That works for short-term memory within a context window's limit, but it doesn't survive a new session and gets expensive as history grows. Long-term memory with extraction and search solves both problems: it's bounded and it outlives the thread.

### What happens if Mem0 extracts a wrong or outdated fact?

It stays in the store until corrected. Give users a way to review or clear what's remembered about them, and treat memory extraction the same way you'd treat any other automated write to user data: logged and correctable.

### Can someone build this memory layer for me?

Yes. RapidDev builds short-term and long-term memory layers on LangGraph, Mem0, and the Claude Agent SDK, including the fact-review tooling most tutorials skip. A free 30-minute consultation is the fastest way to scope your version.

---

Source: https://www.rapidevelopers.com/build-ai-agent/how-to-add-memory-to-an-ai-agent
© RapidDev — https://www.rapidevelopers.com/build-ai-agent/how-to-add-memory-to-an-ai-agent
