内容
# 记忆系统
<p align="center"><img src="docs/assets/logo.png" width="160" alt="记忆系统 logo"/></p>
<p align="center"><strong>每个 AI 代理都有一份记忆。</strong></p>
<p align="center">
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="许可证:MIT"></a>
<a href="package.json"><img src="https://img.shields.io/badge/node-%3E%3D22-339933?logo=node.js&logoColor=white" alt="Node >=22"></a>
<a href="https://modelcontextprotocol.io"><img src="https://img.shields.io/badge/MCP-Streamable%20HTTP-6b46c1" alt="MCP"></a>
<a href="deploy/setup-pi.sh"><img src="https://img.shields.io/badge/deploy-self--hosted-orange" alt="自托管"></a>
</p>
克劳德代码、光标、开源代码、Codex CLI 和自定义代理目前都保留自己的上下文——在一个工具中做出的决定对其他工具是不可见的,切换设备意味着从头开始。记忆系统是一个小型自托管服务器(MCP + REST),为它们提供一个共同的认知:结构化记忆、混合文档搜索(RAG)、项目地图和基于角色的系统提示。它在您自己的网络上运行在树莓派 5 上,并跟随您跨越每台机器和每个代理。
## 为什么存在
多代理工作流存在一个上下文问题:
- 在与克劳德代码配对时做出的决定,在一个小时后对光标不可见。
- 从桌面切换到笔记本电脑(或手机)意味着重新解释您正在做的事情。
- 每个代理都从头开始重新推导项目上下文,而不是读取共享的结构化地图。
- “我昨天学了 X”没有持久的存储位置——它要么存在于滚动历史中,要么不存在。
记忆系统对此提供了一个刻意为之的小型解决方案:一台服务器、一个 SQLite 文件、一种协议(MCP),以及所有代理已经使用的 REST 接口,没有矢量数据库集群、消息队列或 Docker 层——只有足够的インフラ结构来使记忆持久且跨工具和设备可搜索。
## 功能
- **共享记忆** - 事实、偏好、决策(附带理由)和操作指南,由任何代理保存并由其他代理检索。混合搜索(BM25 via FTS5 + 矢量 via `sqlite-vec`,与 Reciprocal Rank Fusion 合并)根据词汇或语义匹配找到正确的记忆。
- **RAG 文档存储** - 导入笔记、README、研究总结或学习总结;markdown 感知分块、自动嵌入、混合检索,附带来源引用。
- **项目地图** - 每个项目一个 YAML 支持的记录:摘要、堆栈、决策、当前关注点、下一步骤。任何代理、任何设备,都可以调用 `project_get("name")` 并立即获得完整上下文。
- **基于角色的系统提示** - 一个提示库(高级软件架构师、代码审查员、调试专家、安全工程师、前端工程师、DevOps/SRE、ML 工程师),具有共享的“工程思维”核心自动注入到每个角色中,包括本地模型使用的提示。
- **本地 AI 协调** - 将简单的/批量文本工作路由到本地 LLM(LM Studio,无 API 成本)和图像/视频/音频生成到 ComfyUI,两者都通过 `local_llm` / `media_generate` 从任何连接的代理驱动。
- **跨设备同步** - 一个本地优先、最后写入获胜的同步模型,以便在设备上创建的记忆和项目地图可以与主实例(Pi)干净地协调。
- **MCP + REST,相同核心** - 每个功能都通过 MCP 工具(适用于通过 Streamable HTTP 使用 MCP 的代理)和 REST 端点(适用于脚本、自定义代理和 Web UI)公开 - 一个实现,两个入口。
- **Web UI** - 一个用于浏览记忆、RAG 文档、项目和提示的小型 React 仪表板,适用于浏览器,包括手机。
## 架构
```
┌──────────────────────────────────────────────────────────────┐
│ 树莓派 5 — "中心" (Tailscale IP: 100.x.x.x) │
│ │
│ ┌────────────────────────────────────────────┐ │
│ │ 中心服务器 (Node 22, systemd) │ │
│ │ ├── MCP 端点 /mcp (Streamable HTTP) │ │
│ │ ├── REST API /api/* (脚本、代理) │ │
│ │ └── Web UI / (仪表板,PWA) │ │
│ └───────────────┬────────────────────────────┘ │
│ │ │
│ ┌───────────────▼────────────────────────────┐ │
│ │ SQLite (单个文件:hub.db) │ │
│ │ ├── 记忆 (结构化记忆) │ │
│ │ ├── 文档 (RAG 源文档) │ │
│ │ ├── 分块 + 矢量 (sqlite-vec 嵌入) │ │
│ │ ├── 分块_fts (FTS5 BM25 索引) │ │
│ │ └── 项目 (项目地图) │ │
│ └────────────────────────────────────────────┘ │
│ │
│ 每夜备份:sqlite 备份 + markdown 导出 → git 推送 │
└──────────────────────────────────────────────────────────────┘
▲ Tailscale(私有网络;Funnel 可选用于公共访问)
│
┌─────┴──────────────────────────────────────┐
│ 设备(桌面、笔记本电脑、手机) │
│ ├── 克劳德代码 → MCP (Streamable HTTP) │
│ ├── 光标 / Windsurf → MCP (mcp.json) │
│ ├── 开源代码 → MCP (opencode.json) │
│ ├── Codex CLI → MCP (config.toml) │
│ ├── claude.ai / ChatGPT / Gemini → MCP (Funnel + ?token=) │
│ └── 自定义脚本 → REST API │
└────────────────────────────────────────────┘
```
嵌入调用(Gemini API)仅从 Pi 发出 - 客户端发送原始文本,因此 API 密钥仅存在于一个位置。
有关完整的数据模型和分阶段的建设计划,请参见 [`PLAN.md`](PLAN.md)。
## 截图
| 仪表板 | RAG 搜索 | 提示 | 移动设备 |
|---|---|---|---|
|  |  |  |  |
## 快速开始
### 选项 A:一键安装程序
```bash
# macOS / Linux
curl -fsSL https://raw.githubusercontent.com/fthsrbst/mnema/main/scripts/install.sh | bash
```
```powershell
# Windows
irm https://raw.githubusercontent.com/fthsrbst/mnema/main/scripts/install.ps1 | iex
```
安装程序克隆存储库、安装依赖项、构建并编写一个初始 `.env`。
### 选项 B:手动
```bash
git clone https://github.com/fthsrbst/mnema.git
cd mnema
npm ci
npm run build
cp .env.example .env # 编辑 HUB_TOKEN、GEMINI_API_KEY(可选)
npm run dev # http://127.0.0.1:8033
```
没有 `GEMINI_API_KEY`,服务器仍然运行 - 它会退回到仅限 FTS(关键词)搜索而不是混合搜索。没有任何内容会崩溃;您会失去语义召回,直到您添加密钥。
### 树莓派部署
```bash
curl -fsSL https://raw.githubusercontent.com/fthsrbst/mnema/main/deploy/setup-pi.sh | bash
```
这安装 Node 22,克隆存储库,构建服务器 + Web UI,生成带有随机 `HUB_TOKEN` 的 `.env`,安装 systemd 单元(`hub@<user>`),并安排每日备份 cron 作业。有关详细信息,请参见 [`deploy/setup-pi.sh`](deploy/setup-pi.sh) 和 [`deploy/clients.md`](deploy/clients.md)。
## 连接代理
每个代理都与相同的 `/mcp` 端点通信。将 `<HUB>` 替换为您的服务器 URL(本地为 `http://127.0.0.1:8033`,在您的 tailnet 上为 `http://100.x.x.x:8033`)并将 `<TOKEN>` 替换为您的 `HUB_TOKEN`。
**克劳德代码**
```bash
claude mcp add --transport http --scope user hub <HUB>/mcp \
--header "Authorization: Bearer <TOKEN>"
```
**光标 / Windsurf** (`~/.cursor/mcp.json`)
```json
{
"mcpServers": {
"hub": {
"url": "<HUB>/mcp",
"headers": { "Authorization": "Bearer <TOKEN>" }
}
}
}
```
**开源代码** (`~/.config/opencode/opencode.json`)
```json
{
"mcp": {
"hub": {
"type": "remote",
"url": "<HUB>/mcp",
"headers": { "Authorization": "Bearer <TOKEN>" }
}
}
}
```
**Codex CLI** (`~/.codex/config.toml`)
```toml
[mcp_servers.hub]
url = "<HUB>/mcp"
http_headers = { "Authorization" = "Bearer <TOKEN>" }
```
这四个条目不是每个客户端手动维护的 - 它们都来自一个文件 [`mcp-servers.json`](mcp-servers.json),该文件还列出了辅助 MCP 服务器(`context7`、`playwright`、`sequential-thinking`):
```json
{
"servers": {
"hub": {
"url": "$HUB_URL/mcp",
"headers": { "Authorization": "Bearer $HUB_TOKEN" }
}
}
}
```
在设备上运行 `hub sync` 解析 `$HUB_URL` / `$HUB_TOKEN` 从该设备的 `hub config`,将结果写入每个检测到的客户端的配置文件(`~/.claude.json`、`~/.cursor/mcp.json`、`~/.config/opencode/opencode.json`、`~/.codex/config.toml`),复制共享技能集到 `~/.claude/skills/`,并更新 `CLAUDE.md` / `AGENTS.md` 中的托管块,以便每个代理都知道中心存在以及何时使用它。完整的客户端详细信息: [`deploy/clients.md`](deploy/clients.md)。
## 自动回忆钩子
这个功能使共享记忆实际被使用,而不是放在那里未被读取:克劳德代码的 `UserPromptSubmit` 钩子在您发送的**每个消息**上运行 `hub recall --hook`,在代理看到消息之前。钩子从标准输入读取提示,跳过短消息和斜杠命令,通过 `GET /api/recall?q=<prompt>&format=text` 调用中心 hub,并打印它找到的相关记忆/RAG 分块 - 然后代理已经有了该上下文,并且不需要显式“搜索记忆”的步骤。
它故意保持沉默:如果中心 hub 无法访问、速度慢或返回错误,则钩子退出 `0`,您的提示将不受影响地通过。自动回忆只能添加上下文 - 它永远不会阻止或中断对话。
将 [`deploy/claude-code-settings.example.json`](deploy/claude-code-settings.example.json) 中的钩子块合并到 `~/.claude/settings.json` 中:
```json
{
"hooks": {
"UserPromptSubmit": [
{ "hooks": [{ "type": "command", "command": "hub recall --hook", "timeout": 5 }] }
]
}
}
```
`hub sync` 还会在 `CLAUDE.md` / `AGENTS.md` 中写入一个托管块,告诉代理 **何时** 写回 - 保存带有理由的决策,记录会话前关闭,保持项目地图最新 - 因此回忆和捕获作为一个循环工作,而不是单向查找。
## 安全说明
记忆系统的身份验证模型故意简单 - 在将其公开给超出您自己的机器之前,请阅读以下内容:
- **单个 bearer token。** `.env` 中的 `HUB_TOKEN` 控制除 `/health` 之外的每个请求。如果为空,则身份验证完全关闭(适用于本地开发,不适用于其他任何情况)。没有每个代理的范围或轮换工具 - 轮换意味着更改 `.env`、重启服务并手动更新每个连接的客户端。
- **两种发送 token 的方式。** 大多数客户端发送 `Authorization: Bearer <token>`;无法附加自定义标头的平台(claude.ai、ChatGPT、Gemini)退回到 URL 中的 `?token=<HUB_TOKEN>`。URL 中的 token 有实际的权衡(浏览器历史记录、代理/访问日志)- 参见 [`docs/connectors.md`](docs/connectors.md) 以获取完整的说明。
- **Tailscale 是默认网络边界。** 中心监听私有 tailnet 地址;除非您明确运行 `tailscale funnel`,否则从开放的互联网上无法访问任何内容。Funnel 使端点 **完全公开** - bearer token 成为互联网和您的记忆存储之间唯一的立足点,因此请将启用它视为一种刻意、临时的操作,而不是默认操作。
- **`/outputs` 无需身份验证,但有目的。** 生成的媒体(`data/outputs`,通过 `image_generate` / `media_generate`)和 Web UI 的静态外壳无需身份验证提供(`express.static`,在 `src/server/index.ts` 中的 token 中间件之前挂载),以便仪表板中的 `<img>` / `<video>` 标签在没有 token 填充的 URL 的情况下工作。所有 **数据** 端点(`/api/*`,`/mcp`)仍在 bearer 检查后面。除非您将敏感数据放入 `data/outputs` 中。
这是一个个人规模的工具,不适用于多租户或公共部署 - 请参阅下面的成熟度表,了解实际的战斗测试程度。
## 路线图
尚未构建,在 [`PLAN.md`](PLAN.md) 中跟踪(Faz 5/6):
- **`hub ask "<question>"`** - RAG + Gemini Flash,直接终端 Q&A,无需打开代理。
- **快速捕获** - 一个移动友好的单输入 Web UI,用于将注释或链接直接放入 RAG(带有自动获取 + 链接摘要)。
- **监视模式** - 自动在更改时重新索引笔记/文档文件夹。
- **`hub timeline <project>`** - 项目的事件记录和会话的时序转储。
- **每周记忆维护摘要** - 一个 cron 作业,报告过期/冲突的记忆条目,而不是简单地让它们积累。
- **Qdrant 迁移路径** - `sqlite-vec` 适用于大约 1M 矢量;如果达到上限,则迁移到专用矢量存储已计划但未实现。
## 成熟度 / 诚实表
没有通货膨胀 - 这是实际可靠的部分与仍然粗糙的部分:
| 区域 | 状态 | 备注 |
|---|---|---|
| 记忆 CRUD + 混合搜索 | 稳定 | 每天使用;仅限 FTS 备用测试 |
| RAG 导入 + 搜索 | 稳定 | 分块是 markdown 感知的但简单;无重新排序模型 |
| 项目地图 | 稳定 | YAML + DB 同步有效;无冲突 UI 超出 LWW |
| MCP 服务器(工具) | 稳定 | `src/server/mcp.ts` 中列出的所有工具每天都在使用 |
| REST API | 稳定 | 镜像 MCP 工具;CLI 和 Web UI 使用 |
| 跨设备同步(LWW) | 功能性,轻度测试 | 作者的 2-3 设备设置有效;未针对大量并发写入进行压力测试 |
| Web UI | 功能性 | 涵盖记忆/RAG/项目/提示浏览;不是精致的产品 UI |
| 本地 LLM 协调(LM Studio) | 功能性 | 当 LM Studio 可达时有效;基本错误处理之外无重试/队列 |
| 媒体生成(ComfyUI) | 实验性 | 作者自己的工作流有效;需要编写自己的 `workflows/*.json` |
| 公共连接器公开(Funnel + `?token=`) | 功能性,使用时请谨慎 | URL 中的 token 是一个真正的权衡 - 参见 [`docs/connectors.md`](docs/connectors.md) |
| 身份验证模型 | 基础 | 单个 bearer token,无每个代理的范围或轮换自动化 |
| 备份/恢复 | 功能性 | 夜间 cron + markdown 导出存在;恢复路径是手动的 |
| Qdrant / 更大规模的矢量存储 | 未构建 | `sqlite-vec` 适用于大约 1M 矢量;迁移路径已计划但未实现 |
这是一个个人规模的工具,适用于运行少量设备,不适用于多租户或公共部署 - 请参阅上述令牌 + Funnel 模型。
## 许可证
MIT - 参见 [`LICENSE`](LICENSE)。