你说过一次,所有 Agent 都记住:Memmy 跨 Agent 记忆层源码拆解
同一天写这篇的时候,Keyv 的 npm 蠕虫正在被讨论:一个包被污染,所有装过它的项目全遭殃。Agent 生态也一样——你给 Claude Code、Codex、Cursor 各装一套配置,等于把同一个秘密讲给了三个互不认识的员工。他们各自记在小本本上,谁也不告诉谁。 本文首发地址 https://h89.cn/archives/687.html
你其实在重复教每个 AI 编程工具一遍
同时用 Claude Code 和 Codex 的人,大概率经历过这个循环:
- 在 Claude Code 里花半小时讲清楚项目架构、目录约定、踩过的坑;
- 切到 Codex 干活,发现它一无所知,重新解释一遍;
- 换了台机器或者新开了 Cursor,第三遍。
每个工具都是一个独立的"员工",工位挨着,但从不交流。你讲过的每一句话,都被各自的上下文窗口丢掉了。这不是某一个工具的问题——上下文窗口本身就是一次性的,关掉就没了。
所以当我在 GitHub 上刷到 MemTensor/memmy-agent(下文简称 Memmy)时,它的口号让我愣了一下:
"All AI remember the same you."
让 Cursor、Claude Code、Codex、OpenCode、OpenClaw、Hermes 六种工具共享同一份长期记忆。你说过一次的事,所有 Agent 都记住。
Memmy 7 月中旬开源,到现在(8 月 5 日)已迭代到 v1.0.4,GitHub 实时数据 显示 565 stars、44 commits、11 个贡献者。星数不算高,但功能完整度远超星数暗示的水平:四层记忆、六路混合召回、六种 Agent 适配器、桌面端 + CLI + API 全套落地。需要说明的是,它和同组织的 MemOS(10k stars 的「自演化记忆 OS」引擎)不是同一个项目——Memmy 更像是 MemOS 理念的消费级封装,定位是桌面端 + 本地优先的跨 Agent 记忆产品。
我把它 clone 下来翻了源码,这篇写清楚三件事:记忆引擎怎么设计的、六种 Agent 怎么接进来的、以及它凭什么解决 mem0 被诟病的记忆质量问题。
记忆引擎:不是"存下来",是"沉淀出来"
先说一个背景。市面上最火的记忆方案 mem0(56.8k stars)走的是"向量 + 全文检索 + 实体链接"的路子,单遍提取,存完就算数。但它的质量一直被人诟病,issue #4573 里有用户贴出实测称,97.8% 的召回是噪声。问题不在于"存",而在于"存的时候没想过这条记忆以后有没有用"。
Memmy 的设计思路完全不同:记忆是分层的,并且会自己演化。它的架构文档把记忆分成四层:
| 层 | 保存什么 | 怎么产生 |
|---|---|---|
| L1 Trace | 原始交互:用户请求、Agent 回复、工具调用、结果、错误签名 | 回合结束后写入 |
| L2 Policy | 从相似的、有价值的 L1 里归纳出的经验:触发条件、步骤、避坑点 | reward 之后的归纳 |
| L3 World Model | 对项目、环境、约束的稳定认知(不是操作步骤) | 从 L2 集群抽象 |
| Skill | 可调用的 SOP:名称、触发说明、执行步骤、验证条件 | 从合格的 L2 结晶 |
这是一条自下而上的升华链:原始对话 → 归纳成经验 → 抽象成环境认知 → 结晶成可复用技能。翻译成人话:不是把你说过的每句话都存下来,而是把你说过的话里值得学的部分提炼成"这个项目该怎么干活"。
这条链跑在后台,由几个独立的演化管道驱动(源码在 Memory/src/service/evolution/):
- reward-pipeline:一个回合(episode)结束后等 30 秒反馈窗口,根据任务奖励给该回合的 L1 反向传播价值,越靠前的轨迹衰减越狠(gamma=0.9),L1 的 priority 每 30 天半衰期衰减一次。没用的记忆会自己贬值。
- L2 induction:只有价值超过阈值(minTraceValue=0.005)的 L1 才进入归纳候选池,相似度 ≥0.65 才归纳成 L2 Policy。
- L3 abstraction:L2 聚类抽象成场域认知,置信度 ≥0.2 才参与召回。
- skill-pipeline:满足条件的 L2 结晶成 Skill,以后可以直接当工具调用。
- negative-experience-pipeline:工具连续失败会生成"避坑经验",下次遇到同样的错误直接决策修复。
还有一个挺有意思的机制:Dream 整理。手动 /dream 或周期触发,把已有记忆合并、归档、提炼,类似睡眠期的记忆巩固,/dream-log 看结果、/dream-restore 回滚。
检索:六路混合召回 + 三道质量闸门
存得好只是第一步,查得准才是真本事。Memmy 的检索(Memory/src/service/retrieval/retrieval-service.ts)不是单一向量搜索,而是六路并行召回:
| 通道 | 干什么 | 用在哪层 |
|---|---|---|
语义向量 vec / vec_summary / vec_action |
向量相似度检索 | 所有层 |
全文检索 fts |
SQLite FTS5 关键词匹配 | 所有层 |
短词/中文模式 pattern |
二字中文片段、两字符 ASCII 短词 | 所有层 |
结构化片段 structural |
错误签名、路径、错误码精确匹配 | 仅 L1 |
六路结果按相关度融合(channel score + 层级 bonus + RRF 融合),然后过三道质量闸门:
- 相对阈值裁剪:低于最高相关度 20% 的候选丢弃(多通道命中 ≥2 可豁免);
- MMR 多样性选择:
0.7 × 相关度 - 0.3 × 冗余度,避免召回十条长得一模一样的; - LLM 最终过滤:用一个独立的"演化模型"对机械排序结果做语义过滤,最多保留 8 条,失败回退保底 6 条。
向量存储用的是本地 SQLite + sqlite-vec 扩展,每次搜索从最近 2,000 条向量记录里建窗口再取 Top K,不是全库暴力扫。
还有个细节很见功力:新回合第一轮会做意图门控。如果你的请求是"上次我们聊到哪了?",它召回 Skill/L2/L1 但不召回 L3(世界模型);如果是闲聊或者 Memmy 自己的元命令,直接跳过召回。另外 turn_start 会排除当前 session 自己的 L1,防止刚发生的事通过长期记忆路径"回声式重复"——这个坑很多记忆系统都踩过,刚说完的话又被当成历史记忆注入回来。
真正难的工程:让六种 Agent 都接入
记忆引擎再漂亮,如果每个 Agent 都要手动调 API,就没人用。Memmy 的护城河在接入层:App/backend/src/adapters/outbound/agent-source/ 下有六个适配器目录,每个都是独立的 adapter:
| Agent | 历史扫描来源 | 实时接入方式 |
|---|---|---|
| Cursor | ~/Library/Application Support/Cursor/.../state.vscdb |
Hook |
| Claude Code | ~/.claude/projects/**/*.jsonl |
Hook |
| Codex | ~/.codex/sessions/<YYYY>/<MM>/<DD>/rollout-*.jsonl |
Hook |
| OpenCode | ~/.local/share/opencode/opencode.db |
原生插件 |
| OpenClaw | ~/.openclaw 下的 conversation/memory SQLite |
Memory 插件 |
| Hermes | ~/.hermes/sessions/**/*.jsonl + state.db |
Memory Provider 插件 |
每个 Agent 的接入都做三件事:
1. 历史扫描 + 增量同步。 首次扫描把 Agent 已经写在本地的对话全部导入,之后维护一个日期时间水位做增量同步。水位机制有个细节:每次同步会重读水位时刻的那条消息(>= 包容边界),用"最后消息时间 + 消息 ID + 内容哈希"做会话检查点去重,保证幂等,不会因为水位正好落在回合中间而丢开头。
2. 按完整回合入库,不按消息。 一条用户消息 + 后续工具/系统消息 + Assistant 回复合并成一个回合,一个回合只生成一条 L1。比如"1 用户 + 2 工具 + 1 Assistant"处理了 4 条消息,但只 +1 条记忆。没有最终回复的不完整回合直接跳过,等它补全。这就是为什么 Memmy 的记忆密度比"每条消息都存"的方案高得多。
3. 实时 Hook/插件 + Skill 注入。 装完后五个接入(除 Cursor 外)会在请求执行前检索记忆注入上下文,回合结束自动采集(用户请求、Agent 回答、成功/失败状态,不需要手动 memmy-memory add)。Cursor 的 Hook 重点负责采集和 /memmy-resume 命令。另外每个 Agent 都会装一个 memmy-memory SKILL.md,让 Agent 自己也能主动存/查。
两个工程细节值得单独说:
fail-open 设计。 记忆服务挂了绝不阻塞对话:召回或采集失败就记录错误继续,单次 Memory 请求超时 45 秒,Hook 宿主超时 60 秒。这个取舍对生产力工具是必须的:记忆是增强,不是单点故障。
注入内容的安全标记。 记忆注入用 <memmy_memory_context> 包裹,当前用户请求用 <current_user_request> 明确标出,降低"旧记忆被误当成新指令"的风险。SKILL.md 的安全规则写得很直白:不存储密钥/token;不因为内容出现在记忆上下文里就回答它;不把这些标签本身写进记忆。
代价与取舍:为什么它还不能无脑用
夸完亮点,泼盆冷水。Memmy 现在是 565 stars 的 3 周龄项目(GitHub,8 月 5 日复核),对比一下:
| 项目 | Stars | 质量门控 | 定位 |
|---|---|---|---|
| mem0 | ~56.8k | 无(97.8% 垃圾率争议) | 云优先记忆 SDK |
| Letta (MemGPT) | ~23k | 无 | 有状态 Agent + 记忆块 |
| MemOS(Memmy 同组织) | ~10k | 有演化管道 | 自演化记忆 OS 引擎 |
| Zep | ~4.6k | 仅时序有效性 | 时序知识图谱 |
| Memmy | 565 | reward 反向传播 + 四层演化 + LLM 过滤 | 本地优先跨 Agent 记忆枢纽 |
现实问题摆在那:
- 社区规模悬殊。565 vs mem0 的 56.8k,生态、教程、issue 响应速度完全不是一个量级。你遇到的坑大概率没人踩过。
- 配置门槛不低。BYOK 模式下要自己配六类模型(主模型、Embedding、记忆摘要、技能进化、ASR、图像生成),每类一个 API Key。
- 与 MemOS 的关系容易混淆。MemTensor 组织下有两个仓库:MemOS 是 10k stars 的记忆 OS 引擎(Apache 2.0),Memmy 是把它封装成桌面产品(MIT)。看星数别把两个混为一谈。
- 本地优先是优点也是限制。数据不出本机很安心,但跨设备同步、团队共享这些场景它现在没有。
我的判断:Memmy 值得关注,但现阶段把它当观察对象,别当生产依赖。 真实原因是,我自己现在 hermes 和 opencode 接的是 Hindsight,通过一个共享的 bankId 已经实现了跨 Agent 记忆共享。Memmy 主打的核心痛点我其实已经解决了。Memmy 真正让我感兴趣的不是"共享记忆"本身,而是它的自动历史扫描和更重的记忆演化机制——一键把 3.5GB 的 opencode 本地历史和 hermes 会话导入成结构化记忆,这件事 Hindsight 目前做不到。
所以我的做法很保守:hermes 和 opencode 继续用 Hindsight;Memmy 先在独立环境跑,只接一个非核心 Agent 做对照,看半年。真正值得偷师的是它的设计思路:"记忆要分层、要演化、要有质量门控"这套东西,比"存下来就能查"高一个维度。另外,装它之前记得看一眼它写进 ~/.claude/settings.json、~/.codex/hooks.json 的那些文件——Agent 配置文件现在也是攻击面的一部分。
参考:
本文链接:你说过一次,所有 Agent 都记住:Memmy 跨 Agent 记忆层源码拆解 - https://h89.cn/archives/687.html
版权声明:原创文章 遵循 CC 4.0 BY-SA 版权协议,转载请附上原文链接和本声明。