让编程智能体先查被否决的设计
作者基于495份架构决策记录,建议保存被否决方案及原因,并将查阅历史决策设为智能体设计流程的必需步骤。使用相关技能的17次会话中,15次引用了否决或冲突记录,但推翻旧决策也会触发确认。
AI 深度解读
AI 编程助手会记住你最终采用的方案,却未必知道哪些路已经走过、为什么被否决。karasu 的作者积累了 495 份架构决策记录(ADR),观察到它们最有用的时刻,是后来有人提出相似需求时,Agent 把过去的拒绝理由重新带进设计。
这篇文章的结论很具体:记录被放弃的选项,再把「设计前检查历史决策」设为必经步骤。不过,历史被找回来之后也有代价:你想推翻旧决定,Agent 就可能停下来确认。
最该留下的,可能是当初为什么没选
karasu 是作者开发的架构图工具,从 2026 年 3 月开始就在 docs/adr/ 保存 ADR。统计覆盖 2026-03-12 至 11-09,共 495 份;新增 ADR 的提交中,395 次带有 Claude Code 的共同作者署名,占 80%。
ADR 不只是记录「决定用了什么」。被放弃的方案及其理由,往往更能帮助后续设计,因为新需求可能换了表述,却撞上同一个限制。
11 月 2 日,作者希望把低风险 PR 的自动合并迁到 GitHub Actions:每十分钟检查一次 risk: low PR,CI 通过就合并。原有流程由 Claude Code 开启自动合并,auto mode 下还要经过一个 LLM 分类器,判断命令能否执行。作者想减少这层依赖,让合并更可靠。
Agent 最初赞同,认为新方案会替换定义风险分级的 ADR-3286,应先写设计文档。随后,它按流程检查历史,找到了 ADR-3416:那里已经否决过「由 Actions 开启自动合并」。
问题不在检查频率,而在合并身份。按照原文描述,使用 GITHUB_TOKEN 完成的合并,其进入 main 的推送不会触发 deploy 等工作流。PR 可以合进去,文档站却不再发布。ADR-3416 原本讨论每日重建 ADR 索引,拒绝理由却同样适用于这次需求。
这个发现最终进入设计的三个位置:明确工作流触发限制;把新增 GitHub App 或 personal access token 所涉及的凭据决策单独交给作者;增加「进入 main 的身份能否触发 push 工作流」的测试视角。
最后的实现先只报告判断结果,暂不合并或评论。
历史记录真正有用的部分,是让旧约束参与新设计。
为什么写进技能步骤,比放进文档更关键
仓库里有 ADR,不代表 Agent 会主动阅读。
作者在 7 月做过一个小型受控实验:要求 Agent 重做一个已经被否决的方案。请求前加入「编写设计或实施计划前,搜索 docs/adr/,始终检查相关决策或拒绝记录」后,找到目标 ADR 的结果从 0/3 变成了 3/3。
样本很小,但它提供了一个可以执行的改法。作者随后修改 Claude Code 开发技能集合 hane,把检查历史冲突、尤其是被拒方案,设为设计文档技能和启动开发技能的必经步骤。这次调整记录在 hane 的 ADR-63,日期是 2026-07-09。
本次文章观察的是日常使用:2026-10-13 至 11-10 的日志包含 149 个主会话,以及它们启动的 442 个子 Agent。其中使用设计文档技能的 17 个会话,有 15 个引用了拒绝过类似想法或与当前想法冲突的 ADR。
统计方法也需要一起看。作者筛选的是同时出现 ADR 编号,以及「拒绝」「放弃」「冲突」「推翻」等词的消息,再逐条阅读其中六例。这能说明相关记录确实进入了讨论,但不能证明所有相关 ADR 都被完整查到。
例如,Agent 找到 ADR-2898 曾否决 auto_incremental_review: false;也找到 ADR-2249、ADR-2262 曾拒绝在永久链接页面放计数器。
对于程序员,这里的流程变化很小:在需求进入设计之前,增加一次有明确搜索目标的检查。它检查的不只是「以前怎么做」,还包括「以前为什么不这么做」。
ADR 的作用会延伸到评审和代码里
作者还检查了 1,342 个 issue、2,397 个 PR 的正文、评论和评审。排除各 ADR 自己对应的起始 issue 和 PR 后,495 份 ADR 中有 408 份被后来创建的 issue 或 PR 引用,占 82%。
这些引用并不都用来阻止新功能,有些用于划清边界。
例如,ADR-105 在 4 月决定不实现 PNG 导出;6 月的 PR #1796 又加入了 PNG 输出,但只放在一个服务端函数里。它明确说明没有推翻 ADR-105,因为此前放弃的是 CLI 和应用中的 PNG 功能。同样叫「PNG 导出」,适用范围不同,决策可以并存。
另一些引用则直接终止提案:issue #2957 想在原始 issue 中追踪合并后验证项,被 ADR-3271 的拒绝记录挡下;issue #832 想让 usecases 声明基于属性的授权,也因 ADR-834 对产品词汇范围的限制而放弃。
评审里还有用 ADR 回应 CodeRabbit 建议的例子。不过,作者账号下的一些回复由 Claude Code 撰写,无法逐条区分引用来自人还是 Agent。
决策也会进入代码:167 份 ADR 被非测试代码引用,76 份被测试引用。25 份已被替代的 ADR 中,仍有 15 份被代码或配置引用。
下面这行注释用于解释:旧 ADR 虽然整体被替代,其中一部分决定仍然有效。
* The one direction of ADR-1990 decision 2 that survives.
要看的是 decision 2。它把引用精确到了某一项决定,提醒读代码的 Agent:文件级的「已替代」,不等于其中每个结论都作废。作者读到的相关案例并非单纯忘记清理引用,但这也暴露出 ADR 状态表达粒度不足的问题。
我的判断
我赞同把拒绝理由写下来。它能补充代码和测试难以解释的内容:为什么一个看起来合理的方向没有被采用,以及当时受什么条件限制。与只保存最终方案相比,这些信息更适合用于评估后来出现的相似需求。
但「495 份 ADR」不能作为效果证明。karasu 从第一天就使用 ADR,没有前后对照。作者也明确说,这是对实际作用的观察,不能证明 ADR 导致开发质量提升。15/17 是引用现象,不能直接当成正确决策率;7 月的 0/3 与 3/3 也不足以证明对各种团队都有效。
这里还有一个迁移前提:作者已经把决策记录、技能和开发流程连在一起。一般团队如果只建立一个目录,没人维护、Agent 也没有检索步骤,很难期待相同表现。
成本同样没有算完。ADR 正文长度的中位数从 3 月的 2,308 字符增长到 11 月的 6,941 字符,作者未统计维护耗时。当一份 ADR 包含多个决定,后来只推翻其中一部分时,自动生成的当前决策清单还可能错误保留旧结论;作者正在通过 kompiro/adr-tools#37 探索工具侧的表达方式。
另一个代价是确认。149 个会话里,27 个会话出现过提及 ADR 的确认问题,共 29 次,其中七次是在询问如何处理对既有决策的修改。例如,是否要让 High PR 也自动合并,而 ADR-3286 当前只允许 Low。
这不是 Agent 自行加戏,而是规则明确要求:推翻历史决定时,说明冲突并获得确认。可以在 ADR 中提前写下重新评估条件,降低讨论成本,但作者承认,写记录时通常无法预见这些条件。
历史决定适合成为重新评估的依据,不能替代对当前条件的判断。
能拿来做什么
- 在前端或 Node 项目的重要决策里,补充被拒方案、拒绝原因和适用范围。尤其要区分限制针对 CLI、服务端还是应用界面,避免以后看到相同功能名就误判为冲突。
- 在 AI 编程的设计步骤中明确要求:先搜索
docs/adr/,检查相关决定和被否方案,再说明它们如何影响本次设计。已有技能流程的项目,可以把这一步放进固定流程。 - 修改自动合并或部署流程时,把执行身份、凭据和后续工作流能否触发列为检查项。原文案例提醒我们,合并成功与发布链路正常需要分别验证。
- 当新需求确实要推翻旧决定时,明确说明要修改哪一项、哪些理由已经变化,并同步更新状态和代码引用。能预见重新评估条件时就写下,无法预见时保留必要确认。