174 lines
5.6 KiB
Markdown
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)
|