
- Complete Mem0 OSS integration with hybrid datastore - PostgreSQL + pgvector for vector storage - Neo4j 5.18 for graph relationships - Google Gemini embeddings integration - Comprehensive monitoring with correlation IDs - Real-time statistics and performance tracking - Production-grade observability features - Clean repository with no exposed secrets
227 lines
No EOL
8.6 KiB
Markdown
227 lines
No EOL
8.6 KiB
Markdown
# Personalized Search with Mem0 and Tavily
|
|
|
|
## Overview
|
|
|
|
Imagine asking a search assistant for "coffee shops nearby" and instead of generic results, it shows remote-work-friendly cafes with great wifi in your city because it remembers you mentioned working remotely before. Or when you search for "lunchbox ideas for kids" it knows you have a **7-year-old daughter** and recommends **peanut-free options** that align with her allergy.
|
|
|
|
That's what we are going to build today, a **Personalized Search Assistant** powered by **Mem0** for memory and [Tavily](https://tavily.com/) for real-time search.
|
|
|
|
## Why Personalized Search
|
|
|
|
Most assistants treat every query like they've never seen you before. That means repeating yourself about your location, diet, or preferences, and getting results that feel generic.
|
|
|
|
- With **Mem0**, your assistant builds a memory of the user's world.
|
|
- With **Tavily**, it fetches fresh and accurate results in real time.
|
|
|
|
Together, they make every interaction **smarter, faster, and more personal**.
|
|
|
|
## Prerequisites
|
|
|
|
Before you begin, make sure you have:
|
|
|
|
1. **Install the dependencies:**
|
|
```bash
|
|
pip install langchain mem0ai langchain-tavily langchain-openai
|
|
```
|
|
|
|
2. **Set up your API keys** in a .env file:
|
|
```bash
|
|
OPENAI_API_KEY=your-openai-key
|
|
TAVILY_API_KEY=your-tavily-key
|
|
MEM0_API_KEY=your-mem0-key
|
|
```
|
|
|
|
## Code Walkthrough
|
|
|
|
Let's break down the main components.
|
|
|
|
### 1: Initialize Mem0 with Custom Instructions
|
|
|
|
We configure Mem0 with custom instructions that guide it to infer user memories tailored specifically for our usecase.
|
|
|
|
```python
|
|
from mem0 import MemoryClient
|
|
|
|
mem0_client = MemoryClient()
|
|
|
|
mem0_client.project.update(
|
|
custom_instructions='''
|
|
INFER THE MEMORIES FROM USER QUERIES EVEN IF IT'S A QUESTION.
|
|
|
|
We are building personalized search for which we need to understand about user's preferences and life
|
|
and extract facts and memories accordingly.
|
|
'''
|
|
)
|
|
```
|
|
|
|
Now, if a user casually mentions "I need to pick up my daughter", or "What's the weather at Los Angeles", Mem0 remembers they have a daughter or user is somewhat interested/connected with Los Angeles in terms of location, those will be referred for future searches.
|
|
|
|
### 2. Simulating User History
|
|
|
|
To test personalization, we preload some sample conversation history for a user:
|
|
|
|
```python
|
|
def setup_user_history(user_id):
|
|
conversations = [
|
|
[{"role": "user", "content": "What will be the weather today at Los Angeles? I need to pick up my daughter from office."},
|
|
{"role": "assistant", "content": "I'll check the weather in LA for you."}],
|
|
[{"role": "user", "content": "I'm looking for vegan restaurants in Santa Monica"},
|
|
{"role": "assistant", "content": "I'll find great vegan options in Santa Monica."}],
|
|
[{"role": "user", "content": "My 7-year-old daughter is allergic to peanuts"},
|
|
{"role": "assistant", "content": "I'll remember to check for peanut-free options."}],
|
|
[{"role": "user", "content": "I work remotely and need coffee shops with good wifi"},
|
|
{"role": "assistant", "content": "I'll find remote-work-friendly coffee shops."}],
|
|
[{"role": "user", "content": "We love hiking and outdoor activities on weekends"},
|
|
{"role": "assistant", "content": "Great! I'll keep your outdoor activity preferences in mind."}],
|
|
]
|
|
|
|
for conversation in conversations:
|
|
mem0_client.add(conversation, user_id=user_id, output_format="v1.1")
|
|
```
|
|
|
|
This gives the agent a baseline understanding of the user's lifestyle and needs.
|
|
|
|
### 3. Retrieving User Context from Memory
|
|
|
|
When a user makes a new search query, we retrieve relevant memories to enhance the search query:
|
|
|
|
```python
|
|
def get_user_context(user_id, query):
|
|
filters = {"AND": [{"user_id": user_id}]}
|
|
user_memories = mem0_client.search(query=query, version="v2", filters=filters)
|
|
|
|
if user_memories:
|
|
context = "\n".join([f"- {memory['memory']}" for memory in user_memories])
|
|
return context
|
|
else:
|
|
return "No previous user context available."
|
|
```
|
|
|
|
This context is injected into the search agent so results are personalized.
|
|
|
|
### 4. Creating the Personalized Search Agent
|
|
|
|
The agent uses Tavily search, but always augments search queries with user context:
|
|
|
|
```python
|
|
def create_personalized_search_agent(user_context):
|
|
tavily_search = TavilySearch(
|
|
max_results=10,
|
|
search_depth="advanced",
|
|
include_answer=True,
|
|
topic="general"
|
|
)
|
|
|
|
tools = [tavily_search]
|
|
|
|
prompt = ChatPromptTemplate.from_messages([
|
|
("system", f"""You are a personalized search assistant.
|
|
|
|
USER CONTEXT AND PREFERENCES:
|
|
{user_context}
|
|
|
|
YOUR ROLE:
|
|
1. Analyze the user's query and context.
|
|
2. Enhance the query with relevant personal memories.
|
|
3. Always use tavily_search for results.
|
|
4. Explain which memories influenced personalization.
|
|
"""),
|
|
MessagesPlaceholder(variable_name="messages"),
|
|
MessagesPlaceholder(variable_name="agent_scratchpad"),
|
|
])
|
|
|
|
agent = create_openai_tools_agent(llm=llm, tools=tools, prompt=prompt)
|
|
return AgentExecutor(agent=agent, tools=tools, verbose=True, return_intermediate_steps=True)
|
|
```
|
|
|
|
### 5. Run a Personalized Search
|
|
|
|
The workflow ties everything together:
|
|
|
|
```python
|
|
def conduct_personalized_search(user_id, query):
|
|
user_context = get_user_context(user_id, query)
|
|
agent_executor = create_personalized_search_agent(user_context)
|
|
|
|
response = agent_executor.invoke({"messages": [HumanMessage(content=query)]})
|
|
return {"agent_response": response['output']}
|
|
```
|
|
|
|
### 6. Store New Interactions
|
|
|
|
Every new query/response pair is stored for future personalization:
|
|
|
|
```python
|
|
def store_search_interaction(user_id, original_query, agent_response):
|
|
interaction = [
|
|
{"role": "user", "content": f"Searched for: {original_query}"},
|
|
{"role": "assistant", "content": f"Results based on preferences: {agent_response}"}
|
|
]
|
|
mem0_client.add(messages=interaction, user_id=user_id, output_format="v1.1")
|
|
```
|
|
|
|
### Full Example Run
|
|
|
|
```python
|
|
if __name__ == "__main__":
|
|
user_id = "john"
|
|
setup_user_history(user_id)
|
|
|
|
queries = [
|
|
"good coffee shops nearby for working",
|
|
"what can I make for my kid in lunch?"
|
|
]
|
|
|
|
for q in queries:
|
|
results = conduct_personalized_search(user_id, q)
|
|
print(f"\nQuery: {q}")
|
|
print(f"Personalized Response: {results['agent_response']}")
|
|
```
|
|
|
|
## How It Works in Practice
|
|
|
|
Here's how personalization plays out:
|
|
|
|
1. **Context Gathering**: User previously mentioned living in Los Angeles, being vegan, and having a 7-year-old daughter allergic to peanuts.
|
|
|
|
2. **Enhanced Search Query**:
|
|
- **Original Query**: "good coffee shops nearby for working"
|
|
- **Enhanced Query**: "good coffee shops in Los Angeles with strong wifi, remote-work-friendly"
|
|
|
|
3. **Personalized Results**: The assistant only returns wifi-friendly, work-friendly cafes near Los Angeles.
|
|
|
|
4. **Memory Update**: Interaction is saved for better future recommendations.
|
|
|
|
## Key Benefits
|
|
|
|
1. **Context Awareness**: Remembers user preferences and personal details
|
|
2. **Intelligent Query Enhancement**: Automatically improves search queries with personal context
|
|
3. **Continuous Learning**: Gets better with each interaction
|
|
4. **Real-time Results**: Combines memory with fresh search data
|
|
5. **Privacy-Focused**: Personal data stays within the Mem0 system
|
|
|
|
## Use Cases
|
|
|
|
- **Shopping Assistants**: Remember dietary restrictions, sizes, and brand preferences
|
|
- **Travel Planning**: Recall budget constraints, accessibility needs, and past preferences
|
|
- **Content Discovery**: Suggest articles, videos, or products based on interests
|
|
- **Local Services**: Find services that match past requirements and preferences
|
|
- **Health & Wellness**: Remember health conditions, allergies, and fitness goals
|
|
|
|
## Security Compliance
|
|
|
|
🔐 **Mem0 is now SOC 2 and HIPAA compliant!** We're committed to the highest standards of data security and privacy, enabling secure memory for enterprises, healthcare, and beyond.
|
|
|
|
## Conclusion
|
|
|
|
With Mem0 + Tavily, you can build a search assistant that doesn't just fetch results but understands the person behind the query. Whether for shopping, travel, or daily life, this approach turns a generic search into a truly personalized experience.
|
|
|
|
**Full Code**: [Personalized Search GitHub](https://github.com/mem0ai/mem0/blob/main/examples/misc/personalized_search.py)
|
|
|
|
## Next Steps
|
|
|
|
1. **Experiment with different search domains** (shopping, travel, local services)
|
|
2. **Add more sophisticated memory categorization** for better context retrieval
|
|
3. **Implement user feedback loops** to improve memory accuracy
|
|
4. **Scale to multiple users** with proper data isolation
|
|
5. **Add privacy controls** for memory management and deletion |