给 agent 的记忆瘦身:常驻和按需分层
给 agent 加记忆,前几周是纯收益:它记得你的偏好,记得上次踩的坑,不用每次重新解释。
几个月之后,问题来了。记忆文件越来越多,每次启动要读的东西越来越长。agent 什么都「记得」,但真正相关的那几条被淹在一大堆旧任务、旧状态、过期结论里。更糟的是,旧结论会被当成现在的事实。
我之前写过怎么用一个 git 仓库在多台机器、多个 agent 之间同步记忆。这篇讲另一件事:记忆多了以后,怎么瘦身。
一、两层:常驻和按需
规则很简单,只有两层:
| 层 | 内容 | 什么时候读 |
|---|---|---|
| 常驻 | 规则、共享摘要、本机本 agent 的摘要、自动生成的近期动态 | 每次启动读一次 |
| 按需 | 方向与策略、历史记忆、项目文件、工作流、交接、收件箱 | 当前任务需要时才读 |
项目上下文属于按需层,不是第三层。一个文件放在哪一层,和它重不重要无关,只和它是不是每次都要用有关。
二、常驻层只回答三个问题
常驻层在任何检索之前,先回答三个问题:
- 我在为谁工作:用户是谁、主要做什么。
- 现在的目标是什么:当前的优先级和非目标,附复核日期。
- 最近动了什么:过去几天改过哪些记忆和项目。
第三个问题变化太快,手写一定会过期,所以它是自动生成的:每次会话启动时,一个脚本从 git 历史里算出最近 7 天改过的记忆文件、最近 30 天动过的项目,各自带一行描述,写进一个本地文件。它不提交——每次启动都重新生成,提交的话会每个会话产生一个提交,还会在多台机器之间冲突。
除此之外,常驻层只放稳定偏好、必要边界和几个检索入口。
三、哪些东西不该进常驻
这一条比「该放什么」更重要。不进常驻的:
- 项目待办和进度。 它们几天就变,放进常驻就是在制造过期事实。
- 事故经过。 事故的教训可以压成一句规则放常驻,经过本身放按需。
- 旧状态。 「某个分支还没推」「某个 PR 等合并」——这种句子一周后几乎一定是错的。
- 宿主已经提供的通用指令。 工具自己会告诉 agent 怎么用工具,不需要在记忆里再抄一遍。
还有一条容易漏的:链接是路由,不是加载命令。 常驻文件里可以放指向主题文件的链接,但 agent 不应该把链接全部点开读一遍,更不能递归加载。
四、给常驻层定预算
不定预算,常驻层一定会慢慢长胖。我的默认预算按字节算:规则 4 KB,共享摘要 4 KB,每个 agent 的摘要 2 KB,自动生成的近期动态 2 KB,一次启动最多 12 KB。
有一个检查脚本在提交前跑,检查每个常驻文件有没有超预算。它从不截断内容——超了就报出来,由人决定是压缩、移走还是拆分。预算是维护时的检查,不是运行时随手丢规则的许可。
效果是可以测的。在我自己的库上(约 180 个记忆文件,总共三十多万 token):老办法全量启动约 7 万 token;分层之后常驻启动约 640 token;带一个主题文件处理具体任务约 3600 token。
五、按需层:靠路由,不靠少读
按需层的扩展方式,不是「把一个大文件读少一点」,而是路由:
常驻摘要 → 记忆索引 → 一两个描述匹配的主题文件。
为此,大的记忆文件按原有标题拆成主题文件,每个文件写一行触发式描述——不是「关于 git」,而是「做 git 操作或并行协作前读:管道吞退出码、切分支搬走在飞改动、禁裸 stash……」。索引由脚本从这些描述自动生成。agent 读索引,按描述挑一两个文件打开,其余不碰。
拆分时有一条纪律:原文逐字搬,不在拆分时改内容。 内容的改动留给后面的蒸馏,并且要验证每个原始标题恰好落在一个主题文件里。
六、纠正多了,才升级到常驻
一条规则从按需升级到常驻,我的判据是:重复纠正。
比如「全程用中文回复,长任务中途也不许切英文」。它最开始只是普通记忆,同一个会话里被我纠正了三次之后,升级成常驻规则,并且在后台任务的进度播报里也适用。
反过来,常驻里的东西过期了要删,错了要改,而且要留下修订理由。我的一条身份记录曾经写错过,后来更正时保留了原文作对照,写明哪一句作废、为什么——这样下一个读到它的 agent 不会照旧口径讲。
七、旧结论不等于现在的事实
最后一条,也是最难做到的:权威不会让一条旧的事实陈述变成当前事实。
每条记忆带来源日期和适用范围。读到一条三周前的「某某已完成」,agent 应该去核实当前状态,而不是直接引用。历史任务和旧交接也不构成当前授权——上周让它做的事,不等于这周还要它做。
收束
记忆系统的难点不在于记住,在于忘掉什么、什么时候想起来。
我的答案是两层:常驻层只回答「为谁、为什么、最近动了什么」,并且有预算;其余全部按需检索,靠描述路由。 重复纠正的才升级,过期的要删,旧的要核实。
agent 启动时读得越少,读到的就越可能是对的。