From 763372851eefc1dac01cb293b82c6fa1773fe924 Mon Sep 17 00:00:00 2001 From: HuaqingXu Date: Fri, 6 Mar 2026 20:52:16 +0800 Subject: [PATCH] init --- .env.example | 16 ++ Dockerfile | 27 +++ Makefile | 7 + OLLAMA_DOCKER.md | 493 ++++++++++++++++++++++++++++++++++++++++++++ README.md | 105 ++++++++++ TECH_STACK.md | 284 +++++++++++++++++++++++++ dev.Dockerfile | 25 +++ docker-compose.yaml | 57 +++++ main.py | 229 ++++++++++++++++++++ requirements.txt | 6 + 10 files changed, 1249 insertions(+) create mode 100644 .env.example create mode 100644 Dockerfile create mode 100644 Makefile create mode 100644 OLLAMA_DOCKER.md create mode 100644 README.md create mode 100644 TECH_STACK.md create mode 100644 dev.Dockerfile create mode 100644 docker-compose.yaml create mode 100644 main.py create mode 100644 requirements.txt diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..6ba4e60 --- /dev/null +++ b/.env.example @@ -0,0 +1,16 @@ +# ChromaDB Configuration +CHROMA_DB_PATH=/app/chroma_db +CHROMA_COLLECTION_NAME=memories + +# SQLite Configuration +SQLITE_DB_PATH=/app/graph_store.db + +# Ollama Configuration +# When using Docker Compose with Ollama service, use: http://ollama:11434 +# When running Ollama on host machine, use: http://host.docker.internal:11434 +OLLAMA_HOST=http://ollama:11434 +OLLAMA_LLM_MODEL=llama3.2 +OLLAMA_EMBEDDER_MODEL=nomic-embed-text + +# History Database Configuration +HISTORY_DB_PATH=/app/history/history.db diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..b9691f8 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,27 @@ +FROM python:3.12-slim + +WORKDIR /app + +COPY requirements.txt . + +RUN pip install --no-cache-dir -r requirements.txt + +COPY . . + +# Create directories for ChromaDB, SQLite and history database +RUN mkdir -p /app/chroma_db /app/history + +EXPOSE 8000 + +ENV PYTHONUNBUFFERED=1 + +# Default environment variables for ChromaDB, SQLite and Ollama +ENV CHROMA_DB_PATH=/app/chroma_db +ENV CHROMA_COLLECTION_NAME=memories +ENV SQLITE_DB_PATH=/app/graph_store.db +ENV OLLAMA_HOST=http://host.docker.internal:11434 +ENV OLLAMA_LLM_MODEL=llama3.2 +ENV OLLAMA_EMBEDDER_MODEL=nomic-embed-text +ENV HISTORY_DB_PATH=/app/history/history.db + +CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..9b1b388 --- /dev/null +++ b/Makefile @@ -0,0 +1,7 @@ +build: + docker build -t mem0-api-server . + +run_local: + docker run -p 8000:8000 -v $(shell pwd):/app mem0-api-server --env-file .env + +.PHONY: build run_local diff --git a/OLLAMA_DOCKER.md b/OLLAMA_DOCKER.md new file mode 100644 index 0000000..6ba76bc --- /dev/null +++ b/OLLAMA_DOCKER.md @@ -0,0 +1,493 @@ +# Ollama Docker Compose 部署指南 + +## 📋 概述 + +现在 Mem0 Server 的 docker-compose.yaml 已经包含了 Ollama 服务,所有组件都可以通过 Docker Compose 统一管理。 + +--- + +## 🏗️ 新架构 + +### 技术架构 +``` +┌─────────────┐ +│ Mem0 App │ (FastAPI, port: 8888) +└──────┬──────┘ + │ + ├──→ ┌─────────────┐ + │ │ Ollama │ (port: 11434) + │ │ LLM+AI │ + │ └─────────────┘ + │ + ├──→ ┌─────────────┐ + │ │ ChromaDB │ (Embedded) + │ └─────────────┘ + │ + └──→ ┌─────────────┐ + │ SQLite │ (Embedded) + └─────────────┘ +``` + +### 服务列表 +- `mem0` - FastAPI 应用(端口 8888) +- `ollama` - Ollama AI 服务(端口 11434) + +--- + +## 🚀 快速开始 + +### 方式 1:使用 GPU(推荐) + +如果您的机器有 NVIDIA GPU: + +```bash +# 启动所有服务 +docker-compose --profile gpu up -d + +# 查看状态 +docker-compose ps + +# 查看日志 +docker-compose logs -f ollama +``` + +### 方式 2:仅使用 CPU + +如果没有 GPU: + +```bash +# 启动所有服务(不使用 GPU profile) +docker-compose up -d + +# 注意:Ollama 在 CPU 模式下可能较慢 +``` + +--- + +## 📊 docker-compose.yaml 配置说明 + +### Ollama 服务配置 + +```yaml +ollama: + image: ollama/ollama:latest + container_name: ollama + restart: on-failure + networks: + - mem0_network + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:11434/api/tags"] + interval: 5s + timeout: 5s + retries: 10 + start_period: 60s # 给 Ollama 60 秒启动时间 + volumes: + - ollama_data:/root/.ollama # 持久化模型数据 + ports: + - "11434:11434" # 暴露 Ollama API + profiles: ["gpu"] # GPU 配置 + deploy: + resources: + reservations: + devices: + - driver: nvidia + count: all + capabilities: [gpu] +``` + +### Mem0 服务配置更新 + +```yaml +mem0: + environment: + - OLLAMA_HOST=http://ollama:11434 # 使用 Docker 网络访问 Ollama + - OLLAMA_LLM_MODEL=llama3.2 + - OLLAMA_EMBEDDER_MODEL=nomic-embed-text + depends_on: + ollama: + condition: service_healthy # 等待 Ollama 健康检查通过 +``` + +--- + +## 🔧 使用步骤 + +### 1. 首次启动 + +```bash +# 启动服务 +docker-compose --profile gpu up -d + +# 等待 Ollama 启动完成(约 60 秒) +docker-compose logs -f ollama + +# 查看已加载的模型 +docker exec ollama ollama list +``` + +### 2. 下载模型 + +首次使用需要下载模型: + +```bash +# 进入 Ollama 容器 +docker exec -it ollama bash + +# 下载 LLM 模型 +ollama pull llama3.2 + +# 下载嵌入模型 +ollama pull nomic-embed-text + +# 退出 +exit +``` + +或者一次性下载: + +```bash +docker exec ollama ollama pull llama3.2 +docker exec ollama ollama pull nomic-embed-text +``` + +### 3. 测试 Ollama + +```bash +# 测试 Ollama API +curl http://localhost:11434/api/tags + +# 测试生成 +curl http://localhost:11434/api/generate -d '{ + "model": "llama3.2", + "prompt": "Hello, how are you?" +}' +``` + +### 4. 测试 Mem0 API + +```bash +# 访问 API 文档 +http://localhost:8888/docs + +# 创建记忆 +curl -X POST http://localhost:8888/memories \ + -H "Content-Type: application/json" \ + -d '{ + "messages": [ + {"role": "user", "content": "你好"}, + {"role": "assistant", "content": "你好!有什么可以帮助你的?"} + ], + "user_id": "test_user" + }' +``` + +--- + +## 💾 数据持久化 + +### Ollama 数据卷 +- **名称**: `ollama_data` +- **路径**: `/root/.ollama` +- **内容**: 下载的模型文件、配置等 + +### 查看数据卷 +```bash +# 查看数据卷信息 +docker volume inspect ollama_data + +# 查看数据卷位置 +docker volume ls | grep ollama_data +``` + +--- + +## ⚙️ 配置选项 + +### 使用不同的模型 + +编辑 `.env` 文件: + +```bash +OLLAMA_LLM_MODEL=mistral +OLLAMA_EMBEDDER_MODEL=mxbai-embed-large +``` + +重启服务: +```bash +docker-compose --profile gpu up -d +``` + +### 调整 Ollama 资源 + +如果需要更多 GPU 资源: + +```yaml +deploy: + resources: + reservations: + devices: + - driver: nvidia + device_ids: ['0', '1'] # 使用特定 GPU + capabilities: [gpu] +``` + +--- + +## 🔍 故障排查 + +### Ollama 启动失败 + +```bash +# 查看详细日志 +docker-compose logs ollama + +# 检查健康状态 +docker-compose ps ollama + +# 进入容器调试 +docker exec -it ollama bash +``` + +### 模型下载慢 + +```bash +# 设置国内镜像(如果可用) +export OLLAMA_MODELS=https://mirror.ghproxy.com/https://github.com/ollama/ollama/releases/download + +# 或者手动下载模型文件后挂载 +``` + +### GPU 不可用 + +```bash +# 检查 NVIDIA Docker 是否安装 +nvidia-smi + +# 检查容器是否识别 GPU +docker exec ollama nvidia-smi + +# 如果没有 GPU,使用 CPU 模式 +docker-compose up -d +``` + +### Mem0 无法连接 Ollama + +```bash +# 检查网络连通性 +docker exec mem0 ping ollama + +# 检查 Ollama 是否运行 +docker exec mem0 curl http://ollama:11434/api/tags + +# 查看依赖关系 +docker-compose ps +``` + +--- + +## 🎯 优势特点 + +### 统一管理 +- ✅ 所有服务通过 docker-compose 管理 +- ✅ 一键启动/停止 +- ✅ 自动处理依赖关系 + +### 数据隔离 +- ✅ Ollama 数据独立存储 +- ✅ 不会污染宿主机环境 +- ✅ 易于备份和迁移 + +### 网络自动化 +- ✅ Docker 网络自动配置 +- ✅ 服务间通过服务名通信 +- ✅ 无需手动配置 IP + +### 健康检查 +- ✅ 自动检测 Ollama 状态 +- ✅ Mem0 等待 Ollama 就绪 +- ✅ 提高系统可靠性 + +--- + +## 📈 性能优化 + +### GPU 加速 +```yaml +# 启用 GPU 支持 +profiles: ["gpu"] +deploy: + resources: + reservations: + devices: + - driver: nvidia + count: all + capabilities: [gpu] +``` + +### 内存优化 +```yaml +# 限制最大内存使用 +deploy: + resources: + limits: + memory: 8G + reservations: + memory: 4G +``` + +### 并发优化 +```bash +# 设置 Ollama 并发数 +docker exec ollama sh -c 'echo "OLLAMA_NUM_PARALLEL=4" >> /root/.ollama/config.json' +``` + +--- + +## 🔄 常用命令 + +### 启动服务 +```bash +# 带 GPU 支持 +docker-compose --profile gpu up -d + +# 仅 CPU +docker-compose up -d +``` + +### 停止服务 +```bash +docker-compose --profile gpu down +``` + +### 查看状态 +```bash +# 查看所有服务 +docker-compose ps + +# 查看 Ollama 日志 +docker-compose logs -f ollama + +# 查看 Mem0 日志 +docker-compose logs -f mem0 +``` + +### 重启服务 +```bash +# 重启 Ollama +docker-compose restart ollama + +# 重启 Mem0 +docker-compose restart mem0 + +# 重启所有 +docker-compose restart +``` + +### 进入容器 +```bash +# 进入 Ollama 容器 +docker exec -it ollama bash + +# 进入 Mem0 容器 +docker exec -it mem0 bash +``` + +### 管理模型 +```bash +# 列出已安装的模型 +docker exec ollama ollama list + +# 下载新模型 +docker exec ollama ollama pull mistral + +# 删除模型 +docker exec ollama ollama rm llama3.2 + +# 查看模型信息 +docker exec ollama ollama show llama3.2 +``` + +--- + +## 💡 最佳实践 + +### 1. 首次部署 +```bash +# 1. 启动服务 +docker-compose --profile gpu up -d + +# 2. 等待 Ollama 就绪 +sleep 60 + +# 3. 下载所需模型 +docker exec ollama ollama pull llama3.2 +docker exec ollama ollama pull nomic-embed-text + +# 4. 测试 API +curl http://localhost:8888/docs +``` + +### 2. 日常使用 +```bash +# 启动 +docker-compose --profile gpu up -d + +# 停止 +docker-compose --profile gpu down + +# 重启 +docker-compose --profile gpu restart +``` + +### 3. 数据备份 +```bash +# 备份 Ollama 数据 +docker run --rm \ + -v ollama_data:/data \ + -v $(pwd):/backup \ + alpine tar czf /backup/ollama_backup.tar.gz /data +``` + +### 4. 恢复数据 +```bash +# 恢复 Ollama 数据 +docker run --rm \ + -v ollama_data:/data \ + -v $(pwd):/backup \ + alpine tar xzf /backup/ollama_backup.tar.gz -C / +``` + +--- + +## 🆘 常见问题 + +### Q1: Ollama 启动很慢? +**A:** Ollama 首次启动需要加载模型,可能需要 60 秒。健康检查配置了 `start_period: 60s` 来等待。 + +### Q2: 如何切换模型? +**A:** 修改 `.env` 中的 `OLLAMA_LLM_MODEL`,然后重启服务,并确保新模型已下载。 + +### Q3: GPU 内存不足? +**A:** 使用更小的模型(如 `phi3`),或限制并发数。 + +### Q4: 如何完全清理? +**A:** +```bash +docker-compose --profile gpu down -v # 删除所有数据卷 +``` + +### Q5: 可以在没有 GPU 的情况下运行吗? +**A:** 可以,但速度较慢。使用 `docker-compose up -d`(不带 gpu profile)。 + +--- + +## 📚 相关文档 + +- [README.md](./README.md) - 项目主文档 +- [TECH_STACK.md](./TECH_STACK.md) - 技术架构说明 +- [QUICK_START.md](./QUICK_START.md) - 快速入门 +- [DEPLOYMENT.md](./DEPLOYMENT.md) - 详细部署指南 + +--- + +现在所有服务都集成在 docker-compose.yaml 中,管理更加简单统一!🎉 diff --git a/README.md b/README.md new file mode 100644 index 0000000..c79f040 --- /dev/null +++ b/README.md @@ -0,0 +1,105 @@ +# Mem0 REST API Server + +Mem0 provides a REST API server (written using FastAPI). Users can perform all operations through REST endpoints. The API also includes OpenAPI documentation, accessible at `/docs` when the server is running. + +## Features + +- **Create memories:** Create memories based on messages for a user, agent, or run. +- **Retrieve memories:** Get all memories for a given user, agent, or run. +- **Search memories:** Search stored memories based on a query. +- **Update memories:** Update an existing memory. +- **Delete memories:** Delete a specific memory or all memories for a user, agent, or run. +- **Reset memories:** Reset all memories for a user, agent, or run. +- **OpenAPI Documentation:** Accessible via `/docs` endpoint. + +## Technology Stack + +- **Vector Store**: ChromaDB - 高性能向量数据库 +- **Graph Store**: SQLite - 轻量级图存储 +- **LLM & Embedder**: Ollama - 本地大模型服务 + +## Quick Start + +### 方式 1: Docker Compose(最简单) + +```bash +# 1. 复制环境变量配置 +cp .env.example .env + +# 2. 编辑 .env 文件,根据需要修改配置 +# vi .env 或 nano .env + +# 3. 启动所有服务(包括 Ollama) +docker-compose --profile gpu up -d + +# 4. 访问 API 文档 +open http://localhost:8888/docs +``` + +**注意**: 首次启动需要下载 Ollama 模型,请等待约 60 秒。 + +### 方式 2: Docker 命令部署 + +```bash +# 1. 构建镜像 +docker build -t mem0-server . + +# 2. 运行容器(通过环境变量传入配置) +docker run -d \ + --name mem0-server \ + -p 8000:8000 \ + -v chroma_data:/app/chroma_db \ + -v sqlite_data:/app/graph_store.db \ + -v history_data:/app/history \ + --add-host=host.docker.internal:host-gateway \ + -e CHROMA_DB_PATH=/app/chroma_db \ + -e CHROMA_COLLECTION_NAME=memories \ + -e SQLITE_DB_PATH=/app/graph_store.db \ + -e OLLAMA_HOST=http://host.docker.internal:11434 \ + -e OLLAMA_LLM_MODEL=llama3.2 \ + -e OLLAMA_EMBEDDER_MODEL=nomic-embed-text \ + -e REDIS_HOST=host.docker.internal \ + -e REDIS_PORT=6379 \ + mem0-server +``` + +## 环境变量配置 + +所有配置都可以通过环境变量传入: + +| 变量名 | 说明 | 默认值 | +|--------|------|--------| +| `CHROMA_DB_PATH` | ChromaDB 数据路径 | `/app/chroma_db` | +| `CHROMA_COLLECTION_NAME` | ChromaDB 集合名称 | `memories` | +| `SQLITE_DB_PATH` | SQLite 数据库路径 | `/app/graph_store.db` | +| `OLLAMA_HOST` | Ollama 服务地址 | `http://localhost:11434` | +| `OLLAMA_LLM_MODEL` | LLM 模型名称 | `llama3.2` | +| `OLLAMA_EMBEDDER_MODEL` | Embedder 模型名称 | `nomic-embed-text` | +| `HISTORY_DB_PATH` | 历史数据库路径 | `/app/history/history.db` | + +详细部署文档请查看 [DEPLOYMENT.md](./DEPLOYMENT.md) + +## Prerequisites + +Before running the server, ensure you have: + +1. **Ollama installed and running** on your host machine + ```bash + # Install Ollama from https://ollama.ai + ollama pull llama3.2 + ollama pull nomic-embed-text + ``` + +2. **Docker and Docker Compose** installed + +## API Endpoints + +- `POST /memories` - Create new memories +- `GET /memories` - Retrieve all memories +- `GET /memories/{memory_id}` - Get a specific memory +- `POST /search` - Search memories +- `PUT /memories/{memory_id}` - Update a memory +- `DELETE /memories/{memory_id}` - Delete a memory +- `DELETE /memories` - Delete all memories for an identifier +- `POST /reset` - Reset all memories +- `GET /docs` - OpenAPI documentation diff --git a/TECH_STACK.md b/TECH_STACK.md new file mode 100644 index 0000000..af1188a --- /dev/null +++ b/TECH_STACK.md @@ -0,0 +1,284 @@ +# Mem0 Server 技术架构 + +## 📋 技术栈 + +Mem0 Server 采用简洁高效的技术架构,所有组件均通过环境变量配置。 + +### 核心组件 + +| 组件 | 技术 | 用途 | 存储方式 | +|------|------|------|----------| +| **Vector Store** | ChromaDB | 向量存储,用于语义搜索 | 文件系统 | +| **Graph Store** | SQLite | 图存储,管理实体关系 | 文件系统 | +| **LLM** | Ollama | 大语言模型,文本生成 | 外部服务 | +| **Embedder** | Ollama | 嵌入模型,向量化文本 | 外部服务 | + +--- + +## 🏗️ 架构图 + +``` +┌─────────────┐ +│ Mem0 App │ (FastAPI, port: 8888) +│ main.py │ +└──────┬──────┘ + │ + ├──→ ┌─────────────┐ + │ │ ChromaDB │ (Embedded) + │ │ Vectors │ + │ └─────────────┘ + │ + ├──→ ┌─────────────┐ + │ │ SQLite │ (Embedded) + │ │ Graph │ + │ └─────────────┘ + │ + └──→ ┌─────────────┐ + │ Ollama │ (External Service) + │ LLM + AI │ + └─────────────┘ +``` + +--- + +## 🔧 技术选型理由 + +### ChromaDB(向量存储) +- ✅ **轻量级**:无需独立数据库服务 +- ✅ **易部署**:嵌入式设计,开箱即用 +- ✅ **高性能**:专为向量相似度搜索优化 +- ✅ **持久化**:数据直接存储到文件系统 + +### SQLite(图存储) +- ✅ **零配置**:无需安装和配置 +- ✅ **单文件**:数据存储在单个文件中 +- ✅ **成熟稳定**:经过广泛验证的数据库 +- ✅ **事务支持**:ACID 事务保证数据一致性 + +### Ollama(AI 服务) +- ✅ **本地运行**:数据隐私和安全 +- ✅ **模型丰富**:支持多种开源模型 +- ✅ **易于使用**:简单的 API 接口 +- ✅ **性能优秀**:优化的推理引擎 + +--- + +## 📊 环境变量配置 + +所有配置通过环境变量传入,实现配置与代码分离。 + +### 必需的环境变量 + +```bash +# ChromaDB 配置 +CHROMA_DB_PATH=/app/chroma_db +CHROMA_COLLECTION_NAME=memories + +# SQLite 配置 +SQLITE_DB_PATH=/app/graph_store.db + +# Ollama 配置 +OLLAMA_HOST=http://host.docker.internal:11434 +OLLAMA_LLM_MODEL=llama3.2 +OLLAMA_EMBEDDER_MODEL=nomic-embed-text + +# 历史数据库配置 +HISTORY_DB_PATH=/app/history/history.db +``` + +### 环境变量说明 + +| 变量名 | 说明 | 默认值 | 示例 | +|--------|------|--------|------| +| `CHROMA_DB_PATH` | ChromaDB 数据存储路径 | `/app/chroma_db` | `/data/chroma` | +| `CHROMA_COLLECTION_NAME` | ChromaDB 集合名称 | `memories` | `my_memories` | +| `SQLITE_DB_PATH` | SQLite 数据库路径 | `/app/graph_store.db` | `/data/graph.db` | +| `OLLAMA_HOST` | Ollama 服务地址 | `http://localhost:11434` | `http://ollama:11434` | +| `OLLAMA_LLM_MODEL` | LLM 模型名称 | `llama3.2` | `mistral`, `llama3.1` | +| `OLLAMA_EMBEDDER_MODEL` | Embedder 模型名称 | `nomic-embed-text` | `mxbai-embed-large` | +| `HISTORY_DB_PATH` | 历史数据库路径 | `/app/history/history.db` | `/data/history.db` | + +--- + +## 🚀 部署方式 + +### Docker Compose(推荐) + +```yaml +services: + mem0: + build: . + ports: + - "8888:8000" + volumes: + - ./chroma_db:/app/chroma_db + - ./history:/app/history + environment: + - CHROMA_DB_PATH=/app/chroma_db + - CHROMA_COLLECTION_NAME=memories + - SQLITE_DB_PATH=/app/graph_store.db + - OLLAMA_HOST=http://host.docker.internal:11434 + - OLLAMA_LLM_MODEL=llama3.2 + - OLLAMA_EMBEDDER_MODEL=nomic-embed-text +``` + +启动命令: +```bash +docker-compose up -d +``` + +### Docker 命令 + +```bash +docker run -d \ + --name mem0-server \ + -p 8888:8000 \ + -v $(pwd)/chroma_db:/app/chroma_db \ + -v $(pwd)/history:/app/history \ + -e CHROMA_DB_PATH=/app/chroma_db \ + -e CHROMA_COLLECTION_NAME=memories \ + -e SQLITE_DB_PATH=/app/graph_store.db \ + -e OLLAMA_HOST=http://host.docker.internal:11434 \ + -e OLLAMA_LLM_MODEL=llama3.2 \ + -e OLLAMA_EMBEDDER_MODEL=nomic-embed-text \ + mem0-server +``` + +--- + +## 💾 数据持久化 + +### ChromaDB 数据 +- **位置**:`./chroma_db/` +- **内容**:向量数据、集合元数据 +- **格式**:ChromaDB 内部格式 + +### SQLite 数据 +- **位置**:`./graph_store.db`(或自定义路径) +- **内容**:图结构数据、实体关系 +- **格式**:SQLite 数据库文件 + +### 历史数据 +- **位置**:`./history/history.db` +- **内容**:记忆变更历史记录 +- **格式**:SQLite 数据库文件 + +--- + +## 🔍 工作流程 + +### 1. 创建记忆 +``` +用户消息 → FastAPI → Memory.add() + ↓ +Ollama Embedder → 生成向量 + ↓ +ChromaDB → 存储向量 + ↓ +SQLite → 存储实体关系 + ↓ +返回结果 +``` + +### 2. 搜索记忆 +``` +搜索查询 → FastAPI → Memory.search() + ↓ +Ollama Embedder → 查询向量化 + ↓ +ChromaDB → 向量相似度搜索 + ↓ +返回匹配的记忆 +``` + +### 3. 获取记忆 +``` +用户 ID → FastAPI → Memory.get_all() + ↓ +SQLite → 查询图关系 + ↓ +ChromaDB → 获取相关向量 + ↓ +返回结构化记忆 +``` + +--- + +## 🎯 优势特点 + +### 简洁性 +- ✅ 无外部数据库依赖 +- ✅ 配置文件少 +- ✅ 易于理解和维护 + +### 灵活性 +- ✅ 所有配置通过环境变量 +- ✅ 支持自定义模型 +- ✅ 可切换不同组件 + +### 可扩展性 +- ✅ ChromaDB 支持集群部署 +- ✅ SQLite 可替换为 PostgreSQL +- ✅ Ollama 可替换为其他 LLM 服务 + +### 数据隐私 +- ✅ 本地运行 AI 模型 +- ✅ 数据不上传第三方 +- ✅ 完全可控的数据流 + +--- + +## 📈 性能特性 + +### ChromaDB +- 毫秒级向量相似度搜索 +- 支持百万级向量规模 +- 内存映射加速查询 + +### SQLite +- 微秒级简单查询 +- 事务安全保证 +- 自动索引优化 + +### Ollama +- GPU 加速推理(如可用) +- 批量处理优化 +- 模型缓存机制 + +--- + +## 🛠️ 开发建议 + +### 本地开发 +```bash +# 使用开发模式运行 +docker-compose -f docker-compose.yaml up --build + +# 查看日志 +docker-compose logs -f mem0 +``` + +### 生产部署 +- 使用固定版本镜像 +- 配置数据卷备份 +- 监控资源使用 +- 设置健康检查 + +### 性能优化 +- 调整 ChromaDB 批次大小 +- 优化 SQLite 索引 +- 使用更快的存储介质(SSD) +- 增加 Ollama 并发配置 + +--- + +## 📚 相关文档 + +- [README.md](./README.md) - 项目主文档 +- [DEPLOYMENT.md](./DEPLOYMENT.md) - 详细部署指南 +- [QUICK_START.md](./QUICK_START.md) - 快速入门 +- [ENV_VARIABLES.md](./ENV_VARIABLES.md) - 环境变量详解 + +--- + +这个简洁的技术架构专注于核心功能,避免了不必要的复杂性,同时保持了强大的扩展能力!🎉 diff --git a/dev.Dockerfile b/dev.Dockerfile new file mode 100644 index 0000000..852b52c --- /dev/null +++ b/dev.Dockerfile @@ -0,0 +1,25 @@ +FROM python:3.12 + +WORKDIR /app + +# Install Poetry +RUN curl -sSL https://install.python-poetry.org | python3 - +ENV PATH="/root/.local/bin:$PATH" + +# Copy requirements first for better caching +COPY server/requirements.txt . +RUN pip install -r requirements.txt + +# Install mem0 in editable mode using Poetry +WORKDIR /app/packages +COPY pyproject.toml . +COPY poetry.lock . +COPY README.md . +COPY mem0 ./mem0 +RUN pip install -e .[graph] + +# Return to app directory and copy server code +WORKDIR /app +COPY server . + +CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"] diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..0ec56ea --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,57 @@ +name: mem0-dev + +services: + mem0: + build: + context: .. # Set context to parent directory + dockerfile: server/dev.Dockerfile + ports: + - "8888:8000" + env_file: + - .env + networks: + - mem0_network + volumes: + - ./chroma_db:/app/chroma_db # ChromaDB storage + - ./history:/app/history # History db location + - .:/app # Server code. This allows to reload the app when the server code is updated + - ../mem0:/app/packages/mem0 # Mem0 library. This allows to reload the app when the library code is updated + command: uvicorn main:app --host 0.0.0.0 --port 8000 --reload # Enable auto-reload + environment: + - PYTHONDONTWRITEBYTECODE=1 # Prevents Python from writing .pyc files + - PYTHONUNBUFFERED=1 # Ensures Python output is sent straight to terminal + - CHROMA_DB_PATH=/app/chroma_db + - CHROMA_COLLECTION_NAME=memories + - SQLITE_DB_PATH=/app/graph_store.db + - OLLAMA_HOST=http://ollama:11434 + - OLLAMA_LLM_MODEL=llama3.2 + - OLLAMA_EMBEDDER_MODEL=nomic-embed-text + - HISTORY_DB_PATH=/app/history/history.db + depends_on: + ollama: + condition: service_healthy + + ollama: + image: ollama/ollama:latest + container_name: ollama + restart: on-failure + networks: + - mem0_network + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:11434/api/tags"] + interval: 5s + timeout: 5s + retries: 10 + start_period: 60s + volumes: + - ollama_data:/root/.ollama + ports: + - "11434:11434" + profiles: ["gpu"] + +volumes: + ollama_data: {} + +networks: + mem0_network: + driver: bridge \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..154319e --- /dev/null +++ b/main.py @@ -0,0 +1,229 @@ +import logging +import os +from typing import Any, Dict, List, Optional + +from dotenv import load_dotenv +from fastapi import FastAPI, HTTPException +from fastapi.responses import JSONResponse, RedirectResponse +from pydantic import BaseModel, Field + +from mem0 import Memory + +logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s") + +# Load environment variables +load_dotenv() + +# ChromaDB configuration +CHROMA_DB_PATH = os.environ.get("CHROMA_DB_PATH", "/app/chroma_db") +CHROMA_COLLECTION_NAME = os.environ.get("CHROMA_COLLECTION_NAME", "memories") + +# SQLite configuration for graph store +SQLITE_DB_PATH = os.environ.get("SQLITE_DB_PATH", "/app/graph_store.db") + +# Ollama configuration +OLLAMA_HOST = os.environ.get("OLLAMA_HOST", "http://localhost:11434") +OLLAMA_LLM_MODEL = os.environ.get("OLLAMA_LLM_MODEL", "llama3.2") +OLLAMA_EMBEDDER_MODEL = os.environ.get("OLLAMA_EMBEDDER_MODEL", "nomic-embed-text") + +HISTORY_DB_PATH = os.environ.get("HISTORY_DB_PATH", "/app/history/history.db") + +DEFAULT_CONFIG = { + "version": "v1.1", + "vector_store": { + "provider": "chroma", + "config": { + "path": CHROMA_DB_PATH, + "collection_name": CHROMA_COLLECTION_NAME, + }, + }, + "graph_store": { + "provider": "sqlite", + "config": {"db_path": SQLITE_DB_PATH}, + }, + "llm": { + "provider": "ollama", + "config": { + "host": OLLAMA_HOST, + "model": OLLAMA_LLM_MODEL, + "temperature": 0.2, + }, + }, + "embedder": { + "provider": "ollama", + "config": { + "host": OLLAMA_HOST, + "model": OLLAMA_EMBEDDER_MODEL, + }, + }, + "history_db_path": HISTORY_DB_PATH, +} + + +MEMORY_INSTANCE = Memory.from_config(DEFAULT_CONFIG) + +app = FastAPI( + title="Mem0 REST APIs", + description="A REST API for managing and searching memories for your AI Agents and Apps.", + version="1.0.0", +) + + +class Message(BaseModel): + role: str = Field(..., description="Role of the message (user or assistant).") + content: str = Field(..., description="Message content.") + + +class MemoryCreate(BaseModel): + messages: List[Message] = Field(..., description="List of messages to store.") + user_id: Optional[str] = None + agent_id: Optional[str] = None + run_id: Optional[str] = None + metadata: Optional[Dict[str, Any]] = None + + +class SearchRequest(BaseModel): + query: str = Field(..., description="Search query.") + user_id: Optional[str] = None + run_id: Optional[str] = None + agent_id: Optional[str] = None + filters: Optional[Dict[str, Any]] = None + + +@app.post("/configure", summary="Configure Mem0") +def set_config(config: Dict[str, Any]): + """Set memory configuration.""" + global MEMORY_INSTANCE + MEMORY_INSTANCE = Memory.from_config(config) + return {"message": "Configuration set successfully"} + + +@app.post("/memories", summary="Create memories") +def add_memory(memory_create: MemoryCreate): + """Store new memories.""" + if not any([memory_create.user_id, memory_create.agent_id, memory_create.run_id]): + raise HTTPException(status_code=400, detail="At least one identifier (user_id, agent_id, run_id) is required.") + + params = {k: v for k, v in memory_create.model_dump().items() if v is not None and k != "messages"} + try: + response = MEMORY_INSTANCE.add(messages=[m.model_dump() for m in memory_create.messages], **params) + return JSONResponse(content=response) + except Exception as e: + logging.exception("Error in add_memory:") # This will log the full traceback + raise HTTPException(status_code=500, detail=str(e)) + + +@app.get("/memories", summary="Get memories") +def get_all_memories( + user_id: Optional[str] = None, + run_id: Optional[str] = None, + agent_id: Optional[str] = None, +): + """Retrieve stored memories.""" + if not any([user_id, run_id, agent_id]): + raise HTTPException(status_code=400, detail="At least one identifier is required.") + try: + params = { + k: v for k, v in {"user_id": user_id, "run_id": run_id, "agent_id": agent_id}.items() if v is not None + } + return MEMORY_INSTANCE.get_all(**params) + except Exception as e: + logging.exception("Error in get_all_memories:") + raise HTTPException(status_code=500, detail=str(e)) + + +@app.get("/memories/{memory_id}", summary="Get a memory") +def get_memory(memory_id: str): + """Retrieve a specific memory by ID.""" + try: + return MEMORY_INSTANCE.get(memory_id) + except Exception as e: + logging.exception("Error in get_memory:") + raise HTTPException(status_code=500, detail=str(e)) + + +@app.post("/search", summary="Search memories") +def search_memories(search_req: SearchRequest): + """Search for memories based on a query.""" + try: + params = {k: v for k, v in search_req.model_dump().items() if v is not None and k != "query"} + return MEMORY_INSTANCE.search(query=search_req.query, **params) + except Exception as e: + logging.exception("Error in search_memories:") + raise HTTPException(status_code=500, detail=str(e)) + + +@app.put("/memories/{memory_id}", summary="Update a memory") +def update_memory(memory_id: str, updated_memory: Dict[str, Any]): + """Update an existing memory with new content. + + Args: + memory_id (str): ID of the memory to update + updated_memory (str): New content to update the memory with + + Returns: + dict: Success message indicating the memory was updated + """ + try: + return MEMORY_INSTANCE.update(memory_id=memory_id, data=updated_memory) + except Exception as e: + logging.exception("Error in update_memory:") + raise HTTPException(status_code=500, detail=str(e)) + + +@app.get("/memories/{memory_id}/history", summary="Get memory history") +def memory_history(memory_id: str): + """Retrieve memory history.""" + try: + return MEMORY_INSTANCE.history(memory_id=memory_id) + except Exception as e: + logging.exception("Error in memory_history:") + raise HTTPException(status_code=500, detail=str(e)) + + +@app.delete("/memories/{memory_id}", summary="Delete a memory") +def delete_memory(memory_id: str): + """Delete a specific memory by ID.""" + try: + MEMORY_INSTANCE.delete(memory_id=memory_id) + return {"message": "Memory deleted successfully"} + except Exception as e: + logging.exception("Error in delete_memory:") + raise HTTPException(status_code=500, detail=str(e)) + + +@app.delete("/memories", summary="Delete all memories") +def delete_all_memories( + user_id: Optional[str] = None, + run_id: Optional[str] = None, + agent_id: Optional[str] = None, +): + """Delete all memories for a given identifier.""" + if not any([user_id, run_id, agent_id]): + raise HTTPException(status_code=400, detail="At least one identifier is required.") + try: + params = { + k: v for k, v in {"user_id": user_id, "run_id": run_id, "agent_id": agent_id}.items() if v is not None + } + MEMORY_INSTANCE.delete_all(**params) + return {"message": "All relevant memories deleted"} + except Exception as e: + logging.exception("Error in delete_all_memories:") + raise HTTPException(status_code=500, detail=str(e)) + + +@app.post("/reset", summary="Reset all memories") +def reset_memory(): + """Completely reset stored memories.""" + try: + MEMORY_INSTANCE.reset() + return {"message": "All memories reset"} + except Exception as e: + logging.exception("Error in reset_memory:") + raise HTTPException(status_code=500, detail=str(e)) + + +@app.get("/", summary="Redirect to the OpenAPI documentation", include_in_schema=False) +def home(): + """Redirect to the OpenAPI documentation.""" + return RedirectResponse(url="/docs") diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e9bd7a7 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,6 @@ +fastapi==0.115.8 +uvicorn==0.34.0 +pydantic==2.10.4 +mem0ai>=0.1.48 +python-dotenv==1.0.1 +chromadb>=0.4.22