让编码代理设计前先查历史决策
作者保留架构决策及被否决方案,并在编码代理常驻规则中加入“设计前检查历史决策”,报告相关小样本测试由 0/3 提升至 3/3。实践强调记录结论、状态和简短理由,并指出实验会受其他文档中重复信息的干扰。
AI 深度解读
给 Coding Agent 留下几百份设计记录,它就会自动避开团队踩过的坑吗?作者在自己的架构图工具 karasu 上做了十轮、一百多次运行后发现:记录存在,不代表 Agent 会读。真正改变结果的,是一条要求它在设计前检索历史决策的规则。
这组实验最有用的地方,是把问题从「文档能不能提高代码质量」缩小到「新需求撞上旧决策时,Agent 能不能发现」。它给出了一套成本很低的做法,也暴露了个人项目实验推向一般团队时的边界。
删掉文档,为什么测不出差别
作者长期维护架构决策记录(Architecture Decision Record,ADR):设计经过讨论、实现后,确认的决策进入 docs/adr/;考虑过但没采用的方案也保留,状态标为 not_adopted。
实验时,仓库已经积累了 263 份 ADR,约 980,000 个字符,另有约 130,000 个字符的关系图和有效决策索引、70 条测试视角记录,以及 Agent 常驻规则。实验使用无界面的 Claude Code,模型固定为 Claude Opus 4.8,每次试验都将克隆仓库重置到初始状态。
第一轮思路很直接:比较完整仓库、删除全部 ADR、保留 ADR 正文但移除链接与索引这三种条件,观察同一需求生成的设计文档。结果没有系统性差异。
原因是历史决策并没有随着文件一起消失。同一条政策可能同时存在于 ADR、概念文档与规格、代码中的来源注释、Git 历史这四层。代码里一句 per ADR-20260514-02 就可能把 Agent 引回旧决策。后续实验中,Agent 甚至通过 git log 找到了删除提交,把被删掉的理由读了回来。
所以,删除 ADR 并不等于删除历史上下文。这个实验很难隔离文档的作用。
作者随后换了观察对象:只挑那些「明确决定不做,而且没有留下实现痕迹」的方案,再提出一个与之冲突的需求,检查 Agent 是否发现旧结论。
真正起作用的,是设计前必须检查
karasu 曾否决过一个提议:放弃花括号语法,改成类似 YAML 的形式。理由是边的声明不适合 YAML 结构,而半像 YAML 的语法容易制造误解。这个否决只留在 ADR 中。
作者重新提出了类似需求,但不透露 ADR 的存在。保留 ADR 时,Agent 在三次试验中全部找到旧记录,说明该方案曾被否决,并询问是否推翻。删除 ADR 后,三次中有两次直接生成迁移设计文档,甚至提交了变更。
构建工具链迁移的否决也复现了这一差异。PNG 导出则没有:旧决策是「不放进应用,而在服务端生成供图片嵌入」,代码仍然保留了实现,Agent 可以从实现重建决策。
但记录齐全也不保证有效。在另一个关于 Agent 会话重命名功能的实验中,即便所有记录都在,Agent 也只在 9 次试验中的 1 次读到否决 ADR。偏工具类的需求,并不会自然引导它去查 docs/adr/;那份 130,000 字符的索引也很少被主动打开。
作者于是加了一句要求:写设计或实现提案前,先搜索历史决策与否决记录。在对应的三次对照中,找到目标否决 ADR 的次数从 0/3 变成 3/3。
随后,他把要求放进 .claude/rules/decision-check.md,同样取得了 3/3。规则全文如下,它解决的是「Agent 什么时候必须去查」:
## Decision check before design and implementation
Before starting to design a new feature, weigh an implementation approach, or
write a design doc, always search `docs/adr/` for related ADRs, rejections
(`not_adopted`), or superseded decisions.
- If you find one, answer with that decision in mind.
- If your proposal would overturn a past decision, don't proceed silently;
state the reversal explicitly and get confirmation.
要看的是最后两行:规则允许推翻历史决策,但要求显式说明并获得确认,避免一次临时需求悄悄重启已经结束的讨论。
冲突请求下,有规则时平均花费 $0.80、4 turns,没有规则时是 $1.33、18 turns。这些是各三次试验的均值,按实验时 Opus 4.8 的价格计算。发现冲突后提前停下,比完成一份建立在错误前提上的设计便宜。
检查也有成本:对不冲突的请求,每次搜索成本约 $0.83。实验没有观察到无冲突时错误停止,但样本不足以证明这种情况不会发生。
状态负责拦住重做,理由负责少走弯路
作者还把 ADR 中的理由删掉,只留下「不要实现」的一行结论与状态。结果三次试验中,Agent 都停下来请求确认。
防止旧方案被悄悄重启,最小记录可以很短。
不过,没有理由的 Agent 仍然要重新调查:它可能把「重新研究当初为什么否决」写进设计前提,或者去翻提交历史。一行原因,就能省掉这部分工作。如果记录还写清「什么条件变化后可以重新考虑」,确认问题也会更具体。
理由还承担了搜索入口的作用。作者故意避开原需求词汇,例如不用 YAML,而说「冒号与缩进的表示法」,12 次试验仍全部找到目标记录。即使文件名不匹配,正文里的花括号、缩进等领域词汇,也能帮助检索命中。
相比之下,复杂知识图谱几乎没被读取。这次实验里真正支持检索的,是描述清楚的文件名、正文关键词,以及强制检查的规则。作者因此倾向于只维护轻量的有效决策列表。
规则放在哪,也有取舍。实验验证的是没有路径条件的常驻规则;作者认为它与 CLAUDE.md 属于同类常驻层,但没有测过两种位置的遵守差异。放进设计文档 skill 可以按需加载、节省上下文,却依赖任务确实触发 skill,这种形式没有在本轮验证。模板增加必填的「相关既有决策」栏目,则能让人工评审检查是否查过历史。
我的判断
我认同作者把观察单位缩小到「一项旧决策与一个冲突请求」。它比比较设计文档长短更容易判断:有没有找到记录,有没有指出冲突,有没有静默推进,行为都比较明确。
但 0/3 到 3/3 只能当作一个值得复测的信号。这是单个个人项目、单个模型,主要条件各三次试验。作者用另一个模型在不知道实验条件的情况下重新分类,39 次试验的一致率为 85%,κ = 0.72,主要结论的各组判断一致;这增强了结果可信度,却没有消除 Git 历史泄漏、Agent 已有工具知识等干扰。
「重索引没必要」也应限定范围。实验说明这个 Agent 在这些任务中很少主动读图谱,并没有比较更大仓库、不同检索工具或多团队协作下的效果。常驻规则、skill 和模板之间,也只有常驻规则得到此次实测支持,其余属于工作流判断。
原文还有一个表述需要打问号:作者称 980,000 个字符放不进百万 token 上下文。字符与 token 不能直接等同,仅凭字符数无法得出这个结论。不过,实验实际测的是选择性读取,而非全文塞入,这一点仍然成立。
至于后记提到四个月后、积累到 495 份 ADR 的日常使用回顾,原文没有展开结果,不能拿它补足本轮证据。
能拿来做什么
- 给前端或 Node 项目保留被否决的方案,至少写清提案、结论、
not_adopted状态和一行理由;能补上重新考虑的条件更好。 - 在 Coding Agent 的常驻规则里加入设计前检索步骤,明确要求搜索
docs/adr/,遇到反转历史决策的方案时先说明冲突并确认。 - 在设计文档模板中要求填写相关决策记录。评审时检查它是否解释了与旧决策的关系,避免只填一个文件链接就算完成。
- 从仓库挑一个没有实现痕迹的旧否决,用自然措辞重新提出需求,比较加规则前后的检索与停止行为;同时记录无冲突任务的额外搜索成本。