docs(quick_start): update guide for ReMe MCP usage

- Rename ExperienceMaker to ReMe
- Simplify server setup instructions
- Add detailed Python client examples for MCP tools
- Include personal memory usage instructions
- Remove unnecessary sections and clarify existing content
This commit is contained in:
jinli.yl 2025-09-01 17:39:48 +08:00
parent abb1a86aef
commit 883dab7166
7 changed files with 1443 additions and 713 deletions

View file

@ -0,0 +1,287 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Task Memory Demo for MemoryScope using MCP Client
This script demonstrates how to use the task memory capabilities of MemoryScope
through the MCP client interface. It shows how to run an agent, summarize conversations,
retrieve memories, and manage the memory workspace.
"""
import json
import time
import asyncio
from typing import List, Dict, Any, Optional
from fastmcp import Client
from mcp.types import CallToolResult
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
# API configuration
MCP_URL = "http://0.0.0.0:8002/sse/"
WORKSPACE_ID = "test_workspace"
async def delete_workspace(client: Client) -> None:
"""
Delete the current workspace from the vector store
Args:
client: MCP client instance
Returns:
None
"""
try:
result = await client.call_tool(
"vector_store",
arguments={
"workspace_id": WORKSPACE_ID,
"action": "delete",
}
)
print(f"Workspace '{WORKSPACE_ID}' deleted successfully")
except Exception as e:
print(f"Error deleting workspace: {e}")
async def run_agent(client: Client, query: str, dump_messages: bool = False) -> List[Dict[str, Any]]:
"""
Run the agent with a specific query
Args:
client: MCP client instance
query: The query to send to the agent
dump_messages: Whether to save messages to a file
Returns:
List of message objects from the conversation
"""
try:
result = await client.call_tool(
"react",
arguments={"query": query}
)
# Extract and display the answer
response_data = json.loads(result.content)
answer = response_data.get("answer", "")
print(f"Agent response: {answer}")
# Get the conversation messages
messages = response_data.get("messages", [])
# Optionally save messages to file
if dump_messages and messages:
with open("messages.jsonl", "w") as f:
f.write(json.dumps(messages, indent=2, ensure_ascii=False))
print(f"Messages saved to messages.jsonl")
return messages
except Exception as e:
print(f"Error running agent: {e}")
return []
async def run_summary(client: Client, messages: List[Dict[str, Any]], enable_dump_memory: bool = True) -> None:
"""
Generate a summary of conversation messages and create task memories
Args:
client: MCP client instance
messages: List of message objects from a conversation
enable_dump_memory: Whether to save memory list to a file
Returns:
None
"""
if not messages:
print("No messages to summarize")
return
try:
result = await client.call_tool(
"summary_task_memory",
arguments={
"workspace_id": WORKSPACE_ID,
"trajectories": [
{"messages": messages, "score": 1.0}
]
}
)
response_data = json.loads(result.content)
# Extract memory list from response
memory_list = response_data.get("metadata", {}).get("memory_list", [])
print(f"Memory list: {memory_list}")
# Optionally save memory list to file
if enable_dump_memory and memory_list:
with open("task_memory.jsonl", "w") as f:
f.write(json.dumps(memory_list, indent=2, ensure_ascii=False))
print(f"Memory saved to task_memory.jsonl")
except Exception as e:
print(f"Error running summary: {e}")
async def run_retrieve(client: Client, query: str) -> str:
"""
Retrieve relevant task memories based on a query
Args:
client: MCP client instance
query: The query to retrieve relevant memories
Returns:
String containing the retrieved memory answer
"""
try:
result = await client.call_tool(
"retrieve_task_memory",
arguments={
"workspace_id": WORKSPACE_ID,
"query": query,
}
)
response_data = json.loads(result.content)
# Extract and return the answer
answer = response_data.get("answer", "")
print(f"Retrieved memory: {answer}")
return answer
except Exception as e:
print(f"Error retrieving memory: {e}")
return ""
async def run_agent_with_memory(client: Client, query_first: str, query_second: str, enable_dump_memory: bool = True) -> List[Dict[str, Any]]:
"""
Run the agent with memory augmentation
This function demonstrates how to use task memory to enhance agent responses:
1. First run the agent with the second query to build memory
2. Then summarize the conversation to create memories
3. Retrieve relevant memories for the first query
4. Run the agent with the first query augmented with retrieved memories
Args:
client: MCP client instance
query_first: The query to run with memory augmentation
query_second: The query to build initial memories
enable_dump_memory: Whether to save memory list to a file
Returns:
List of message objects from the final conversation
"""
# Run agent with second query to build initial memories
print(f"\n--- Building memories with query: '{query_second}' ---")
messages = await run_agent(client, query=query_second)
# Summarize conversation to create memories
print("\n--- Summarizing conversation to create memories ---")
await run_summary(client, messages, enable_dump_memory)
await asyncio.sleep(1)
# Retrieve relevant memories for the first query
print(f"\n--- Retrieving memories for query: '{query_first}' ---")
retrieved_memory = await run_retrieve(client, query_first)
# Run agent with first query augmented with retrieved memories
print(f"\n--- Running agent with memory-augmented query ---")
augmented_query = f"{retrieved_memory}\n\nUser Question:\n{query_first}"
print(f"Augmented query: {augmented_query}")
messages = await run_agent(client, query=augmented_query)
return messages
async def dump_memory(client: Client, path: str = "./") -> None:
"""
Dump the vector store memories to disk
Args:
client: MCP client instance
path: Directory path to save the memories
Returns:
None
"""
try:
result = await client.call_tool(
"vector_store",
arguments={
"workspace_id": WORKSPACE_ID,
"action": "dump",
"path": path,
}
)
print(f"Memory dumped to {path}")
except Exception as e:
print(f"Error dumping memory: {e}")
async def load_memory(client: Client, path: str = "./") -> None:
"""
Load memories from disk into the vector store
Args:
client: MCP client instance
path: Directory path to load the memories from
Returns:
None
"""
try:
result = await client.call_tool(
"vector_store",
arguments={
"workspace_id": WORKSPACE_ID,
"action": "load",
"path": path,
}
)
print(f"Memory loaded from {path}")
except Exception as e:
print(f"Error loading memory: {e}")
async def main() -> None:
"""
Main function to demonstrate task memory workflow
"""
# Define example queries
query1 = "Analyze Xiaomi Corporation"
query2 = "Analyze the company Tesla."
print("=== Task Memory Demo (MCP Client) ===")
async with Client(MCP_URL) as client:
# Step 1: Clean up workspace
print("\n1. Deleting workspace...")
await delete_workspace(client)
# Step 2: Run agent with first query and save messages
print("\n2. Running agent with first query...")
await run_agent(client, query=query1, dump_messages=True)
# Step 3: Demonstrate memory-augmented agent
print("\n3. Running memory-augmented agent workflow...")
await run_agent_with_memory(client, query_first=query1, query_second=query2)
# Step 4: Demonstrate memory persistence
print("\n4. Dumping memory to disk...")
await dump_memory(client)
print("\n5. Loading memory from disk...")
await load_memory(client)
print("\n=== Demo Complete ===")
if __name__ == "__main__":
asyncio.run(main())

View file

@ -1,15 +1,14 @@
# ExperienceMaker MCP Quick Start Guide
# MCP Quick Start Guide
This guide will help you get started with ExperienceMaker using the Model Context Protocol (MCP) interface for seamless
This guide will help you get started with ReMe using the Model Context Protocol (MCP) interface for seamless
integration with MCP-compatible clients.
## 🚀 What You'll Learn
- How to set up ExperienceMaker MCP server
- Connect to the server using MCP clients
- Run an agent and generate experiences via MCP
- Retrieve and apply experiences through MCP tools
- Build experience-enhanced agents with MCP integration
- How to set up and configure ReMe MCP server
- How to connect to the server using Python MCP clients
- How to use task memory operations through MCP
- How to build experience-enhanced agents with MCP integration
## 📋 Prerequisites
@ -23,14 +22,14 @@ integration with MCP-compatible clients.
### Option 1: Install from PyPI (Recommended)
```bash
pip install experiencemaker
pip install reme_ai
```
### Option 2: Install from Source
```bash
git clone https://github.com/modelscope/ExperienceMaker.git
cd ExperienceMaker
git clone https://github.com/modelscope/ReMe.git
cd ReMe
pip install .
```
@ -39,77 +38,58 @@ pip install .
Create a `.env` file in your project directory:
```bash
# Required: LLM API configuration
LLM_API_KEY="sk-xxx"
LLM_BASE_URL="https://xxx.com/v1"
FLOW_EMBEDDING_API_KEY=sk-xxxx
FLOW_EMBEDDING_BASE_URL=https://xxxx/v1
# Required: Embedding model configuration
EMBEDDING_MODEL_API_KEY="sk-xxx"
EMBEDDING_MODEL_BASE_URL="https://xxx.com/v1"
# Optional: Elasticsearch configuration (if using Elasticsearch backend)
ES_HOSTS="http://localhost:9200"
FLOW_LLM_API_KEY=sk-xxxx
FLOW_LLM_BASE_URL=https://xxxx/v1
```
## 🚀 Start the MCP Server
## 🚀 Building an MCP Server with ReMe
### Option 1: STDIO Transport (Recommended for MCP clients)
ReMe provides a flexible framework for building MCP servers that can communicate using either STDIO or SSE (Server-Sent
Events) transport protocols.
### Starting the MCP Server
#### Option 1: STDIO Transport (Recommended for MCP clients)
```bash
experiencemaker_mcp \
mcp_transport=stdio \
llm.default.model_name=qwen3-32b \
reme \
backend=mcp \
mcp.transport=stdio \
llm.default.model_name=qwen3-30b-a3b-thinking-2507 \
embedding_model.default.model_name=text-embedding-v4 \
vector_store.default.backend=local_file
vector_store.default.backend=local
```
### Option 2: SSE Transport (Server-Sent Events)
#### Option 2: SSE Transport (Server-Sent Events)
```bash
experiencemaker_mcp \
mcp_transport=sse \
reme \
backend=mcp \
mcp.transport=sse \
http_service.port=8001 \
llm.default.model_name=qwen3-32b \
llm.default.model_name=qwen3-30b-a3b-thinking-2507 \
embedding_model.default.model_name=text-embedding-v4 \
vector_store.default.backend=local_file
vector_store.default.backend=local
```
The SSE server will start on `http://localhost:8001/sse`
The SSE server will start on `http://localhost:8002/sse`
### Elasticsearch Backend
### Configuring MCP Server for Claude Desktop
```bash
experiencemaker_mcp \
mcp_transport=stdio \
llm.default.model_name=qwen3-32b \
embedding_model.default.model_name=text-embedding-v4 \
vector_store.default.backend=elasticsearch
```
**Setup Elasticsearch:**
```bash
export ES_HOSTS="http://localhost:9200"
# Quick setup using Elastic's official script
curl -fsSL https://elastic.co/start-local | sh
```
📖 **Need Help?** Refer to [Vector Store Setup](vector_store_setup.md) for comprehensive deployment guidance.
## 🔧 Configure MCP Client
### Claude Desktop Configuration
Add to your Claude Desktop `claude_desktop_config.json`:
To integrate with Claude Desktop, add the following configuration to your `claude_desktop_config.json`:
```json
{
"mcpServers": {
"experiencemaker": {
"command": "experiencemaker_mcp",
"reme": {
"command": "reme",
"args": [
"mcp_transport=stdio",
"llm.default.model_name=qwen3-32b",
"backend=mcp",
"mcp.transport=stdio",
"llm.default.model_name=qwen3-30b-a3b-thinking-2507",
"embedding_model.default.model_name=text-embedding-v4",
"vector_store.default.backend=local_file"
]
@ -118,453 +98,311 @@ Add to your Claude Desktop `claude_desktop_config.json`:
}
```
### Custom MCP Client Configuration
This configuration:
If using a custom MCP client, connect to:
1. Registers a new MCP server named "reme"
2. Specifies the command to launch the server (`reme`)
3. Configures the server to use STDIO transport
4. Sets the LLM and embedding models to use
5. Configures the vector store backend
- **STDIO**: Use subprocess to communicate with the server
- **SSE**: Connect to `http://localhost:8001/sse`
### Advanced Server Configuration Options
## 📝 Using ExperienceMaker MCP Tools
For more advanced use cases, you can configure the server with additional parameters:
The MCP server exposes three main tools:
```bash
# Full configuration example
reme \
backend=mcp \
mcp.transport=stdio \
http_service.host=0.0.0.0 \
http_service.port=8002 \
llm.default.model_name=qwen3-30b-a3b-thinking-2507 \
embedding_model.default.model_name=text-embedding-v4 \
vector_store.default.backend=elasticsearch \
```
- `retriever`: Retrieve experiences from workspace
- `summarizer`: Transform trajectories into experiences
- `vector_store`: Manage vector store operations
## 🔌 Using Python Client to Call MCP Services
Note: The `workspace_id` serves as your experience storage namespace. Experiences in different workspaces remain
completely isolated.
The ReMe framework provides a Python client for interacting with MCP services. This section focuses specifically on
using the `summary_task_memory` and `retrieve_task_memory` tools.
### 📊 Using the Summarizer Tool
### Setting Up the Python MCP Client
Transform conversation trajectories into valuable experiences using batch summarization.
First, install the required packages:
**Tool Parameters:**
```bash
pip install fastmcp dotenv
```
- `traj_list`: List of trajectories (each containing messages and score)
- `workspace_id`: Workspace identifier (default: "default")
- `config`: Additional configuration parameters (optional)
<details open>
<summary><b>Python MCP Client Example</b></summary>
Then, create a basic client connection:
```python
import asyncio
from fastmcp import Client
from dotenv import load_dotenv
from experiencemaker.schema.message import Message, Trajectory, Role
from experiencemaker.schema.request import SummarizerRequest
from experiencemaker.service.mcp_client import MCPClient
# Load environment variables
load_dotenv()
# MCP server URL (for SSE transport)
MCP_URL = "http://0.0.0.0:8002/sse/"
WORKSPACE_ID = "my_workspace"
async def example_summarizer():
async with MCPClient(base_url="http://0.0.0.0:8001/sse") as client:
# Create trajectory with conversation
trajectory = Trajectory(
messages=[
Message(role=Role.USER, content="Hello, how can I solve a math problem?"),
Message(role=Role.ASSISTANT, content="I'd be happy to help! What math problem are you working on?"),
Message(role=Role.USER, content="What is 2+2?"),
Message(role=Role.ASSISTANT, content="2+2 equals 4.")
],
score=1.0 # Success score
)
request = SummarizerRequest(
workspace_id="math_workspace",
traj_list=[trajectory]
)
response = await client.call_summarizer(request)
print("Generated experiences:")
for experience in response.experience_list:
print(f"- {experience.content}")
async def main():
async with Client(MCP_URL) as client:
# Your MCP operations will go here
pass
# Run the example
asyncio.run(example_summarizer())
if __name__ == "__main__":
asyncio.run(main())
```
</details>
### Using the Task Memory Summarizer
<details>
<summary><b>MCP Tool Call (JSON)</b></summary>
The `summary_task_memory` tool transforms conversation trajectories into valuable task memories:
```json
{
"method": "tools/call",
"params": {
"name": "summarizer",
"arguments": {
"traj_list": [
{
"messages": [
{
"role": "user",
"content": "Hello, how can I solve a math problem?"
},
{
"role": "assistant",
"content": "I'd be happy to help! What math problem are you working on?"
},
{
"role": "user",
"content": "What is 2+2?"
},
{
"role": "assistant",
"content": "2+2 equals 4."
```python
async def run_summary(client, messages):
"""
Generate a summary of conversation messages and create task memories
Args:
client: MCP client instance
messages: List of message objects from a conversation
Returns:
None
"""
try:
result = await client.call_tool(
"summary_task_memory",
arguments={
"workspace_id": "my_workspace",
"trajectories": [
{"messages": messages, "score": 1.0}
]
}
],
"score": 1.0
)
# Parse the response
import json
response_data = json.loads(result.content)
# Extract memory list from response
memory_list = response_data.get("metadata", {}).get("memory_list", [])
print(f"Created memories: {memory_list}")
# Optionally save memories to file
with open("task_memory.jsonl", "w") as f:
f.write(json.dumps(memory_list, indent=2, ensure_ascii=False))
except Exception as e:
print(f"Error running summary: {e}")
```
### Using the Task Memory Retriever
The `retrieve_task_memory` tool allows you to retrieve relevant memories based on a query:
```python
async def run_retrieve(client, query):
"""
Retrieve relevant task memories based on a query
Args:
client: MCP client instance
query: The query to retrieve relevant memories
Returns:
String containing the retrieved memory answer
"""
try:
result = await client.call_tool(
"retrieve_task_memory",
arguments={
"workspace_id": "my_workspace",
"query": query,
}
)
# Parse the response
import json
response_data = json.loads(result.content)
# Extract and return the answer
answer = response_data.get("answer", "")
print(f"Retrieved memory: {answer}")
return answer
except Exception as e:
print(f"Error retrieving memory: {e}")
return ""
```
### Complete Memory-Augmented Agent Example
Here's a complete example showing how to build a memory-augmented agent using the MCP client:
```python
import json
import asyncio
from fastmcp import Client
from dotenv import load_dotenv
# Load environment variables
load_dotenv()
# API configuration
MCP_URL = "http://0.0.0.0:8002/sse/"
WORKSPACE_ID = "test_workspace"
async def run_agent(client, query):
"""Run the agent with a specific query"""
result = await client.call_tool(
"react",
arguments={"query": query}
)
response_data = json.loads(result.content)
answer = response_data.get("answer", "")
messages = response_data.get("messages", [])
return messages
async def run_summary(client, messages):
"""Generate task memories from conversation"""
result = await client.call_tool(
"summary_task_memory",
arguments={
"workspace_id": WORKSPACE_ID,
"trajectories": [
{"messages": messages, "score": 1.0}
]
}
],
"workspace_id": "math_workspace"
}
}
}
)
response_data = json.loads(result.content)
memory_list = response_data.get("metadata", {}).get("memory_list", [])
return memory_list
async def run_retrieve(client, query):
"""Retrieve relevant task memories"""
result = await client.call_tool(
"retrieve_task_memory",
arguments={
"workspace_id": WORKSPACE_ID,
"query": query,
}
)
response_data = json.loads(result.content)
answer = response_data.get("answer", "")
return answer
async def memory_augmented_workflow():
"""Complete memory-augmented agent workflow"""
query1 = "Analyze Xiaomi Corporation"
query2 = "Analyze the company Tesla."
async with Client(MCP_URL) as client:
# Step 1: Build initial memories with query2
print(f"Building memories with: '{query2}'")
messages = await run_agent(client, query=query2)
# Step 2: Summarize conversation to create memories
print("Creating memories from conversation")
memory_list = await run_summary(client, messages)
print(f"Created {len(memory_list)} memories")
# Step 3: Retrieve relevant memories for query1
print(f"Retrieving memories for: '{query1}'")
retrieved_memory = await run_retrieve(client, query1)
# Step 4: Run agent with memory-augmented query
print("Running memory-augmented agent")
augmented_query = f"{retrieved_memory}\n\nUser Question:\n{query1}"
final_messages = await run_agent(client, query=augmented_query)
# Extract the agent's final answer
final_answer = ""
for msg in final_messages:
if msg.get("role") == "assistant" and msg.get("content"):
final_answer = msg.get("content")
break
print(f"Memory-augmented response: {final_answer}")
# Run the workflow
if __name__ == "__main__":
asyncio.run(memory_augmented_workflow())
```
</details>
### Managing Vector Store with MCP
### 🔍 Using the Retriever Tool
Intelligently search and retrieve the most relevant experiences from your workspace.
**Tool Parameters:**
- `query`: Search query string
- `messages`: List of conversation messages (optional)
- `top_k`: Number of top experiences to retrieve (default: 1)
- `workspace_id`: Workspace identifier (default: "default")
- `config`: Additional configuration parameters (optional)
<details open>
<summary><b>Python MCP Client Example</b></summary>
You can also manage your vector store through MCP:
```python
import asyncio
from experiencemaker.service.mcp_client import MCPClient
from experiencemaker.schema.request import RetrieverRequest
async def manage_vector_store(client):
# Delete a workspace
await client.call_tool(
"vector_store",
arguments={
"workspace_id": WORKSPACE_ID,
"action": "delete",
}
)
# Dump memories to disk
await client.call_tool(
"vector_store",
arguments={
"workspace_id": WORKSPACE_ID,
"action": "dump",
"path": "./backups/",
}
)
async def example_retriever():
async with MCPClient(base_url="http://0.0.0.0:8001/sse") as client:
request = RetrieverRequest(
workspace_id="math_workspace",
query="How to solve basic arithmetic problems?",
top_k=3
)
response = await client.call_retriever(request)
print(f"Retrieved experiences: {response.experience_merged}")
print(f"Experience list:")
for exp in response.experience_list:
print(f"- {exp.content}")
# Run the example
asyncio.run(example_retriever())
# Load memories from disk
await client.call_tool(
"vector_store",
arguments={
"workspace_id": WORKSPACE_ID,
"action": "load",
"path": "./backups/",
}
)
```
</details>
<details>
<summary><b>MCP Tool Call (JSON)</b></summary>
```json
{
"method": "tools/call",
"params": {
"name": "retriever",
"arguments": {
"query": "How to solve basic arithmetic problems?",
"top_k": 3,
"workspace_id": "math_workspace"
}
}
}
```
</details>
### 💾 Using the Vector Store Tool
Manage vector store operations for workspace data.
**Tool Parameters:**
- `action`: Action to perform ("dump", "load", "delete", "copy")
- `workspace_id`: Target workspace identifier
- `src_workspace_id`: Source workspace (for copy operation)
- `path`: File system path (for dump/load operations, default: "./")
- `config`: Additional configuration parameters (optional)
#### Dump Experiences From Vector Store
<details open>
<summary><b>Python MCP Client Example</b></summary>
```python
import asyncio
from experiencemaker.service.mcp_client import MCPClient
from experiencemaker.schema.request import VectorStoreRequest
async def example_dump():
async with MCPClient(base_url="http://0.0.0.0:8001/sse") as client:
request = VectorStoreRequest(
workspace_id="math_workspace",
action="dump",
path="./backups/"
)
response = await client.call_vector_store(request)
print(f"Dump result: {response}")
# Run the example
asyncio.run(example_dump())
```
</details>
<details>
<summary><b>MCP Tool Call (JSON)</b></summary>
```json
{
"method": "tools/call",
"params": {
"name": "vector_store",
"arguments": {
"action": "dump",
"workspace_id": "math_workspace",
"path": "./backups/"
}
}
}
```
</details>
#### Load Experiences To Vector Store
<details open>
<summary><b>Python MCP Client Example</b></summary>
```python
import asyncio
from experiencemaker.service.mcp_client import MCPClient
from experiencemaker.schema.request import VectorStoreRequest
async def example_load():
async with MCPClient(base_url="http://0.0.0.0:8001/sse") as client:
request = VectorStoreRequest(
workspace_id="math_workspace",
action="load",
path="./backups/"
)
response = await client.call_vector_store(request)
print(f"Load result: {response}")
# Run the example
asyncio.run(example_load())
```
</details>
#### Delete Workspace
<details open>
<summary><b>Python MCP Client Example</b></summary>
```python
import asyncio
from experiencemaker.service.mcp_client import MCPClient
from experiencemaker.schema.request import VectorStoreRequest
async def example_delete():
async with MCPClient(base_url="http://0.0.0.0:8001/sse") as client:
request = VectorStoreRequest(
workspace_id="math_workspace",
action="delete"
)
response = await client.call_vector_store(request)
print(f"Delete result: {response}")
# Run the example
asyncio.run(example_delete())
```
</details>
#### Copy Workspace
<details open>
<summary><b>Python MCP Client Example</b></summary>
```python
import asyncio
from experiencemaker.service.mcp_client import MCPClient
from experiencemaker.schema.request import VectorStoreRequest
async def example_copy():
async with MCPClient(base_url="http://0.0.0.0:8001/sse") as client:
request = VectorStoreRequest(
workspace_id="math_workspace_copy",
action="copy",
src_workspace_id="math_workspace"
)
response = await client.call_vector_store(request)
print(f"Copy result: {response}")
# Run the example
asyncio.run(example_copy())
```
</details>
## 🔄 Complete MCP Workflow Example
Here's a complete example showing the full workflow:
```python
import asyncio
from experiencemaker.service.mcp_client import MCPClient
from experiencemaker.schema.request import SummarizerRequest, RetrieverRequest
from experiencemaker.schema.message import Message, Trajectory, Role
async def complete_workflow():
async with MCPClient(base_url="http://0.0.0.0:8001/sse") as client:
print("Available tools:", await client.list_tools())
# Step 1: Create experiences from trajectories
trajectory = Trajectory(
messages=[
Message(role=Role.USER, content="How do I calculate compound interest?"),
Message(role=Role.ASSISTANT,
content="Compound interest is calculated using the formula A = P(1 + r/n)^(nt), where A is the final amount, P is the principal, r is the annual interest rate, n is the number of times interest is compounded per year, and t is the time in years."),
Message(role=Role.USER, content="Can you give me an example?"),
Message(role=Role.ASSISTANT,
content="Sure! If you invest $1000 at 5% annual interest compounded monthly for 2 years: A = 1000(1 + 0.05/12)^(12*2) = $1104.94")
],
score=1.0
)
summarizer_request = SummarizerRequest(
workspace_id="finance_workspace",
traj_list=[trajectory]
)
summarizer_response = await client.call_summarizer(summarizer_request)
print(f"Created {len(summarizer_response.experience_list)} experiences")
# Step 2: Retrieve relevant experiences
retriever_request = RetrieverRequest(
workspace_id="finance_workspace",
query="How to calculate interest on investments?",
top_k=2
)
retriever_response = await client.call_retriever(retriever_request)
print(f"Retrieved experiences: {retriever_response.experience_merged}")
# Run the complete workflow
asyncio.run(complete_workflow())
```
## 🎭 Claude Desktop Integration
Once configured with Claude Desktop, you can directly ask Claude to use ExperienceMaker tools:
```
Claude, please use the summarizer tool to create experiences from this conversation about solving math problems, then retrieve similar experiences when I ask about arithmetic.
```
Claude will automatically call the appropriate MCP tools and provide contextually relevant responses based on your
stored experiences.
## 🐛 Common Issues
## 🐛 Common Issues and Troubleshooting
### MCP Server Won't Start
- Check if the required ports are available (for SSE transport)
- Verify your API keys in `.env` file
- Ensure Python version is 3.12+
- Check MCP transport configuration
### MCP Client Connection Issues
- For STDIO: Ensure the command path is correct in your MCP client config
- For SSE: Verify the server URL and port accessibility
- Check firewall settings for SSE connections
### No Experiences Retrieved
### No Memories Retrieved
- Make sure you've run the summarizer tool first to create experiences
- Make sure you've run the summarizer tool first to create memories
- Check if workspace_id matches between operations
- Verify vector store backend is properly configured
### API Connection Errors
- Confirm LLM_BASE_URL and API keys are correct
- Test API access independently
- Check network connectivity
## 🔧 Advanced Configuration
### Custom MCP Client Setup
```python
# For STDIO transport
async with MCPClient(enable_sse=False) as client:
# Your MCP operations here
pass
# For SSE transport with custom URL
async with MCPClient(base_url="http://custom-host:8001/sse") as client:
# Your MCP operations here
pass
```
### Server Configuration Options
```bash
# Full configuration example
experiencemaker_mcp \
mcp_transport=stdio \
http_service.host=0.0.0.0 \
http_service.port=8001 \
llm.default.model_name=qwen3-32b \
llm.default.api_key=${LLM_API_KEY} \
llm.default.base_url=${LLM_BASE_URL} \
embedding_model.default.model_name=text-embedding-v4 \
embedding_model.default.api_key=${EMBEDDING_MODEL_API_KEY} \
embedding_model.default.base_url=${EMBEDDING_MODEL_BASE_URL} \
vector_store.default.backend=elasticsearch \
vector_store.default.host=localhost \
vector_store.default.port=9200
```
---
🎯 **You're all set!** You now have a working ExperienceMaker MCP setup that can seamlessly integrate with MCP-compatible
clients and learn from interactions to improve over time through the standardized MCP protocol.
## 📚 Next Steps
- Explore the [Configuration Guide](configuration_guide.md) for advanced customization
- Check out [cookbook examples](../cookbook/) for practical implementations
- Learn about [Vector Store Setup](vector_store_setup.md) for production deployments
- Review the [Operations Documentation](operations_documentation.md) for maintenance procedures

View file

@ -0,0 +1,124 @@
# Personal Memory in reme
## Configuration Logic
reme's personal memory system consists of two main components: retrieval and summarization. The configuration for these components is defined in the default.yaml file.
### Retrieval Configuration (`retrieve_personal_memory`)
```yaml
retrieve_personal_memory:
flow_content: set_query_op >> (extract_time_op | (retrieve_memory_op >> semantic_rank_op)) >> fuse_rerank_op
```
This flow performs the following operations:
1. `set_query_op`: Prepares the query for memory retrieval
2. Parallel paths:
- `extract_time_op`: Extracts time-related information from the query
- `retrieve_memory_op >> semantic_rank_op`: Retrieves memories and ranks them semantically
3. `fuse_rerank_op`: Combines and reranks the results for final output
### Summarization Configuration (`summary_personal_memory`)
```yaml
summary_personal_memory:
flow_content: info_filter_op >> (get_observation_op | get_observation_with_time_op | load_today_memory_op) >> contra_repeat_op >> update_vector_store_op
```
This flow performs the following operations:
1. `info_filter_op`: Filters incoming information to extract relevant personal details
2. Parallel paths for observation extraction:
- `get_observation_op`: Extracts general observations
- `get_observation_with_time_op`: Extracts observations with time context
- `load_today_memory_op`: Loads memories from the current day
3. `contra_repeat_op`: Removes contradictions and repetitions
4. `update_vector_store_op`: Stores the processed memories in the vector database
## Basic Usage
The following example demonstrates how to use personal memory in MemoryScope:
### 1. Setup
```python
import asyncio
import json
import aiohttp
# API base URL (default is http://0.0.0.0:8002)
base_url = "http://0.0.0.0:8002"
workspace_id = "personal_memory_demo"
```
### 2. Clear Existing Memories
```python
async with aiohttp.ClientSession() as session:
# Delete existing workspace memories
async with session.post(
f"{base_url}/vector_store",
json={
"action": "delete",
"workspace_id": workspace_id,
},
headers={"Content-Type": "application/json"}
) as response:
result = await response.json()
```
### 3. Create Conversation with Personal Information
```python
# Example conversation with personal details
messages = [
{"role": "user", "content": "My name is John Smith, I'm 28 years old"},
{"role": "assistant", "content": "Nice to meet you, John!"},
{"role": "user", "content": "I'm a software engineer working with Python"},
{"role": "assistant", "content": "I see, you're a Python engineer."},
# Additional conversation messages...
]
```
### 4. Summarize Personal Memories
```python
async with session.post(
f"{base_url}/summary_personal_memory",
json={
"trajectories": [
{"messages": messages, "score": 1.0}
],
"workspace_id": workspace_id,
},
headers={"Content-Type": "application/json"}
) as response:
result = await response.json()
```
### 5. Retrieve Personal Memories
```python
# Example queries to retrieve personal information
queries = [
"What's my name and age?",
"What do I do for work?",
"What are my hobbies?"
]
for query in queries:
async with session.post(
f"{base_url}/retrieve_personal_memory",
json={
"query": query,
"workspace_id": workspace_id,
},
headers={"Content-Type": "application/json"}
) as response:
result = await response.json()
print(f"Query: {query}")
print(f"Answer: {result.get('answer', '')}")
```
## Complete Example
For a complete working example, refer to `/cookbook/simple_demo/use_personal_memory_demo.py` in the reme repository.

View file

@ -0,0 +1,152 @@
# Personal Memory Retrieve Operations
This document describes the operations used in the personal memory retrieval flow of MemoryScope. The retrieval flow is defined in the configuration as:
```yaml
retrieve_personal_memory:
flow_content: set_query_op >> (extract_time_op | (retrieve_memory_op >> semantic_rank_op)) >> fuse_rerank_op
```
## SetQueryOp
### Functionality
`SetQueryOp` prepares the query for memory retrieval by setting the query and its associated timestamp into the context. It's the first operation in the personal memory retrieval flow.
### Parameters
- `op.set_query_op.params.timestamp`: (Optional) Integer timestamp to use instead of the current time. If not provided, the current timestamp will be used.
### Implementation Details
The operation:
1. Takes the query from the context (which is guaranteed to exist as a flow input requirement)
2. Sets a timestamp (either current time or from parameters)
3. Stores the query and timestamp as a tuple in the context for downstream operations
## ExtractTimeOp
### Functionality
`ExtractTimeOp` identifies and extracts time-related information from the query. It uses an LLM to analyze the query text and determine any temporal references or constraints.
### Parameters
- `op.extract_time_op.params.language`: Language for time extraction (defaults to "en")
### Implementation Details
The operation:
1. Checks if the query contains datetime keywords
2. If time-related words are found, it prepares a prompt for the LLM with:
- System instructions
- Few-shot examples
- The user's query and current time
3. Parses the LLM response to extract time information (year, month, day, etc.)
4. Stores the extracted time dictionary in the context for downstream operations
## RetrieveMemoryOp
### Functionality
`RetrieveMemoryOp` retrieves memories from the vector store based on the query. It extends the `RecallVectorStoreOp` class to provide memory retrieval functionality.
### Parameters
- `op.retrieve_memory_op.params.recall_key`: Key in the context to use as the query (default: "query")
- `op.retrieve_memory_op.params.top_k`: Maximum number of memories to retrieve (default: 3)
- `op.retrieve_memory_op.params.threshold_score`: (Optional) Minimum similarity score for memories (filters out memories below this threshold)
### Implementation Details
The operation:
1. Retrieves the query from the context
2. Searches the vector store for relevant memories based on the query
3. Removes duplicate memories
4. Filters memories by threshold score if specified
5. Stores the retrieved memories in the context for downstream operations
## SemanticRankOp
### Functionality
`SemanticRankOp` ranks memories based on their semantic relevance to the query using an LLM. This improves the quality of retrieved memories by considering deeper semantic relationships beyond vector similarity.
### Parameters
- `op.semantic_rank_op.params.enable_ranker`: Whether to enable semantic ranking (default: true)
- `op.semantic_rank_op.params.output_memory_max_count`: Maximum number of memories to output (default: 10)
### Implementation Details
The operation:
1. Retrieves the memory list from the context
2. If ranking is enabled and there are more memories than the output limit:
- Removes duplicates based on content
- Formats memories for LLM ranking
- Asks the LLM to rank memories by relevance on a scale of 0.0 to 1.0
- Parses the ranking results and applies scores to memories
3. Sorts memories by score
4. Stores the ranked memories in the context for downstream operations
## FuseRerankOp
### Functionality
`FuseRerankOp` performs the final reranking of memories by combining multiple factors: semantic scores, memory types, and temporal relevance. It also formats the final output.
### Parameters
- `op.fuse_rerank_op.params.fuse_score_threshold`: Minimum score threshold for memories (default: 0.1)
- `op.fuse_rerank_op.params.fuse_ratio_dict`: Dictionary of memory type to score multiplier ratios (default: {"conversation": 0.5, "observation": 1, "obs_customized": 1.2, "insight": 2.0})
- `op.fuse_rerank_op.params.fuse_time_ratio`: Score multiplier for time-relevant memories (default: 2.0)
- `op.fuse_rerank_op.params.output_memory_max_count`: Maximum number of memories to output (default: 5)
### Implementation Details
The operation:
1. Retrieves extracted time information and memory list from the context
2. For each memory:
- Checks if the memory score is above the threshold
- Applies a type-based adjustment factor based on the memory type
- Determines time relevance by matching memory time metadata with extracted time
- Calculates the final score by multiplying the original score by type and time factors
3. Sorts memories by the reranked scores
4. Selects the top-K memories based on the output limit
5. Formats memories for output with timestamps if available
6. Stores both the formatted output and the memory list in the context
## PrintMemoryOp
### Functionality
`PrintMemoryOp` formats the retrieved memories for display to the user. It provides a clean, structured representation of the memory content.
### Parameters
No specific parameters for this operation.
### Implementation Details
The operation:
1. Retrieves the memory list from the context
2. Formats each memory with:
- Memory index
- When to use information
- Content
- Additional metadata (if available)
3. Joins the formatted memories into a single string
4. Stores the formatted string in the context as the response answer
## ReadMessageOp
### Functionality
`ReadMessageOp` fetches unmemorized chat messages from the context. This is useful for retrieving recent conversations that haven't been processed into memories yet.
### Parameters
- `op.read_message_op.params.contextual_msg_max_count`: Maximum number of contextual messages to retrieve (default: 10)
### Implementation Details
The operation:
1. Retrieves chat messages from the context
2. Filters for messages that:
- Are not marked as memorized
- Contain the target name
3. Flattens the messages into a single list
4. Sorts messages by creation time if available
5. Stores the filtered messages back in the context
## Complete Flow Execution
When the personal memory retrieval flow executes:
1. `SetQueryOp` prepares the query with timestamp
2. Two parallel paths execute:
- `ExtractTimeOp` extracts time information from the query
- `RetrieveMemoryOp` followed by `SemanticRankOp` retrieves and ranks memories
3. `FuseRerankOp` combines the results, considering both semantic relevance and time information
4. The final output is a ranked list of memories relevant to the query
This flow provides a sophisticated memory retrieval system that considers semantic relevance, memory types, and temporal context to deliver the most appropriate memories for a given query.

View file

@ -0,0 +1,196 @@
# Personal Memory Summary Operations
This document provides a detailed overview of the operations (ops) used in the personal memory summarization flow in MemoryScope. Each operation plays a specific role in processing, filtering, and storing personal memories.
## Overview
As defined in the configuration, the personal memory summarization flow follows this sequence:
```yaml
summary_personal_memory:
flow_content: info_filter_op >> (get_observation_op | get_observation_with_time_op | load_today_memory_op) >> contra_repeat_op >> update_vector_store_op
```
This document describes each operation in detail, including its purpose, parameters, and configuration options.
## InfoFilterOp
### Purpose
Filters messages based on information content scores, retaining only those that include significant information about the user.
### Parameters
- `op.info_filter_op.params.preserved_scores`: Comma-separated string of scores to preserve (default: "2,3")
- `op.info_filter_op.params.info_filter_msg_max_size`: Maximum size of messages to process (default: 200)
### Description
This operation analyzes messages to determine which ones contain valuable personal information. It uses an LLM to score each message on a scale of 0-3:
- 0: No user information
- 1: Hypothetical or fictional content
- 2: General or time-sensitive information
- 3: Clear, important information or explicitly requested records
Only messages with scores specified in `preserved_scores` are retained. Messages are also filtered to exclude those already memorized and to only include messages from the user.
## GetObservationOp
### Purpose
Extracts general observations about the user from messages that don't contain time-related information.
### Parameters
No specific parameters for this operation.
### Description
This operation processes messages that don't contain time-related keywords. It uses an LLM to extract meaningful observations about the user from these messages. Each observation includes:
- Content: The actual observation text
- Keywords: Tags that indicate when this observation might be relevant
- Source message: The original message that led to this observation
The operation creates `PersonalMemory` objects with observation type "personal_info" for each extracted observation.
## GetObservationWithTimeOp
### Purpose
Extracts observations with time context from messages that contain time-related information.
### Parameters
No specific parameters for this operation.
### Description
This operation is the counterpart to `GetObservationOp` but focuses specifically on messages containing time-related keywords. It extracts observations while preserving the time context, which is important for memories related to schedules, appointments, or time-specific preferences.
The operation creates `PersonalMemory` objects with observation type "personal_info_with_time" for each extracted observation, including the time information in the metadata.
## LoadTodayMemoryOp
### Purpose
Loads memories created today from the vector store to prevent duplication and enable updating of recent memories.
### Parameters
- `op.load_today_memory_op.params.top_k`: Maximum number of memories to retrieve (default: 50)
### Description
This operation retrieves memories created on the current day using vector store search with date filtering. It converts vector nodes to memory objects and makes them available for deduplication in subsequent operations. This helps ensure that new observations don't create redundant memories for information already captured earlier in the day.
## ContraRepeatOp
### Purpose
Identifies and removes contradictory or repetitive information from the collected memories.
### Parameters
- `op.contra_repeat_op.params.contra_repeat_max_count`: Maximum number of memories to process (default: 50)
- `op.contra_repeat_op.params.enable_contra_repeat`: Whether to enable contradiction/repetition checking (default: true)
### Description
This operation analyzes the combined memories from previous operations (observation_memories, observation_memories_with_time, today_memories) to identify contradictions or redundancies. It uses an LLM to evaluate each memory and mark it as:
- "Contradiction": Contradicts other memories
- "Contained": Redundant as the information is already contained in other memories
- "None": Unique and should be kept
Memories marked as contradictory or contained are filtered out, and their IDs are tracked for deletion from the vector store.
## LongContraRepeatOp
### Purpose
Performs more sophisticated contradiction and redundancy analysis for longer-term memory management.
### Parameters
- `op.long_contra_repeat_op.params.long_contra_repeat_max_count`: Maximum number of memories to process (default: 50)
- `op.long_contra_repeat_op.params.enable_long_contra_repeat`: Whether to enable this operation (default: true)
### Description
This operation extends the basic contradiction analysis of `ContraRepeatOp` with the ability to resolve conflicts by modifying contradictory memories rather than simply removing them. It's particularly useful for managing long-term personal memories where information might evolve over time.
For contradictory memories, it can either:
- Modify the content to resolve the contradiction
- Remove the memory if it's completely invalidated
- Keep the most accurate/recent information
## UpdateInsightOp
### Purpose
Updates existing insight values based on new observations.
### Parameters
- `op.update_insight_op.params.update_insight_threshold`: Minimum relevance score threshold (default: 0.3)
- `op.update_insight_op.params.update_insight_max_count`: Maximum number of insights to update (default: 5)
### Description
This operation integrates new observations into existing insights about the user. It:
1. Scores insight memories based on relevance to new observations
2. Selects the top insights that meet the relevance threshold
3. Updates each selected insight using an LLM to incorporate the new information
4. Creates updated insight memories with the original ID but new content
This helps maintain accurate and up-to-date insights as new information about the user becomes available.
## GetReflectionSubjectOp
### Purpose
Generates reflection subjects (topics) from personal memories for insight extraction.
### Parameters
- `op.get_reflection_subject_op.params.reflect_obs_cnt_threshold`: Minimum number of memories required for reflection (default: 10)
- `op.get_reflection_subject_op.params.reflect_num_questions`: Maximum number of new subjects to generate (default: 3)
### Description
This operation analyzes a collection of personal memories to identify potential topics for reflection and insight generation. It:
1. Checks if there are sufficient memories for meaningful reflection
2. Extracts existing insight subjects to avoid duplication
3. Uses an LLM to generate new reflection subjects based on memory content
4. Creates insight memory objects for these new subjects
The generated subjects serve as focal points for organizing and synthesizing personal information about the user.
## UpdateVectorStoreOp
### Purpose
Stores the processed memories in the vector database and removes deleted memories.
### Parameters
No specific parameters for this operation.
### Description
This operation is the final step in the personal memory summarization flow. It:
1. Deletes memories that were marked for removal (contradictory or redundant)
2. Inserts new or updated memories into the vector store
3. Records the number of deleted and inserted memories
This ensures that the vector store remains up-to-date with the latest processed memories.
## Configuration Example
Here's an example of how to configure these operations in your YAML configuration:
```yaml
op:
info_filter_op:
params:
preserved_scores: "2,3"
info_filter_msg_max_size: 200
load_today_memory_op:
params:
top_k: 50
contra_repeat_op:
params:
contra_repeat_max_count: 50
enable_contra_repeat: true
long_contra_repeat_op:
params:
long_contra_repeat_max_count: 50
enable_long_contra_repeat: true
update_insight_op:
params:
update_insight_threshold: 0.3
update_insight_max_count: 5
get_reflection_subject_op:
params:
reflect_obs_cnt_threshold: 10
reflect_num_questions: 3
```
This configuration can be adjusted based on your specific requirements for personal memory processing.

View file

@ -0,0 +1,390 @@
# 🚀 Vector Store API Guide
This guide covers the vector store implementations available in flowllm, their APIs, and how to use them effectively.
## 📋 Overview
flowllm provides multiple vector store backends for different use cases:
- **LocalVectorStore** (`backend=local`) - 📁 Simple file-based storage for development and small datasets
- **ChromaVectorStore** (`backend=chroma`) - 🔮 Embedded vector database for moderate scale
- **EsVectorStore** (`backend=elasticsearch`) - 🔍 Elasticsearch-based storage for production and large scale
All vector stores implement the `BaseVectorStore` interface, providing a consistent API across implementations.
## 🔄 Common API Methods
All vector store implementations share these core methods:
### Workspace Management
```python
# Check if workspace exists
store.exist_workspace(workspace_id: str) -> bool
# Create a new workspace
store.create_workspace(workspace_id: str, **kwargs)
# Delete a workspace
store.delete_workspace(workspace_id: str, **kwargs)
# Copy a workspace
store.copy_workspace(src_workspace_id: str, dest_workspace_id: str, **kwargs)
```
### Data Operations
```python
# Insert nodes (single or list)
store.insert(nodes: VectorNode | List[VectorNode], workspace_id: str, **kwargs)
# Delete nodes by ID
store.delete(node_ids: str | List[str], workspace_id: str, **kwargs)
# Search for similar nodes
store.search(query: str, workspace_id: str, top_k: int = 1, **kwargs) -> List[VectorNode]
# Iterate through workspace nodes
for node in store.iter_workspace_nodes(workspace_id: str, **kwargs):
# Process each node
```
### Import/Export
```python
# Export workspace to file
store.dump_workspace(workspace_id: str, path: str | Path = "", callback_fn=None, **kwargs)
# Import workspace from file
store.load_workspace(workspace_id: str, path: str | Path = "", nodes: List[VectorNode] = None,
callback_fn=None, **kwargs)
```
## ⚡ Vector Store Implementations
### 1. 📁 LocalVectorStore (`backend=local`)
A simple file-based vector store that saves data to local JSONL files.
#### 💡 When to Use
- **Development and testing** - No external dependencies required 🛠️
- **Small datasets** - Suitable for datasets with < 10,000 vectors 📊
- **Single-user applications** - Limited concurrent access support 👤
#### ⚙️ Configuration
```python
from flowllm.storage.vector_store import LocalVectorStore
from flowllm.embedding_model import OpenAICompatibleEmbeddingModel
from flowllm.utils.common_utils import load_env
# Load environment variables (for API keys)
load_env()
# Initialize embedding model
embedding_model = OpenAICompatibleEmbeddingModel(dimensions=1024, model_name="text-embedding-v4")
# Initialize vector store
vector_store = LocalVectorStore(
embedding_model=embedding_model,
store_dir="./file_vector_store", # Directory to store JSONL files
batch_size=1024 # Batch size for operations
)
```
#### 💻 Example Usage
```python
from flowllm.schema.vector_node import VectorNode
# Create workspace
workspace_id = "my_workspace"
vector_store.create_workspace(workspace_id)
# Create nodes
nodes = [
VectorNode(
unique_id="node1",
workspace_id=workspace_id,
content="Artificial intelligence is revolutionizing technology",
metadata={"category": "tech", "source": "article1"}
),
VectorNode(
unique_id="node2",
workspace_id=workspace_id,
content="Machine learning enables data-driven insights",
metadata={"category": "tech", "source": "article2"}
)
]
# Insert nodes
vector_store.insert(nodes, workspace_id)
# Search
results = vector_store.search("What is AI?", workspace_id, top_k=2)
for result in results:
print(f"Content: {result.content}")
print(f"Metadata: {result.metadata}")
print(f"Score: {result.metadata.get('score', 'N/A')}")
```
### 2. 🔮 ChromaVectorStore (`backend=chroma`)
An embedded vector database that provides persistent storage with advanced features.
#### 💡 When to Use
- **Local development** with persistence requirements 🏠
- **Medium-scale applications** (10K - 1M vectors) 📈
- **Applications requiring metadata filtering** 🔍
#### ⚙️ Configuration
```python
from flowllm.storage.vector_store import ChromaVectorStore
from flowllm.embedding_model import OpenAICompatibleEmbeddingModel
from flowllm.utils.common_utils import load_env
# Load environment variables
load_env()
# Initialize embedding model
embedding_model = OpenAICompatibleEmbeddingModel(dimensions=1024, model_name="text-embedding-v4")
# Initialize vector store
vector_store = ChromaVectorStore(
embedding_model=embedding_model,
store_dir="./chroma_vector_store", # Directory for Chroma database
batch_size=1024 # Batch size for operations
)
```
#### 💻 Example Usage
```python
from flowllm.schema.vector_node import VectorNode
workspace_id = "chroma_workspace"
# Check if workspace exists and create if needed
if not vector_store.exist_workspace(workspace_id):
vector_store.create_workspace(workspace_id)
# Create nodes with metadata
nodes = [
VectorNode(
unique_id="node1",
workspace_id=workspace_id,
content="Deep learning models require large datasets",
metadata={
"category": "AI",
"difficulty": "advanced",
"topic": "deep_learning"
}
),
VectorNode(
unique_id="node2",
workspace_id=workspace_id,
content="Transformer architecture revolutionized NLP",
metadata={
"category": "AI",
"difficulty": "intermediate",
"topic": "transformers"
}
)
]
# Insert nodes
vector_store.insert(nodes, workspace_id)
# Search
results = vector_store.search("deep learning", workspace_id, top_k=5)
for result in results:
print(f"Content: {result.content}")
print(f"Metadata: {result.metadata}")
```
### 3. 🔍 EsVectorStore (`backend=elasticsearch`)
Production-grade vector search using Elasticsearch with advanced filtering and scaling capabilities.
#### 💡 When to Use
- **Production environments** requiring high availability 🏭
- **Large-scale applications** (1M+ vectors) 🚀
- **Complex filtering requirements** on metadata 🎯
#### 🛠️ Setup Elasticsearch
Before using EsVectorStore, set up Elasticsearch:
##### Option 1: Docker Run
```bash
# Pull the latest Elasticsearch image
docker pull docker.elastic.co/elasticsearch/elasticsearch-wolfi:9.0.0
# Run Elasticsearch container
docker run -p 9200:9200 \
-e "discovery.type=single-node" \
-e "xpack.security.enabled=false" \
-e "xpack.license.self_generated.type=trial" \
-e "http.host=0.0.0.0" \
docker.elastic.co/elasticsearch/elasticsearch-wolfi:9.0.0
```
##### Environment Configuration
```bash
export FLOW_ES_HOSTS=http://localhost:9200
```
#### ⚙️ Configuration
```python
from flowllm.storage.vector_store import EsVectorStore
from flowllm.embedding_model import OpenAICompatibleEmbeddingModel
from flowllm.utils.common_utils import load_env
import os
# Load environment variables
load_env()
# Initialize embedding model
embedding_model = OpenAICompatibleEmbeddingModel(dimensions=1024, model_name="text-embedding-v4")
# Initialize vector store
vector_store = EsVectorStore(
embedding_model=embedding_model,
hosts=os.getenv("FLOW_ES_HOSTS", "http://localhost:9200"), # Elasticsearch hosts
basic_auth=None, # ("username", "password") for auth
batch_size=1024 # Batch size for bulk operations
)
```
#### 🎯 Advanced Filtering
EsVectorStore supports advanced filtering capabilities:
```python
# Add term filters
vector_store.add_term_filter("metadata.category", "technology")
# Add range filters
vector_store.add_range_filter("metadata.score", gte=0.8)
vector_store.add_range_filter("metadata.timestamp", gte="2024-01-01", lte="2024-12-31")
# Search with filters applied
results = vector_store.search("machine learning", workspace_id, top_k=10)
# Clear filters for next search
vector_store.clear_filter()
```
#### 💻 Example Usage
```python
from flowllm.schema.vector_node import VectorNode
# Define workspace
workspace_id = "production_workspace"
# Create workspace if needed
if not vector_store.exist_workspace(workspace_id):
vector_store.create_workspace(workspace_id)
# Create nodes with rich metadata
nodes = [
VectorNode(
unique_id="doc1",
workspace_id=workspace_id,
content="Transformer architecture revolutionized NLP",
metadata={
"category": "AI",
"subcategory": "NLP",
"author": "research_team",
"timestamp": "2024-01-15",
"confidence": 0.95,
"tags": ["transformer", "nlp", "attention"]
}
)
]
# Insert with refresh for immediate availability
vector_store.insert(nodes, workspace_id, refresh=True)
# Advanced search with filters
vector_store.add_term_filter("metadata.category", "AI")
vector_store.add_range_filter("metadata.confidence", gte=0.9)
results = vector_store.search("transformer models", workspace_id, top_k=5)
for result in results:
print(f"Score: {result.metadata.get('score', 'N/A')}")
print(f"Content: {result.content}")
print(f"Metadata: {result.metadata}")
```
## 📝 Working with VectorNode
The `VectorNode` class is the fundamental data unit for all vector stores:
```python
from flowllm.schema.vector_node import VectorNode
# Create a node
node = VectorNode(
unique_id="unique_identifier", # Unique ID for the node (required)
workspace_id="my_workspace", # Workspace ID (required)
content="Text content to embed", # Content to be embedded (required)
metadata={ # Optional metadata
"source": "document1",
"category": "technology",
"timestamp": "2024-08-29"
},
vector=None # Vector will be generated automatically if None
)
```
## 🔄 Import/Export Example
Export and import workspaces for backup or transfer:
```python
# Export workspace to file
vector_store.dump_workspace(
workspace_id="my_workspace",
path="./backup_data" # Directory to store the exported data
)
# Import workspace from file
vector_store.load_workspace(
workspace_id="new_workspace",
path="./backup_data" # Directory containing the exported data
)
# Copy workspace within the same store
vector_store.copy_workspace(
src_workspace_id="original_workspace",
dest_workspace_id="copied_workspace"
)
```
## 🧩 Integration with Embedding Models
All vector stores require an embedding model to function:
```python
from flowllm.embedding_model import OpenAICompatibleEmbeddingModel
# Initialize embedding model
embedding_model = OpenAICompatibleEmbeddingModel(
dimensions=1024, # Embedding dimensions
model_name="text-embedding-v4", # Model name
batch_size=32 # Batch size for embedding generation
)
# Pass to vector store
vector_store = LocalVectorStore(
embedding_model=embedding_model,
store_dir="./vector_store"
)
```
🎉 This guide provides everything you need to work with vector stores in flowllm. Choose the implementation that best fits your use case and scale up as needed! ✨

View file

@ -1,257 +0,0 @@
# 🚀 Vector Store Quick Start Guide
This comprehensive guide covers all available vector store implementations in ExperienceMaker, their differences, use cases, and setup instructions.
## 📋 Overview
ExperienceMaker supports multiple vector store backends for different use cases and deployment scenarios:
- **FileVectorStore** (`backend=local_file`) - 📁 Local file-based storage for development and small datasets
- **ChromaVectorStore** (`backend=chroma`) - 🔮 Embedded vector database for local development and moderate scale
- **EsVectorStore** (`backend=elasticsearch`) - 🔍 Elasticsearch-based storage for production and large scale
## ⚡ Vector Store Implementations
### 1. 📁 FileVectorStore (`backend=local_file`)
A simple file-based vector store that saves data to local JSONL files. Perfect for development, testing, and small datasets.
#### 💡 When to Use
- **Development and testing** - No external dependencies required 🛠️
- **Small datasets** - Suitable for datasets with < 10,000 vectors 📊
- **Single-user applications** - No concurrent access support 👤
- **Prototyping** - Quick setup without infrastructure ⚡
#### ✨ Features
- ✅ No external dependencies
- ✅ Simple file-based persistence
- ✅ Built-in cosine similarity search
- ❌ No concurrent access support
- ❌ Limited scalability
- ❌ No advanced filtering
#### ⚙️ Configuration Parameters
```python
from experiencemaker.vector_store import FileVectorStore
from experiencemaker.embedding_model.openai_compatible_embedding_model import OpenAICompatibleEmbeddingModel
embedding_model = OpenAICompatibleEmbeddingModel(dimensions=1024, model_name="text-embedding-v4")
vector_store = FileVectorStore(
embedding_model=embedding_model,
store_dir="./file_vector_store", # Directory to store JSONL files
batch_size=1024 # Batch size for operations
)
```
#### 💻 Example Usage
```python
# Create workspace and insert data
workspace_id = "my_workspace"
vector_store.create_workspace(workspace_id)
nodes = [
VectorNode(
workspace_id=workspace_id,
content="Artificial intelligence is revolutionizing technology",
metadata={"category": "tech", "source": "article1"}
),
VectorNode(
workspace_id=workspace_id,
content="Machine learning enables data-driven insights",
metadata={"category": "tech", "source": "article2"}
)
]
vector_store.insert(nodes, workspace_id)
# Search
results = vector_store.search("What is AI?", workspace_id, top_k=2)
```
### 2. 🔮 ChromaVectorStore (`backend=chroma`)
An embedded vector database that provides persistent storage with advanced features while remaining easy to deploy.
#### 💡 When to Use
- **Local development** with persistence requirements 🏠
- **Medium-scale applications** (10K - 1M vectors) 📈
- **Multi-user applications** with moderate concurrency 👥
- **Applications requiring metadata filtering** 🔍
- **Docker deployments** without external database dependencies 🐳
#### ✨ Features
- ✅ Persistent embedded database
- ✅ Advanced metadata filtering
- ✅ Built-in vector indexing (HNSW)
- ✅ HTTP API support
- ✅ Concurrent access support
- ✅ Collection management
- ❌ Limited horizontal scaling
#### ⚙️ Configuration Parameters
```python
from experiencemaker.vector_store import ChromaVectorStore
from experiencemaker.embedding_model.openai_compatible_embedding_model import OpenAICompatibleEmbeddingModel
embedding_model = OpenAICompatibleEmbeddingModel(dimensions=1024, model_name="text-embedding-v4")
vector_store = ChromaVectorStore(
embedding_model=embedding_model,
store_dir="./chroma_vector_store", # Directory for Chroma database
batch_size=1024 # Batch size for operations
)
```
#### 💻 Example Usage
```python
workspace_id = "chroma_workspace"
# Check if workspace exists
if not vector_store.exist_workspace(workspace_id):
vector_store.create_workspace(workspace_id)
# Insert with metadata
nodes = [
VectorNode(
workspace_id=workspace_id,
content="Deep learning models require large datasets",
metadata={"category": "AI", "difficulty": "advanced", "topic": "deep_learning"}
)
]
vector_store.insert(nodes, workspace_id)
# Search with results
results = vector_store.search("deep learning", workspace_id, top_k=5)
for result in results:
print(f"Content: {result.content}")
print(f"Metadata: {result.metadata}")
```
### 3. 🔍 EsVectorStore (`backend=elasticsearch`)
Production-grade vector search using Elasticsearch with advanced filtering, scaling, and enterprise features.
#### 💡 When to Use
- **Production environments** requiring high availability 🏭
- **Large-scale applications** (1M+ vectors) 🚀
- **High-throughput scenarios** with many concurrent users ⚡
- **Complex filtering requirements** on metadata 🎯
- **Distributed deployments** across multiple nodes 🌐
- **Enterprise environments** with existing Elasticsearch infrastructure 🏢
#### ✨ Features
- ✅ Horizontal scaling
- ✅ High availability and fault tolerance
- ✅ Advanced filtering and aggregations
- ✅ Real-time indexing and search
- ✅ Cluster management
- ✅ Enterprise security features
- ✅ Monitoring and analytics
- ❌ Complex setup and maintenance
- ❌ Higher resource requirements
#### 🛠️ Setup Elasticsearch
Before using EsVectorStore, you need to set up Elasticsearch. Choose one of the following methods:
##### Option 1: All-in-One Script (Recommended for Development) 🎯
```bash
curl -fsSL https://elastic.co/start-local | sh
```
##### Option 2: Docker Run with HTTP Host 🐳
```bash
# Pull the latest Elasticsearch image
docker pull docker.elastic.co/elasticsearch/elasticsearch-wolfi:9.0.0
# Run Elasticsearch container
docker run -p 9200:9200 \
-e "discovery.type=single-node" \
-e "xpack.security.enabled=false" \
-e "xpack.license.self_generated.type=trial" \
-e "http.host=0.0.0.0" \
docker.elastic.co/elasticsearch/elasticsearch-wolfi:9.0.0
```
##### 🔧 Environment Configuration
Set the Elasticsearch hosts environment variable:
```bash
export ES_HOSTS=http://localhost:9200
```
#### ⚙️ Configuration Parameters
```python
from experiencemaker.vector_store import EsVectorStore
from experiencemaker.embedding_model.openai_compatible_embedding_model import OpenAICompatibleEmbeddingModel
import os
embedding_model = OpenAICompatibleEmbeddingModel(dimensions=1024, model_name="text-embedding-v4")
vector_store = EsVectorStore(
embedding_model=embedding_model,
hosts=os.getenv("ES_HOSTS", "http://localhost:9200"), # Elasticsearch hosts
basic_auth=None, # ("username", "password") for auth
batch_size=1024, # Batch size for bulk operations
retrieve_filters=[] # Pre-configured filters
)
```
#### 🎯 Advanced Filtering
EsVectorStore supports advanced filtering capabilities:
```python
# Add term filters
vector_store.add_term_filter("metadata.category", "technology")
vector_store.add_term_filter("metadata.language", "en")
# Add range filters
vector_store.add_range_filter("metadata.score", gte=0.8)
vector_store.add_range_filter("metadata.timestamp", gte="2024-01-01", lte="2024-12-31")
# Search with filters applied
results = vector_store.search("machine learning", workspace_id, top_k=10)
# Clear filters for next search
vector_store.clear_filter()
```
#### 💻 Example Usage
```python
from experiencemaker.schema.vector_node import VectorNode
# Configure connection
workspace_id = "production_workspace"
# Create workspace with custom mapping
if not vector_store.exist_workspace(workspace_id):
vector_store.create_workspace(workspace_id)
# Insert with rich metadata
nodes = [
VectorNode(
workspace_id=workspace_id,
content="Transformer architecture revolutionized NLP",
metadata={
"category": "AI",
"subcategory": "NLP",
"author": "research_team",
"timestamp": "2024-01-15",
"confidence": 0.95,
"tags": ["transformer", "nlp", "attention"]
}
)
]
# Insert with refresh for immediate availability
vector_store.insert(nodes, workspace_id, refresh=True)
# Advanced search with filters
vector_store.add_term_filter("metadata.category", "AI")
vector_store.add_range_filter("metadata.confidence", gte=0.9)
results = vector_store.search("transformer models", workspace_id, top_k=5)
for result in results:
print(f"Score: {result.metadata.get('_score', 'N/A')}")
print(f"Content: {result.content}")
print(f"Metadata: {result.metadata}")
```
🎉 This guide provides everything you need to get started with vector stores in ExperienceMaker. Choose the implementation that best fits your use case and scale up as needed! ✨