mem
by cyhano
README.md
# mem
本地中文语义记忆工具 —— 给 AI coding agent(ZCode / 任意支持 MCP 的客户端)提供「按需召回、不全量注入」的事实型长期记忆。
## 为什么用它
- **中文语义召回好**:embedding 走硅基流动 `BAAI/bge-m3`(1024 维),比本地 MiniLM 对中文友好得多(实测"换说法"查询相似度 0.71 vs 0.42)。
- **不全量注入**:不像 `MEMORY.md` 每轮全量塞进上下文,而是 agent 用到时才 `mem_search`,只把命中的几条注入。
- **自动召唤(hook)**:会话开始注入概览、每次提问自动召回、回合结束提醒沉淀 —— 三个 hook 形成闭环。
- **能整理**:支持 `update`(改过时内容)、`merge`(合并重复)、`link`(Obsidian 式双链)。
- **零运维**:单 SQLite 文件 + 单入口脚本,无外部服务。
## 安装
```bash
cd ~/code
git clone https://github.com/cyhano/mem.git
cd mem
pnpm install
pnpm build
```
需要 Node.js ≥ 18(推荐 20+)和 pnpm。
## 配置
写 `~/.config/mem/config.json`(或设环境变量 `MEM_CONFIG_PATH` 指向它):
```json
{
"dbPath": "/Users/you/.local/share/mem/knowledge.db",
"embedding": {
"provider": "siliconflow",
"baseUrl": "https://api.siliconflow.cn/v1",
"apiKey": "你的硅基流动 key(或环境变量 SILICONFLOW_API_KEY)",
"model": "BAAI/bge-m3",
"dim": 1024
}
}
```
> `apiKey` 也支持通过环境变量 `SILICONFLOW_API_KEY` 注入,避免明文落盘。
## CLI 用法
```bash
node dist/cli.js save "标题" "正文" [--kind fact|decision|config|command] [--project 项目名]
node dist/cli.js search "自然语言查询" [--top 5] [--project 项目名]
node dist/cli.js list [--project 项目名]
node dist/cli.js count
node dist/cli.js delete <id>
# 整理
node dist/cli.js update <id> [--title xx] [--content xx] [--kind xx] [--project xx|全局]
node dist/cli.js merge <目标id> <源id> # 源并入目标后删除源
# 链接(Obsidian 式单向链 + 反向链接)
node dist/cli.js link <A的id> <B的id> # A → B
node dist/cli.js unlink <A的id> <B的id>
node dist/cli.js links <id> # 看出链 + 反链
```
`project` 语义:**不传 = 全局记忆**(任何项目都能搜到);显式传 `--project` = 归属某项目。全局单库,`search`/`list` 可加 `--project` 过滤。
## 接入 ZCode
### MCP
在 `~/.zcode/cli/config.json` 的 `mcp.servers` 里加:
```json
{
"mcp": {
"servers": {
"mem": {
"type": "stdio",
"command": "/绝对路径/node",
"args": ["/绝对路径/mem/dist/mcp.js"]
}
}
}
}
```
提供四个工具:`mem_save`、`mem_search`、`mem_list`、`mem_delete`(以及 `mem_update`、`mem_merge`)。
### hook(自动召回/沉淀)
在 `~/.zcode/cli/config.json` 的 `hooks.events` 里注册(三选一或全要):
```json
{
"hooks": {
"enabled": true,
"events": {
"SessionStart": [
{ "hooks": [{ "type": "process", "command": "/绝对路径/node",
"args": ["/绝对路径/mem/hooks/auto-status.mjs"], "timeoutMs": 15000 }] }
],
"UserPromptSubmit": [
{ "hooks": [{ "type": "process", "command": "/绝对路径/node",
"args": ["/绝对路径/mem/hooks/auto-recall.mjs"], "timeoutMs": 20000 }] }
],
"Stop": [
{ "hooks": [{ "type": "command",
"command": "python3 /绝对路径/mem/hooks/auto-capture.py", "timeout": 10 }] }
]
}
}
}
```
> 注意:hook 的 `matcher` 字段不要写成空字符串 `""`,要么省略、要么给 ≥1 字符 —— 空串会导致整个配置解析失败。
三个 hook 的作用:
| 事件 | 脚本 | 作用 |
|------|------|------|
| `SessionStart` | `auto-status.mjs` | 会话开始注入记忆概览(总数 + 最近标题) |
| `UserPromptSubmit` | `auto-recall.mjs` | 每次提问自动召回相关记忆注入上下文 |
| `Stop` | `auto-capture.py` | 回合结束检测运维/配置类产出,引导存记忆 |
## 架构
```
src/
├── config.ts # 配置加载 + 默认值
├── embed.ts # embedding(硅基流动 /v1/embeddings)+ 余弦相似度
├── store.ts # SQLite 存储(memories 表 + links 表)
├── core.ts # save/search/update/merge/link 核心逻辑
├── server.ts # MCP server(stdio)
├── cli.ts # 命令行
└── hook-*.ts # hook 专用输出端
hooks/ # 三个 hook 脚本
```
- **存储**:better-sqlite3 单文件,`memories` 表存正文 + blob 向量,`links` 表存单向链接。
- **召回**:查询向量化后与所有记忆暴力算余弦相似度,取 topK(<1 万条时足够快)。
- **链接**:单向存(`from → to`),反链自动算,对齐 Obsidian 双链语义;删记忆级联清理链接。
## 许可证
MITThis server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessSyncing