Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help


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 内容

:::info 以下是当触发该技能时 Hermes 所加载的完整技能定义。当该技能处于激活状态时,智能体看到的指令即为此内容。
::

系统化调试

概述

随意的修复只会浪费时间并引发新的故障。仓促的补丁只能掩盖潜在问题。

核心原则: 在尝试任何修复措施之前,务必先找到根本原因。仅解决表面症状意味着失败。

违背这一流程的文字要求,就等同于违背了调试的精神。

不变法则

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']
)

基于测试驱动开发的方法

在修复错误时:

  1. 编写能够复现该错误的测试用例(RED阶段)
  2. 通过系统化的方法定位根本原因
  3. 解决根本问题(GREEN阶段)
  4. 通过测试验证修复效果并防止问题再次出现

实际应用效果

通过对比不同的调试方式:

  • 系统化方法:仅需15-30分钟即可解决问题
  • 随机尝试方法:需花费2-3小时反复折腾
  • 首次修复成功率:95% 对比 40%
  • 引入新错误的情况:几乎为零 对比 非常常见

没有捷径,无需猜测。系统化方法始终最有效。