agentsclimarketplace

Systematic debugging

Skill huangwb8/skills/awesome-code/agents/systematic-debugging

General Skills Development Pipeline - Claude Code & Codex

Install
npx -y skills add huangwb8/skills --skill systematic-debugging

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

What its author says it does

Copied from the file, not written here

Use when encountering any bug, test failure, or unexpected behavior, before proposing fixes - four-phase framework (root cause investigation, pattern analysis, hypothesis testing, implementation). NO FIXES WITHOUT ROOT CAUSE INVESTIGATION FIRST.

SKILL.md

12.0 KB, as published. Nobody here has run it

Systematic Debugging - 系统化调试

BenszAPI 任务工作区

本 Skill 的新任务中间文件统一写入 ./.bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/{skill名}/input|output|log/。同一任务复用一个任务根目录;多 Skill 协作才创建 shared/。正式交付物不写入该目录,历史隐藏目录只允许显式兼容读取、迁移或清理。

与 bensz-collect-bugs 的协作约定

  • 因本 skill 设计缺陷导致的 bug,先用 bensz-collect-bugs 规范记录到 ~/.bensz-skills/bugs/,不要直接修改用户本地已安装的 skill 源码;若有 workaround,先记 bug,再继续完成任务。
  • 只有用户明确要求“report bensz skills bugs”等公开上报时,才用本地 gh 上传新增 bug 到 huangwb8/bensz-bugs;不要 pull / clone 整个仓库。

铁律

NO FIXES WITHOUT ROOT CAUSE INVESTIGATION FIRST

违反规则的信件就是违反规则的精神。

无例外

  • 不跳过根因调查直接修复
  • 不基于猜测进行修复
  • 不尝试多个更改同时测试
  • 不在不完全理解的情况下修复

常见合理化

借口现实
"快速修复现在,稍后调查"永不会有"稍后"。技术债积累
"尝试改变 X,看是否有效"猜测不是调试。可能碰巧修复但未理解
"添加多个更改,运行测试"无法确定哪个更改有效。浪费调试时间
"可能大概差不多是 X"模糊理解导致错误修复
"不完全理解但可能有效"理解不完全=修复不完整

红色标志 - 停止并重新开始

  • "快速修复现在,稍后调查"
  • "尝试改变 X,看是否有效"
  • "添加多个更改,运行测试"
  • "可能大概差不多是 X,让我修复"
  • "不完全理解但可能有效"
  • 基于猜测而非证据的修复

所有这些意味着:停止修复。回到根因调查阶段。


四阶段框架

阶段 1:根因调查

任何修复前

  1. 仔细阅读错误消息

    • 不要跳过错误或警告
    • 它们通常包含确切解决方案
  2. 一致复现

    • 你能可靠触发吗?
  3. 检查最近变更

    • 什么变更可能导致此问题?
  4. 多组件系统收集证据

    # 对于每个组件边界:
    - 记录进入组件的数据
    - 记录退出组件的数据
    - 验证环境/配置传播
    - 检查每层状态
    运行一次以收集显示何处中断的证据
    然后分析证据以识别失败组件
    然后调查该特定组件
    
  5. 追踪数据流

    • 向后追踪到坏值起源

阶段 2:模式分析

  1. 找到工作示例
  2. 与参考对比
  3. 识别差异
  4. 理解依赖

阶段 3:假设与测试

  1. 形成单一假设:"我认为 X 是根本原因,因为 Y"
  2. 最小化测试:进行最小可能更改
  3. 验证后再继续
  4. 3+ 次修复失败时:质疑架构

阶段 4:实现

  1. 创建失败测试用例
  2. 实施单一修复:只改验证该假设所需的最小范围
  3. 验证修复:一次只验证一个假设,不把多个修复混在同一次验证里
  4. 收敛范围:避免顺手重构、无关格式化或新增未证明必要的抽象
  5. 如果 3+ 次修复失败:质疑架构

核心理念

系统化调试 不是碰运气,而是方法化地解决问题的科学流程。

┌─────────────────────────────────────────────────────────┐
│  收集证据 → 形成假设 → 系统验证 → 定位根因 → 实施修复  │
└─────────────────────────────────────────────────────────┘

核心原则

  • 基于证据,而非猜测
  • 治疗根本原因,而非症状
  • 一次验证一个假设
  • 记录整个过程

何时使用本技能

在以下场景时激活:

  • 出现错误、异常、Bug
  • 需要分析堆栈追踪(Stack Trace)
  • 提到"调试"、"排查问题"、"定位根因"
  • 生产环境问题分析
  • 跨文件或跨模块的问题追踪
  • 间歇性 Bug(时有时无)

调试工作流程

步骤 1:收集证据 📋

信息收集清单

证据类型收集方法重要性
完整堆栈追踪复制完整错误信息⭐⭐⭐⭐⭐
相关日志查看应用日志⭐⭐⭐⭐⭐
复现步骤记录如何触发问题⭐⭐⭐⭐
环境信息OS、版本、依赖⭐⭐⭐
代码变更最近的 Git 提交⭐⭐⭐⭐
用户输入触发问题的数据⭐⭐⭐

堆栈追踪分析示例

# 示例错误
Traceback (most recent call last):
  File "app.py", line 45, in process_order
    result = payment_service.charge(amount)
  File "payment.py", line 78, in charge
    return api_client.post("/charge", data)
  File "api.py", line 23, in post
    response = self.session.request(method, url, **kwargs)
ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed

分析要点

  1. 从下往上读:最下面是根本原因
  2. 追踪调用链:app.py → payment.py → api.py
  3. 识别错误类型:SSL 证书验证失败
  4. 定位失败点:api.py 第 23 行

步骤 2:形成假设 💡

假设生成规则

  1. 基于证据:不要凭空猜测
  2. 优先考虑最近变更
  3. 从简单到复杂排序
  4. 一次只关注一个假设

假设模板

假设:[问题描述] 的原因是 [根本原因]
触发条件:[什么情况下会出现]
验证方法:[如何证明或否定]

假设示例

假设:SSL 错误的原因是生产环境缺少证书文件
触发条件:部署到生产环境后首次调用 API
验证方法:检查 /etc/ssl/certs/ 目录是否存在证书

常见根因分类

类别典型原因检查方法
配置问题环境变量、配置文件错误检查 .env、config
依赖问题版本冲突、缺失依赖检查 requirements.txt
数据问题空值、格式错误、边界值检查输入数据
并发问题竞态条件、死锁检查锁、线程安全
资源问题内存泄漏、连接池耗尽检查资源使用
逻辑错误边界条件、空值处理代码审查

步骤 3:系统验证 🔍

验证原则

  1. 一次验证一个假设(控制变量)
  2. 设计最小化验证实验
  3. 记录验证过程和结果
  4. 用排除法缩小范围

验证方法

# 方法 1:添加日志
def process_order(order_id):
    logger.info(f"Processing order: {order_id}")
    order = get_order(order_id)
    logger.debug(f"Order data: {order}")
    # ...

# 方法 2:断点调试
import pdb; pdb.set_trace()

# 方法 3:简化输入
def test():
    # 用最小输入验证
    process_order({"id": 1, "amount": 0})

验证记录模板

## 假设验证记录

### 假设 1:证书文件缺失
- **验证方法**:检查文件是否存在
- **验证结果**:❌ 文件存在
- **结论**:假设不成立,排除

### 假设 2:证书过期
- **验证方法**:检查证书有效期
- **验证结果**:✅ 证书已于 3 天前过期
- **结论**:假设成立,定位根因

步骤 4:定位根因 🎯

区分症状与根因

使用五问法(5 Whys)深入挖掘:

问题:订单处理失败

Why 1: 为什么失败?
→ API 调用返回 500 错误

Why 2: 为什么 API 返回 500?
→ 数据库查询超时

Why 3: 为什么查询超时?
→ 缺少索引导致全表扫描

Why 4: 为什么缺少索引?
→ 新增字段时未同步添加索引

Why 5: 为什么未添加索引?
→ 没有 Code Review 流程

根因:缺少 Code Review 机制(而非"API 返回 500")

根因特征

  • 可操作:可以采取措施
  • 可预防:可以防止再次发生
  • 系统级:不是个人失误

步骤 5:实施修复 🔧

修复原则

  1. 最小化修复范围
  2. 添加回归测试
  3. 修复后验证
  4. 更新文档

修复清单

## 修复计划

### 代码修复
- [ ] 修改代码:[具体位置]
- [ ] 添加测试:[测试用例]
- [ ] 运行测试确认通过

### 预防措施
- [ ] 添加检查机制
- [ ] 更新文档
- [ ] 团队分享经验

### 验证
- [ ] 本地验证
- [ ] 测试环境验证
- [ ] 生产环境验证

调试技巧库

技巧 1:二分法调试

当问题可能出现在多个位置时:

# 在中间点添加日志
def complex_function(data):
    logger.info("Step 1: Start")
    result1 = step1(data)
    logger.info(f"Step 1 result: {result1}")

    logger.info("Step 2: Start")
    result2 = step2(result1)
    logger.info(f"Step 2 result: {result2}")

    logger.info("Step 3: Start")
    result3 = step3(result2)
    logger.info(f"Step 3 result: {result3}")

    return result3

技巧 2:最小化复现

# 从复杂场景中提取最小复现用例
def test_minimal_reproduction():
    # 不需要完整的订单数据
    order = {"amount": 100}  # 最小输入
    result = process_payment(order)
    assert result.success

技巧 3:对比法调试

# 对比工作版本和失败版本
def test_working_vs_broken():
    # 工作版本
    result_working = old_api_call(data)

    # 失败版本
    try:
        result_broken = new_api_call(data)
    except Exception as e:
        print(f"Broken: {e}")

    # 对比差异
    compare_results(result_working, result_broken)

技巧 4:环境隔离

# 使用 Docker 隔离环境
docker run -it python:3.11 bash

# 或使用虚拟环境
python -m venv debug_env
source debug_env/bin/activate

常见问题模式

模式 1:时序问题

症状:间歇性失败,时好时坏

根因:竞态条件、异步操作未正确等待

调试方法

# 添加重试和延迟
from tenacity import retry, stop_after_attempt, wait_fixed

@retry(stop=stop_after_attempt(3), wait=wait_fixed(1))
def flaky_operation():
    # 可能失败的操作
    pass

模式 2:内存问题

症状:性能逐渐下降,最终崩溃

根因:内存泄漏

调试方法

import tracemalloc

tracemalloc.start()
# ... 运行代码 ...
snapshot = tracemalloc.take_snapshot()
top_stats = snapshot.statistics('lineno')
for stat in top_stats[:10]:
    print(stat)

模式 3:状态污染

症状:测试单独通过,批量运行失败

根因:测试间共享状态

调试方法

@pytest.fixture(autouse=True)
def reset_state():
    # 每个测试前重置状态
    reset_database()
    reset_cache()
    yield
    cleanup()

验证清单

修复完成后,检查:

  • 根本原因已识别(非症状)
  • 修复方案最小化
  • 添加回归测试
  • 本地验证通过
  • 文档已更新(如需要)
  • 团队已分享经验
  • 预防措施已实施

相关参考

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.