前言
昨天(2天的总结)搭建了基础设施,今天的核心任务是解决一个根本性问题:AI Agent 的记忆系统,应该怎么设计?
我是运维出身,对"系统设计"有一种职业性的敏感。当一个系统出现问题时,我习惯先问:这个系统的设计目标是什么?它现在的行为符不符合这个目标?
我们的记忆系统,目标是"让 Agent 记住重要的信息,在需要时能想起来"。
但实际运行中的问题是:记忆越来越多、越来越乱、越来越不准。
本文完整记录了记忆系统重构的全过程:从诊断问题本质,到研究 iCode 的完整解决方案,到最后落地我们自己的精准记忆架构。
一、问题诊断:为什么"堆记忆"越堆越乱
1.1 改造前的记忆现状
改造前,我的 MEMORY.md(wangj Bot)是什么样的?
130 行,并且还在持续增长...
每天都往里追加:
- 今天做了什么
- 哪个接口通了
- 哪个 Bot 没回复
- 团队分工变了
- 下周要做什么
- 某个文件的路径是什么
- 某个函数的参数是什么
...
最后 MEMORY.md 变成了一个什么都有但什么都找不到的垃圾桶。
不只是我。团队里每个 Bot 的 MEMORY.md 都是这样——有的 Bot 甚至没有归档机制,跨日记忆完全丢失。
1.2 三个真实案例
案例一:feiyuadmin v3 开发协调
4月3日早上,确定了 v3 由刘强东主导。4月3日晚上,确认了演示 deadline 是 21:00。4月4日新会话开始时,Bot 不记得这个决策——因为 MEMORY.md 里没有清晰的索引,这个信息淹没在大量文本中。
案例二:飞书 relay 路由失败
多个 Bot 的 open_id 和实际不符,导致 @mention 消息完全无法路由。问题根源:记忆里的 open_id 是旧的,实际已经变了。Bot 引用了过时的记忆,导致消息发到了不存在的地址。
案例三:Nginx 配置路径
MEMORY.md 里记录了旧的配置路径。实际配置已经迁移,但记忆没有更新。每次引用都要先 grep 验证——这说明记忆已经不是"准的"了。
1.3 根本原因分析
"堆记忆"的思路天然会导致三个问题:
问题一:没有分层
所有信息堆在一个文件里,越堆越大。查找信息要从头读到尾,效率极低。
问题二:没有召回机制
记忆只是在文件里"存在",没有"被想起来"的机制。Bot 在工作时不会主动去翻 MEMORY.md,只有上下文快满的时候才想起来要搜一下。
问题三:没有精准性要求
记忆里的文件路径、版本号、接口地址可能早就过时了,但没人更新。Bot 引用了过时记忆,导致用了不存在的文件或函数。
三个案例的共同教训:记忆的价值在于召回时是准确的,不在于存了多少。
二、研究 iCode 的完整记忆架构
2.1 发现:iCode 有三层记忆系统
研究 iCode 源码后发现,它的记忆系统远比我们想象的精密。核心是三层存储,各司其职:
Layer 1: Session Memory(会话进行中)
位置:.claude/sessions/<uuid>/memory.md
更新:每轮结束后自动增量写入,不阻塞主会话
特点:forked subagent 在后台写入,零感知
Layer 2: Daily Log(append-only 日志)
位置:~/.claude/memory/logs/YYYY/MM/YYYY-MM-DD.md
规则:只追加,不改旧内容,永远不丢历史
特点:凌晨 dream skill 自动蒸馏
Layer 3: MEMORY.md + Topic Files(蒸馏后的索引)
位置:.claude/MEMORY.md + .claude/memory/*.md
规则:从 daily log 蒸馏而来,不直接写入
特点:200 行上限,超出自动截断警告
三层各司其职的好处:
Session Memory:处理当前工作的上下文
Daily Log:永远不丢历史
MEMORY.md:精准索引,按需召回
2.2 最关键的设计:两步写记忆
iCode 的 prompt 里明确规定了记忆写入的两步流程:
Step 1:写内容到独立文件(带 frontmatter)
---
name: 用户反馈
description: 不要在没确认前执行大范围改动
type: feedback
---
Why: 上次重构没通知相关人,导致联调失败
How: 超过3个文件的改动必须先群里通报
Step 2:MEMORY.md 只写指针(一行,~150字)
- feedback: 不要未确认执行大范围改动 (feedback/用户反馈.md)
这解决了"什么都往 MEMORY.md 里堆"的问题。MEMORY.md 是目录,不是仓库。
2.3 四种记忆类型的 scope 规则
iCode 把记忆分成四种类型,每种有严格的应用场景:
| 类型 | 何时保存 | Scope 规则 |
|---|---|---|
| user | 用户透露角色/偏好时 | always private |
| feedback | 纠正 OR 确认时 | default private,team 仅项目级约定 |
| project | 了解谁做什么/决策时 | strongly bias toward team |
| reference | 了解外部系统/工具时 | usually team |
project 是 strongly bias toward team——这意味着项目决策要让所有相关 Bot 都能看到。相比之下,我们之前的做法是各 Bot 独立写 project 记忆,互相不知道。
2.4 recall 前必须验证
这是我们之前完全没有的机制:
❌ 错误:记忆说 nginx 配置在 /etc/nginx/sites-available/feiyuadmin,直接用
✅ 正确:记忆说配置在那里 → 先 cat 验证 → 确认后再用
原因:记忆可能过时(文件被删、改名、路径变了),引用前必须验证。
iCode 的原文是这样说的:
"Trusting recall: Before acting on a memory, verify it. If a memory mentions a file, check that it still exists. If it mentions a function or flag, grep for it."
2.5 extractMemories:每轮结束自动提取
iCode 最有价值的能力之一:每轮结束后自动提取记忆。
触发时机:每个 query 结束时(final response,无 tool calls) 触发方式:handleStopHooks → extractMemories 运行方式:runForkedAgent(共享 prompt cache,零开销) 写入位置:auto-memory 目录
这意味着 iCode 会话进行中就在增量写记忆,不是等会话结束。
但这个能力在 OpenClaw 无法复制,因为:
- OpenClaw 没有"每轮结束"事件触发点
- OpenClaw 没有 forked subagent 能力
教训:研究竞品时,区分"设计思想"和"底层能力",只迁移能落地的部分。
三、重构方案:精准索引架构
3.1 三条核心原则
经过对比分析,我们确定了三条原则:
原则一:MEMORY.md 是索引,不是仓库
原则二:memory_search 按需检索,不是全加载
原则三:引用具体信息前必须先验证
3.2 最终架构
MEMORY.md(索引,<50行)
↓
├─ memory/feiyuadmin.md ← 项目详情(按项目名,不含版本号)
├─ memory/team.md ← 团队/relay
├─ memory/system.md ← 系统/技能
└─ memory/YYYY-MM-DD.md ← 每日归档(cron 自动追加)
为什么项目文件叫 feiyuadmin.md 而不是 v3.md?
因为 v3 是版本号,如果明天升到 v4,文件名就要改,架构就要动。但项目名是稳定的,叫 feiyuadmin.md 永远不用改。
3.3 MEMORY.md 的新格式
精简到 50 行以内:
# MEMORY — 精准索引
> MEMORY.md = 索引 | memory/ = 内容 | recall = 按需检索
## 索引
| 主题 | 文件 |
|------|------|
| feiyuadmin 项目 | memory/feiyuadmin.md |
| 团队 | memory/team.md |
| 系统 | memory/system.md |
## 重要决策
- v3 deadline: 今晚 21:00(NL2SQL 演示+低代码待建表)
- LLM 方案待凯哥确认
- 移动端 H5 先不做
## recall 规则
| 需求 | 动作 |
|------|------|
| 查 v3 详情 | memory_search("feiyuadmin") |
| 查团队 | memory_search("team") |
| 查系统 | memory_search("system") |
| 查当日 | 直接读 memory/YYYY-MM-DD.md |
3.4 topic 文件命名规范
每个项目独立一个文件,不和版本号绑定:
feiyuadmin.md ← 项目名,永久不变
team.md ← 团队(通用,所有项目共享)
system.md ← 系统/技能(通用)
YYYY-MM-DD.md ← 归档(cron 自动追加,保留7天)
四、Skill 体系:让规范可执行
4.1 memory skill 的完整设计
改造后的 memory skill 包含完整的写入规范:
什么能记忆:
| 类型 | 能记 | 格式 |
|---|---|---|
| 决策+原因 | ✅ | 事实 + Why(动机) + How(影响) |
| 用户偏好 | ✅ | 偏好 + Why + How 调整 |
| 项目进展 | ✅ | 状态 + deadline(绝对日期) |
| 外部系统路径 | ✅ | 系统名 + 路径/链接 + 用途 |
| 团队分工 | ✅ | 角色 + Bot + 负责内容 |
| 阻塞问题 | ✅ | 问题 + 原因 + 状态 |
什么不能记忆:
| 类型 | 不能记 | 原因 |
|---|---|---|
| 代码模式/架构 | ❌ | 从代码读,不从记忆读 |
| git 历史 | ❌ | git log 是权威 |
| 调试方案 | ❌ | 修复在代码里,commit 有上下文 |
| 配置文件内容 | ❌ | 记路径,不记内容 |
| 未经确认的信息 | ❌ | 先验证再记 |
| 临时状态 | ❌ | 进行中不是记忆 |
| 过期的决策 | ❌ | 及时删除或标注作废 |
4.2 recall 前验证规则
这是最关键的规则,加入 skill 后变成强制执行:
| 记忆说 | 必须先做 |
|---|---|
| 文件路径存在 | ls 或 test -f 验证 |
| 函数名还在 | grep -r "函数名" . 验证 |
| 配置项有效 | cat 对应文件验证 |
| 版本号/账号/密码 | 读文件或问用户确认 |
4.3 brief skill:规范协作沟通方式
基于 iCode 的 Brief Tool prompt,我设计了一个简单的 brief skill,核心公式:
ack → work → result
为什么 ack 这么重要?
因为 AI 的响应时间不确定。简单问题秒回可以省略 ack;但需要 exec/读文件/跨 Bot 协作时,必须先 ack 让用户知道在处理了。
❌ 错误:
用户问了个问题,直接丢结果
→ 用户等了半天以为没反应
✅ 正确:
先 ack:"On it — 检查一下 NL2SQL 接口"
做工作:发现路由未注册
给结果:"接口不通,404,原因是路由配置少了这条路由"
4.4 team-coord v3:阶段化工作流
基于 iCode 的 Coordinator Mode,重写了 team-coord 技能:
Phase 1:并行研究
→ sessions_send 同时发给所有相关 Bot
→ 各 Bot 分别调查自己负责的模块
Phase 2:综合理解(最关键)
→ 协调者必须先读懂所有结果
→ 产出:具体文件路径 + 行号 + 怎么改 + 验收标准
→ ❌ 不说"基于调查结果做"→ ✅ 说"在 X 文件第 Y 行改 Z"
Phase 3:执行分配
→ 分配给具体 Bot,给完整 briefing
Phase 4:验证
→ 必须贴实测结果,不能口头说"可以了"
五、执行:13 个 Bot 统一改造
5.1 改造的 Bot 列表
wangj — 运维,我
daji — 妲己,秘书
liujq — 刘强东,技术总监
liyanh — 李彦宏,后端开发
zhouhy — 周鸿祎,测试
leijun — 雷军,前端开发
mahuit — 马化腾,产品经理
mayun — 马云,市场经理
mengyt — 孟羽童,秘书长
fullstack — fullstack
xiaohongshu — xiaohongshu
zhangcy — 张朝阳
mengwz — 孟晚舟
5.2 改造步骤
每个 Bot 都需要:
Step 1:创建 memory/ 目录
Step 2:建立三个 topic 文件
- memory/feiyuadmin.md (项目详情)
- memory/team.md (团队/relay)
- memory/system.md (系统/技能)
Step 3:重写 MEMORY.md 为精准索引格式
Step 4:确保行数控制在 50 行以内
Step 5:验证 skill 注册状态
5.3 验证结果
改造后统计:
MEMORY.md 行数:
- wangj: 45 行 ✅
- daji: 22 行 ✅
- liujq: 22 行 ✅
- mayun: 22 行 ✅
- liyanh: 22 行 ✅
- zhouhy: 22 行 ✅
- leijun: 22 行 ✅
- mahuit: 22 行 ✅
- mengyt: 22 行 ✅
- fullstack: 13 行 ✅
- xiaohongshu: 13 行 ✅
- zhangcy: 13 行 ✅
- mengwz: 13 行 ✅
所有 Bot 的 topic 文件结构一致,索引清晰,可搜索。
六、iCode 记忆系统完整架构解析
6.1 append-only Daily Log
iCode 的 daily log 是只追加不修改的:
# 2026-04-03
## 14:00
- 用户要求修复 NL2SQL 接口
- 发现路由配置缺少 nl2sql/query 路由
## 14:30
- 用户确认 deadline 是今晚 21:00
- 原因是凯哥要求演示
为什么只追加?
因为修改会有问题:如果一个决策后来被推翻,直接修改记忆会丢失历史——你不知道这个决策是什么时候做的、为什么做的。只追加保留了完整的决策演变过程。
6.2 distillation(蒸馏)机制
每天凌晨,dream skill 会自动:
1. 读取当日 daily log
2. 提取关键信息
3. 写入/更新 MEMORY.md 索引
4. 写入/更新 topic 文件
5. 清理过期信息
这个机制保证了:
MEMORY.md 永远是当天的索引,不会无限膨胀
daily log 保留了完整历史,可以追溯
topic 文件按领域组织,精准可查
6.3 防并发机制(consolidationLock)
如果多个进程同时运行 distillation,可能会冲突。iCode 通过三闸门控制:
闸门一:Time — 距上次 >= minHours(默认 24h)
闸门二:Sessions — 新 transcript 数 >= minSessions(默认 5个)
闸门三:Lock — 没有其他进程在合并中
三个条件都满足,才会启动 distillation。这保证了历史不会被并发操作破坏。
七、反思:为什么"什么都记"是错的
7.1 记忆的价值在召回,不在存储
我们的大脑不是硬盘。大脑擅长的是在需要的时候想起来,不是记住所有事情。
AI Agent 的记忆系统也应该遵循同样的原则:不是为了"记住",而是为了在合适的时机被想起来。
一个记住了 1000 件事但 300 件已经过时的记忆系统,不如一个记住了 50 件事但件件准确的系统。
7.2 "精准"比"全面"更重要
recall 前验证机制的价值就在这里:宁可少记,也要确保记住的都是准的。
当你知道记忆里的每一条信息都是准的,你才能信任它。当你信任它,你才能真正依赖它做决策。
7.3 三层记忆的各自职责
瞬时缓存(当前会话)→ 处理当前工作的上下文
↓ 整理写入
短期记忆(YYYY-MM-DD)→ 每天归档,工作结束就归档
↓ 蒸馏
长期记忆(MEMORY.md) → 只存索引,精准指针,不堆内容
三层各司其职,才不会混乱。
7.4 什么时候该记忆
判断标准只有一条:
这条信息,在未来的某个时候,我还会需要吗?
如果答案是"会",再问第二个问题:
这条信息,从哪里获取最准确?
如果记忆是来源之一,再问第三个问题:
这条信息,从记忆获取和从原始来源获取,哪个更快更准?
三个问题的答案都指向记忆,才值得记。
八、继续深挖的方向
这次改造还有很多没解决的事:
架构层面的限制:
├── OpenClaw 没有"每轮结束"事件,无法自动提取记忆
├── OpenClaw 没有 forked agent,无法后台异步写记忆
├── append-only daily log 需要完整的事件机制
├── MEMORY.md 行数限制需要 OpenClaw 原生支持
└── 防并发蒸馏锁需要底层调度支持
可持续优化的方向:
├── recall 命中率的追踪(有没有重复 recall 同一信息)
├── 跨 Bot 共享记忆(目前各 Bot 独立,team.md 内容重复)
├── 记忆的 decay 机制(多久没用到就降权)
└── 记忆和代码的同步(文件改了,记忆里的路径要同步更新)
结语
记忆系统改造的核心收获不是"用什么架构",而是**"什么应该记、什么不应该记"**。
一个好的记忆系统,应该让 Agent 在需要的时候,能以足够快的速度,找到足够准确的信息。
不是"记住一切",而是**"在需要时能想起来,并且想起来的都是准的"**。
这才是记忆系统设计的核心目标。