# Memory Agents API 这是一个用统一 HTTP 接口对比 Agent 记忆方案的后端项目。当前接入了 Text2Mem、Mem0、Letta、ReMe 和 memU。五个系统都通过 `MemoryAgent` 暴露相同的对话、记忆查询、删除、审计和重置能力,前端不需要关心各 SDK 的接口差异。 建议第一次阅读时先运行内置的 Text2Mem。它不依赖第三方记忆 SDK,未配置模型和 PostgreSQL 时也能通过本地规则及 JSON 文件工作。 ## 环境要求 - Python 3.11+ - PostgreSQL(可选,生产存储;需要安装 pgvector 扩展) - OpenAI 兼容的 Chat Completions 和 Embeddings 服务(可选) ## 快速启动 在当前目录执行: ```bash python3.11 -m venv .venv source .venv/bin/activate pip install -e . pip install pytest pytest-asyncio ruff uvicorn app.main:app --reload --port 8000 ``` 打开 `http://127.0.0.1:8000/docs` 可以直接调试接口。先检查服务状态: ```bash curl http://127.0.0.1:8000/api/health curl http://127.0.0.1:8000/api/systems ``` 默认情况下,PostgreSQL 连接失败会自动退回 `local-json`,Text2Mem 仍可使用。可以用下面的请求验证完整流程: ```bash curl -X POST http://127.0.0.1:8000/api/chat \ -H 'Content-Type: application/json' \ -d '{"system":"text2mem","message":"记住:项目数据库使用 PostgreSQL"}' curl -X POST http://127.0.0.1:8000/api/chat \ -H 'Content-Type: application/json' \ -d '{"system":"text2mem","message":"项目使用什么数据库?"}' ``` ## 配置 项目通过环境变量配置,常用变量如下: | 变量 | 默认值 | 说明 | | --- | --- | --- | | `WORKSPACE_ID` | `local-workspace` | 数据隔离使用的工作区标识 | | `DATA_DIR` | `MemoryAgents/data` | 本地 JSON、ReMe、memU 文件目录 | | `DATABASE_URL` | `postgresql://memory:memory@localhost:54329/memory_agents` | PostgreSQL 连接串 | | `LLM_BASE_URL` | `https://api.openai.com/v1` | 对话模型接口地址 | | `LLM_API_KEY` | 空 | 对话模型密钥 | | `LLM_MODEL` | `gpt-4o-mini` | 对话模型名 | | `EMBEDDING_BASE_URL` | `https://api.openai.com/v1` | 向量接口地址 | | `EMBEDDING_API_KEY` | 空 | 向量接口密钥 | | `EMBEDDING_MODEL` | `text-embedding-3-small` | 向量模型名 | | `EMBEDDING_DIMENSIONS` | `1536` | 向量维度,必须和模型、数据库表一致 | | `EMBEDDING_MIN_SCORE` | `0.35` | 语义召回最低相似度 | | `REME_ENABLED` 等 | `false` | 是否启用对应第三方适配器 | 开发时可以先在 shell 中 `export`,也可以按 `app/config.py` 的加载路径放置 `.env`。建议显式设置 `DATA_DIR`,避免从不同目录启动时混淆数据位置。 启用第三方实现前,需要安装对应依赖: ```bash pip install -e '.[reme]' pip install -e '.[mem0]' pip install -e '.[letta]' pip install -e '.[memu]' ``` Mem0、Letta 和 memU 目前仍是适配骨架,代码中的 `setup_hint` 列出了尚未闭环的能力,默认不要开启。ReMe 已实现文件记忆、词面检索和 pgvector 语义召回。 ## 目录结构 ```text backend/ ├── app/ │ ├── main.py # FastAPI 入口和路由 │ ├── config.py # 环境变量与 SDK 兼容配置 │ ├── schemas.py # 请求、响应、记忆和审计模型 │ ├── registry.py # 记忆适配器注册表 │ ├── db.py # PostgreSQL / 本地 JSON 统一存储 │ ├── llm.py # OpenAI 兼容对话客户端 │ ├── embeddings.py # OpenAI 兼容向量客户端 │ └── adapters/ │ ├── base.py # 所有适配器的公共契约 │ ├── text2mem.py # 内置教学实现 │ ├── reme.py # ReMe 文件记忆实现 │ ├── mem0.py # Mem0 适配器 │ ├── letta.py # Letta 适配器 │ └── memu.py # memU 适配器 └── tests/ # 核心写入、检索和重置测试 ``` ## 核心调用链 一次 `/api/chat` 请求的处理过程: 1. `app/main.py:chat()` 根据请求中的 `system` 从注册表取出适配器。 2. 适配器的 `chat()` 决定是否写入记忆,并执行该系统自己的检索流程。 3. 公共数据通过 `MemoryRepository` 写入 PostgreSQL;数据库不可用时写入本地 JSON。 4. 需要语义检索时,`embedding_client` 生成查询向量,存储层计算相似度。 5. 召回内容交给 `llm` 生成回答;Text2Mem 在模型不可用时返回本地证据。 6. 写入、检索、删除等动作通过 `_audit()` 留下审计记录。 ### Text2Mem Text2Mem 最适合用来理解项目。`_should_encode()` 先判断输入是陈述还是问题;陈述由 `_memory_type()` 分为语义、情景、流程和任务状态四类。`_encode()` 负责去重和持久化,`_retrieve()` 将词面重合、记忆类型加分和向量相似度合并排序。 这里的规则是教学实现,不是通用中文意图识别器。调整正则时应同时补充 `tests/test_text2mem.py`,避免普通问题被误写入长期记忆。 ### ReMe ReMe 把 Markdown 文件作为真实记忆源。每轮对话按需执行自动记忆和重建索引,再通过规则扩展、可选模型改写、ReMe 文件检索和 pgvector 检索合并证据。后台定时任务被显式关闭,目的是让文件变化和模型费用都由请求触发。 删除 ReMe 记忆时会删除文件、清理公共向量并重建索引;全量重置还会移除 ReMe 工作目录。 ### 存储层 `MemoryRepository` 维护三类数据:`memory_items`、`audit_events` 和 `memory_embeddings`。PostgreSQL 使用 HNSW 索引做向量近邻搜索;本地模式使用 JSON 保存数据,并在进程内计算余弦相似度。 本地 JSON 主要用于快速体验和测试,不适合并发写入。部署环境应使用 PostgreSQL,并确保 pgvector 列维度与 `EMBEDDING_DIMENSIONS` 一致。 ## API 一览 | 方法 | 路径 | 用途 | | --- | --- | --- | | `GET` | `/api/health` | 检查存储、模型和向量配置 | | `GET` | `/api/systems` | 查看五个记忆系统的可用状态 | | `POST` | `/api/chat` | 指定记忆系统进行对话 | | `GET` | `/api/memories` | 查询某个系统的记忆 | | `DELETE` | `/api/memories/{memory_id}` | 删除指定记忆 | | `GET` | `/api/audit` | 查询操作审计记录 | | `POST` | `/api/reset` | 重置单个系统或全部系统 | `POST /api/reset` 不传 `system` 会逐个调用所有适配器。这个行为不能简单替换为清空公共表,因为 ReMe 等适配器还有自己的文件或索引。 ## 测试和检查 ```bash pytest ruff check app tests ``` 测试默认使用临时本地存储,不要求 PostgreSQL、模型或第三方记忆 SDK。新增适配器时,至少需要覆盖系统状态、不可用提示、写入/检索、删除和重置行为。 ## 新增一个记忆适配器 1. 在 `app/adapters/` 下新增类并继承 `MemoryAgent`。 2. 设置唯一的 `id` 和 `SystemDescriptor`,实现 `chat()`。 3. 如果使用公共存储,复用 `self.repo`;外部存储需要重写 `memories()`、`delete_memory()` 和 `reset()`。 4. 在 `SystemName` 中加入系统 ID,并在 `build_registry()` 注册实例。 5. 为启用条件、失败降级和数据清理补充测试。 适配器返回的 `ChatResponse` 中,`memory_context` 是本轮使用或可展示的记忆,`memory_events` 描述本轮写入和检索动作,`audit_events` 用于排查实际执行路径。三者含义不要混用。