# AI Agents Memory: Mem0 + LangGraph Agent Integration

In this blog we’ll walk through practical steps to add long‑term memory to your AI agents using **Mem0** and **LangGraph**. We’ll build incrementally, tackling one section at a time so you can follow along and run the code as you read.

## Table of Contents

1. **Mem0 Basics** – Adding, updating, and searching memories
    
2. **LangGraph Integration** – Wiring Mem0 into a LangGraph agent
    
3. **Vector DB Setup** – Swapping the default SQLite store for Qdrant
    
4. **Cloud Usage** – Using the Mem0 Cloud Platform for scalable memory management
    

---

## Why do AI agents need memory?

When an LLM‑powered agent starts a brand‑new conversation it has no context about who it’s talking to or what happened in earlier sessions. Relying on the raw *chat history* works only inside a single session and quickly bloats your prompt window.  
Long‑term **memory** lets the agent:

* **Remember user‑level facts** (name, preferences, past actions) across sessions
    
* **Personalise responses** without re‑asking the same questions
    
* **Stay efficient** by storing distilled facts instead of the entire transcript
    

#### Chat history vs memory

| Aspect | Chat history (session) | Long‑term memory (Mem0) |
| --- | --- | --- |
| Lifespan | Only current session | Persists across sessions |
| Granularity | Full message text | Distilled facts & metadata |
| Storage | In‑prompt list of messages | External DB / vector store |
| Cost impact | Grows token count quickly | Minimal extra tokens |

---

## 1\. Mem0 Basics – Adding, Updating & Searching Memories

### Quick setup

```python
from mem0 import Memory
memory = Memory.from_config({"history_db_path": "history.db"})  # local SQLite file
```

**Why the explicit config?** Mem0 defaults to a *read‑only* temp database, so writes will fail. Pointing it to `history.db` (or any path you prefer) gives the library a place to persist memories. You can extend the same `config` dict to

* **Override the LLM** (provider, model, temperature, etc.)
    
* **Plug in a vector store** for semantic search (we’ll wire up Qdrant in Section 3).
    

Example – switching to GPT‑4.1‑mini:

```python
config = {
    "history_db_path": "history.db",
    "llm": {
        "provider": "openai",
        "config": {
            "model": "gpt-4.1-mini",
            "temperature": 0.2,
            "max_tokens": 2000
        }
    }
}
memory = Memory.from_config(config)
```

### Add your first memories

```python
memory.add([
    {"role": "user", "content": "Hi, I'm Pradip Nichite. I run FutureSmart AI, where we build custom AI solutions."}
], user_id="pradip")

memory.add([
    {"role": "user", "content": "I love building RAG and AI Agent solutions that actually work in production."}
], user_id="pradip", metadata={"category": "preferences"})
```

Sample response:

```python
{'results': [{'id': '5408e326‑b26b‑4737‑a404‑299887b8d597',
  'memory': 'Loves building RAG and AI Agent solutions that work in production',
  'event': 'ADD'}]}
```

Mem0 distills each raw chat message into a concise fact so retrieval stays lightweight.

---

### Search

```python
related = memory.search("who am i", user_id="pradip")
related
```

Full output:

```python
{'results': [{'id': '647935d5-f913-496d-96e3-2233d7459f38',
   'memory': 'Name is Pradip Nichite',
   'hash': 'fa942a6331bb89da286d4a9e296d1008',
   'metadata': None,
   'score': 0.2294486506181006,
   'created_at': '2025-07-12T10:58:49.132915-07:00',
   'updated_at': None,
   'user_id': 'pradip'},
  {'id': 'c763c19a-7e9f-4180-8c82-012f4da5f637',
   'memory': 'Runs FutureSmart AI',
   'hash': '68a143a88a3e67ae9ebfb9575bcf49a7',
   'metadata': None,
   'score': 0.1551292009096673,
   'created_at': '2025-07-12T10:58:49.158843-07:00',
   'updated_at': None,
   'user_id': 'pradip'},
  {'id': '5408e326-b26b-4737-a404-299887b8d597',
   'memory': 'Loves building RAG and AI Agent solutions that work in production',
......
   'user_id': 'pradip'},
  {'id': '1baa6793-507f-46b1-8e01-b90dfa1e73b6',
   'memory': 'Builds custom AI solutions',
.......
   'user_id': 'pradip'}]}
```

`score` is cosine similarity—higher means closer semantic match.

### Get all memories for a user

```python
all_memories = memory.get_all(user_id="pradip")
```

Returns the full list (same schema as `search`, without scores).

### Retrieve a single memory

```python
mem_id = "1baa6793-507f-46b1-8e01-b90dfa1e73b6"
memory.get(mem_id)
```

Full output:

```python
{'id': '1baa6793-507f-46b1-8e01-b90dfa1e73b6',
 'memory': 'Builds custom Gen AI solutions',
 'hash': '502bdf5771e4ef9a812453b51870f0b2',
 'metadata': None,
 'score': None,
 'created_at': '2025-07-12T10:58:49.182159-07:00',
 'updated_at': '2025-07-12T11:02:34.594521-07:00',
 'user_id': 'pradip'}
{'id': '1baa...73b6',
 'memory': 'Builds custom Gen AI solutions',
 'created_at': ..., 'updated_at': ...}
```

### Update a memory

```python
memory.update(memory_id=mem_id, data="Builds custom Gen AI solutions")
# → {'message': 'Memory updated successfully!'}
```

### View change history

```python
history = memory.history(memory_id=mem_id)
```

Full output:

```python
[{'id': 'e7242249-430a-4bf2-b4df-ca0e4b99e69a',
  'memory_id': '1baa6793-507f-46b1-8e01-b90dfa1e73b6',
  'old_memory': None,
  'new_memory': 'Builds custom AI solutions',
  'event': 'ADD',
  'created_at': '2025-07-12T10:58:49.182159-07:00',
  'updated_at': None,
  'is_deleted': False,
  'actor_id': None,
  'role': None},
 {'id': '9d2e9706-b0c2-480b-b37a-07bb6143767d',
  'memory_id': '1baa6793-507f-46b1-8e01-b90dfa1e73b6',
  'old_memory': 'Builds custom AI solutions',
  'new_memory': 'Builds custom Gen AI solutions',
  'event': 'UPDATE',
  'created_at': '2025-07-12T10:58:49.182159-07:00',
  'updated_at': '2025-07-12T11:02:34.594521-07:00',
  'is_deleted': False,
  'actor_id': None,
  'role': None}]
```

Each entry records the old & new value plus timestamp—handy for auditing:

```python
[{'event': 'ADD',    'old_memory': None,                     'new_memory': 'Builds custom AI solutions'},
 {'event': 'UPDATE', 'old_memory': 'Builds custom AI solutions',
  'new_memory': 'Builds custom Gen AI solutions'}]
```

That wraps up the core CRUD API.

---

## 2\. LangGraph Integration – Wiring Mem0 into an Agent

**New to LangGraph?** Watch my YouTube walkthrough that covers LangGraph basics all the way to advanced patterns.

%[https://youtu.be/60XDTWhklLA?si=wrxb_SJ7XaMsel2B] 

Below we build the simplest possible LangGraph agent that:

1. Accepts user messages.
    
2. Retrieves relevant memories from Mem0.
    
3. Injects them into the system prompt for personalised replies.
    
4. Writes the new interaction back to Mem0.
    

### a) Define the shared state

```python
from typing import Annotated, TypedDict
from langgraph.graph.message import add_messages
from langchain_core.messages import BaseMessage

class State(TypedDict):
    """Conversation state passed between nodes"""
    messages: Annotated[list[BaseMessage], add_messages]  # chat history for this request
    mem0_user_id: str                                     # maps to Mem0 user record
```

### b) Init the LLM

```python
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-4.1-mini", temperature=0.7)
```

### c) Create the chatbot node

```python
from langchain_core.messages import HumanMessage, AIMessage, SystemMessage

def chatbot(state: State):
    global memory  # re‑use the Mem0 instance from Section 1
    msgs = state["messages"]
    uid = state["mem0_user_id"]

    # 1️⃣ Retrieve memories relevant to the latest user msg
    mems = memory.search(msgs[-1].content, user_id=uid)
    print(f"Retrieved Memories: {mems}")

    # Build context string
    if mems["results"]:
        context = "
".join(f"- {m['memory']}" for m in mems["results"])
    else:
        context = "No relevant information found."

    system = SystemMessage(content=f"""You are a helpful assistant. Use the provided context to personalise your responses.
Relevant information from previous conversations:
{context}""")

    # 2️⃣ Invoke the LLM
    response = llm.invoke([system] + msgs)

    # 3️⃣ Persist the new turn
    memory.add([
        {"role": "user", "content": msgs[-1].content},
        {"role": "assistant", "content": response.content}
    ], user_id=uid)

    return {"messages": [response]}
```

**How the node uses Mem0**

1. **Search:** For every incoming user message, we call `memory.search()` with the text and `user_id`. This performs a vector‑similarity lookup and returns any facts previously stored about the user.
    
2. **Prompt injection:** Those facts are concatenated into a bullet list (`context`) and inserted into a system prompt so the LLM can personalise its reply.
    
3. **Add:** After the LLM responds, we persist **both** the latest user message and the assistant reply via `memory.add()`. Mem0 distils them into new memories ready for the next turn.
    

### d) Build & compile the graph

```python
from langgraph.graph import StateGraph, START, END

graph_builder = StateGraph(State)

graph_builder.add_node("chatbot", chatbot)

graph_builder.add_edge(START, "chatbot")

graph_builder.add_edge("chatbot", END)

graph = graph_builder.compile()
print("Graph compiled successfully ✅")
```

### e) Command‑line loop for quick testing

```python
from langgraph_core.messages import HumanMessage

def run_conversation(user_input: str, mem0_user_id: str):
    state = {"messages": [HumanMessage(content=user_input)], "mem0_user_id": mem0_user_id}
    result = graph.invoke(state)
    print("🤖", result["messages"][-1].content)

if __name__ == "__main__":
    uid = "customer_pradip"
    while True:
        inp = input("You: ")
        if inp.lower() in {"quit", "exit", "bye"}:
            break
        run_conversation(inp, uid)
```

Run it, send two or three messages, then restart the script and ask *“who am I?”*—you’ll see the agent recall facts from the earlier run thanks to Mem0’s long‑term store.

---

## 3\. Vector DB Setup – Configuring Mem0 with Qdrant

SQLite works for quick tests, but once memories grow you’ll want a proper vector store. **Qdrant Cloud** offers a generous free tier and plugs straight into Mem0.

### a) Spin up / locate a Qdrant Cloud cluster

Grab the cluster URL and create an API key from the Qdrant dashboard.

```bash
# Install the Python client
!pip -q install qdrant_client
```

### b) Verify connectivity (optional)

```python
from qdrant_client import QdrantClient

qdrant = QdrantClient(
    url="https://<cluster-id>.<region>.aws.cloud.qdrant.io:6333",
    api_key=userdata.get("Qdrant_API_KEY")
)
print(qdrant.get_collections())  # sanity‑check
```

### c) Tell Mem0 to use Qdrant

```python
collection_name = "mem0_yt"

config = {
    "vector_store": {
        "provider": "qdrant",
        "config": {
            "collection_name": collection_name,
            "host": "<cluster-host>",
            "port": 6333,
            "api_key": userdata.get("Qdrant_API_KEY")
        }
    }
}

memory = Memory.from_config(config)
```

### d) One‑time payload index

Mem0 filters by `user_id` when searching, so Qdrant needs a keyword index on that field. If you skip this step you’ll get:

```text
400 Bad Request – Index required but not found for "user_id" of type [keyword]
```

Create it once, then you’re good:

```python
qdrant.create_payload_index(
    collection_name=collection_name,
    field_name="user_id",
    field_schema="keyword"
)
```

### e) Insert and query as usual

```python
messages = [
    {"role": "user", "content": "Hi, I'm Pradip Nichite. I run FutureSmart AI."},
    {"role": "user", "content": "I love building RAG and AI Agent solutions that work in production."}
]
memory.add(messages, user_id="pradip")
```

From here all CRUD and LangGraph logic stays exactly the same—only the storage layer has changed.

---

## 4\. Cloud Usage – Using the Mem0 Cloud Platform

If you’d rather skip managing your own DBs, Mem0 offers a hosted platform with a clean UI to inspect and edit memories.

### a) Authenticate

```python
from mem0 import MemoryClient

client = MemoryClient(api_key=userdata.get("Mem0_API_KEY"))
```

### b) Add messages (same schema as before)

```python
messages = [
    {"role": "user",      "content": "Hi, I am Pradip. I am Founder of FutureSmart AI"},
    {"role": "assistant", "content": "Hi Pradip"}
]

client.add(messages, user_id="Pradip_Founder")
```

### c) Inspect in the dashboard

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1752475996169/f275c471-8fd7-4dc4-bf00-8e5308d124cf.png align="center")

> You’ll see two distilled memories automatically extracted, complete with timestamps and editable fields.

The hosted store supports the same search/update/history API, so you can swap `Memory` for `MemoryClient` with minimal changes.

---

### Watch the full walkthrough

Prefer video? I recorded a step‑by‑step YouTube demo that mirrors this blog, including live coding and UI tours – check it out here 👇

%[https://youtu.be/e-wBojpJrrQ] 

---

## Need a Custom AI Solution?

At **FutureSmart AI** we specialise in designing and shipping production‑grade AI systems—RAG agents, document parsers, NL2SQL bots, multi‑agent workflows, and more.

→ **See our case studies:** [https://futuresmart.ai/case-studies](https://futuresmart.ai/case-studies)  
→ **Try the LangGraph‑powered FutureSmart Agent:** [https://agent.futuresmart.ai/](https://agent.futuresmart.ai/)  
→ **Get in touch:** email us at [**contact@futuresmart.ai**](mailto:contact@futuresmart.ai) to discuss how we can build or fine‑tune an AI solution for your business.
