深入 rohitg00/agentmemory:11k Star 的 AI Agent 记忆引擎
每个用过 AI 编码 Agent 的人都会遇到同一个问题:每次新开一个会话,都要重新解释一遍项目背景。
CLAUDE.md、.cursorrules 这些静态文件最多塞 200 行就会过时。你手动更新的频率永远跟不上 Agent 实际产出的信息量。
agentmemory(11k ⭐)就是为了解决这个问题而生的。它不只是一个记忆存储方案,而是一套完整的 Agent 原生记忆引擎——有 hooks 自动捕获、有检索、有生命周期管理、有多 Agent 共享。
这篇文章会从源码层面完整拆解它。
一、它解决了什么问题?
项目的 README 举了个很形象的例子:
Session 1 你配置了 JWT 认证。Session 2 你问 "怎么做限流"。Agent 已经知道你用的是 jose 中间件、文件在
src/middleware/auth.ts、测试覆盖了 token 校验、你选了 jose 而不是 jsonwebtoken 是因为 Edge 兼容性。不用重新解释。不用复制粘贴。Agent 就是知道。
这不是魔法——这是 12 个生命周期 Hook + 4 层记忆合并 + 三路 RRF 融合检索共同工作的结果。
二、整体架构
技术栈
| 层 | 技术 |
|---|---|
| 核心引擎 | iii-engine(自研函数式引擎) |
| 存储 | SQLite(better-sqlite3) |
| 全文索引 | BM25(自实现 FTS) |
| 向量嵌入 | @xenova/transformers → all-MiniLM-L6-v2(可选) |
| 知识图谱 | 实体关系推理(自实现) |
| API 层 | REST(121 endpoints)+ MCP(51 tools)+ iii 函数 |
| 语言 | TypeScript |
关键设计决策:零外部数据库依赖。没有 Postgres、没有 Qdrant、没有 Redis。一个 npx @agentmemory/agentmemory 就能跑。
三、核心特性
1. 12 个 Auto Hook——这是最根本的差异化
这是 agentmemory 区别于 mem0、Letta 等竞品的最关键特性:记忆是自动捕获的,不需要开发者手动调 API。
它直接在 Claude Code / Codex CLI 的生命周期中插入了 12 个钩子:
| Hook | 触发时机 | 作用 |
|---|---|---|
SessionStart | 会话开始时 | 注入历史上下文 |
UserPromptSubmit | 用户发送消息 | 捕获用户意图 |
PreToolUse | 工具调用前 | 注入相关记忆到当前工具 |
PostToolUse | 工具返回后 | 记录工具结果 |
PreCompact | 上下文压缩前 | 再注入一次防止丢失 |
Stop / SessionEnd | 会话结束 | 触发摘要和记忆合并 |
Subagent | 子 Agent 产生 | 记录子会话 |
TaskCompleted | 任务完成 | 记录完成状态 |
PostToolUseSuccess/Failure | 工具结果 | 区分成功/失败信号 |
对比其他方案:
| 方案 | 怎么添加记忆 |
|---|---|
| agentmemory | 12 hooks 自动捕获,零手动 |
| mem0 | 必须手动调 add() |
| Letta/MemGPT | Agent 自编辑记忆 |
| CLAUDE.md | 完全手写 |
这是一个体验层面的质变——从 "开发者负责记" 变成了 "系统自动记"。
2. 4 层记忆生命周期——防止无限膨胀
光有捕获不行。如果不做管理,记忆库会随时间无限膨胀,噪声淹没信号。
agentmemory 设计了 4 层记忆等级:
每层的关键机制:
- 语义衰减:不仅按时间衰减,还检测内容特征——包含 "TODO:"、"in progress" 等模式的记忆会被优先降级
- 被动反馈:每次
recall时,top-3 命中自动加分(24h 内限 3 次/条) - Write Guard:写入前进行语义去重 + 冲突检测 + 类型合并
- 归档驱逐:被淘汰的记忆进入归档,可手动恢复
这是 hooks 之外的第二个硬功夫——没有生命周期管理的记忆系统,最终都会变成垃圾场。
3. RRF 三路融合检索——95.2% R@5 的来源
检索是 agentmemory 最硬的工程指标。它不是单用向量搜索,而是三路并行 + RRF 融合:
三路各自的作用:
| 检索方式 | 原理 | 擅长 | 独立 R@5 |
|---|---|---|---|
| BM25 | 关键词精确匹配 | "jwt refresh token 过期时间" 这种精确查询 | 86.2% |
| 向量语义 | 嵌入余弦相似度 | "那个认证怎么续期" 这种语义泛化 | — |
| 知识图谱 | 实体关系推理 | 跨实体推理 "Auth 中间件 -> 哪个文件" | — |
| RRF 融合 | 三路排名加权合并 | 综合互补,消除单路盲区 | 95.2% |
RRF 的核心公式:
score(d) = 1/(k + r₁(d)) + 1/(k + r₂(d)) + 1/(k + r₃(d))
——把三路的排名简单粗暴地融合,没有 ML 权重调优。
4. 多 Agent 共享记忆——跨工具的知识连续性
一个 agentmemory 服务可以被所有主流 Agent 同时连接:
| Agent | 接入方式 | 集成深度 |
|---|---|---|
| Claude Code | 原生插件 + 12 hooks | 最深 |
| Codex CLI | 原生插件 + 6 hooks | 深 |
| Cursor | MCP | 标准 |
| Gemini CLI | MCP | 标准 |
| OpenCode | MCP | 标准 |
| Windsurf | MCP | 标准 |
| Cline / Roo Code | MCP | 标准 |
| Aider | REST API | 基础 |
| Hermes | Memory Provider 插件 | 深 |
| 任意 MCP 客户端 | MCP | 标准 |
这意味着你在 Claude Code 里写过的代码背景,在 Cursor 里也能直接用。记忆不再绑定到某个 IDE 或 Agent。
5. Session Replay + 实时 Viewer
每个会话的每个工具调用都被记录成离散事件,可以在浏览器里回放。已有的 Claude Code JSONL 日志也可以通过 import-jsonl 导入。
6. 51 个 MCP Tools
agentmemory 注册了 51 个 MCP 工具(通过 @agentmemory/mcp),分为几类:
记忆操作: memory_save, memory_recall, memory_smart_search, memory_forget
会话管理: memory_sessions, memory_session_start, memory_session_end
批量操作: memory_list, memory_export, memory_import
治理: memory_governance_delete, memory_audit
另有 4 个内建技能(Slash Command):/recall、/remember、/session-history、/forget。
四、向量搜索的实现——153 行手写代码
这是很多人的第一反应:95.2% 的检索精度,用的什么向量库?
答案有点意外——什么向量库都没用。
源码在 src/state/vector-index.ts,只有 153 行:
// 存在内存 Map 里
export class VectorIndex {
private vectors: Map<string, { embedding: Float32Array; sessionId: string }> = new Map();
// 手写 for 循环算余弦相似度
function cosineSimilarity(a: Float32Array, b: Float32Array): number {
if (a.length !== b.length) return 0;
let dot = 0, normA = 0, normB = 0;
for (let i = 0; i < a.length; i++) {
dot += a[i] * b[i];
normA += a[i] * a[i];
normB += b[i] * b[i];
}
const denom = Math.sqrt(normA) * Math.sqrt(normB);
return denom === 0 ? 0 : dot / denom;
}
// 搜索时暴力遍历所有向量
search(query: Float32Array, limit = 20) {
for (const [obsId, entry] of this.vectors) {
const score = cosineSimilarity(query, entry.embedding);
// top-k 堆
}
}
完整数据流:
没有 IVF,没有 HNSW,没有 PQ,没有任何近似最近邻索引。全量暴力扫描。
为什么这么做?
| 考量 | 结论 |
|---|---|
| 数据规模 | Coding Agent 记忆 ~几千到几万条,暴力扫描 < 2ms |
| 部署体验 | 不需要 Docker、Postgres、Qdrant,npx 一行启动 |
| 可维护性 | 153 行代码零黑盒,出 bug 十分钟定位 |
| 兜底策略 | 不装向量依赖也能跑,BM25 保底 R@5 86.2% |
这 153 行代码替换了一个重型外部依赖。换来的不是性能,而是 极低的 adoption barrier——这才是 11k Star 的真正原因。
五、Token 效率与成本
agentmemory 最有说服力的指标之一是它的 Token 消耗:
| 方案 | 年均 Token | 年均成本 |
|---|---|---|
| 粘贴全部历史 | 19.5M+ | 超出上下文窗口 |
| LLM 摘要 | ~650K | ~$500 |
| agentmemory | ~170K | ~$10 |
| agentmemory + 本地嵌入 | ~170K | $0 |
每会话只需注入约 1,900 tokens(3 条 BM25 + 3 条向量 + 1 条图谱 + 优先级排序后的上下文),而非几十万的原始日志。
注入优先级策略:
1. 未完成的 Scratchpad(~2K chars)
2. 最近的 Topic 条目(~2K chars)
3. 今日 Daily Log(~3K chars,尾部)
4. RRF 检索命中的记忆(~2.5K chars)
5. MEMORY.md 核心知识(~4K chars,中间截断)
6. 昨日 Daily Log(~3K chars,最低优先级)
每个条目严格按照优先级分配 Token 预算,超出时从低优先级开始截断。
六、竞品对比
| 维度 | agentmemory | mem0 (53K⭐) | Letta/MemGPT (22K⭐) | CLAUDE.md |
|---|---|---|---|---|
| 类型 | 记忆引擎 + MCP 服务 | 记忆层 API | 完整 Agent 运行时 | 静态文件 |
| 检索 R@5 | 95.2% | 68.5% | 83.2% | N/A(grep) |
| 自动捕获 | 12 hooks,零手动 | 手动 add() | Agent 自编辑 | 手动编辑 |
| 搜索方式 | BM25 + 向量 + 图谱 RRF | 向量 + 图谱 | 向量(档案式) | 全量加载 |
| 多 Agent 共享 | MCP + REST + 租约 + 信号 | API(无协调) | 仅 Letta 运行时 | 每个 Agent 独立 |
| 框架锁定 | 无(任何 MCP 客户端) | 无 | 高(必须用 Letta) | 按 Agent 格式 |
| 外部依赖 | 无(SQLite 就够了) | Qdrant / pgvector | Postgres + 向量 DB | 无 |
| 记忆生命周期 | 4 层合并 + 衰减 + 自动遗忘 | 被动提取 | Agent 管理 | 手动清理 |
| 自托管 | ✅ 默认 | 可选 | 可选 | ✅ |
| 实时查看器 | ✅ :3113 | 云面板 | 云面板 | ❌ |
| Session Replay | ✅ 时间线回放 | ❌ | ❌ | ❌ |
来源:项目 README 中的 benchmark/COMPARISON.md。嵌入模型统一使用 all-MiniLM-L6-v2,基准为 LongMemEval-S(ICLR 2025,500 questions)。
七、工程哲学总结
agentmemory 的设计选择背后有几个清晰的判断:
-
Hooks 比 API 重要——让系统自动记,而不是让人手动记。12 个生命周期 Hook 是体验质变的核心。
-
生命周期比存储重要——没有衰减和治理,记忆库最终会变成垃圾堆。4 层合并 + Write Guard + 语义衰减,这些才是长期可用的保障。
-
融合检索比单一向量重要——BM25 兜底 + 向量语义 + 图谱推理,三路互补把 R@5 拉到 95.2%。纯向量搜索(mem0)只有 68.5%。
-
部署体验比特性列表重要——
npx一行启动,零外部依赖。153 行手写向量索引换来的不是性能,而是谁都能在 30 秒内跑起来的 adoption barrier。 -
Token 效率是最好的 UX——每会话 1,900 tokens 而不是 19.5M,这既是省钱,也是让模型更聚焦的手段。
最后,项目 README 里有一句话说得很好:
你的 Agent 在 Session 1 记住的东西,Session 2 不应该重新学一遍。
agentmemory 就是这句话的工程实现——用 12 个 Hook 自动捕获,用 4 层生命周期管理,用三路 RRF 融合检索,最终做到让 Agent 真正拥有跨会话的记忆。