title: “Systematic Debugging — 4-phase root cause debugging: understand bugs before fixing” sidebar_label: “Systematic Debugging” description: “4-phase root cause debugging: understand bugs before fixing”
{/* 本页面由 website/scripts/generate-skill-docs.py 根据该技能的 SKILL.md 文件自动生成。请直接编辑源文件 SKILL.md,而非此页面。 */}
系统化调试
四阶段根本原因排查法:在解决问题之前先深入理解故障本质。
技能元数据
| 来源 | 内置(默认已安装) |
| 路径 | skills/software-development/systematic-debugging |
| 版本 | 1.1.0 |
| 创建者 | Hermes Agent(基于 obra/superpowers 改编) |
| 许可协议 | MIT |
| 支持平台 | linux、macos、windows |
| 标签 | 调试、故障排除、问题解决、根本原因、调查 |
| 相关技能 | 测试驱动开发、计划制定、子代理驱动开发 |
参考:完整 SKILL.md 内容
系统化调试
概述
随意的修复只会浪费时间并引发新的故障。仓促的补丁只能掩盖潜在问题。
核心原则: 在尝试任何修复措施之前,务必先找到根本原因。仅解决表面症状意味着失败。
违背这一流程的文字要求,就等同于违背了调试的精神。
不变法则
NO FIXES WITHOUT ROOT CAUSE INVESTIGATION FIRST
如果您尚未完成第一阶段,就无法提出修复方案。
适用场景
适用于任何技术问题:
- 测试失败
- 生产环境中的漏洞
- 意外行为
- 性能问题
- 构建失败
- 集成问题
尤其建议在以下情况使用:
- 时间紧迫(紧急情况下容易凭直觉猜测)
- 似乎“只需快速修复一下”就能解决问题
- 已经尝试过多种修复方法
- 之前的修复方案无效
- 对问题尚未完全理解
以下情况切勿跳过此步骤:
- 问题看似简单(简单的漏洞也有根本原因)
- 时间仓促(匆忙处理必然会导致返工)
- 有人要求立即解决问题(系统化处理比盲目尝试更高效)
四个阶段
在进入下一阶段之前,必须完成当前阶段的所有任务。
第一阶段:根本原因分析
在尝试任何修复方案之前:
1. 仔细阅读错误信息
- 不要跳过错误提示或警告信息
- 它们通常包含解决问题的关键线索
- 完整阅读堆栈跟踪信息
- 记下行号、文件路径及错误代码
操作方法: 对相关源文件使用 read_file 命令,再使用 search_files 在代码库中查找错误字符串。
2. 稳定复现问题
- 能够可靠地触发该问题吗?
- 具体操作步骤是什么?
- 每次都会出现该问题吗?
- 如果无法复现 → 需要收集更多数据,切勿凭猜测处理
操作方法: 使用 terminal 工具运行失败的测试或触发该漏洞。
# Run specific failing test
pytest tests/test_module.py::test_name -v
# Run with verbose output
pytest tests/test_module.py -v --tb=long
3. 检查近期变更
- 哪些变更可能导致了此问题?
- Git差异对比、最新提交记录
- 新增的依赖项、配置更改
操作步骤:
# Recent commits
git log --oneline -10
# Uncommitted changes
git diff
# Changes in specific file
git log -p --follow src/problematic_file.py | head -100
4. 在多组件系统中收集故障证据
当系统包含多个组件时(API → 服务 → 数据库,CI → 构建 → 部署):
在提出修复方案之前,先添加诊断工具:
针对每个组件边界:
- 记录进入该组件的数据
- 记录离开该组件的数据
- 验证环境/配置是否正确传递
- 检查各层级的状态
运行一次以收集能显示故障发生位置的证据。 随后分析这些证据,确定出出现问题的组件。 最后针对该特定组件进行深入排查。
5. 追踪数据流
当错误位于调用栈的深层时:
- 有问题的值源自何处?
- 是哪个函数传入了有问题的值?
- 持续向上追踪直至找到源头
- 应从根源解决问题,而非仅处理表面症状
操作建议: 使用 search_files 功能来追踪相关引用。
# Find where the function is called
search_files("function_name(", path="src/", file_glob="*.py")
# Find where the variable is set
search_files("variable_name\\s*=", path="src/", file_glob="*.py")
第一阶段完成检查清单
- 已完整阅读并理解错误信息
- 能稳定复现该问题
- 已识别并审查最近的代码变更
- 已收集相关证据(日志、系统状态、数据流)
- 已将问题定位到具体组件/代码
- 已形成根本原因假设
注意: 在弄清楚问题产生的原因之前,请勿进入第二阶段。
第二阶段:模式分析
在修复问题之前先找出规律:
1. 寻找正常运行的示例
- 在同一代码库中查找类似的正常运行代码
- 与出现故障的代码相比,哪些部分是正常的?
操作建议: 使用 search_files 命令来查找相似的模式:
search_files("similar_pattern", path="src/", file_glob="*.py")
2. 与参考实现进行对比
- 若要实现某种模式,务必完整阅读参考实现
- 不要粗略浏览——需逐行研读
- 在应用该模式之前,必须对其有透彻的理解
3. 确定差异点
- 正常运行与出错状态之间有何不同?
- 无论差异多么微小,都需一一列出
- 切勿认为“那无关紧要”
4. 明确依赖关系
- 它还需要哪些其他组件?
- 需要哪些设置、配置或环境条件?
- 它基于哪些假设运行?
第三阶段:假设提出与测试
科学方法:
1. 提出单一假设
- 清晰陈述:“我认为X是根本原因,因为Y”
- 将其写下来
- 表述要具体,避免模糊
2. 最小化测试范围
- 为验证假设而进行尽可能小的改动
- 每次只调整一个变量
- 不要同时修复多个问题
3. 继续之前先进行验证
- 测试成功?→ 进入第四阶段
- 测试失败?→ 提出新的假设
- 切勿在原有问题上再叠加更多修复措施
4. 当不确定时
- 直接说明“我不明白X”
- 不要假装知晓
- 向用户寻求帮助
- 进一步深入研究
第四阶段:实际实现
要解决根本原因,而非表面症状:
1. 创建失败的测试用例
- 采用最简单的复现方式
- 如有可能,将其转化为自动化测试
- 在开始修复之前必须先有该测试用例
- 可运用“测试驱动开发”相关技能
2. 实施单一修复措施
- 针对已确定的根本原因进行修正
- 每次只做一项更改
- 不要趁机顺便进行其他优化
- 也不要一次性进行大规模重构
3. 验证修复效果
# Run the specific regression test
pytest tests/test_module.py::test_regression -v
# Run full suite — no regressions
pytest tests/ -q
4. 若修复无效——“三次法则”
- 停止。
- 统计:你已经尝试过多少种修复方法?
- 若少于3种:返回第一阶段,利用新获取的信息重新分析。
- 若达到3种或以上:立即停止,并对架构进行审视(见下文第5步)。
- 未经架构层面的讨论,切勿尝试第4种修复方法。
5. 若3种及以上修复均失败:审视架构
表明存在架构问题的典型特征:
- 每次修复都会在不同的地方暴露出新的共享状态或耦合问题。
- 实施修复需要大规模的代码重构。
- 每次修复都会在其他地方引发新的故障现象。
应立即停止并深入思考基本原则:
- 这种设计模式从根本上是否合理?
- 我们是否只是出于惯性而坚持使用它?
- 是应该重构架构,还是继续仅仅解决表面症状?
在尝试更多修复之前,务必与用户进行充分讨论。
这并非假设不成立——而是架构本身存在问题。
警示信号——立即停止并遵循流程
如果你发现自己有如下想法:
- “先快速解决,稍后再深入调查”
- “试试修改X,看看是否有效”
- “一次性做多个更改,然后运行测试”
- “跳过测试,我手动验证即可”
- “问题大概率是X,让我去修复它”
- “虽然不完全明白,但这个方法或许可行”
- “按常规思路应该是X,但我打算稍作调整”
- “主要问题如下:[列出未经验证的修复方案]”
- 在未梳理数据流之前就直接提出解决方案
- “再试一次修复”(即便已经尝试过2次及以上)
- 每次修复都在不同的地方引发新问题
以上所有情况都意味着:立即停止,返回第一阶段。
若3种及以上修复均失败: 对架构进行审视(第4阶段第5步)。
常见的借口与事实
| 借口 | 实际情况 |
|---|---|
| “问题很简单,不需要遵循流程” | 简单的问题也有根本原因。对于简单错误,遵循流程反而能更快解决问题。 |
| “情况紧急,没时间按流程来” | 系统化的调试方式比反复试错的效率更高。 |
| “先试试这个,之后再调查” | 第一次修复就会定下后续解决问题的模式,应从一开始就做好。 |
| “等确认修复有效后再写测试” | 未经测试的修复方案无法长期稳定运行,先测试才能验证效果。 |
| “同时进行多项修复可以节省时间” | 这样无法确定到底是哪项修改起了作用,还可能引发新的错误。 |
| “文档太长,我就稍作调整再应用” | 不完全理解内容就尝试应用,必然会导致错误,务必通读完整文档。 |
| “我看到了问题,让我来修复它” | 只看到表面症状并不等同于理解了根本原因。 |
| “再试一次修复”(在2次及以上失败后) | 3次及以上失败意味着存在架构问题,应审视问题模式,而非继续尝试修复。 |
快速参考指南
| 阶段 | 关键活动 | 成功标准 |
|---|---|---|
| 1. 查明根本原因 | 查看错误信息、复现问题、检查变更内容、收集证据、梳理数据流 | 明确问题的本质及其成因 |
| 2. 分析问题模式 | 寻找有效的解决方案案例、进行对比、找出差异点 | 了解问题所在的不同之处 |
| 3. 建立假设 | 形成理论假设、逐步进行最小化测试、每次只改变一个变量 | 确认假设成立或形成新的假设 |
| 4. 实施修复 | 编写回归测试、解决根本原因、进行验证 | 错误已修复,所有测试均通过 |
Hermes Agent集成
调查工具
在第一阶段可使用以下Hermes工具:
search_files— 查找错误字符串、追踪函数调用路径、定位问题模式。read_file— 读取带行号的源代码,以便进行精准分析。terminal— 运行测试、查看Git历史记录、复现故障。web_search/web_extract— 查找错误信息相关的资料及库文档。
结合delegate_task使用
对于复杂的多组件调试场景,可调度子代理来协助调查:
delegate_task(
goal="Investigate why [specific test/behavior] fails",
context="""
Follow systematic-debugging skill:
1. Read the error message carefully
2. Reproduce the issue
3. Trace the data flow to find root cause
4. Report findings — do NOT fix yet
Error: [paste full error]
File: [path to failing code]
Test command: [exact command]
""",
toolsets=['terminal', 'file']
)
基于测试驱动开发的方法
在修复错误时:
- 编写能够复现该错误的测试用例(RED阶段)
- 通过系统化的方法定位根本原因
- 解决根本问题(GREEN阶段)
- 通过测试验证修复效果并防止问题再次出现
实际应用效果
通过对比不同的调试方式:
- 系统化方法:仅需15-30分钟即可解决问题
- 随机尝试方法:需花费2-3小时反复折腾
- 首次修复成功率:95% 对比 40%
- 引入新错误的情况:几乎为零 对比 非常常见
没有捷径,无需猜测。系统化方法始终最有效。