给 agent 装个“小本本”:用 Learnings.md 记下踩过的坑

题图:Mike Tinnion via Unsplash

MindStudio 有篇文章讲怎么给 Claude Code skill 加一个 Learnings.md,让 agent 跨会话”长记性”。读完发现这跟我这几个月一直在做的几乎是同一件事,正好借这篇文章把思路捋清楚,顺便记下自己用下来的体会。

问题:skill 不会进步

Claude Code 每次开新会话都是”失忆”的。没有上一次运行的记忆,不知道上次什么做成了、什么失败了,也不记得三个星期前花二十分钟查过的一个 API 怪癖。

skill 是定义好、反复跑的工作流。单次任务这样没问题,但 skill 这种”隔三差五就跑一次”的东西,每次从零开始就亏了——它不是越用越好,而是全靠你手动补充上下文,看着它一遍遍重复同样的错误,然后你只能不断往系统提示词里塞笔记,最后堆成一堵墙。

核心做法:一个文件

思路很简单:一个 Learnings.md 放在项目里,Claude 开始任务前读它,任务结束后往里写新条目。下次运行,上一轮的经验就在上下文里了。没有数据库、没有向量检索,就一个文件。

这背后的原理不玄:Claude 不需要持久记忆,它需要的是”开工时能读到一份结构清晰的文件”。人写知识库也是一样——写下来就不靠记忆。区别在于这里 Claude 既读又写,而且配置好之后它能稳定地做这两件事。

用 markdown 也是对的:Claude 读写它没有额外负担,标题和列表提供结构,人能直接审阅和改,还能跟着代码一起进 git。

我自己怎么用的

文章里教的配置和我实际在做的差不多,我挑了觉得关键的几点说说。

会话前读、结束后写,两条都不能省

读这步容易做到,让 agent”真的用上”反而要下点功夫。文章提了个技巧:让 agent 开工前先把 Learnings.md 的内容总结成 3-5 条要点。光让它”读一下”它可能会扫过,但让它”总结”就逼着它真处理了内容。

写这步更难,因为 Claude 会把更新当成可选动作跳过。要写成无条件的:”结束会话前必须更新 Learnings.md,就算没发现新东西也要写一笔确认。”这样还能留审计痕迹——哪次跑了没产出、哪次有新发现,一目了然。

写”能用的”经验,别写废话

文章这句我特别认同:“Avoid relative imports in /utils — the build step resolves them incorrectly” 是有用的,“Be careful with imports” 不是。

下面这些基本没用:

  • 数据库层要小心
  • /legacy 的测试比较难搞
  • API 调用有时候行为出人意料

都没说清楚”小心什么”、”难在哪”、”什么叫出人意料”。Claude 没法照着行动,还白占上下文。

条目带个 confidence 分级(high/medium/low)也有用。低置信度的是”只遇到过一次的猜想”,高置信度的是”确立的规则”。不区分的话,Claude 没法判断该多坚定地执行某条规则。

文件要维护,会膨胀

这是个共享文档,Claude 往里加、你来删改,两边一起维护。每隔几周过一遍:把经过多轮验证的低置信度条目升级、删掉重构后已经失效的、重写 Claude 写得含糊的、加一些它自己发现不了的项目知识。

目标是一份”信号密集”的文件。30 行精准的条目比 200 行过时观察有用得多。

我踩过的坑

文章列的常见错误里,有三个我确实遇到过。

读了不等于用了。 光在 CLAUDE.md 里写”开工前读 Learnings.md”没用,agent 会假装读过。用总结那招强制它过一遍,效果立竿见影。

别拿它替代系统提示词。 Learnings.md 装的是”运行中发现的动态知识”,系统提示词和 CLAUDE.md 装的是”你决定的静态知识”。两者互补,不是替换。把该放系统提示词的指令塞进 Learnings.md,或者反过来,都会乱。

一个 skill 一个文件,别混。 同一仓库里跑多个不同工作流时,给各自开一个。混在一起,Django 的观察对 Next.js 的工作流就是噪音。

我对这个模式的看法

它其实不是新东西,就是”把隐性知识落成文件”这一套,只是这次读写双方换成了 agent。跟我在 Matt Pocock 的 skills 里看到的 CONTEXT.md 共享语言、还有我自己博客的 AGENTS.md,都是同一个思路:用文件给 agent 续上下文,而不是靠它自己记。文件会进 git、能被 review、能剪枝,这套工程纪律搬到 AI 上一样成立。

要说局限,文件是被动的,agent 写什么质量取决于它怎么理解和归纳,需要人定期盯。另外这种模式解决的是”跨会话记忆”,解决不了模型本身的推理上限——写满了不表示它就能做对。

链接