[docs] Essential cookbook added and overall revamp to the structure of cookbooks (#3668)

This commit is contained in:
Parth Sharma
2025-10-27 00:19:29 +05:30
committed by GitHub
parent 2c18355dd2
commit 7be32641c7
46 changed files with 3356 additions and 226 deletions
@@ -0,0 +1,525 @@
---
title: Build a Mem0 Companion
description: "Spin up a fitness coach that remembers goals, adapts tone, and keeps sessions personal."
---
Essentially, creating a companion out of LLMs is as simple as a loop. But these loops work great for one type of character without personalization and fall short as soon as you restart the chat.
Problem: LLMs are stateless. GPT doesn't remember conversations. You could stuff everything inside the context window, but that becomes slow, expensive, and breaks at scale.
The solution: Mem0. It extracts and stores what matters from conversations, then retrieves it when needed. Your companion remembers user preferences, past events, and history.
In this cookbook we'll build a **fitness companion** that:
- Remembers user goals across sessions
- Recalls past workouts and progress
- Adapts its personality based on user preferences
- Handles both short-term context (today's chat) and long-term memory (months of history)
By the end, you'll have a working fitness companion and know how to handle common production challenges.
---
## The Basic Loop with Memory
Max wants to train for a marathon. He starts chatting with Ray, an AI running coach.
```python
from openai import OpenAI
from mem0 import MemoryClient
openai_client = OpenAI(api_key="your-openai-key")
mem0_client = MemoryClient(api_key="your-mem0-key")
def chat(user_input, user_id):
# Retrieve relevant memories
memories = mem0_client.search(user_input, user_id=user_id, limit=5)
context = "\\n".join(m["memory"] for m in memories["results"])
# Call LLM with memory context
response = openai_client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": f"You're Ray, a running coach. Memories:\\n{context}"},
{"role": "user", "content": user_input}
]
).choices[0].message.content
# Store the exchange
mem0_client.add([
{"role": "user", "content": user_input},
{"role": "assistant", "content": response}
], user_id=user_id)
return response
```
**Session 1:**
```python
chat("I want to run a marathon in under 4 hours", user_id="max")
# Output: "That's a solid goal. What's your current weekly mileage?"
# Stored in Mem0: "Max wants to run sub-4 marathon"
```
**Session 2 (next day, app restarted):**
```python
chat("What should I focus on today?", user_id="max")
# Output: "Based on your sub-4 marathon goal, let's work on building your aerobic base..."
```
<Info>
Ray remembers Max's goal across sessions. The app restarted, but the memory persisted. This is the core pattern: retrieve memories, pass them as context, store new exchanges.
</Info>
Ray remembers. Restart the app, and the goal persists. From here on, we'll focus on just the Mem0 API calls.
---
## Organizing Memory by Type
### Separating Temporary from Permanent
Max mentions his knee hurts. That's different from his marathon goal - one is temporary, the other is long-term.
**Categories vs Metadata:**
- **Categories**: AI-assigned by Mem0 based on content (you can't force them)
- **Metadata**: Manually set by you for forced tagging
Define custom categories at the project level. Mem0 will automatically tag memories with relevant categories based on content:
```python
mem0_client.project.update(custom_categories=[
{"goals": "Race targets and training objectives"},
{"constraints": "Injuries, limitations, recovery needs"},
{"preferences": "Training style, surfaces, schedules"}
])
```
<Note>
**Categories vs Metadata:** Categories are AI-assigned by Mem0 based on content semantics. You define the palette, Mem0 picks which ones apply. If you need guaranteed tagging, use `metadata` instead.
</Note>
Now when you add memories, Mem0 automatically assigns the appropriate categories:
```python
# Add goal - Mem0 automatically tags it as "goals"
mem0_client.add(
[{"role": "user", "content": "Sub-4 marathon is my A-race"}],
user_id="max"
)
# Add constraint - Mem0 automatically tags it as "constraints"
mem0_client.add(
[{"role": "user", "content": "My right knee flares up on downhills"}],
user_id="max"
)
```
Mem0 reads the content and intelligently picks which categories apply. You define the palette, it handles the tagging.
**Important:** You cannot force specific categories. Mem0's platform decides which categories are relevant based on content. If you need to force-tag something, use `metadata` instead:
```python
# Force tag using metadata (not categories)
mem0_client.add(
[{"role": "user", "content": "Some workout note"}],
user_id="max",
metadata={"workout_type": "speed", "forced_tag": "custom_label"}
)
```
### Filtering by Category
Retrieve just constraints for workout planning:
```python
constraints = mem0_client.search(
"injury concerns",
user_id="max",
filters={"categories": {"in": ["constraints"]}}
)
print([m["memory"] for m in constraints["results"]])
# Output: ["Max's right knee flares up on downhills"]
```
Ray can plan workouts that avoid aggravating Max's knee, without pulling in race goals or other unrelated memories.
---
## Filtering What Gets Stored
### The Problem
Run the basic loop for a week and check what's stored:
```python
memories = mem0_client.get_all(user_id="max")
print([m["memory"] for m in memories["results"]])
# Output: ["Max wants to run marathon under 4 hours", "hey", "lol ok", "cool thanks", "gtg bye"]
```
<Warning>
Without filters, Mem0 stores everything—greetings, filler, and casual chat. This pollutes retrieval: instead of pulling "marathon goal," you get "lol ok." Set custom instructions to keep memory clean.
</Warning>
Noise. Greetings and filler clutter the memory.
### Custom Instructions
Tell Mem0 what matters:
```python
mem0_client.project.update(custom_instructions="""
Extract from running coach conversations:
- Training goals and race targets
- Physical constraints or injuries
- Training preferences (time of day, surfaces, weather)
- Progress milestones
Exclude:
- Greetings and filler
- Casual chatter
- Hypotheticals unless planning related
""")
```
Now chat again:
```python
chat("hey how's it going", user_id="max")
chat("I prefer trail running over roads", user_id="max")
memories = mem0_client.get_all(user_id="max")
print([m["memory"] for m in memories["results"]])
# Output: ["Max wants to run marathon under 4 hours", "Max prefers trail running over roads"]
```
<Info>
**Expected output:** Only 2 memories stored—the marathon goal and trail preference. The greeting "hey how's it going" was filtered out automatically. Custom instructions are working.
</Info>
Only meaningful facts. Filler gets dropped automatically.
---
---
## Agent Memory for Personality
### Why Agents Need Memory Too
Max prefers direct feedback, not motivational fluff. Ray needs to remember how to communicate - that's agent memory, separate from user memory.
Store agent personality:
```python
mem0_client.add(
[{"role": "system", "content": "Max wants direct, data-driven feedback. Skip motivational language."}],
agent_id="ray_coach"
)
```
Retrieve agent style alongside user memories:
```python
# Get coach personality
agent_memories = mem0_client.search("coaching style", agent_id="ray_coach")
# Output: ["Max wants direct, data-driven feedback. Skip motivational language."]
# Store conversations with agent_id
mem0_client.add([
{"role": "user", "content": "How'd my run look today?"},
{"role": "assistant", "content": "Pace was 8:15/mile. Heart rate 152, zone 2."}
], user_id="max", agent_id="ray_coach")
```
<Info>
**Expected behavior:** Ray's responses are now data-driven and direct. The agent memory stored the coaching style preference, so future responses adapt automatically without Max having to repeat his preference.
</Info>
No "Great job!" or "Keep it up!" - just data. Ray adapts to Max's preference.
---
## Managing Short-Term Context
### When to Store in Mem0
Don't send every single message to Mem0. Keep recent context in memory, let Mem0 handle the important long-term facts.
```python
# Store only meaningful exchanges in Mem0
mem0_client.add([
{"role": "user", "content": "I want to run a marathon"},
{"role": "assistant", "content": "Let's build a training plan"}
], user_id="max")
# Skip storing filler
# "hey" → don't store
# "cool thanks" → don't store
# Or rely on custom_instructions to filter automatically
```
Last 10 messages in your app's buffer. Important facts in Mem0. Faster, cheaper, still works.
---
## Time-Bound Memories
### Auto-Expiring Facts
Max tweaks his ankle. It'll heal in two weeks - the memory should expire too.
```python
from datetime import datetime, timedelta
expiration = (datetime.now() + timedelta(days=14)).strftime("%Y-%m-%d")
mem0_client.add(
[{"role": "user", "content": "Rolled my left ankle, needs rest"}],
user_id="max",
expiration_date=expiration
)
```
In 14 days, this memory disappears automatically. Ray stops asking about the ankle.
---
## Putting It All Together
Here's the Mem0 setup combining everything:
```python
from mem0 import MemoryClient
from datetime import datetime, timedelta
mem0_client = MemoryClient(api_key="your-mem0-key")
# Configure memory filtering and categories
mem0_client.project.update(
custom_instructions="""
Extract: goals, constraints, preferences, progress
Exclude: greetings, filler, casual chat
""",
custom_categories=[
{"name": "goals", "description": "Training targets"},
{"name": "constraints", "description": "Injuries and limitations"},
{"name": "preferences", "description": "Training style"}
]
)
```
**Week 1 - Store goals and preferences:**
```python
mem0_client.add([
{"role": "user", "content": "I want to run a sub-4 marathon"},
{"role": "assistant", "content": "Got it. Let's build a training plan."}
], user_id="max", agent_id="ray", categories=["goals"])
mem0_client.add([
{"role": "user", "content": "I prefer trail running over roads"}
], user_id="max", categories=["preferences"])
```
**Week 3 - Temporary injury with expiration:**
```python
expiration = (datetime.now() + timedelta(days=14)).strftime("%Y-%m-%d")
mem0_client.add(
[{"role": "user", "content": "Rolled ankle, need light workouts"}],
user_id="max",
categories=["constraints"],
expiration_date=expiration
)
```
**Retrieve for context:**
```python
memories = mem0_client.search("training plan", user_id="max", limit=5)
# Gets: marathon goal, trail preference, ankle injury (if still valid)
```
Ray remembers goals, preferences, and personality. Handles temporary injuries. Works across sessions.
---
## Common Production Patterns
### Episodic Stories with run_id
Training for Boston is different from training for New York. Separate the memory threads:
```python
mem0_client.add(messages, user_id="max", run_id="boston-2025")
mem0_client.add(messages, user_id="max", run_id="nyc-2025")
# Retrieve only Boston memories
boston_memories = mem0_client.search(
"training plan",
user_id="max",
run_id="boston-2025"
)
```
Each race gets its own episodic boundary. No cross-contamination.
### Importing Historical Data
Max has 6 months of training logs to backfill:
```python
old_logs = [
[{"role": "user", "content": "Completed 20-mile long run"}],
[{"role": "user", "content": "Hit 8:00 pace on tempo run"}],
]
for log in old_logs:
mem0_client.add(log, user_id="max")
```
### Handling Contradictions
Max changes his goal from sub-4 to sub-3:45:
```python
# Find the old memory
memories = mem0_client.get_all(user_id="max")
goal_memory = [m for m in memories["results"] if "sub-4" in m["memory"]][0]
# Update it
mem0_client.update(goal_memory["id"], "Max wants to run sub-3:45 marathon")
```
Update instead of creating duplicates.
### Multiple Agents
Max works with Ray for running and Jordan for strength training:
```python
chat("easy run today", user_id="max", agent_id="ray")
chat("leg day workout", user_id="max", agent_id="jordan")
```
Each coach maintains separate personality memory while sharing user context.
### Filtering by Date
Prioritize recent training over old data:
```python
recent = mem0_client.search(
"training progress",
user_id="max",
filters={"created_at": {"gte": "2025-10-01"}}
)
```
### Metadata Tagging
Tag workouts by type:
```python
mem0_client.add(
[{"role": "user", "content": "10x400m intervals"}],
user_id="max",
metadata={"workout_type": "speed", "intensity": "high"}
)
# Later, find all speed workouts
speed_sessions = mem0_client.search(
"speed work",
user_id="max",
filters={"metadata": {"workout_type": "speed"}}
)
```
### Pruning Old Memories
Delete irrelevant memories:
```python
mem0_client.delete(memory_id="mem_xyz")
# Or clear an entire run_id
mem0_client.delete_all(user_id="max", run_id="old-training-cycle")
```
---
## What You Built
A companion that:
- **Persists across sessions** - Mem0 storage
- **Filters noise** - custom instructions
- **Organizes by type** - categories
- **Adapts personality** - **`agent_id`**
- **Stays fast** - short-term buffer
- **Handles temporal facts** - expiration
- **Scales to production** - batching, metadata, pruning
This pattern works for any companion: fitness coaches, tutors, roleplay characters, therapy bots, creative writing partners.
---
<Tip>
Start with 2-3 categories max (e.g., goals, constraints, preferences). More categories dilute tagging accuracy. You can always add more later after seeing what Mem0 extracts.
</Tip>
---
## Production Checklist
Before launching:
- Set custom instructions for your domain
- Define 2-3 categories (goals, constraints, preferences)
- Add expiration strategy for time-bound facts
- Implement error handling for API calls
- Monitor memory quality in Mem0 dashboard
- Clear test data from production project
---
<CardGroup cols={2}>
<Card title="Build AI with Personality" icon="sparkles" href="/cookbooks/essentials/building-ai-with-personality">
Separate user and agent memories so companions stay consistent across sessions.
</Card>
<Card title="Tag Support Memories" icon="tag" href="/cookbooks/essentials/tagging-and-organizing-memories">
Organize customer context to keep assistants responsive at scale.
</Card>
</CardGroup>
@@ -0,0 +1,603 @@
---
title: Scope User vs Agent Memories
description: "Use **user_id** and **agent_id** to balance personalization with consistent assistant behavior."
---
# Build AI with Distinct Personalities
While building memory systems for AI apps, you need to juggle between agent and user memories. The user delivers information from their side, but there's often value inside the agent's responses as well.
Unlike other memory APIs, we built one that allows you the flexibility to store memory from all sources. User and agent memories in Mem0 are handled by:
- **user_id** - Memories about specific users
- **agent_id** - Memories from the agent itself
In this guide, you'll see how these parameters work together, along with practical examples to help you build a fitness coach that remembers user workouts while maintaining a consistent coaching personality.
---
## User Memories
Let's start by tracking individual user workouts. We'll use **`user_id`** to keep each person's data separate.
```python
from openai import OpenAI
from mem0 import MemoryClient
import os
openai_client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
mem0_client = MemoryClient()
# Sarah logs her workout
mem0_client.add(
"Completed 5K run in 28 minutes - felt great!",
user_id="sarah"
)
# Mike logs his workout
mem0_client.add(
"Bench press: 185 lbs x 10 reps, 3 sets",
user_id="mike"
)
```
Now when we coach Sarah, we retrieve only her workout history:
```python
# Get Sarah's workout history
sarah_history = mem0_client.search(
"What exercises has Sarah done recently?",
filters={"user_id": "sarah"}
)
# Generate coaching advice
response = openai_client.chat.completions.create(
model="gpt-4",
messages=[
{"role": "system", "content": "You're a supportive fitness coach."},
{"role": "user", "content": f"Based on this history: {sarah_history}, suggest the next workout."}
]
)
print(response.choices[0].message.content)
```
**Output:**
```
Great job on that 5K! Your endurance is building nicely. Let's add some
strength work to complement your running. Try 3 sets of bodyweight squats
(15 reps each) to strengthen your legs and improve your running power.
```
<Info>
**Expected output:** Sarah gets running advice based on her 5K, not Mike's bench press data. The **`user_id`** filter ensures memories are isolated—each user only sees their own workout history.
</Info>
This works perfectly! Each user has private workout history, and Sarah never sees Mike's data.
---
## Adding Coach Personality
Our fitness coach needs a consistent personality - supportive, motivational, and celebrates small wins. Let's see what happens if we try storing this with **`user_id`**:
```python
# Adding coach personality for Sarah
mem0_client.add(
"I'm a supportive fitness coach who celebrates every achievement and uses athlete-focused language",
user_id="sarah"
)
# Adding the same personality for Mike
mem0_client.add(
"I'm a supportive fitness coach who celebrates every achievement and uses athlete-focused language",
user_id="mike"
)
# For 1,000 users, we'd repeat this 1,000 times...
```
This approach has some limitations:
1. **Duplication**: We're storing the same coaching personality 1,000 times for 1,000 users
2. **Hard to update**: Want to change the coaching style? Update 1,000 memories
3. **Mixed with user data**: Coach personality and user workouts are stored together, making queries complex
<Warning>
Storing agent personality with **`user_id`** doesn't scale. For 10,000 users, you'd duplicate the same personality 10,000 times. Updating the coaching style means updating 10,000 separate memories. This wastes storage and makes maintenance impossible.
</Warning>
What if the coach could have a personality that's shared across all users?
---
## Agent Memories
Here's where **`agent_id`** comes in. We can store the coach's personality once and share it across all users:
```python
# Store coach personality ONCE with agent_id
mem0_client.add(
"I'm FitCoach - a supportive fitness coach who celebrates every achievement. "
"I use motivational language, focus on progress over perfection, and help users build sustainable habits.",
agent_id="fitcoach_v1"
)
# Sarah's workout (still private)
mem0_client.add(
"Completed 5K run in 28 minutes",
user_id="sarah"
)
# Mike's workout (still private)
mem0_client.add(
"Bench press: 185 lbs x 10 reps, 3 sets",
user_id="mike"
)
```
Now when coaching Sarah, we retrieve both the agent's personality AND her workout history:
```python
# Get both coach personality and Sarah's workouts
coaching_context = mem0_client.search(
"coaching context for Sarah",
filters={
"OR": [
{"agent_id": "fitcoach_v1"}, # Coach personality
{"user_id": "sarah"} # Sarah's workout history
]
}
)
# Generate personalized coaching
response = openai_client.chat.completions.create(
model="gpt-4",
messages=[
{"role": "system", "content": str(coaching_context)},
{"role": "user", "content": "What should I focus on in my next workout?"}
]
)
print(response.choices[0].message.content)
```
**Output:**
```
Amazing work on that 5K! 🎉 You're crushing your running goals!
Now let's build some complementary strength. I recommend adding bodyweight
squats to your routine - they'll make you an even stronger runner. Start
with 3 sets of 15 reps, and remember: progress over perfection!
```
Notice how the response has the motivational tone (from **`agent_id`**) combined with personalized advice based on Sarah's 5K run (from **`user_id`**).
The coach personality is now:
- ✅ Stored once, shared by all users
- ✅ Easy to update (change one memory, affects all users)
- ✅ Cleanly separated from user workout data
<Info>
**Expected behavior:** The response combines the motivational tone (from **`agent_id`**) with Sarah's specific 5K progress (from **`user_id`**). One agent personality, infinite users—update the agent once, and all users get the new coaching style.
</Info>
---
## Combining Both: Relationship Memories
There's a third type of memory - one that captures the relationship between a specific user and the coach. To store these, use `metadata` to track which agent the relationship is with:
```python
# Coach personality (shared across all users)
mem0_client.add(
"I'm FitCoach - supportive and motivational",
agent_id="fitcoach_v1"
)
# Sarah's workout data (private to Sarah)
mem0_client.add(
"Goal: Run a half marathon by June. Currently runs 5K comfortably.",
user_id="sarah"
)
# Sarah-Coach relationship (stored as user memory with agent context in metadata)
mem0_client.add(
"Sarah and I have an inside joke: 'No pain, no protein shake!' "
"She responds best to gentle encouragement after tough workouts.",
user_id="sarah",
metadata={"agent_id": "fitcoach_v1", "type": "relationship"}
)
# Mike-Coach relationship (different from Sarah's)
mem0_client.add(
"Mike prefers data-driven feedback with specific numbers and percentages. "
"Less motivational talk, more concrete metrics.",
user_id="mike",
metadata={"agent_id": "fitcoach_v1", "type": "relationship"}
)
```
Now when coaching Sarah, retrieve her data including relationship with this specific coach:
```python
# Get Sarah's memories including relationship with fitcoach_v1
sarah_context = mem0_client.search(
"How should I coach Sarah today?",
user_id="sarah",
filters={"metadata": {"agent_id": "fitcoach_v1"}}
)
# Get coach personality
coach_personality = mem0_client.search(
"coaching personality",
agent_id="fitcoach_v1"
)
# Combine both contexts
full_context = str(coach_personality) + "\\n" + str(sarah_context)
response = openai_client.chat.completions.create(
model="gpt-4",
messages=[
{"role": "system", "content": full_context},
{"role": "user", "content": "Just finished today's workout!"}
]
)
print(response.choices[0].message.content)
```
**Output:**
```
Awesome work today! 💪 No pain, no protein shake, right? 😄
You're making real progress toward that half marathon goal. Keep this
momentum going - your consistency is your superpower!
```
When coaching Mike with the same approach:
```python
# Get Mike's memories including relationship with fitcoach_v1
mike_context = mem0_client.search(
"How should I coach Mike today?",
user_id="mike",
filters={"metadata": {"agent_id": "fitcoach_v1"}}
)
coach_personality = mem0_client.search(
"coaching personality",
agent_id="fitcoach_v1"
)
full_context = str(coach_personality) + "\\n" + str(mike_context)
# ... same coaching code ...
```
**Output:**
```
Solid session. Your bench press shows 8% improvement over last week
(171 lbs avg to 185 lbs). Target: 200 lbs by end of month.
On track at current rate (+3.2% weekly).
```
Same coach, completely different experience based on each user's relationship preferences stored in metadata.
<Note>
**Relationship memories** are stored with **`user_id`** (they're private to each user) but include `agent_id` in metadata to track which agent the relationship is with. This lets you retrieve the user's preferences for how this specific agent should interact with them.
</Note>
---
## Putting It All Together
Here's a complete example showing all three memory layers working together:
```python
from openai import OpenAI
from mem0 import MemoryClient
import os
# Initialize clients
openai_client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
mem0_client = MemoryClient()
# Layer 1: Agent personality (shared)
mem0_client.add(
"I'm FitCoach - supportive, motivational, celebrates small wins",
agent_id="fitcoach_v1",
metadata={"type": "personality"}
)
# Layer 2: User profile (private)
mem0_client.add(
"Sarah's goal: Run half marathon by June. Currently comfortable at 5K distance.",
user_id="sarah",
metadata={"type": "profile"}
)
# Layer 3: Relationship (stored as user memory with agent context in metadata)
mem0_client.add(
"Sarah responds best to encouragement. Inside joke: 'No pain, no protein shake!'",
user_id="sarah",
metadata={"agent_id": "fitcoach_v1", "type": "relationship"}
)
# Log today's workout
mem0_client.add(
"Completed 8K run in 45 minutes - new personal record!",
user_id="sarah",
metadata={"type": "workout", "date": "2025-01-23"}
)
# Generate coaching response
# Get Sarah's context (includes all her memories)
sarah_context = mem0_client.search(
"Generate coaching advice for Sarah",
user_id="sarah"
)
# Get coach personality
coach_personality = mem0_client.search(
"coaching personality",
agent_id="fitcoach_v1"
)
# Combine contexts
full_context = str(coach_personality) + "\\n" + str(sarah_context)
response = openai_client.chat.completions.create(
model="gpt-4",
messages=[
{"role": "system", "content": full_context},
{"role": "user", "content": "Just finished my run today!"}
]
)
print(response.choices[0].message.content)
```
**Output:**
```
🎉 YES! 8K is a HUGE milestone! You just crushed your previous distance!
Remember when you could barely do 5K? Look at you now! That half marathon
in June is looking more achievable every single day. No pain, no protein
shake - and today, you EARNED that shake! 💪
Next week, let's aim for 9K. You're ready for it!
```
The response combines:
- ✅ Motivational tone (agent personality)
- ✅ Specific goal reference (Sarah's profile)
- ✅ Inside joke (relationship memory)
- ✅ Progress tracking (workout history)
---
![image.png](building_ai_with_personality%20295f22c70c908182affdfc87ec79f2db/image.png)
**Three memory layers:**
1. **Agent memories** (blue) - Shared personality and capabilities
2. **User memories** (red) - Private workout data and goals
3. **Relationship memories** (purple) - User memories with agent context stored in metadata
---
## When to Use What
### Use **`user_id`** only (most apps)
**Best for:** Apps that just need to track user-specific data without AI personality
**Examples:**
- Todo lists
- Note-taking apps
- Personal finance trackers
- Support ticket history
```python
mem0_client.add(
"Bought groceries for $127.43",
user_id="sarah"
)
```
---
### Use **`agent_id`** only (rare)
**Best for:** AI tools that work the same for everyone, no user-specific data
**Examples:**
- Calculator bots
- Language translators
- Company policy assistants (same policies for all)
```python
mem0_client.add(
"I can calculate: arithmetic, algebra, basic calculus. I cannot solve differential equations.",
agent_id="calculator_v1"
)
```
---
### Use both **`user_id`** and **`agent_id`** (AI with personality)
**Best for:** AI agents with persistent personalities that remember individual users
**Examples:**
- Fitness coaches (this guide!)
- Educational tutors
- AI companions
- Therapy/mental health bots
- Game NPCs with character development
```python
# Agent personality (shared across all users)
mem0_client.add(
"Coaching personality and style",
agent_id="agent_name"
)
# User data (private)
mem0_client.add(
"User's goals and progress",
user_id="user_name"
)
# Relationship (user memory with agent context in metadata)
mem0_client.add(
"User's relationship with this specific agent",
user_id="user_name",
metadata={"agent_id": "agent_name", "type": "relationship"}
)
```
---
<Tip>
**When to combine user_id + agent_id:** Use both when your AI has a consistent personality that should work the same for everyone (agent_id), while also tracking individual user data (user_id). Most personal AI assistants, coaches, and tutors fit this pattern.
</Tip>
---
## Best Practices
### 1. Use clear naming conventions
```python
# Good: Descriptive and versioned
agent_id="fitcoach_v1"
user_id="sarah_123"
# Bad: Generic and unclear
agent_id="agent1"
user_id="user_abc"
```
### 2. Tag memories with metadata
```python
# For relationship memories, store agent context in metadata
mem0_client.add(
content,
user_id="sarah",
metadata={
"agent_id": "fitcoach_v1",
"type": "relationship",
"version": "v1"
}
)
```
### 3. Test data isolation
Ensure users never see each other's data:
```python
# Get Mike's memories
mike_memories = mem0_client.get_all(filters={"user_id": "mike"})
# Get Sarah's memories
sarah_memories = mem0_client.get_all(filters={"user_id": "sarah"})
# Verify no overlap
assert len(set(mike_memories) & set(sarah_memories)) == 0, "Data leak detected!"
```
### 4. Version your agents
Allows A/B testing different coaching styles:
```python
# Version 1: Gentle and encouraging
mem0_client.add(
"I'm supportive and celebrate small wins",
agent_id="fitcoach_v1"
)
# Version 2: Data-driven and metric-focused
mem0_client.add(
"I provide concrete metrics and percentage improvements",
agent_id="fitcoach_v2"
)
# Assign users to different versions by storing version in metadata
mem0_client.add(
"Sarah's workout preferences and relationship with coach",
user_id="sarah",
metadata={"agent_id": "fitcoach_v1"}
)
mem0_client.add(
"Mike's workout preferences and relationship with coach",
user_id="mike",
metadata={"agent_id": "fitcoach_v2"}
)
```
---
## What You Built
A fitness coach with three-layer memory architecture:
- **Agent personality (agent_id)** - Shared coaching style across all users, updated once
- **User profiles (user_id)** - Private workout history, goals, and progress for each person
- **Relationship memories (user_id + metadata)** - Personalized interaction preferences per user-agent pair
- **Data isolation** - Sarah never sees Mike's workouts, guaranteed by user_id filtering
This pattern scales from 10 to 10,000 users without duplicating agent personality.
---
## Summary
With Mem0's **`user_id`** and **`agent_id`** parameters, you can build AI agents that maintain consistent personalities across all users while remembering individual user data privately. Store relationship preferences with **`user_id`** and track agent context in metadata.
Most apps only need **`user_id`**. Add **`agent_id`** when your AI needs a consistent personality that evolves independently from user data—fitness coaches, tutors, therapy bots, and game NPCs all fit this pattern.
<CardGroup cols={2}>
<Card title="Control What Gets Stored" icon="filter" href="/cookbooks/essentials/controlling-memory-ingestion">
Filter low-signal conversations before they pollute long-term memory.
</Card>
<Card title="Organize Support Memories" icon="tag" href="/cookbooks/essentials/tagging-and-organizing-memories">
Categorize customer context so teams can retrieve the right facts fast.
</Card>
</CardGroup>
Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

@@ -0,0 +1,361 @@
---
title: Choose Vector vs Graph Memory
description: "Blend vector search with graph relationships to answer multi-hop questions."
---
Most AI agents use vector stores for RAG operations - they work great for semantic search and retrieving relevant context. But there's a gap when queries require understanding connections between entities.
Mem0 brings graph memory into the picture to fill this gap. In this cookbook, we'll create a company knowledge base with Mem0, using both vector and graph stores. You'll learn when each one helps along the way.
---
## Vector and Graph Stores
When you add a memory to Mem0, it goes into a **vector store** by default. Vector stores are excellent at semantic search - finding memories that match the meaning of your query.
**Graph stores** work differently. They extract **entities** (people, projects, teams) and **relationships between them** (works_with, reports_to, member_of). This lets you answer questions that need connecting information across multiple memories.
We will go through examples in this cookbook while building a company's knowledge base along the way.
---
## Starting Simple
Since we're building a company knowledge base, let's add some employee information:
```python
from mem0 import MemoryClient
client = MemoryClient(api_key="your-api-key")
# Add employee info
client.add("Emma is a software engineer in Seattle", user_id="company_kb")
client.add("David is a product manager in Austin", user_id="company_kb")
```
Now let's search for Emma's role:
```python
results = client.search("What does Emma do?", filters={"user_id": "company_kb"})
print(results['results'][0]['memory'])
```
**Output:**
```
Emma is a software engineer in Seattle
```
<Info>
**Expected output:** Vector search returned Emma's role instantly. When queries ask for facts directly stored in one memory, vector semantic search is perfect—fast and accurate.
</Info>
This works perfectly. Vector search found the memory that semantically matches "What does Emma do?" and returned Emma's role.
---
## Adding Team Structure
Let's add some information about how the team works together:
```python
client.add("Emma works with David on the mobile app redesign", user_id="company_kb")
client.add("David reports to Rachel, who manages the design team", user_id="company_kb")
```
Now we have two pieces of information stored:
1. Emma works with David
2. David reports to Rachel
Let's try asking something that needs both pieces:
```python
results = client.search(
"Who is Emma's teammate's manager?",
filters={"user_id": "company_kb"}
)
for r in results['results']:
print(r['memory'])
```
**Output:**
```
Emma works with David on the mobile app redesign
David reports to Rachel, who manages the design team
```
Vector search returned both memories, but it didn't connect them. You'd need to manually figure out:
- Emma's teammate is David (from memory 1)
- David's manager is Rachel (from memory 2)
- So the answer is Rachel
<Warning>
Vector search can't traverse relationships. It returns relevant memories, but you must connect the dots manually. For "Who is Emma's teammate's manager?", vector search gives you the pieces—not the answer. This breaks down as queries get more complex (3+ hops).
</Warning>
---
## Enter Graph Memory
Let's add the same information with graph memory enabled:
```python
client.add(
"Emma works with David on the mobile app redesign",
user_id="company_kb",
enable_graph=True
)
client.add(
"David reports to Rachel, who manages the design team",
user_id="company_kb",
enable_graph=True
)
```
When you set `enable_graph=True`, Mem0 extracts entities and relationships:
- `emma --[works_with]--> david`
- `david --[reports_to]--> rachel`
- `rachel --[manages]--> design_team`
Now the same query works differently:
```python
results = client.search(
"Who is Emma's teammate's manager?",
filters={"user_id": "company_kb"},
enable_graph=True
)
print(results['results'][0]['memory'])
print("\\nRelationships found:")
for rel in results.get('relations', []):
print(f" {rel['source']}, {rel['target']} ({rel['relationship']})")
```
**Output:**
```
David reports to Rachel, who manages the design team
Relationships found:
emma, david (works_with)
david, rachel (reports_to)
```
<Info>
**Expected behavior:** Graph memory returns the direct answer—"David reports to Rachel"—plus the relationship chain that got there. No manual connecting needed. The graph traversed: Emma → works_with → David → reports_to → Rachel.
</Info>
Graph memory traversed the relationships automatically: Emma works with David, David reports to Rachel, so Rachel is the answer.
---
## How It Connects
Here's what the graph looks like behind the scenes:
```mermaid
graph LR
Emma[Emma] -->|works_with| David[David]
David -->|reports_to| Rachel[Rachel]
Rachel -->|manages| DesignTeam[Design Team]
David -->|works_on| MobileApp[Mobile App]
Emma -->|works_on| MobileApp
```
Graph memory lets you discover relations and memories which are tricky to do with direct vector stores.
Vector search would need the exact words in your query to match. Graph memory follows the connections.
---
## When to Use Each
Use **vector store** (default) when:
- Searching documents by semantic similarity
- Looking up facts that don't need relationships
- Building FAQs or knowledge bases where each item stands alone
Use **graph memory** when:
- Tracking organizational hierarchies (who reports to whom)
- Understanding project teams (who collaborates with whom)
- Building CRMs (which contacts connect to which companies)
- Product recommendations (what items are bought together)
For our company knowledge base, we'll use both:
- Vector for individual facts: "Emma specializes in React"
- Graph for relationships: "Emma works with David"
---
## Putting It Together
Let's build a small company knowledge base with both approaches:
```python
# Facts about individuals - vector store is fine
client.add("Emma specializes in React and TypeScript", user_id="company_kb")
client.add("David has 5 years of product management experience", user_id="company_kb")
# Relationships - use graph memory
client.add(
"Emma and David work together on the mobile app",
user_id="company_kb",
enable_graph=True
)
client.add(
"David reports to Rachel",
user_id="company_kb",
enable_graph=True
)
client.add(
"Rachel runs weekly team syncs every Tuesday",
user_id="company_kb",
enable_graph=True
)
```
Now we can ask different types of questions:
```python
# Direct fact - vector search
results = client.search("What are Emma's skills?", filters={"user_id": "company_kb"})
print(results['results'][0]['memory'])
```
**Output:**
```
Emma specializes in React and TypeScript
```
```python
# Multi-hop relationship - graph search
results = client.search(
"What meetings does Emma's project manager's boss run?",
filters={"user_id": "company_kb"},
enable_graph=True
)
print(results['results'][0]['memory'])
```
**Output:**
```
Rachel runs weekly team syncs every Tuesday
```
Graph memory connected: Emma works with David, David reports to Rachel, Rachel runs team syncs.
<Tip>
Enable graph memory when your queries need multi-hop traversal: org charts (who reports to whom), project teams (who collaborates), CRMs (which contacts connect to companies). For single-fact lookups, stick with vector search—it's faster and cheaper.
</Tip>
---
## The Tradeoff
Graph memory adds processing time and cost. When you call `client.add()` with `enable_graph=True`, Mem0 makes extra LLM calls to extract entities and relationships.
<Note>
**Cost consideration:** Graph memory extraction adds ~2-3 extra LLM calls per `add()` operation to identify entities and relationships. Use it selectively—enable graph for organizational structure and long-term relationships, skip it for temporary notes and simple facts.
</Note>
Use graph memory when the relationship traversal adds real value. For most use cases, vector search is sufficient and faster.
```python
# Long-term organizational structure - worth using graph
client.add(
"Emma mentors two junior engineers on the frontend team",
user_id="company_kb",
enable_graph=True
)
# Temporary notes - skip graph, not worth the cost
client.add(
"Emma is out sick today",
user_id="company_kb",
run_id="daily_notes"
)
```
---
## Enabling Graph Memory
You can enable graph memory in two ways:
**Per-call** (recommended to start):
```python
client.add("Emma works with David", user_id="company_kb", enable_graph=True)
client.search("team structure", filters={"user_id": "company_kb"}, enable_graph=True)
```
**Project-wide** (if most of your data has relationships):
```python
client.project.update(enable_graph=True)
# Now every add uses graph automatically
client.add("Emma mentors Jordan", user_id="company_kb")
```
---
## What You Built
A hybrid company knowledge base that combines both architectures:
- **Vector search** - Fast semantic lookups for individual facts (Emma's skills, David's experience)
- **Graph memory** - Multi-hop relationship traversal (Emma's teammate's manager, project hierarchies)
- **Selective enablement** - Graph only for long-term organizational structure, vector for everything else
- **Cost optimization** - Skip graph extraction for temporary notes and simple facts
This pattern scales from 10-person startups to enterprise org charts with thousands of employees.
---
## Summary
Vector stores handle most memory operations efficiently—semantic search works great for finding relevant information. Add graph memory when your queries need to understand how entities connect across multiple hops.
The key is knowing which tool fits your query pattern: direct questions work with vectors, multi-hop relationship queries need graphs.
<CardGroup cols={2}>
<Card title="Build AI with Personality" icon="sparkles" href="/cookbooks/essentials/building-ai-with-personality">
Scope memories across user and agent IDs to balance personalization and reuse.
</Card>
<Card title="Export Everything Safely" icon="download" href="/cookbooks/essentials/exporting-memories">
Learn how to migrate or audit stored memories with structured exports.
</Card>
</CardGroup>
@@ -0,0 +1,508 @@
---
title: Control Memory Ingestion
description: "Filter speculation, enforce formats, and gate low-confidence data before it persists."
---
AI assistants plugged with memory systems face a problem - they often store everything. Not every conversation needs to be remembered, and not every detail should go to the memory store. Without proper controls, memory systems accumulate unreliable data.
Mem0 lets you control your memory ingestion pipeline. In this cookbook, we'll demonstrate these controls using a medical assistant example - showing how to filter unwanted data, enforce data formats, and implement confidence-based storage.
---
## Overview
Without controls, everything gets stored - speculation, low-confidence data, and information that shouldn't persist. This uncontrolled ingestion leads to cluttered memory and retrieval failures.
Mem0 provides **three tools to control** what gets stored:
1. **Custom instructions** define what to remember and what to ignore.
2. **Confidence thresholds** ensure only verified facts persist.
3. **Memory updates** let you change information without creating duplicates.
In this tutorial, we will:
- Filter speculative statements with custom instructions
- Configure confidence thresholds for fact verification
- Update stored information without duplication
- Build a complete ingestion pipeline
---
## Setup
```python
from mem0 import MemoryClient
client = MemoryClient(api_key="your-api-key")
```
<Note>
Replace `your-api-key` with your actual Mem0 API key from the [dashboard](https://app.mem0.ai). Without proper API authentication, memory operations will fail.
</Note>
---
## The Problem
Uncontrolled ingestion stores everything, including speculation:
```python
# Patient mentions speculation
messages = [{"role": "user", "content": "I think I might be allergic to penicillin"}]
client.add(messages, user_id="patient_123")
# Check what got stored
results = client.search("patient allergies", filters={"user_id": "patient_123"})
print(results['results'][0]['memory'])
```
**Output:**
```
Patient is allergic to penicillin
```
<Warning>
Without custom instructions, AI assistants treat speculation as confirmed facts. "I think I might be allergic" becomes "Patient is allergic"—a dangerous transformation in sensitive domains like healthcare, legal, or financial services.
</Warning>
The speculation became a confirmed fact. Let's add controls.
---
## Custom Instructions
Custom instructions tell Mem0 what to store and what to ignore.
```python
instructions = """
Only store CONFIRMED medical facts.
Store:
- Confirmed diagnoses from doctors
- Known allergies with documented reactions
- Current medications being taken
Ignore:
- Speculation (words like "might", "maybe", "I think")
- Unverified symptoms
- Casual mentions without confirmation
"""
client.project.update(custom_instructions=instructions)
# Same speculative statement
messages = [{"role": "user", "content": "I think I might be allergic to penicillin"}]
client.add(messages, user_id="patient_123")
# Check what got stored
results = client.get_all(filters={"user_id": "patient_123"})
print(f"Memories stored: {len(results['results'])}")
```
**Output:**
```
Memories stored: 0
```
<Info>
**Expected output:** Zero memories stored. The speculative statement "I think I might be allergic" was filtered out before reaching storage. Custom instructions are actively blocking unreliable data.
</Info>
The speculation was filtered out.
---
## Designing Custom Instructions
When designing instructions, consider the trade-off between precision and recall:
**Too restrictive:** You'll miss important information (false negatives)
```python
# Too strict - filters out useful context
"""
Only store information if explicitly stated by a doctor with full name,
date, time, and medical license number.
"""
```
**Too permissive:** You'll store unreliable data (false positives)
```python
# Too loose - stores speculation as fact
"""
Store any health-related information mentioned.
"""
```
**Balanced approach:**
```python
# Clear categories with examples
"""
Store CONFIRMED facts:
- Diagnoses: "Dr. Smith diagnosed hypertension on March 15th"
- Allergies: "Patient had hives reaction to penicillin"
- Medications: "Taking Lisinopril 10mg daily"
Ignore SPECULATION:
- "I think I might have..."
- "Maybe it's..."
- "Could be related to..."
"""
```
<Tip>
Start with strict instructions (only store confirmed facts), then relax them based on your use case. It's easier to allow more data than to clean up polluted memory. Test with sample conversations before deploying to production.
</Tip>
Start with clear categories and iterate based on retrieval quality.
---
## Confidence Thresholds
Mem0 assigns confidence scores to extracted memories. Use these to filter low-quality data.
### Setting Thresholds
Setting the right confidence threshold depends on your application:
- **High-stakes domains** (medical, legal): Require 0.8+ confidence
- **General assistants**: 0.6+ confidence is often sufficient
- **Exploratory systems**: Lower thresholds (0.4+) capture more data
Test your pipeline with multiple input examples and threshold combinations to find what works for your use case.
```python
# Configure stricter instructions
client.project.update(
custom_instructions="""
Only extract memories with HIGH confidence.
Require specific details (dates, dosages, doctor names) for medical facts.
Skip vague or uncertain statements.
"""
)
# Test with uncertain statement
messages = [{"role": "user", "content": "The doctor mentioned something about my blood pressure"}]
result1 = client.add(messages, user_id="patient_123")
# Test with confirmed fact
messages = [{"role": "user", "content": "Dr. Smith diagnosed me with hypertension on March 15th"}]
result2 = client.add(messages, user_id="patient_123")
print("Vague statement stored:", len(result1['results']) > 0)
print("Confirmed fact stored:", len(result2['results']) > 0)
```
**Output:**
```
Vague statement stored: False
Confirmed fact stored: True
```
<Info icon="check">
**Expected behavior:** Low-confidence extractions are now filtered out automatically. Only verified facts with specific details (names, dates, dosages) persist in memory. The confidence threshold is working.
</Info>
The vague statement was filtered for low confidence. The confirmed fact with specific details was stored.
---
## Filtering Sensitive Information
Custom instructions can prevent storing personal identifiers:
```python
client.project.update(
custom_instructions="""
Medical memory rules:
STORE:
- Confirmed diagnoses
- Verified allergies
- Current medications
NEVER STORE:
- Social Security Numbers
- Insurance policy numbers
- Credit card information
- Full addresses
- Phone numbers
Replace identifiers with generic references if mentioned.
"""
)
# Test with PII
messages = [
{"role": "user", "content": "My SSN is 123-45-6789 and I'm allergic to penicillin"}
]
client.add(messages, user_id="patient_123")
# Check what was stored
results = client.get_all(filters={"user_id": "patient_123"})
for result in results['results']:
print(result['memory'])
```
**Output:**
```
Patient is allergic to penicillin
```
The SSN was filtered out, but the allergy was stored.
---
## Updating Memories
When information changes, update existing memories instead of creating duplicates.
```python
# Initial allergy stored
result = client.add(
[{"role": "user", "content": "Patient confirmed allergy to penicillin with documented hives reaction"}],
user_id="patient_123"
)
memory_id = result['results'][0]['id']
print(f"Stored memory: {memory_id}")
# Later, patient gets retested - allergy was false positive
client.update(
memory_id=memory_id,
text="Patient tested negative for penicillin allergy on April 2nd, 2025. Previous allergy was false positive.",
metadata={"verified": True, "updated_date": "2025-04-02"}
)
# Retrieve the updated memory
updated = client.get(memory_id)
print(f"\\nUpdated memory: {updated['memory']}")
print(f"Metadata: {updated['metadata']}")
```
**Output:**
```
Stored memory: mem_abc123
Updated memory: Patient tested negative for penicillin allergy on April 2nd, 2025. Previous allergy was false positive.
Metadata: {'verified': True, 'updated_date': '2025-04-02'}
```
### Benefits of Updating
**Preserves history:**
- `created_at` shows when the memory was first stored
- `updated_at` shows when it was modified
- Audit trail for compliance
**Avoids conflicts:**
- No duplicate or contradicting memories
- Single source of truth for each fact
**Maintains relationships:**
- If using graph memory, connections to other entities persist
---
## Update vs Delete
When should you update vs delete?
### Update when:
- Information changes but remains relevant
- You need audit history
- The memory has relationships to other data
```python
# Medication dosage changed
client.update(
memory_id=med_id,
text="Taking Lisinopril 20mg daily (increased from 10mg on March 1st)"
)
```
### Delete when:
- Information was completely wrong
- Memory is no longer relevant
- Duplicate entry
```python
# Duplicate entry
client.delete(memory_id)
```
---
## Putting It Together
Here's a complete ingestion pipeline with all controls:
```python
from mem0 import MemoryClient
import os
# Initialize client
client = MemoryClient(api_key=os.getenv("MEM0_API_KEY"))
# Configure custom instructions
client.project.update(
custom_instructions="""
Medical memory assistant rules:
STORE:
- Confirmed diagnoses (with doctor name and date)
- Verified allergies (with reaction details)
- Current medications (with dosage)
IGNORE:
- Speculation (might, maybe, possibly)
- Unverified symptoms
- Personal identifiers (SSN, insurance numbers)
CONFIDENCE:
Require high confidence. Reject vague or uncertain statements.
Require specific details: names, dates, dosages.
"""
)
# Helper function for safe ingestion
def add_medical_memory(content, user_id, metadata=None):
"""Add memory with automatic filtering."""
result = client.add(
[{"role": "user", "content": content}],
user_id=user_id,
metadata=metadata or {}
)
if result['results']:
print(f"✓ Stored: {result['results'][0]['memory']}")
else:
print(f"✗ Filtered: {content}")
return result
# Test cases
print("Testing ingestion pipeline:\\n")
test_cases = [
"I think I might be allergic to penicillin",
"Dr. Johnson confirmed penicillin allergy on Jan 15th with hives reaction",
"Patient SSN is 123-45-6789",
"Currently taking Lisinopril 10mg daily for hypertension",
"Feeling tired lately",
"Dr. Martinez diagnosed Type 2 diabetes on February 3rd, 2025"
]
for content in test_cases:
add_medical_memory(content, user_id="patient_123")
print()
```
**Output:**
```
Testing ingestion pipeline:
✗ Filtered: I think I might be allergic to penicillin
✓ Stored: Patient has confirmed penicillin allergy diagnosed by Dr. Johnson on January 15th with hives reaction
✗ Filtered: Patient SSN is 123-45-6789
✓ Stored: Patient is currently taking Lisinopril 10mg daily for hypertension
✗ Filtered: Feeling tired lately
✓ Stored: Patient diagnosed with Type 2 diabetes by Dr. Martinez on February 3rd, 2025
```
---
## Per-Call Instructions
You can override project-level instructions for specific conversations:
First define custom instructions
```python
custom_instructions="""Emergency intake mode:Store ALL symptoms and observations immediately.
Flag for later review and verification."""
```
```python
# Emergency intake - store everything temporarily
emergency_messages = [
{"role": "user", "content": "Patient arrived with chest pain and shortness of breath"}
]
client.add(
emergency_messages,
user_id="patient_456",
custom_instructions=custom_instructions,
metadata={"type": "emergency", "review_required": True}
)
```
This is useful for:
- Different conversation types (emergency vs routine)
- Channel-specific rules (phone vs in-person)
- Temporary data collection that needs review
---
## What You Built
You now have a medical assistant with production-grade memory controls:
- **Custom instructions** - Filter speculation and enforce confirmed facts only
- **Confidence thresholds** - Gate extractions below 0.7 confidence score
- **Memory updates** - Modify stored information without creating duplicates
- **Per-call instructions** - Apply temporary rules for specific conversations
- **PII filtering** - Block sensitive data (SSNs, insurance numbers) automatically
These controls prevent retrieval failures and ensure your AI assistant works with reliable, verified information.
---
## Summary
Start with conservative filters (only store confirmed facts) and iterate based on your application's needs. Combine custom instructions with confidence thresholds for the most reliable memory ingestion pipeline.
<CardGroup cols={2}>
<Card title="Expire Short-Term Data" icon="timer" href="/cookbooks/essentials/memory-expiration-short-and-long-term">
Automatically clean up session context before it clutters retrieval.
</Card>
<Card title="Choose Your Memory Architecture" icon="sitemap" href="/cookbooks/essentials/choosing-memory-architecture-vector-vs-graph">
Learn when to layer graph memory alongside vectors for multi-hop queries.
</Card>
</CardGroup>
@@ -0,0 +1,289 @@
---
title: Export Stored Memories
description: "Retrieve, review, and migrate user memories with structured exports."
---
Mem0 is a dynamic memory store that gives you full control over your data. Along with storing memories, it gives you the ability to retrieve, export, and migrate your data whenever you need.
This cookbook shows you how to retrieve and export your data for inspection, migration, or compliance.
---
## Setup
```python
from mem0 import MemoryClient
client = MemoryClient(api_key="your-api-key")
```
<Note>
Your API key needs export permissions to download memory data. Check your project settings on the [dashboard](https://app.mem0.ai) if export operations fail with authentication errors.
</Note>
Let's add some sample memories to work with:
```python
# Dev's work history
client.add(
"Dev works at TechCorp as a senior engineer",
user_id="dev",
metadata={"type": "professional"}
)
# Arjun's preferences
client.add(
"Arjun prefers morning meetings and async communication",
user_id="arjun",
metadata={"type": "preference"}
)
# Carl's project notes
client.add(
"Carl is leading the API redesign project, targeting Q2 launch",
user_id="carl",
metadata={"type": "project"}
)
```
---
## Getting All Memories
Use `get_all()` with filters to retrieve everything for a specific user:
```python
dev_memories = client.get_all(
filters={"user_id": "dev"},
page_size=50
)
print(f"Total memories: {dev_memories['count']}")
print(f"First memory: {dev_memories['results'][0]['memory']}")
```
**Output:**
```
Total memories: 1
First memory: Dev works at TechCorp as a senior engineer
```
<Info>
**Expected output:** `get_all()` retrieved Dev's complete memory record. This method returns everything matching your filters—no semantic search, no ranking, just raw retrieval. Perfect for exports and audits.
</Info>
You can filter by metadata to get specific types:
```python
carl_projects = client.get_all(
filters={
"AND": [
{"user_id": "carl"},
{"metadata": {"type": "project"}}
]
}
)
for memory in carl_projects['results']:
print(memory['memory'])
```
**Output:**
```
Carl is leading the API redesign project, targeting Q2 launch
```
---
## Searching Memories
When you need semantic search instead of retrieving everything, use `search()`:
```python
results = client.search(
query="What does Dev do for work?",
filters={"user_id": "dev"},
top_k=5
)
for result in results['results']:
print(f"{result['memory']} (score: {result['score']:.2f})")
```
**Output:**
```
Dev works at TechCorp as a senior engineer (score: 0.89)
```
Search works across all memory fields and ranks by relevance. Use it when you have a specific question, use `get_all()` when you need everything.
---
## Exporting to Structured Format
For migrations or compliance, you can export memories into a structured schema using Pydantic-style JSON schemas.
### Step 1: Define the schema
```python
professional_profile_schema = {
"properties": {
"full_name": {
"type": "string",
"description": "The person's full name"
},
"current_role": {
"type": "string",
"description": "Current job title or role"
},
"company": {
"type": "string",
"description": "Current employer"
}
},
"title": "ProfessionalProfile",
"type": "object"
}
```
### Step 2: Create export job
```python
export_job = client.create_memory_export(
schema=professional_profile_schema,
filters={"user_id": "dev"}
)
print(f"Export ID: {export_job['id']}")
print(f"Status: {export_job['status']}")
```
**Output:**
```
Export ID: exp_abc123
Status: processing
```
<Info>
**Export initiated:** Status is "processing". Large exports may take a few seconds. Poll with `get_memory_export()` until status changes to "completed" before downloading data.
</Info>
### Step 3: Download the export
```python
# Get by ID
export_data = client.get_memory_export(
memory_export_id=export_job['id']
)
print(export_data['data'])
```
**Output:**
```json
{
"full_name": "Dev",
"current_role": "senior engineer",
"company": "TechCorp"
}
```
You can also retrieve exports by filters:
```python
# Get latest export matching filters
export_by_filters = client.get_memory_export(
filters={"user_id": "dev"}
)
print(export_by_filters['data'])
```
---
## Adding Export Instructions
Guide how Mem0 resolves conflicts or formats the export:
```python
export_with_instructions = client.create_memory_export(
schema=professional_profile_schema,
filters={"user_id": "arjun"},
export_instructions="""
1. Use the most recent information if there are conflicts
2. Only include confirmed facts, not speculation
3. Return null for missing fields rather than guessing
"""
)
```
<Tip>
Always check export status before downloading. Call `get_memory_export()` in a loop with a short delay until `status == "completed"`. Attempting to download while still processing returns incomplete data.
</Tip>
---
## Platform Export
You can also export memories directly from the Mem0 platform UI:
1. Navigate to **Memory Exports** in your project dashboard
2. Click **Create Export**
3. Select your filters and schema
4. Download the completed export as JSON
This is useful for one-off exports or manual data reviews.
<Warning>
Exported data expires after 7 days. Download and store exports locally if you need long-term archives. After expiration, you'll need to recreate the export job.
</Warning>
---
## What You Built
A complete memory export system with multiple retrieval methods:
- **Bulk retrieval (get_all)** - Fetch all memories matching filters for comprehensive audits
- **Semantic search** - Query-based lookups with relevance scoring
- **Structured exports** - Pydantic-schema exports for migrations and compliance
- **Export instructions** - Guide conflict resolution and data formatting
- **Platform UI exports** - One-off manual downloads via dashboard
This covers data portability, GDPR compliance, system migrations, and manual reviews.
---
## Summary
Use **`get_all()`** for bulk retrieval, **`search()`** for specific questions, and **`create_memory_export()`** for structured data exports with custom schemas. Remember exports expire after 7 days—download them locally for long-term archives.
<CardGroup cols={2}>
<Card title="Expire Short-Term Data" icon="timer" href="/cookbooks/essentials/memory-expiration-short-and-long-term">
Keep exports lean by clearing session context before you archive it.
</Card>
<Card title="Control Memory Ingestion" icon="filter" href="/cookbooks/essentials/controlling-memory-ingestion">
Ensure only verified insights make it into your export pipeline.
</Card>
</CardGroup>
@@ -0,0 +1,277 @@
---
title: Set Memory Expiration
description: "Define short-term versus long-term retention so the store stays fresh."
---
While building memory systems, we realized their size grows fast. Session notes, temporary context, chat history - everything starts accumulating and bogging down the system. This pollutes search results and increase storage costs. Not every memory needs to persist forever.
In this cookbook, we'll go through how to use short-term vs long-term memories and see where it's best to use them.
---
## Overview
By default, Mem0 memories persist forever. This works for user preferences and core facts, but temporary data should expire automatically.
In this tutorial, we will:
- Understand default (permanent) memory behavior
- Add expiration dates for temporary memories
- Decide what should be temporary vs permanent
---
## Setup
```python
from mem0 import MemoryClient
from datetime import datetime, timedelta
client = MemoryClient(api_key="your-api-key")
```
<Note>
Import `datetime` and `timedelta` to calculate expiration dates. Without these imports, you'll need to manually format ISO timestamps—error-prone and harder to read.
</Note>
---
## Default Behavior: Everything Persists
By default, all memories persist forever:
```python
# Store user preference
client.add("User prefers dark mode", user_id="sarah")
# Store session context
client.add("Currently browsing electronics category", user_id="sarah")
# 6 months later - both still exist
results = client.get_all(filters={"user_id": "sarah"})
print(f"Total memories: {len(results['results'])}")
```
**Output:**
```
Total memories: 2
```
Both the preference and session context persist. The preference is useful, but the 6-month-old session context is not.
---
## The Problem: Memory Bloat
Without expiration, memories accumulate forever. Session notes from weeks ago mix with current preferences. Storage grows, search results get polluted with irrelevant old context, and retrieval quality degrades.
<Warning>
Memory bloat degrades search quality. When "User prefers dark mode" competes with "Currently browsing electronics" from 6 months ago, semantic search returns stale session data instead of actual preferences. Old memories pollute retrieval.
</Warning>
---
## Short-Term Memories: Adding Expiration
Set `expiration_date` to make memories temporary:
```python
from datetime import datetime, timedelta
# Session context - expires in 7 days
expires_at = (datetime.now() + timedelta(days=7)).isoformat()
client.add(
"Currently browsing electronics category",
user_id="sarah",
expiration_date=expires_at
)
# User preference - no expiration, persists forever
client.add(
"User prefers dark mode",
user_id="sarah"
)
```
<Info icon="check">
**Expected behavior:** After 7 days, the session context automatically disappears—no cron jobs, no manual cleanup. The preference persists forever. Mem0 handles expiration transparently.
</Info>
Memories with `expiration_date` are automatically removed after expiring. No cleanup job needed - Mem0 handles it.
<Tip>
Start conservative with short expiration windows (7 days), then extend them based on usage patterns. It's easier to increase retention than to clean up over-retained stale data. Monitor search quality to find the right balance.
</Tip>
---
## When to Use Each
### Permanent Memories (no expiration_date):
**Use for:**
- User preferences and settings
- Account information
- Important facts and milestones
- Historical data that matters long-term
```python
client.add("User prefers email notifications", user_id="sarah")
client.add("User's birthday is March 15th", user_id="sarah")
client.add("User completed onboarding on Jan 5th", user_id="sarah")
```
### Temporary Memories (with expiration_date):
**Use for:**
- Session context (current page, browsing history)
- Temporary reminders
- Recent chat history
- Cached data
```python
expires_7d = (datetime.now() + timedelta(days=7)).isoformat()
client.add(
"Currently viewing product ABC123",
user_id="sarah",
expiration_date=expires_7d
)
client.add(
"Asked about return policy",
user_id="sarah",
expiration_date=expires_7d
)
```
---
## Setting Different Expiration Periods
Different data needs different lifetimes:
```python
# Session context - 7 days
expires_7d = (datetime.now() + timedelta(days=7)).isoformat()
client.add("Browsing electronics", user_id="sarah", expiration_date=expires_7d)
# Recent chat - 30 days
expires_30d = (datetime.now() + timedelta(days=30)).isoformat()
client.add("User asked about warranty", user_id="sarah", expiration_date=expires_30d)
# Important preference - no expiration
client.add("User prefers dark mode", user_id="sarah")
```
---
## Using Metadata to Track Memory Types
Tag memories to make filtering easier:
```python
expires_7d = (datetime.now() + timedelta(days=7)).isoformat()
# Tag session context
client.add(
"Browsing electronics",
user_id="sarah",
expiration_date=expires_7d,
metadata={"type": "session"}
)
# Tag preference
client.add(
"User prefers dark mode",
user_id="sarah",
metadata={"type": "preference"}
)
# Query only preferences
preferences = client.get_all(
filters={
"AND": [
{"user_id": "sarah"},
{"metadata": {"type": "preference"}}
]
}
)
```
---
## Checking Expiration Status
See which memories will expire and when:
```python
results = client.get_all(filters={"user_id": "sarah"})
for memory in results['results']:
exp_date = memory.get('expiration_date')
if exp_date:
print(f"Temporary: {memory['memory']}")
print(f" Expires: {exp_date}\\n")
else:
print(f"Permanent: {memory['memory']}\\n")
```
**Output:**
```
Temporary: Browsing electronics
Expires: 2025-11-01T10:30:00Z
Temporary: Viewed MacBook Pro and Dell XPS
Expires: 2025-11-01T10:30:00Z
Permanent: User prefers dark mode
Permanent: User prefers email notifications
```
---
## What You Built
A self-cleaning memory system with automatic retention policies:
- **Automatic expiration** - Memories self-destruct after defined periods, no cron jobs needed
- **Tiered retention** - 7-day session context, 30-day chat history, permanent preferences
- **Metadata tagging** - Classify memories by type (session, preference, chat) for filtered retrieval
- **Expiration tracking** - Check which memories will expire and when using `get_all()`
This pattern keeps storage costs low and search quality high as your memory store scales.
---
## Summary
Memory expiration keeps storage clean and search results relevant. Use **`expiration_date`** for temporary data (session context, recent chats), skip it for permanent facts (preferences, account info). Mem0 handles cleanup automatically—no background jobs required.
Start by identifying what's temporary versus permanent, then set conservative expiration windows and adjust based on retrieval quality.
<CardGroup cols={2}>
<Card title="Control Memory Ingestion" icon="filter" href="/cookbooks/essentials/controlling-memory-ingestion">
Pair expirations with ingestion rules so only trusted context persists.
</Card>
<Card title="Export Memories Safely" icon="download" href="/cookbooks/essentials/exporting-memories">
Build compliant archives once your retention windows are dialed in.
</Card>
</CardGroup>
@@ -0,0 +1,251 @@
---
title: Tag and Organize Memories
description: "Let Mem0 auto-categorize support data so teams retrieve the right facts fast."
---
When you have large volumes of memory data, sorting it during post-processing becomes difficult. What if your memory store understood the importance of creating tags and buckets without a lot of effort?
Mem0 handles this for you by providing the flexibility to organize memories with custom categories. This cookbook shows you how to tag and organize memories for a customer support platform.
---
## Setup
```python
from mem0 import MemoryClient
client = MemoryClient(api_key="your-api-key")
```
<Note>
Define custom categories at the **project level** with `client.project.update()` before adding memories. Categories apply to all future memories—Mem0 auto-assigns them based on content semantics.
</Note>
---
## The Problem
Without categories, all memories sit in one undifferentiated bucket. Support agents waste time searching through everything to find billing issues, account details, or past tickets.
Let's see what happens without organization:
```python
# Joseph (support agent) stores various customer interactions
client.add(
"Maria called about her account password reset",
user_id="maria",
)
client.add(
"Maria was charged twice for last month's subscription",
user_id="maria",
)
client.add(
"Maria wants to upgrade to the premium plan",
user_id="maria",
)
# Now try to find just billing issues
all_memories = client.get_all(filters={"user_id": "maria"})
print(f"Total memories: {len(all_memories['results'])}")
for memory in all_memories['results']:
print(f"- {memory['memory']}")
```
**Output:**
```
Total memories: 3
- Maria called about her account password reset
- Maria was charged twice for last month's subscription
- Maria wants to upgrade to the premium plan
```
<Warning>
Without categories, agents waste time reading through everything. For a customer with 100 memories, finding one billing issue means scanning all 100. Categories let you filter to exactly what you need—billing issues only, no password resets or feedback mixed in.
</Warning>
Everything is mixed together. Support agents have to read through all memories to find what they need.
---
## Custom Categories
Define categories that match how your support team thinks about customer issues:
```python
custom_categories = [
{"support_tickets": "Customer issues and resolutions"},
{"account_info": "Account details and preferences"},
{"billing": "Payment history and billing questions"},
{"product_feedback": "Feature requests and feedback"},
]
client.project.update(custom_categories=custom_categories)
```
<Tip>
Start with 3-5 clear categories that match how your team thinks. Too many categories dilute auto-tagging accuracy. Add more later if needed—it's easier to expand than to fix over-complicated classification.
</Tip>
These categories are now available project-wide. Every memory can be tagged with one or more categories.
---
## Tagging Memories
Once categories are defined at the project level, Mem0 automatically assigns them based on content:
```python
# Billing issue - automatically tagged as "billing"
client.add(
"Maria was charged twice for last month's subscription",
user_id="maria",
metadata={"priority": "high", "source": "phone_call"}
)
# Account update - automatically tagged as "account_info"
client.add(
"Maria changed her email to maria.new@example.com",
user_id="maria",
metadata={"source": "web_portal"}
)
# Product feedback - automatically tagged as "product_feedback"
client.add(
"Maria requested a dark mode feature for the dashboard",
user_id="maria",
metadata={"source": "chat"}
)
```
Mem0 reads the content and intelligently assigns the appropriate categories. You don't manually tag - the platform does it for you based on the category definitions.
---
## Retrieving by Category
Filter memories by category to find exactly what you need:
```python
# Joseph needs to pull all billing issues for audit
billing_issues = client.get_all(
filters={
"AND": [
{"user_id": "maria"},
{"categories": {"in": ["billing"]}}
]
}
)
print("Billing issues:")
for memory in billing_issues['results']:
print(f"- {memory['memory']}")
```
**Output:**
```
Billing issues:
- Maria was charged twice for last month's subscription
```
<Info icon="check">
**Expected output:** Only the billing issue returned—no password reset, no upgrade request. Category filtering worked. Joseph can audit billing without reading through unrelated support tickets.
</Info>
Only billing-related memories are returned. No need to filter through account updates or feedback.
You can also retrieve multiple categories:
```python
# Get both account info and billing
account_and_billing = client.get_all(
filters={
"AND": [
{"user_id": "maria"},
{"categories": {"in": ["account_info", "billing"]}}
]
}
)
for memory in account_and_billing['results']:
print(f"[{memory['categories'][0]}] {memory['memory']}")
```
**Output:**
```
[account_info] Maria changed her email to maria.new@example.com
[billing] Maria was charged twice for last month's subscription
```
---
## Updating Categories
Categories are automatically assigned based on content. To trigger re-categorization, update the memory content:
```python
# Find memories that need re-categorization
needs_update = client.get_all(
filters={
"AND": [
{"user_id": "maria"},
{"categories": {"in": ["misc"]}}
]
}
)
# Update memory content to trigger re-categorization
for memory in needs_update['results']:
client.update(
memory_id=memory['id'],
data=memory['memory'] # Re-process with current category definitions
)
```
When you update a memory, Mem0 re-analyzes it against your current category definitions. This is useful when you introduce new categories or refine category descriptions.
---
## What You Built
A customer support platform with intelligent memory organization:
- **Project-wide categories** - Support tickets, billing, account info, and product feedback auto-classified
- **Automatic tagging** - Mem0 assigns categories based on content semantics, no manual tagging
- **Filtered retrieval** - Pull only billing issues or only account updates using `categories: {in: [...]}`
- **Re-categorization** - Update memory content to trigger re-analysis against new category definitions
- **Multi-category support** - Memories can belong to multiple categories when appropriate
This pattern scales from 10 customers to 10,000 without degrading retrieval speed.
---
## Summary
Categories make retrieval faster and compliance easier. Define 3-5 clear categories with `client.project.update()`, let Mem0 auto-assign them based on content, then filter with `categories: {in: [...]}` to pull exactly what you need.
Instead of searching through everything, agents jump directly to the information type they need—billing issues, account details, or support tickets.
<CardGroup cols={2}>
<Card title="Control Memory Ingestion" icon="filter" href="/cookbooks/essentials/controlling-memory-ingestion">
Keep categories meaningful by filtering noise before it lands in storage.
</Card>
<Card title="Export Tagged Memories" icon="download" href="/cookbooks/essentials/exporting-memories">
Use categories to drive audits, migrations, and compliance reports.
</Card>
</CardGroup>