|
| 1 | +# Building Memory-Enabled Agents with DSPy ReAct and Mem0 |
| 2 | + |
| 3 | +This tutorial demonstrates how to build intelligent conversational agents that can remember information across interactions using DSPy's ReAct framework combined with [Mem0](https://docs.mem0.ai/)'s memory capabilities. You'll learn to create agents that can store, retrieve, and use contextual information to provide personalized and coherent responses. |
| 4 | + |
| 5 | +## What You'll Build |
| 6 | + |
| 7 | +By the end of this tutorial, you'll have a memory-enabled agent that can: |
| 8 | + |
| 9 | +- **Remember user preferences** and past conversations |
| 10 | +- **Store and retrieve factual information** about users and topics |
| 11 | +- **Use memory to inform decisions** and provide personalized responses |
| 12 | +- **Handle complex multi-turn conversations** with context awareness |
| 13 | +- **Manage different types of memories** (facts, preferences, experiences) |
| 14 | + |
| 15 | +## Prerequisites |
| 16 | + |
| 17 | +- Basic understanding of DSPy and ReAct agents |
| 18 | +- Python 3.9+ installed |
| 19 | +- API keys for your preferred LLM provider |
| 20 | + |
| 21 | +## Installation and Setup |
| 22 | + |
| 23 | +```bash |
| 24 | +pip install dspy mem0ai |
| 25 | +``` |
| 26 | + |
| 27 | +## Step 1: Understanding Mem0 Integration |
| 28 | + |
| 29 | +Mem0 provides a memory layer that can store, search, and retrieve memories for AI agents. Let's start by understanding how to integrate it with DSPy: |
| 30 | + |
| 31 | +```python |
| 32 | +import dspy |
| 33 | +from mem0 import Memory |
| 34 | +import os |
| 35 | +from typing import List, Dict, Any, Optional |
| 36 | +from datetime import datetime |
| 37 | + |
| 38 | +# Configure environment |
| 39 | +os.environ["OPENAI_API_KEY"] = "your-openai-api-key" |
| 40 | + |
| 41 | +# Initialize Mem0 memory system |
| 42 | +config = { |
| 43 | + "llm": { |
| 44 | + "provider": "openai", |
| 45 | + "config": { |
| 46 | + "model": "gpt-4o-mini", |
| 47 | + "temperature": 0.1 |
| 48 | + } |
| 49 | + }, |
| 50 | + "embedder": { |
| 51 | + "provider": "openai", |
| 52 | + "config": { |
| 53 | + "model": "text-embedding-3-small" |
| 54 | + } |
| 55 | + } |
| 56 | +} |
| 57 | +``` |
| 58 | + |
| 59 | +## Step 2: Create Memory-Aware Tools |
| 60 | + |
| 61 | +Let's create tools that can interact with the memory system: |
| 62 | + |
| 63 | +```python |
| 64 | +import datetime |
| 65 | + |
| 66 | +class MemoryTools: |
| 67 | + """Tools for interacting with the Mem0 memory system.""" |
| 68 | + |
| 69 | + def __init__(self, memory: Memory): |
| 70 | + self.memory = memory |
| 71 | + |
| 72 | + def store_memory(self, content: str, user_id: str = "default_user") -> str: |
| 73 | + """Store information in memory.""" |
| 74 | + try: |
| 75 | + self.memory.add(content, user_id=user_id) |
| 76 | + return f"Stored memory: {content}" |
| 77 | + except Exception as e: |
| 78 | + return f"Error storing memory: {str(e)}" |
| 79 | + |
| 80 | + def search_memories(self, query: str, user_id: str = "default_user", limit: int = 5) -> str: |
| 81 | + """Search for relevant memories.""" |
| 82 | + try: |
| 83 | + results = self.memory.search(query, user_id=user_id, limit=limit) |
| 84 | + if not results: |
| 85 | + return "No relevant memories found." |
| 86 | + |
| 87 | + memory_text = "Relevant memories found:\n" |
| 88 | + for i, result in enumerate(results["results"]): |
| 89 | + memory_text += f"{i}. {result['memory']}\n" |
| 90 | + return memory_text |
| 91 | + except Exception as e: |
| 92 | + return f"Error searching memories: {str(e)}" |
| 93 | + |
| 94 | + def get_all_memories(self, user_id: str = "default_user") -> str: |
| 95 | + """Get all memories for a user.""" |
| 96 | + try: |
| 97 | + results = self.memory.get_all(user_id=user_id) |
| 98 | + if not results: |
| 99 | + return "No memories found for this user." |
| 100 | + |
| 101 | + memory_text = "All memories for user:\n" |
| 102 | + for i, result in enumerate(results["results"]): |
| 103 | + memory_text += f"{i}. {result['memory']}\n" |
| 104 | + return memory_text |
| 105 | + except Exception as e: |
| 106 | + return f"Error retrieving memories: {str(e)}" |
| 107 | + |
| 108 | + def update_memory(self, memory_id: str, new_content: str) -> str: |
| 109 | + """Update an existing memory.""" |
| 110 | + try: |
| 111 | + self.memory.update(memory_id, new_content) |
| 112 | + return f"Updated memory with new content: {new_content}" |
| 113 | + except Exception as e: |
| 114 | + return f"Error updating memory: {str(e)}" |
| 115 | + |
| 116 | + def delete_memory(self, memory_id: str) -> str: |
| 117 | + """Delete a specific memory.""" |
| 118 | + try: |
| 119 | + self.memory.delete(memory_id) |
| 120 | + return "Memory deleted successfully." |
| 121 | + except Exception as e: |
| 122 | + return f"Error deleting memory: {str(e)}" |
| 123 | + |
| 124 | +def get_current_time() -> str: |
| 125 | + """Get the current date and time.""" |
| 126 | + return datetime.now().strftime("%Y-%m-%d %H:%M:%S") |
| 127 | +``` |
| 128 | + |
| 129 | +## Step 3: Build the Memory-Enhanced ReAct Agent |
| 130 | + |
| 131 | +Now let's create our main ReAct agent that can use memory: |
| 132 | + |
| 133 | +```python |
| 134 | +class MemoryQA(dspy.Signature): |
| 135 | + """ |
| 136 | + You're a helpful assistant and have access to memory method. |
| 137 | + Whenever you answer a user's input, remember to store the information in memory |
| 138 | + so that you can use it later. |
| 139 | + """ |
| 140 | + user_input: str = dspy.InputField() |
| 141 | + response: str = dspy.OutputField() |
| 142 | + |
| 143 | +class MemoryReActAgent(dspy.Module): |
| 144 | + """A ReAct agent enhanced with Mem0 memory capabilities.""" |
| 145 | + |
| 146 | + def __init__(self, memory: Memory): |
| 147 | + super().__init__() |
| 148 | + self.memory_tools = MemoryTools(memory) |
| 149 | + |
| 150 | + # Create tools list for ReAct |
| 151 | + self.tools = [ |
| 152 | + self.memory_tools.store_memory, |
| 153 | + self.memory_tools.search_memories, |
| 154 | + self.memory_tools.get_all_memories, |
| 155 | + get_current_time, |
| 156 | + self.set_reminder, |
| 157 | + self.get_preferences, |
| 158 | + self.update_preferences, |
| 159 | + ] |
| 160 | + |
| 161 | + # Initialize ReAct with our tools |
| 162 | + self.react = dspy.ReAct( |
| 163 | + signature=MemoryQA, |
| 164 | + tools=self.tools, |
| 165 | + max_iters=6 |
| 166 | + ) |
| 167 | + |
| 168 | + def forward(self, user_input: str): |
| 169 | + """Process user input with memory-aware reasoning.""" |
| 170 | + |
| 171 | + return self.react(user_input=user_input) |
| 172 | + |
| 173 | + def set_reminder(self, reminder_text: str, date_time: str = None, user_id: str = "default_user") -> str: |
| 174 | + """Set a reminder for the user.""" |
| 175 | + reminder = f"Reminder set for {date_time}: {reminder_text}" |
| 176 | + return self.memory_tools.store_memory( |
| 177 | + f"REMINDER: {reminder}", |
| 178 | + user_id=user_id |
| 179 | + ) |
| 180 | + |
| 181 | + def get_preferences(self, category: str = "general", user_id: str = "default_user") -> str: |
| 182 | + """Get user preferences for a specific category.""" |
| 183 | + query = f"user preferences {category}" |
| 184 | + return self.memory_tools.search_memories( |
| 185 | + query=query, |
| 186 | + user_id=user_id |
| 187 | + ) |
| 188 | + |
| 189 | + def update_preferences(self, category: str, preference: str, user_id: str = "default_user") -> str: |
| 190 | + """Update user preferences.""" |
| 191 | + preference_text = f"User preference for {category}: {preference}" |
| 192 | + return self.memory_tools.store_memory( |
| 193 | + preference_text, |
| 194 | + user_id=user_id |
| 195 | + ) |
| 196 | +``` |
| 197 | + |
| 198 | +## Step 4: Running the Memory-Enhanced Agent |
| 199 | + |
| 200 | +Let's create a simple interface to interact with our memory-enabled agent: |
| 201 | + |
| 202 | +```python |
| 203 | +import time |
| 204 | +def run_memory_agent_demo(): |
| 205 | + """Demonstration of memory-enhanced ReAct agent.""" |
| 206 | + |
| 207 | + # Configure DSPy |
| 208 | + lm = dspy.LM(model='openai/gpt-4o-mini') |
| 209 | + dspy.configure(lm=lm) |
| 210 | + |
| 211 | + # Initialize memory system |
| 212 | + memory = Memory.from_config(config) |
| 213 | + |
| 214 | + # Create our agent |
| 215 | + agent = MemoryReActAgent(memory) |
| 216 | + |
| 217 | + # Sample conversation demonstrating memory capabilities |
| 218 | + print("🧠 Memory-Enhanced ReAct Agent Demo") |
| 219 | + print("=" * 50) |
| 220 | + |
| 221 | + conversations = [ |
| 222 | + "Hi, I'm Alice and I love Italian food, especially pasta carbonara.", |
| 223 | + "I'm Alice. I prefer to exercise in the morning around 7 AM.", |
| 224 | + "I'm Alice. What do you remember about my food preferences?", |
| 225 | + "I'm Alice. Set a reminder for me to go grocery shopping tomorrow.", |
| 226 | + "I'm Alice. What are my exercise preferences?", |
| 227 | + "I'm Alice. I also enjoy hiking on weekends.", |
| 228 | + "I'm Alice. What do you know about me so far?" |
| 229 | + ] |
| 230 | + |
| 231 | + for i, user_input in enumerate(conversations, 1): |
| 232 | + print(f"\n📝 User: {user_input}") |
| 233 | + |
| 234 | + try: |
| 235 | + response = agent(user_input=user_input) |
| 236 | + print(f"🤖 Agent: {response.response}") |
| 237 | + time.sleep(1) |
| 238 | + |
| 239 | + except Exception as e: |
| 240 | + print(f"❌ Error: {e}") |
| 241 | + |
| 242 | +# Run the demonstration |
| 243 | +if __name__ == "__main__": |
| 244 | + run_memory_agent_demo() |
| 245 | +``` |
| 246 | + |
| 247 | +## Expected Output |
| 248 | +``` |
| 249 | +🧠 Memory-Enhanced ReAct Agent Demo |
| 250 | +================================================== |
| 251 | +
|
| 252 | +📝 User: Hi, I'm Alice and I love Italian food, especially pasta carbonara. |
| 253 | +
|
| 254 | +🤖 Agent: Hi Alice! It's great to meet you! Pasta carbonara is a delicious choice. Do you have a favorite place to get it, or do you enjoy making it at home? |
| 255 | +
|
| 256 | +📝 User: I'm Alice. I prefer to exercise in the morning around 7 AM. |
| 257 | +
|
| 258 | +🤖 Agent: Nice to meet you, Alice! I've noted that you prefer to exercise in the morning around 7 AM. If you have any questions or need tips related to your morning workouts, feel free to ask! |
| 259 | +
|
| 260 | +📝 User: I'm Alice. What do you remember about my food preferences? |
| 261 | +
|
| 262 | +🤖 Agent: I remember that you love Italian food, and your favorite dish is pasta carbonara! |
| 263 | +
|
| 264 | +📝 User: I'm Alice. Set a reminder for me to go grocery shopping tomorrow. |
| 265 | +
|
| 266 | +🤖 Agent: I have set a reminder for you, Alice, to go grocery shopping tomorrow. |
| 267 | +
|
| 268 | +📝 User: I'm Alice. What are my exercise preferences? |
| 269 | +
|
| 270 | +🤖 Agent: Your exercise preference is to work out in the morning around 7 AM. |
| 271 | +
|
| 272 | +📝 User: I'm Alice. I also enjoy hiking on weekends. |
| 273 | +
|
| 274 | +🤖 Agent: Nice to meet you, Alice! It's great to hear that you enjoy hiking on weekends. If you need any recommendations for trails or tips for your hikes, feel free to ask! |
| 275 | +
|
| 276 | +📝 User: I'm Alice. What do you know about me so far? |
| 277 | +
|
| 278 | +🤖 Agent: So far, I know that you enjoy hiking on weekends, prefer to exercise in the morning around 7 AM, and love Italian food, especially pasta carbonara. Additionally, you have a reminder set for grocery shopping on October 7, 2023. |
| 279 | +``` |
| 280 | + |
| 281 | +## Next Steps |
| 282 | + |
| 283 | +- **Implement memory persistence** with databases (PostgreSQL, MongoDB) |
| 284 | +- **Add memory categorization** and tagging for better organization |
| 285 | +- **Create memory expiration policies** for data management |
| 286 | +- **Build multi-user memory isolation** for production applications |
| 287 | +- **Add memory analytics** and insights |
| 288 | +- **Integrate with vector databases** for enhanced semantic search |
| 289 | +- **Implement memory compression** for long-term storage efficiency |
| 290 | + |
| 291 | +This tutorial demonstrates how DSPy's ReAct framework can be enhanced with Mem0's memory capabilities to create intelligent, context-aware agents that can learn and remember information across interactions, making them more useful for real-world applications. |
0 commit comments