fleet-memory/hindsight-docs/docs/cookbook/per-user-memory.md
Nicolò Boschi 4191597098 add llms.txt
2025-12-10 13:51:21 +01:00

174 lines
5.6 KiB
Markdown

---
sidebar_position: 1
---
# Per-User Memory
The simplest pattern: give your agent persistent memory for each user. The agent remembers past conversations, user preferences, and context across sessions.
## The Problem
Without memory, every conversation starts from scratch:
```
Session 1: "I prefer dark mode and use Python"
Session 2: "What's my preferred language?" → Agent doesn't know
```
## The Solution: One Bank Per User
```
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ User A Bank │ │ User B Bank │ │ User C Bank │
│ │ │ │ │ │
│ - Conversations│ │ - Conversations│ │ - Conversations│
│ - Preferences │ │ - Preferences │ │ - Preferences │
│ - Context │ │ - Context │ │ - Context │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
100% isolated 100% isolated 100% isolated
```
Each user gets their own memory bank. Complete isolation, simple mental model.
## Implementation
### 1. Create a Bank When User Signs Up
```python
from hindsight import HindsightClient
client = HindsightClient()
def on_user_signup(user_id: str):
client.create_bank(
bank_id=f"user-{user_id}",
name=f"Memory for {user_id}"
)
```
### 2. Manage Conversation Sessions
Use `document_id` to group messages belonging to the same conversation. When you retain with the same `document_id`, Hindsight replaces the previous version (upsert behavior), keeping the memory up-to-date as the conversation evolves.
```python
import uuid
class ConversationSession:
def __init__(self, user_id: str):
self.user_id = user_id
self.session_id = str(uuid.uuid4()) # Unique ID for this conversation
self.messages = []
def add_message(self, role: str, content: str):
self.messages.append({"role": role, "content": content})
async def save(self, client: HindsightClient):
"""Save the entire conversation. Replaces previous version if session_id exists."""
await client.retain(
bank_id=f"user-{self.user_id}",
content=self.messages,
document_id=self.session_id # Same ID = upsert (replace old version)
)
```
### 3. Recall Context Before Responding
```python
async def get_context(user_id: str, query: str):
result = await client.recall(
bank_id=f"user-{user_id}",
query=query
)
return result.results
```
### 4. Complete Agent Loop
```python
async def handle_message(session: ConversationSession, user_message: str):
# 1. Add user message to session
session.add_message("user", user_message)
# 2. Recall relevant context from past conversations
context = await client.recall(
bank_id=f"user-{session.user_id}",
query=user_message
)
# 3. Build prompt with memory
prompt = f"""You are a helpful assistant with memory of past conversations.
## What you remember about this user
{format_results(context.results)}
## Current conversation
{format_messages(session.messages)}
"""
# 4. Generate response
response = await llm.complete(prompt)
# 5. Add assistant response to session
session.add_message("assistant", response)
# 6. Save the updated conversation (upserts based on session_id)
await session.save(client)
return response
```
### 5. Starting a New Conversation
```python
# Each new conversation gets a new session with a unique ID
session = ConversationSession(user_id="alice")
# Multiple exchanges in the same conversation
await handle_message(session, "Hi! I'm working on a Python project")
await handle_message(session, "Can you help me with async/await?")
# Start a new conversation later (new session_id)
new_session = ConversationSession(user_id="alice")
await handle_message(new_session, "Different topic today...")
```
## How Document ID Works
The `document_id` parameter is key to managing evolving conversations:
| Scenario | Behavior |
|----------|----------|
| First retain with `document_id="session_123"` | Creates new document |
| Retain again with same `document_id="session_123"` | **Replaces** previous version (upsert) |
| Retain with different `document_id="session_456"` | Creates separate document |
| Retain without `document_id` | Creates new document each time |
This upsert behavior means:
- You always retain the **full conversation** state
- Facts are re-extracted from the complete conversation
- No duplicate or stale facts from old versions
- Memory stays consistent as conversations evolve
## What Gets Remembered
Hindsight automatically extracts and connects:
- **Facts**: "User prefers Python", "User is building a CLI tool"
- **Entities**: People, projects, technologies mentioned
- **Relationships**: How entities relate to each other
- **Temporal context**: When things happened
You don't need to manually extract or structure this - just retain the conversations.
## When to Use This Pattern
**Good fit:**
- Chatbots and assistants
- Personal AI companions
- Any 1:1 user-to-agent interaction
**Consider adding shared knowledge if:**
- You have product docs or FAQs to reference
- Multiple users need access to the same information
- See [Support Agent with Shared Knowledge](./support-agent-with-shared-knowledge)