docs: new algorithm migration guides + memory evaluation (#4811)
Co-authored-by: kartik-mem0 <kartik.labhshetwar@mem0.ai> Co-authored-by: Saket Aryan <saketaryan2002@gmail.com>
This commit is contained in:
@@ -90,7 +90,7 @@ async def get_memory():
|
||||
|
||||
async def safe_memory_usage():
|
||||
async with get_memory() as memory:
|
||||
return await memory.search("test query", user_id="alice")
|
||||
return await memory.search("test query", filters={"user_id": "alice"})
|
||||
```
|
||||
|
||||
<Tip>
|
||||
@@ -145,7 +145,7 @@ async def robust_memory_search():
|
||||
memory = AsyncMemory()
|
||||
|
||||
async def search_operation():
|
||||
return await memory.search("test query", user_id="alice")
|
||||
return await memory.search("test query", filters={"user_id": "alice"})
|
||||
|
||||
return await with_timeout_and_retry(search_operation)
|
||||
```
|
||||
@@ -173,11 +173,11 @@ result = await memory.add(
|
||||
# Search memories
|
||||
results = await memory.search(
|
||||
query="Where am I travelling?",
|
||||
user_id="alice"
|
||||
filters={"user_id": "alice"}
|
||||
)
|
||||
|
||||
# List memories
|
||||
all_memories = await memory.get_all(user_id="alice")
|
||||
all_memories = await memory.get_all(filters={"user_id": "alice"})
|
||||
|
||||
# Get a specific memory
|
||||
specific_memory = await memory.get(memory_id="memory-id-here")
|
||||
@@ -213,13 +213,11 @@ await memory.add(
|
||||
run_id="consultation-001"
|
||||
)
|
||||
|
||||
all_user_memories = await memory.get_all(user_id="alice")
|
||||
agent_memories = await memory.get_all(user_id="alice", agent_id="diet-assistant")
|
||||
session_memories = await memory.get_all(user_id="alice", run_id="consultation-001")
|
||||
all_user_memories = await memory.get_all(filters={"user_id": "alice"})
|
||||
agent_memories = await memory.get_all(filters={"user_id": "alice", "agent_id": "diet-assistant"})
|
||||
session_memories = await memory.get_all(filters={"user_id": "alice", "run_id": "consultation-001"})
|
||||
specific_memories = await memory.get_all(
|
||||
user_id="alice",
|
||||
agent_id="diet-assistant",
|
||||
run_id="consultation-001"
|
||||
filters={"user_id": "alice", "agent_id": "diet-assistant", "run_id": "consultation-001"}
|
||||
)
|
||||
|
||||
history = await memory.history(memory_id="memory-id-here")
|
||||
@@ -240,7 +238,7 @@ async_openai_client = AsyncOpenAI()
|
||||
async_memory = AsyncMemory()
|
||||
|
||||
async def chat_with_memories(message: str, user_id: str = "default_user") -> str:
|
||||
search_result = await async_memory.search(query=message, user_id=user_id, top_k=3)
|
||||
search_result = await async_memory.search(query=message, filters={"user_id": user_id}, top_k=3)
|
||||
relevant_memories = search_result["results"]
|
||||
memories_str = "\n".join(f"- {entry['memory']}" for entry in relevant_memories)
|
||||
|
||||
@@ -255,7 +253,7 @@ async def chat_with_memories(message: str, user_id: str = "default_user") -> str
|
||||
]
|
||||
|
||||
response = await async_openai_client.chat.completions.create(
|
||||
model="gpt-4.1-nano-2025-04-14",
|
||||
model="gpt-5-mini",
|
||||
messages=messages
|
||||
)
|
||||
|
||||
@@ -280,7 +278,7 @@ async def handle_initialization_errors():
|
||||
try:
|
||||
config = MemoryConfig(
|
||||
vector_store={"provider": "chroma", "config": {"path": "./chroma_db"}},
|
||||
llm={"provider": "openai", "config": {"model": "gpt-4.1-nano-2025-04-14"}}
|
||||
llm={"provider": "openai", "config": {"model": "gpt-5-mini"}}
|
||||
)
|
||||
AsyncMemory(config=config)
|
||||
print("AsyncMemory initialized successfully")
|
||||
@@ -297,7 +295,7 @@ async def handle_memory_operation_errors():
|
||||
print(f"Invalid memory ID: {err}")
|
||||
|
||||
try:
|
||||
await memory.search(query="", user_id="alice")
|
||||
await memory.search(query="", filters={"user_id": "alice"})
|
||||
except ValueError as err:
|
||||
print(f"Invalid search query: {err}")
|
||||
```
|
||||
@@ -326,7 +324,7 @@ async def add_memory(messages: list, user_id: str):
|
||||
@app.get("/memories/search")
|
||||
async def search_memories(query: str, user_id: str, limit: int = 10):
|
||||
try:
|
||||
result = await memory.search(query=query, user_id=user_id, top_k=limit)
|
||||
result = await memory.search(query=query, filters={"user_id": user_id}, top_k=limit)
|
||||
return {"status": "success", "data": result}
|
||||
except Exception as exc:
|
||||
raise HTTPException(status_code=500, detail=str(exc))
|
||||
|
||||
@@ -109,7 +109,7 @@ config = {
|
||||
"llm": {
|
||||
"provider": "openai",
|
||||
"config": {
|
||||
"model": "gpt-4.1-nano-2025-04-14",
|
||||
"model": "gpt-5-mini",
|
||||
"temperature": 0.2,
|
||||
"max_tokens": 2000,
|
||||
}
|
||||
|
||||
@@ -1,306 +0,0 @@
|
||||
---
|
||||
title: Custom Update Memory Prompt
|
||||
description: Decide how Mem0 adds, updates, or deletes memories using your own rules.
|
||||
icon: "arrows-rotate"
|
||||
---
|
||||
|
||||
The custom update memory prompt tells Mem0 how to handle changes when new facts arrive. Craft the prompt so the LLM can compare incoming facts with existing memories and choose the right action.
|
||||
|
||||
<Info>
|
||||
**You’ll use this when…**
|
||||
- Stored memories need to stay consistent as users change preferences or correct past statements.
|
||||
- Your product has clear rules for when to add, update, delete, or leave a memory untouched.
|
||||
- You want traceable decisions (ADD, UPDATE, DELETE, NONE) for auditing or compliance.
|
||||
</Info>
|
||||
|
||||
<Warning>
|
||||
Prompts that mix instructions or omit examples can lead to wrong actions like deleting valid memories. Keep the language simple and test each action path.
|
||||
</Warning>
|
||||
|
||||
---
|
||||
|
||||
## Feature anatomy
|
||||
|
||||
- **Action verbs:** The prompt teaches the model to return `ADD`, `UPDATE`, `DELETE`, or `NONE` for every memory entry.
|
||||
- **ID retention:** Updates reuse the original memory ID so downstream systems maintain history.
|
||||
- **Old vs. new text:** Updates include `old_memory` so you can track what changed.
|
||||
- **Decision table:** Your prompt should explain when to use each action and show concrete examples.
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Decision guide">
|
||||
| Action | When to choose it | Output details |
|
||||
| --- | --- | --- |
|
||||
| `ADD` | Fact is new and not stored yet | Generate a new ID and set `event: "ADD"`. |
|
||||
| `UPDATE` | Fact replaces older info about the same topic | Keep the original ID, include `old_memory`. |
|
||||
| `DELETE` | Fact contradicts the stored memory or you explicitly remove it | Keep ID, set `event: "DELETE"`. |
|
||||
| `NONE` | Fact matches existing memory or is irrelevant | Keep ID with `event: "NONE"`. |
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
---
|
||||
|
||||
## Configure it
|
||||
|
||||
### Author the prompt
|
||||
|
||||
<CodeGroup>
|
||||
```python Python
|
||||
UPDATE_MEMORY_PROMPT = """You are a smart memory manager which controls the memory of a system.
|
||||
You can perform four operations: (1) add into the memory, (2) update the memory, (3) delete from the memory, and (4) no change.
|
||||
|
||||
Based on the above four operations, the memory will change.
|
||||
|
||||
Compare newly retrieved facts with the existing memory. For each new fact, decide whether to:
|
||||
- ADD: Add it to the memory as a new element
|
||||
- UPDATE: Update an existing memory element
|
||||
- DELETE: Delete an existing memory element
|
||||
- NONE: Make no change (if the fact is already present or irrelevant)
|
||||
|
||||
There are specific guidelines to select which operation to perform:
|
||||
|
||||
1. **Add**: If the retrieved facts contain new information not present in the memory, then you have to add it by generating a new ID in the id field.
|
||||
- **Example**:
|
||||
- Old Memory:
|
||||
[
|
||||
{
|
||||
"id" : "0",
|
||||
"text" : "User is a software engineer"
|
||||
}
|
||||
]
|
||||
- Retrieved facts: ["Name is John"]
|
||||
- New Memory:
|
||||
{
|
||||
"memory" : [
|
||||
{
|
||||
"id" : "0",
|
||||
"text" : "User is a software engineer",
|
||||
"event" : "NONE"
|
||||
},
|
||||
{
|
||||
"id" : "1",
|
||||
"text" : "Name is John",
|
||||
"event" : "ADD"
|
||||
}
|
||||
]
|
||||
|
||||
}
|
||||
|
||||
2. **Update**: If the retrieved facts contain information that is already present in the memory but the information is totally different, then you have to update it.
|
||||
If the retrieved fact contains information that conveys the same thing as the elements present in the memory, then you have to keep the fact which has the most information.
|
||||
Example (a) -- if the memory contains "User likes to play cricket" and the retrieved fact is "Loves to play cricket with friends", then update the memory with the retrieved facts.
|
||||
Example (b) -- if the memory contains "Likes cheese pizza" and the retrieved fact is "Loves cheese pizza", then you do not need to update it because they convey the same information.
|
||||
If the direction is to update the memory, then you have to update it.
|
||||
Please keep in mind while updating you have to keep the same ID.
|
||||
Please note to return the IDs in the output from the input IDs only and do not generate any new ID.
|
||||
- **Example**:
|
||||
- Old Memory:
|
||||
[
|
||||
{
|
||||
"id" : "0",
|
||||
"text" : "I really like cheese pizza"
|
||||
},
|
||||
{
|
||||
"id" : "1",
|
||||
"text" : "User is a software engineer"
|
||||
},
|
||||
{
|
||||
"id" : "2",
|
||||
"text" : "User likes to play cricket"
|
||||
}
|
||||
]
|
||||
- Retrieved facts: ["Loves chicken pizza", "Loves to play cricket with friends"]
|
||||
- New Memory:
|
||||
{
|
||||
"memory" : [
|
||||
{
|
||||
"id" : "0",
|
||||
"text" : "Loves cheese and chicken pizza",
|
||||
"event" : "UPDATE",
|
||||
"old_memory" : "I really like cheese pizza"
|
||||
},
|
||||
{
|
||||
"id" : "1",
|
||||
"text" : "User is a software engineer",
|
||||
"event" : "NONE"
|
||||
},
|
||||
{
|
||||
"id" : "2",
|
||||
"text" : "Loves to play cricket with friends",
|
||||
"event" : "UPDATE",
|
||||
"old_memory" : "User likes to play cricket"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
3. **Delete**: If the retrieved facts contain information that contradicts the information present in the memory, then you have to delete it. Or if the direction is to delete the memory, then you have to delete it.
|
||||
Please note to return the IDs in the output from the input IDs only and do not generate any new ID.
|
||||
- **Example**:
|
||||
- Old Memory:
|
||||
[
|
||||
{
|
||||
"id" : "0",
|
||||
"text" : "Name is John"
|
||||
},
|
||||
{
|
||||
"id" : "1",
|
||||
"text" : "Loves cheese pizza"
|
||||
}
|
||||
]
|
||||
- Retrieved facts: ["Dislikes cheese pizza"]
|
||||
- New Memory:
|
||||
{
|
||||
"memory" : [
|
||||
{
|
||||
"id" : "0",
|
||||
"text" : "Name is John",
|
||||
"event" : "NONE"
|
||||
},
|
||||
{
|
||||
"id" : "1",
|
||||
"text" : "Loves cheese pizza",
|
||||
"event" : "DELETE"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
4. **No Change**: If the retrieved facts contain information that is already present in the memory, then you do not need to make any changes.
|
||||
- **Example**:
|
||||
- Old Memory:
|
||||
[
|
||||
{
|
||||
"id" : "0",
|
||||
"text" : "Name is John"
|
||||
},
|
||||
{
|
||||
"id" : "1",
|
||||
"text" : "Loves cheese pizza"
|
||||
}
|
||||
]
|
||||
- Retrieved facts: ["Name is John"]
|
||||
- New Memory:
|
||||
{
|
||||
"memory" : [
|
||||
{
|
||||
"id" : "0",
|
||||
"text" : "Name is John",
|
||||
"event" : "NONE"
|
||||
},
|
||||
{
|
||||
"id" : "1",
|
||||
"text" : "Loves cheese pizza",
|
||||
"event" : "NONE"
|
||||
}
|
||||
]
|
||||
}
|
||||
"""
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
### Define the expected output format
|
||||
|
||||
<CodeGroup>
|
||||
```json Add
|
||||
{
|
||||
"memory": [
|
||||
{
|
||||
"id": "0",
|
||||
"text": "This information is new",
|
||||
"event": "ADD"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
```json Update
|
||||
{
|
||||
"memory": [
|
||||
{
|
||||
"id": "0",
|
||||
"text": "This information replaces the old information",
|
||||
"event": "UPDATE",
|
||||
"old_memory": "Old information"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
```json Delete
|
||||
{
|
||||
"memory": [
|
||||
{
|
||||
"id": "0",
|
||||
"text": "This information will be deleted",
|
||||
"event": "DELETE"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
```json No Change
|
||||
{
|
||||
"memory": [
|
||||
{
|
||||
"id": "0",
|
||||
"text": "No changes for this information",
|
||||
"event": "NONE"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
<Info icon="check">
|
||||
Consistent JSON structure makes it easy to parse decisions downstream or log them for auditing.
|
||||
</Info>
|
||||
|
||||
---
|
||||
|
||||
## See it in action
|
||||
|
||||
- Run reconciliation jobs that compare retrieved facts to existing memories.
|
||||
- Feed both sources into the custom prompt, then apply the returned actions (add new entries, update text, delete outdated facts).
|
||||
- Log each decision so product teams can review why a change happened.
|
||||
|
||||
<Note>
|
||||
The prompt works alongside `custom_instructions`—fact extraction identifies candidate facts, and the update prompt decides how to merge them into long-term storage.
|
||||
</Note>
|
||||
|
||||
---
|
||||
|
||||
## Verify the feature is working
|
||||
|
||||
- Test all four actions with targeted examples, including edge cases where facts differ only slightly.
|
||||
- Confirm update responses keep the original IDs and include `old_memory`.
|
||||
- Ensure delete actions only trigger when contradictions appear or when you explicitly request removal.
|
||||
|
||||
---
|
||||
|
||||
## Best practices
|
||||
|
||||
1. **Keep instructions brief:** Remove redundant wording so the LLM focuses on the decision logic.
|
||||
2. **Document your schema:** Share the prompt and examples with your team so everyone knows how memories evolve.
|
||||
3. **Track prompt versions:** When rules change, bump a version number and archive the prior prompt.
|
||||
4. **Review outputs regularly:** Skim audit logs weekly to spot drift or repeated mistakes.
|
||||
5. **Pair with monitoring:** Visualize counts of each action to detect spikes in deletes or updates.
|
||||
|
||||
---
|
||||
|
||||
## Compare prompts
|
||||
|
||||
| Feature | `custom_update_memory_prompt` | `custom_instructions` |
|
||||
| --- | --- | --- |
|
||||
| Primary job | Decide memory actions (ADD/UPDATE/DELETE/NONE) | Pull facts from user and assistant messages |
|
||||
| Inputs | Retrieved facts + existing memory entries | Raw conversation turns |
|
||||
| Output | Structured memory array with events | Array of extracted facts |
|
||||
|
||||
---
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Design Fact Extraction" icon="sparkles" href="/open-source/features/custom-instructions">
|
||||
Coordinate both prompts so fact extraction feeds clean inputs into the update flow.
|
||||
</Card>
|
||||
<Card title="Build Email Automations" icon="inbox" href="/cookbooks/operations/email-automation">
|
||||
See how update prompts keep customer profiles current in a working automation.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
@@ -1,421 +0,0 @@
|
||||
---
|
||||
title: Graph Memory
|
||||
description: "Layer relationships onto Mem0 search so agents remember who did what, when, and with whom."
|
||||
icon: "network-wired"
|
||||
---
|
||||
|
||||
Graph Memory extends Mem0 by persisting nodes and edges alongside embeddings, so recalls stitch together people, places, and events instead of just keywords.
|
||||
|
||||
<Info icon="sparkles">
|
||||
**You’ll use this when…**
|
||||
- Conversation history mixes multiple actors and objects that vectors alone blur together
|
||||
- Compliance or auditing demands a graph of who said what and when
|
||||
- Agent teams need shared context without duplicating every memory in each run
|
||||
</Info>
|
||||
|
||||
## How Graph Memory Maps Context
|
||||
|
||||
Mem0 extracts entities and relationships from every memory write, stores embeddings in your vector database, and mirrors relationships in a graph backend. On retrieval, vector search narrows candidates while the graph returns related context alongside the results.
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
A[Conversation] --> B(Extraction LLM)
|
||||
B --> C[Vector Store]
|
||||
B --> D[Graph Store]
|
||||
E[Query] --> C
|
||||
C --> F[Candidate Memories]
|
||||
F --> D
|
||||
D --> G[Contextual Recall]
|
||||
```
|
||||
|
||||
## How It Works
|
||||
|
||||
<Steps>
|
||||
<Step title="Extract people, places, and facts">
|
||||
Mem0’s extraction LLM identifies entities, relationships, and timestamps from the conversation payload you send to `memory.add`.
|
||||
</Step>
|
||||
<Step title="Store vectors and edges together">
|
||||
Embeddings land in your configured vector database while nodes and edges flow into a graph backend (Neo4j, Memgraph, Neptune, Kuzu, or Apache AGE).
|
||||
</Step>
|
||||
<Step title="Expose graph context at search time">
|
||||
`memory.search` performs vector similarity (optionally reranked by your configured reranker) and returns the results list. Graph Memory runs in parallel and adds related entities in the `relations` array—it does not reorder the vector hits automatically.
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Quickstart (Neo4j Aura)
|
||||
|
||||
<Info icon="clock">
|
||||
**Time to implement:** ~10 minutes · **Prerequisites:** Python 3.10+, Node.js 18+, Neo4j Aura DB (free tier)
|
||||
</Info>
|
||||
|
||||
Provision a free [Neo4j Aura](https://neo4j.com/product/auradb/) instance, copy the Bolt URI, username, and password, then follow the language tab that matches your stack.
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Python">
|
||||
<Steps>
|
||||
<Step title="Install Mem0 with graph extras">
|
||||
```bash
|
||||
pip install "mem0ai[graph]"
|
||||
```
|
||||
</Step>
|
||||
<Step title="Export Neo4j credentials">
|
||||
```bash
|
||||
export NEO4J_URL="neo4j+s://<your-instance>.databases.neo4j.io"
|
||||
export NEO4J_USERNAME="neo4j"
|
||||
export NEO4J_PASSWORD="your-password"
|
||||
```
|
||||
</Step>
|
||||
<Step title="Add and recall a relationship">
|
||||
```python
|
||||
import os
|
||||
from mem0 import Memory
|
||||
|
||||
config = {
|
||||
"graph_store": {
|
||||
"provider": "neo4j",
|
||||
"config": {
|
||||
"url": os.environ["NEO4J_URL"],
|
||||
"username": os.environ["NEO4J_USERNAME"],
|
||||
"password": os.environ["NEO4J_PASSWORD"],
|
||||
"database": "neo4j",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memory = Memory.from_config(config)
|
||||
|
||||
conversation = [
|
||||
{"role": "user", "content": "Alice met Bob at GraphConf 2025 in San Francisco."},
|
||||
{"role": "assistant", "content": "Great! Logging that connection."},
|
||||
]
|
||||
|
||||
memory.add(conversation, user_id="demo-user")
|
||||
|
||||
results = memory.search(
|
||||
"Who did Alice meet at GraphConf?",
|
||||
user_id="demo-user",
|
||||
top_k=3,
|
||||
rerank=True,
|
||||
)
|
||||
|
||||
for hit in results["results"]:
|
||||
print(hit["memory"])
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
</Tab>
|
||||
<Tab title="TypeScript">
|
||||
<Steps>
|
||||
<Step title="Install the OSS SDK">
|
||||
```bash
|
||||
npm install mem0ai
|
||||
```
|
||||
</Step>
|
||||
<Step title="Load Neo4j credentials">
|
||||
```bash
|
||||
export NEO4J_URL="neo4j+s://<your-instance>.databases.neo4j.io"
|
||||
export NEO4J_USERNAME="neo4j"
|
||||
export NEO4J_PASSWORD="your-password"
|
||||
```
|
||||
</Step>
|
||||
<Step title="Enable graph memory and query it">
|
||||
```typescript
|
||||
import { Memory } from "mem0ai/oss";
|
||||
|
||||
const config = {
|
||||
graphStore: {
|
||||
provider: "neo4j",
|
||||
config: {
|
||||
url: process.env.NEO4J_URL!,
|
||||
username: process.env.NEO4J_USERNAME!,
|
||||
password: process.env.NEO4J_PASSWORD!,
|
||||
database: "neo4j",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const memory = new Memory(config);
|
||||
|
||||
const conversation = [
|
||||
{ role: "user", content: "Alice met Bob at GraphConf 2025 in San Francisco." },
|
||||
{ role: "assistant", content: "Great! Logging that connection." },
|
||||
];
|
||||
|
||||
await memory.add(conversation, { userId: "demo-user" });
|
||||
|
||||
const results = await memory.search(
|
||||
"Who did Alice meet at GraphConf?",
|
||||
{ userId: "demo-user", topK: 3, rerank: true }
|
||||
);
|
||||
|
||||
results.results.forEach((hit) => {
|
||||
console.log(hit.memory);
|
||||
});
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
<Info icon="check">
|
||||
Expect to see **Alice met Bob at GraphConf 2025** in the output. In Neo4j Browser run `MATCH (p:Person)-[r]->(q:Person) RETURN p,r,q LIMIT 5;` to confirm the edge exists.
|
||||
</Info>
|
||||
|
||||
<Note>
|
||||
Graph Memory enriches responses by adding related entities in the `relations` key. The ordering of `results` always comes from vector search (plus any reranker you configure); graph edges do not reorder those hits automatically.
|
||||
</Note>
|
||||
|
||||
## Operate Graph Memory Day-to-Day
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Refine extraction prompts">
|
||||
Guide which relationships become nodes and edges.
|
||||
|
||||
<CodeGroup>
|
||||
```python Python
|
||||
import os
|
||||
from mem0 import Memory
|
||||
|
||||
config = {
|
||||
"graph_store": {
|
||||
"provider": "neo4j",
|
||||
"config": {
|
||||
"url": os.environ["NEO4J_URL"],
|
||||
"username": os.environ["NEO4J_USERNAME"],
|
||||
"password": os.environ["NEO4J_PASSWORD"],
|
||||
},
|
||||
"custom_prompt": "Please only capture people, organisations, and project links.",
|
||||
}
|
||||
}
|
||||
|
||||
memory = Memory.from_config(config_dict=config)
|
||||
```
|
||||
|
||||
```typescript TypeScript
|
||||
import { Memory } from "mem0ai/oss";
|
||||
|
||||
const config = {
|
||||
graphStore: {
|
||||
provider: "neo4j",
|
||||
config: {
|
||||
url: process.env.NEO4J_URL!,
|
||||
username: process.env.NEO4J_USERNAME!,
|
||||
password: process.env.NEO4J_PASSWORD!,
|
||||
},
|
||||
customInstructions: "Please only capture people, organisations, and project links.",
|
||||
}
|
||||
};
|
||||
|
||||
const memory = new Memory(config);
|
||||
```
|
||||
</CodeGroup>
|
||||
</Accordion>
|
||||
<Accordion title="Raise the confidence threshold">
|
||||
Keep noisy edges out of the graph by demanding higher extraction confidence.
|
||||
|
||||
```python
|
||||
config["graph_store"]["config"]["threshold"] = 0.75
|
||||
```
|
||||
</Accordion>
|
||||
<Accordion title="Organize multi-agent graphs">
|
||||
Separate or share context across agents and sessions with `user_id`, `agent_id`, and `run_id`.
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript
|
||||
memory.add("I prefer Italian cuisine", { userId: "bob", agentId: "food-assistant" });
|
||||
memory.add("I'm allergic to peanuts", { userId: "bob", agentId: "health-assistant" });
|
||||
memory.add("I live in Seattle", { userId: "bob" });
|
||||
|
||||
const food = await memory.search("What food do I like?", { userId: "bob", agentId: "food-assistant" });
|
||||
const allergies = await memory.search("What are my allergies?", { userId: "bob", agentId: "health-assistant" });
|
||||
const location = await memory.search("Where do I live?", { userId: "bob" });
|
||||
```
|
||||
</CodeGroup>
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
<Note>
|
||||
Monitor graph growth, especially on free tiers, by periodically cleaning dormant nodes: `MATCH (n) WHERE n.lastSeen < date() - duration('P90D') DETACH DELETE n`.
|
||||
</Note>
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Neo4j connection refused">
|
||||
Confirm Bolt connectivity is enabled, credentials match Aura, and your IP is allow-listed. Retry after confirming the URI format is `neo4j+s://...`.
|
||||
</Accordion>
|
||||
<Accordion title="Neptune Analytics rejects requests">
|
||||
Ensure the graph identifier matches the vector dimension used by your embedder and that the IAM role allows `neptune-graph:*DataViaQuery` actions.
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## Decision Points
|
||||
|
||||
- Select the graph store that fits your deployment (managed Aura vs. self-hosted Neo4j vs. AWS Neptune vs. local Kuzu vs. Apache AGE on PostgreSQL).
|
||||
- Decide whether to include a graph store in your config; routine conversations may stay vector-only to save latency.
|
||||
- Set a policy for pruning stale relationships so your graph stays fast and affordable.
|
||||
|
||||
## Provider setup
|
||||
|
||||
Choose your backend and expand the matching panel for configuration details and links.
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Neo4j Aura or self-hosted">
|
||||
Install the APOC plugin for self-hosted deployments, then configure Mem0:
|
||||
|
||||
```typescript
|
||||
import { Memory } from "mem0ai/oss";
|
||||
|
||||
const config = {
|
||||
graphStore: {
|
||||
provider: "neo4j",
|
||||
config: {
|
||||
url: "neo4j+s://<HOST>",
|
||||
username: "neo4j",
|
||||
password: "<PASSWORD>",
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const memory = new Memory(config);
|
||||
```
|
||||
|
||||
Additional docs: [Neo4j Aura Quickstart](https://neo4j.com/docs/aura/), [APOC installation](https://neo4j.com/docs/apoc/current/installation/).
|
||||
</Accordion>
|
||||
<Accordion title="Memgraph (Docker)">
|
||||
Run Memgraph Mage locally with schema introspection enabled:
|
||||
|
||||
```bash
|
||||
docker run -p 7687:7687 memgraph/memgraph-mage:latest --schema-info-enabled=True
|
||||
```
|
||||
|
||||
Then point Mem0 at the instance:
|
||||
|
||||
```python
|
||||
from mem0 import Memory
|
||||
|
||||
config = {
|
||||
"graph_store": {
|
||||
"provider": "memgraph",
|
||||
"config": {
|
||||
"url": "bolt://localhost:7687",
|
||||
"username": "memgraph",
|
||||
"password": "your-password",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
m = Memory.from_config(config_dict=config)
|
||||
```
|
||||
|
||||
Learn more: [Memgraph Docs](https://memgraph.com/docs).
|
||||
</Accordion>
|
||||
<Accordion title="Amazon Neptune Analytics">
|
||||
Match vector dimensions between Neptune and your embedder, enable public connectivity (if needed), and grant IAM permissions:
|
||||
|
||||
```python
|
||||
from mem0 import Memory
|
||||
|
||||
config = {
|
||||
"graph_store": {
|
||||
"provider": "neptune",
|
||||
"config": {
|
||||
"endpoint": "neptune-graph://<GRAPH_ID>",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
m = Memory.from_config(config_dict=config)
|
||||
```
|
||||
|
||||
Reference: [Neptune Analytics Guide](https://docs.aws.amazon.com/neptune/latest/analytics/).
|
||||
</Accordion>
|
||||
<Accordion title="Amazon Neptune DB (with external vectors)">
|
||||
Create a Neptune cluster, enable the public endpoint if you operate outside the VPC, and point Mem0 at the host:
|
||||
|
||||
```python
|
||||
from mem0 import Memory
|
||||
|
||||
config = {
|
||||
"graph_store": {
|
||||
"provider": "neptunedb",
|
||||
"config": {
|
||||
"collection_name": "<VECTOR_COLLECTION_NAME>",
|
||||
"endpoint": "neptune-graph://<HOST_ENDPOINT>",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
m = Memory.from_config(config_dict=config)
|
||||
```
|
||||
|
||||
Reference: [Accessing Data in Neptune DB](https://docs.aws.amazon.com/neptune/latest/userguide/).
|
||||
</Accordion>
|
||||
<Accordion title="Kuzu (embedded)">
|
||||
Kuzu runs in-process, so supply a path (or `:memory:`) for the database file:
|
||||
|
||||
```python
|
||||
config = {
|
||||
"graph_store": {
|
||||
"provider": "kuzu",
|
||||
"config": {
|
||||
"db": "/tmp/mem0-example.kuzu"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Kuzu will clear its state when using `:memory:` once the process exits. See the [Kuzu documentation](https://kuzudb.com/docs/) for advanced settings.
|
||||
</Accordion>
|
||||
<Accordion title="Apache AGE (PostgreSQL extension)">
|
||||
[Apache AGE](https://age.apache.org/) adds graph database capabilities to PostgreSQL, letting you run Cypher queries alongside SQL on the same server. Start AGE via Docker, then configure Mem0:
|
||||
|
||||
```bash
|
||||
docker run --name age-postgres \
|
||||
-e POSTGRES_DB=mem0_db \
|
||||
-e POSTGRES_USER=mem0_user \
|
||||
-e POSTGRES_PASSWORD=mem0_pass \
|
||||
-p 5432:5432 \
|
||||
-d apache/age
|
||||
```
|
||||
|
||||
```python
|
||||
from mem0 import Memory
|
||||
|
||||
config = {
|
||||
"graph_store": {
|
||||
"provider": "apache_age",
|
||||
"config": {
|
||||
"host": "localhost",
|
||||
"port": 5432,
|
||||
"database": "mem0_db",
|
||||
"username": "mem0_user",
|
||||
"password": "mem0_pass",
|
||||
"graph_name": "mem0_graph",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
m = Memory.from_config(config_dict=config)
|
||||
```
|
||||
|
||||
Apache AGE does not have a built-in vector index, so similarity search is computed client-side. This works well for moderate graph sizes; for very large graphs consider pairing AGE with pgvector for the vector store.
|
||||
|
||||
Reference: [Apache AGE documentation](https://age.apache.org/age-manual/master/index.html).
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card
|
||||
title="Enhanced Metadata Filtering"
|
||||
description="Blend field-level filters with graph context to zero in on the right memories."
|
||||
icon="funnel"
|
||||
href="/open-source/features/metadata-filtering"
|
||||
/>
|
||||
<Card
|
||||
title="Reranker-Enhanced Search"
|
||||
description="Layer rerankers on top of vectors and graphs for the cleanest results."
|
||||
icon="sparkles"
|
||||
href="/open-source/features/reranker-search"
|
||||
/>
|
||||
</CardGroup>
|
||||
@@ -41,7 +41,7 @@ messages = [
|
||||
|
||||
chat_completion = client.chat.completions.create(
|
||||
messages=messages,
|
||||
model="gpt-4.1-nano-2025-04-14",
|
||||
model="gpt-5-mini",
|
||||
user_id="alice"
|
||||
)
|
||||
```
|
||||
@@ -69,7 +69,7 @@ client = Mem0(config=config)
|
||||
|
||||
chat_completion = client.chat.completions.create(
|
||||
messages=[{"role": "user", "content": "What's the capital of France?"}],
|
||||
model="gpt-4.1-nano-2025-04-14"
|
||||
model="gpt-5-mini"
|
||||
)
|
||||
```
|
||||
|
||||
@@ -85,14 +85,14 @@ client = Mem0(api_key="m0-xxx")
|
||||
# Store preferences
|
||||
client.chat.completions.create(
|
||||
messages=[{"role": "user", "content": "I love Indian food but I'm allergic to cheese."}],
|
||||
model="gpt-4.1-nano-2025-04-14",
|
||||
model="gpt-5-mini",
|
||||
user_id="alice"
|
||||
)
|
||||
|
||||
# Later conversation reuses the memory
|
||||
response = client.chat.completions.create(
|
||||
messages=[{"role": "user", "content": "Suggest dinner options in San Francisco."}],
|
||||
model="gpt-4.1-nano-2025-04-14",
|
||||
model="gpt-5-mini",
|
||||
user_id="alice"
|
||||
)
|
||||
|
||||
|
||||
@@ -15,9 +15,6 @@ Mem0 Open Source ships with capabilities that adapt memory behavior for producti
|
||||
## Choose your path
|
||||
|
||||
<CardGroup cols={3}>
|
||||
<Card title="Graph Memory" icon="network-wired" href="/open-source/features/graph-memory">
|
||||
Store entity relationships for multi-hop recall.
|
||||
</Card>
|
||||
<Card title="Advanced Metadata Filtering" icon="filter" href="/open-source/features/metadata-filtering">
|
||||
Query with logical operators and nested conditions.
|
||||
</Card>
|
||||
@@ -35,10 +32,7 @@ Mem0 Open Source ships with capabilities that adapt memory behavior for producti
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
<CardGroup cols={3}>
|
||||
<Card title="Custom Memory Updates" icon="arrows-rotate" href="/open-source/features/custom-update-memory-prompt">
|
||||
Control memory refinement with custom instructions.
|
||||
</Card>
|
||||
<CardGroup cols={2}>
|
||||
<Card title="REST API" icon="code" href="/open-source/features/rest-api">
|
||||
HTTP endpoints for language-agnostic integrations.
|
||||
</Card>
|
||||
|
||||
@@ -222,7 +222,7 @@ config = {
|
||||
def smart_search(query, user_id, use_rerank=None):
|
||||
if use_rerank is None:
|
||||
use_rerank = len(query.split()) > 3
|
||||
return m.search(query, user_id=user_id, rerank=use_rerank)
|
||||
return m.search(query, filters={"user_id": user_id}, rerank=use_rerank)
|
||||
```
|
||||
|
||||
<Tip>
|
||||
@@ -233,10 +233,10 @@ def smart_search(query, user_id, use_rerank=None):
|
||||
|
||||
```python
|
||||
try:
|
||||
results = m.search("test query", user_id="alice", rerank=True)
|
||||
results = m.search("test query", filters={"user_id": "alice"}, rerank=True)
|
||||
except Exception as exc:
|
||||
print(f"Reranking failed: {exc}")
|
||||
results = m.search("test query", user_id="alice", rerank=False)
|
||||
results = m.search("test query", filters={"user_id": "alice"}, rerank=False)
|
||||
```
|
||||
|
||||
<Warning>
|
||||
@@ -247,7 +247,7 @@ except Exception as exc:
|
||||
|
||||
```python
|
||||
# Before: basic vector search
|
||||
results = m.search("query", user_id="alice")
|
||||
results = m.search("query", filters={"user_id": "alice"})
|
||||
|
||||
# After: same API with reranking enabled via config
|
||||
config = {
|
||||
@@ -260,7 +260,7 @@ config = {
|
||||
}
|
||||
|
||||
m = Memory.from_config(config)
|
||||
results = m.search("query", user_id="alice")
|
||||
results = m.search("query", filters={"user_id": "alice"})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user