跳到主要内容

系统化调试

4阶段根因调试:先理解缺陷再修复。

Skill 元数据

来源内置(默认安装)
路径skills/software-development/systematic-debugging
版本1.1.0
作者AigenLabs Agent(改编自 obra/superpowers)
许可证MIT
平台linux, macos, windows
标签debugging, troubleshooting, problem-solving, root-cause, investigation
相关 skilltest-driven-development, writing-plans, subagent-driven-development

参考:完整 SKILL.md

信息

以下是 AigenLabs 在触发此 skill 时加载的完整 skill 定义。这是 agent 在 skill 激活时所看到的指令内容。

系统化调试

概述

随机修复浪费时间并引入新缺陷。快速补丁会掩盖根本问题。

核心原则: 在尝试修复之前,务必找到根因。修复症状即是失败。

违反此流程的字面规定,即违反了调试的精神。

铁律

在完成根因调查之前,禁止任何修复

如果尚未完成阶段 1,则不得提出修复方案。

适用场景

适用于任何技术问题:

  • 测试失败
  • 生产环境缺陷
  • 非预期行为
  • 性能问题
  • 构建失败
  • 集成问题

尤其在以下情况下使用:

  • 时间紧迫(紧急情况容易诱发猜测)
  • "只需一个快速修复"看似显而易见
  • 已经尝试了多次修复
  • 上一次修复未生效
  • 对问题尚未完全理解

以下情况不得跳过:

  • 问题看似简单(简单的缺陷同样有根因)
  • 时间紧迫(仓促只会导致返工)
  • 有人要求立即修复(系统化比反复折腾更快)

四个阶段

必须完成每个阶段后,才能进入下一阶段。


阶段 1:根因调查

在尝试任何修复之前:

1. 仔细阅读错误信息

  • 不要跳过错误或警告
  • 其中往往包含确切的解决方案
  • 完整阅读堆栈跟踪
  • 记录行号、文件路径、错误代码

操作: 对相关源文件使用 read_file。使用 search_files 在代码库中查找错误字符串。

2. 稳定复现

  • 能否可靠地触发该问题?
  • 确切步骤是什么?
  • 是否每次都会发生?
  • 若无法复现 → 收集更多数据,不要猜测

操作: 使用 terminal 工具运行失败的测试或触发缺陷:

# 运行特定失败测试
pytest tests/test_module.py::test_name -v

# 使用详细输出运行
pytest tests/test_module.py -v --tb=long

3. 检查近期变更

  • 哪些变更可能导致此问题?
  • Git diff、近期提交
  • 新依赖、配置变更

操作:

# 近期提交
git log --oneline -10

# 未提交的变更
git diff

# 特定文件的变更
git log -p --follow src/problematic_file.py | head -100

4. 在多组件系统中收集证据

当系统包含多个组件时(API → 服务 → 数据库,CI → 构建 → 部署):

在提出修复方案之前,添加诊断埋点:

对每个组件边界:

  • 记录进入该组件的数据
  • 记录离开该组件的数据
  • 验证环境/配置的传播
  • 检查每一层的状态

运行一次以收集证据,确定问题在哪里断裂。 然后分析证据,识别出故障组件。 再针对该具体组件展开调查。

5. 追踪数据流

当错误深藏于调用栈时:

  • 错误值从哪里产生?
  • 是什么以错误值调用了此函数?
  • 持续向上游追踪,直到找到源头
  • 在源头修复,而非在症状处修复

操作: 使用 search_files 追踪引用:

# 查找函数被调用的位置
search_files("function_name(", path="src/", file_glob="*.py")

# 查找变量被赋值的位置
search_files("variable_name\\s*=", path="src/", file_glob="*.py")

阶段 1 完成检查清单

  • 错误信息已完整阅读并理解
  • 问题已稳定复现
  • 近期变更已识别并审查
  • 证据已收集(日志、状态、数据流)
  • 问题已定位到具体组件/代码
  • 根因假设已形成

停止: 在理解问题发生的原因之前,不得进入阶段 2。


阶段 2:模式分析

在修复之前找到规律:

1. 查找可用示例

  • 在同一代码库中找到类似的可用代码
  • 有哪些与故障代码相似但正常运行的代码?

操作: 使用 search_files 查找可比较的模式:

search_files("similar_pattern", path="src/", file_glob="*.py")

2. 与参考实现对比

  • 若在实现某个模式,请完整阅读参考实现
  • 不要略读——逐行阅读
  • 在应用之前完全理解该模式

3. 识别差异

  • 可用代码与故障代码之间有何不同?
  • 列出每一处差异,无论多小
  • 不要假设"那不可能有影响"

4. 理解依赖关系

  • 此组件需要哪些其他组件?
  • 需要哪些设置、配置、环境?
  • 它做了哪些假设?

阶段 3:假设与验证

科学方法:

1. 形成单一假设

  • 清晰陈述:"我认为 X 是根因,因为 Y"
  • 将其写下来
  • 要具体,不要模糊

2. 最小化测试

  • 做出最小可能的变更来验证假设
  • 每次只改变一个变量
  • 不要同时修复多处

3. 继续前验证

  • 有效?→ 进入阶段 4
  • 无效?→ 形成新假设
  • 不要在原有修复上叠加更多修复

4. 当你不确定时

  • 说"我不理解 X"
  • 不要假装知道
  • 向用户寻求帮助
  • 进一步研究

阶段 4:实施

修复根因,而非症状:

1. 创建失败测试用例

  • 尽可能简单的复现
  • 尽可能使用自动化测试
  • 修复前必须先有测试
  • 使用 test-driven-development skill

2. 实施单一修复

  • 针对已识别的根因进行修复
  • 每次只做一处变更
  • 不做"顺手"的改进
  • 不捆绑重构

3. 验证修复

# 运行特定回归测试
pytest tests/test_module.py::test_regression -v

# 运行完整测试套件——确认无回归
pytest tests/ -q

4. 若修复无效——三次规则

  • 停止。
  • 计数:已尝试了多少次修复?
  • 若 < 3:返回阶段 1,结合新信息重新分析
  • 若 ≥ 3:停止并质疑架构(见下方步骤 5)
  • 不得在未进行架构讨论的情况下尝试第 4 次修复

5. 若 3 次以上修复均失败:质疑架构

表明存在架构问题的模式:

  • 每次修复都在不同位置暴露出新的共享状态/耦合
  • 修复需要"大规模重构"才能实施
  • 每次修复都在其他地方产生新症状

停止并质疑根本问题:

  • 此模式从根本上是否合理?
  • 我们是否"出于惯性而坚持"?
  • 应该重构架构,还是继续修复症状?

在尝试更多修复之前,与用户讨论。

这不是假设失败——这是架构错误。


红色警报——停止并遵循流程

如果你发现自己在想:

  • "先快速修复,之后再调查"
  • "试着改一下 X,看看是否有效"
  • "添加多处变更,运行测试"
  • "跳过测试,我会手动验证"
  • "可能是 X,让我修复它"
  • "我还不完全理解,但这可能有效"
  • "模式说 X,但我会以不同方式调整"
  • "以下是主要问题:[列出修复方案,未经调查]"
  • 在追踪数据流之前提出解决方案
  • "再试一次修复"(已尝试 2 次以上时)
  • 每次修复都在不同位置暴露出新问题

以上所有情况均意味着:停止。返回阶段 1。

若 3 次以上修复均失败: 质疑架构(阶段 4 步骤 5)。

常见借口

借口现实
"问题很简单,不需要流程"简单问题同样有根因。流程对简单缺陷而言很快。
"紧急情况,没时间走流程"系统化调试比猜测式反复折腾更快。
"先试试这个,再调查"第一次修复奠定了模式。从一开始就做对。
"确认修复有效后再写测试"未经测试的修复无法持久。先写测试才能证明有效。
"同时做多处修复节省时间"无法隔离有效的那个。会引入新缺陷。
"参考太长,我来调整模式"理解不完整必然导致缺陷。完整阅读。
"我看到问题了,让我修复"看到症状 ≠ 理解根因。
"再试一次修复"(2 次以上失败后)3 次以上失败 = 架构问题。质疑模式,不要再修复。

快速参考

阶段关键活动成功标准
1. 根因阅读错误、复现、检查变更、收集证据、追踪数据流理解是什么以及为什么
2. 模式查找可用示例、对比、识别差异知道差异所在
3. 假设形成理论、最小化测试、每次一个变量已确认或形成新假设
4. 实施创建回归测试、修复根因、验证缺陷已解决,所有测试通过

AigenLabs Agent 集成

调查工具

在阶段 1 中使用以下 AigenLabs 工具:

  • search_files — 查找错误字符串、追踪函数调用、定位模式
  • read_file — 带行号读取源代码,用于精确分析
  • terminal — 运行测试、检查 git 历史、复现缺陷
  • web_search/web_extract — 研究错误信息、查阅库文档

与 delegate_task 配合使用

对于复杂的多组件调试,派发调查子 agent:

delegate_task(
goal="调查为何 [特定测试/行为] 失败",
context="""
遵循 systematic-debugging skill:
1. 仔细阅读错误信息
2. 复现问题
3. 追踪数据流以找到根因
4. 报告发现——暂不修复

错误:[粘贴完整错误]
文件:[故障代码路径]
测试命令:[确切命令]
""",
toolsets=['terminal', 'file']
)

与 test-driven-development 配合使用

修复缺陷时:

  1. 编写能复现缺陷的测试(RED)
  2. 系统化调试以找到根因
  3. 修复根因(GREEN)
  4. 测试证明修复有效并防止回归

实际影响

来自调试会话的数据:

  • 系统化方法:15–30 分钟完成修复
  • 随机修复方法:2–3 小时反复折腾
  • 首次修复成功率:95% vs 40%
  • 引入新缺陷:几乎为零 vs 普遍存在

没有捷径。没有猜测。系统化永远胜出。