Diagnose 是一个面向疑难 Bug 与性能回归的纪律化诊断技能(skill),其核心主张是:调试的关键在于构建一个快速、确定、可由智能体运行的通过/失败信号(反馈回路),其余步骤大多是机械性的。技能要求只有在有明确理由时才可跳过某个阶段。
在探索代码库时,建议使用项目的领域术语表建立对相关模块的清晰心智模型,并查看所触及区域的 ADR(架构决策记录)。
阶段一:构建反馈回路 这是整个技能的核心。如果能为 Bug 建立一个快速、确定、可由智能体运行的通过/失败信号,就能找到原因——二分、假设检验和插桩都只是消费这个信号。若没有这样的信号,盯着代码也无济于事。应在此投入不成比例的精力,积极、有创意,拒绝放弃。
构建反馈回路的可选方式(大致按顺序尝试):
- 在能触达 Bug 的接缝处编写失败测试——单元、集成或端到端。
- 针对运行中的开发服务器使用 curl / HTTP 脚本。
- 使用固定输入调用 CLI,将 stdout 与已知良好快照做 diff。
- 无头浏览器脚本(Playwright / Puppeteer)——驱动 UI,对 DOM/控制台/网络做断言。
- 重放捕获的 trace:把真实网络请求/载荷/事件日志保存到磁盘,在隔离环境中通过代码路径重放。
- 一次性测试装置:启动系统的最小子集(单个服务、模拟依赖),用一次函数调用触发 Bug 代码路径。
- 属性/模糊测试循环:若 Bug 表现为“有时输出错误”,运行 1000 个随机输入寻找失败模式。
- 二分测试装置:若 Bug 出现在两个已知状态(提交、数据集、版本)之间,自动化“在状态 X 启动、检查、重复”,以便用 git bisect run 执行。
- 差分循环:将同一输入分别通过旧版本与新版本(或两种配置)运行并 diff 输出。
- HITL bash 脚本:最后手段。若必须由人点击,用 scripts/hitl-loop.template.sh 驱动,使循环仍然结构化,捕获的输出反馈回来。
构建正确的反馈回路后,Bug 已解决 90%。
迭代回路本身 把回路当作产品来对待。拥有回路后应追问:能否更快(缓存初始化、跳过无关初始化、缩小测试范围)?能否让信号更锐利(针对具体症状断言,而非“没有崩溃”)?能否更确定(固定时间、设定随机种子、隔离文件系统、冻结网络)?30 秒的不稳定回路几乎不比没有回路好;2 秒的确定回路则是调试超能力。
非确定性 Bug 目标不是干净的复现,而是更高的复现率。将触发循环 100 次、并行化、增加压力、缩小时间窗口、注入 sleep。50% 概率的偶发 Bug 可调试,1% 则不行——持续提高复现率直到可调试。
确实无法构建回路时 停下来并明确说明。列出尝试过的方法。向用户请求:(a) 访问能复现问题的环境;(b) 捕获的产物(HAR 文件、日志转储、核心转储、带时间戳的屏幕录制);或 (c) 允许添加临时生产插桩。没有回路就不要进入假设阶段。在拥有可信回路之前,不要进入阶段二。
阶段二:复现 运行回路,观察 Bug 出现。确认:回路产生的失败模式与用户描述一致(而非附近恰好发生的其他失败,错误的 Bug 等于错误的修复);失败在多次运行中可复现(非确定性 Bug 则需达到足够高的复现率);已捕获确切症状(错误消息、错误输出、缓慢的计时),以便后续阶段验证修复是否真正解决。未复现前不要继续。
阶段三:提出假设 在测试任何假设之前,先产生 3–5 个排序后的假设。单一假设会锚定在第一个看似合理的想法上。每个假设必须可证伪:陈述其预测。格式:“如果是原因,那么……会使 Bug 消失 / ……会使它更糟。”若无法陈述预测,该假设只是感觉——丢弃或使其更锐利。在测试前把排序列表展示给用户,他们常拥有领域知识可立即重新排序(“我们刚部署了 #3 的改动”),或知道已被排除的假设。这是低成本的检查点,能节省大量时间。不要阻塞等待——若用户不在,按自己的排序继续。
阶段四:插桩 每个探针必须对应阶段三中的某个具体预测。一次只改变一个变量。工具偏好:若环境支持,优先使用调试器 / REPL 检查(一个断点胜过十条日志);在能区分假设的边界处使用定向日志;绝不“记录一切再 grep”。为每条调试日志打上唯一前缀,例如 [DEBUG-a4f2],结束时清理只需一次 grep。未打标签的日志会留存,打标签的日志会被清除。性能分支:对于性能回归,日志通常是错误的做法。应改为:先建立基线测量(计时装置、performance.now()、profiler、查询计划),然后二分。先测量,后修复。
阶段五:修复 + 回归测试 在修复之前编写回归测试——但仅当存在正确的接缝时。正确的接缝是指测试能在调用点实际触发 Bug 模式。若唯一可用的接缝太浅(Bug 需要多个调用者时只做单调用者测试,或单元测试无法复现触发 Bug 的链路),在此处的回归测试会带来虚假信心。若不存在正确接缝,这本身就是发现,应记录:代码库架构阻碍了 Bug 被锁定,标记给下一阶段。若存在正确接缝:将最小化复现转为该接缝处的失败测试;观察它失败;应用修复;观察它通过;针对原始(未最小化)场景重新运行阶段一的反馈回路。
阶段六:清理 + 复盘 宣布完成前必须:原始复现不再复现(重新运行阶段一回路);回归测试通过(或记录接缝缺失);所有 [DEBUG-...] 插桩已移除(grep 前缀);一次性原型已删除(或移至明确标记的调试位置);在提交 / PR 消息中说明最终正确的假设,以便下一位调试者学习。然后追问:什么本可以预防这个 Bug?若答案涉及架构变更(没有好的测试接缝、调用者纠缠、隐藏耦合),将具体情况交给 /improve-codebase-architecture 技能。在修复完成后再提出建议,而非之前——此时你比开始时拥有更多信息。
致谢与归属 本技能基于 Matt Pocock 的优秀工作。原始仓库:https://github.com/mattpocock/skills 。Copyright (c) Matt Pocock - Agent skills for real engineering workflows (MIT License)。特别感谢 Matt Pocock 慷慨的开源贡献,帮助塑造了这个技能集合。由 webconsulting.at 为本技能集合改编。