🚀 快速安装

复制以下命令并运行,立即安装此 Skill:

npx @anthropic-ai/skills install supercent-io/skills-template/debugging

💡 提示:需要 Node.js 和 NPM

调试

何时使用此技能

  • 遇到运行时错误或异常
  • 代码产生意外输出或行为
  • 性能下降或内存问题
  • 偶发性或难以复现的错误
  • 理解不熟悉的错误消息
  • 事后分析和预防

指示

步骤 1:收集信息

收集有关问题的所有相关上下文:

错误详情

  • 完整的错误消息和堆栈跟踪
  • 错误类型(语法、运行时、逻辑等)
  • 它是什么时候开始发生的?
  • 是否可复现?

环境

  • 语言和版本
  • 框架和依赖项
  • 操作系统和运行时环境
  • 最近对代码或配置的更改
# 检查最近的更改
git log --oneline -10
git diff HEAD~5

# 检查依赖项版本
npm list --depth=0  # Node.js
pip freeze          # Python

步骤 2:复现问题

创建一个最小、可重现的示例:

# 不好:模糊的描述
"该函数有时会失败"

# 好:具体的复现步骤
"""
1. 调用 process_data() 并传入输入:{"id": None}
2. 错误发生:在第 45 行出现 TypeError
3. 预期:返回空字典
4. 实际:引发异常
"""

# 最小复现
def test_reproduce_bug():
    result = process_data({"id": None})  # 在此失败
    assert result == {}

步骤 3:隔离问题

使用二分搜索调试来缩小问题范围:

打印/日志调试

def problematic_function(data):
    print(f"[DEBUG] 输入:{data}")  # 入口点

    result = step_one(data)
    print(f"[DEBUG] step_one 之后:{result}")

    result = step_two(result)
    print(f"[DEBUG] step_two 之后:{result}")  # 问题在这里?

    return step_three(result)

分而治之

# 注释掉一半代码
# 如果错误仍然存在:错误在剩余的一半中
# 如果错误消失:错误在被注释掉的一半中
# 重复直到问题被隔离

步骤 4:分析根本原因

常见的错误模式和解决方案:

模式 症状 解决方案
差一错误 索引越界 检查循环边界
空引用 空指针异常 添加空值检查
竞态条件 间歇性失败 添加同步
内存泄漏 逐渐变慢 检查资源清理
类型不匹配 意外行为 验证类型

要问的问题

  1. 最近发生了什么变化?
  2. 它是否在特定输入下失败?
  3. 是否与环境相关?
  4. 失败中是否有任何模式?

步骤 5:实施修复

通过适当的验证应用修复:

# 修复前:错误
def get_user(user_id):
    return users[user_id]  # 如果未找到,则引发 KeyError

# 修复后:使用适当的处理进行修复
def get_user(user_id):
    if user_id not in users:
        return None  # 或者引发自定义异常
    return users[user_id]

修复检查清单

  • 解决了根本原因,而不仅仅是症状
  • 不破坏现有功能
  • 处理边缘情况
  • 包含适当的错误处理
  • 有测试覆盖率

步骤 6:验证和预防

确保修复有效并防止回归:

# 为特定错误添加测试
def test_bug_fix_issue_123():
    """问题 #123 的回归测试:缺失用户时的 KeyError"""
    result = get_user("nonexistent_id")
    assert result is None  # 不应引发异常

# 添加边缘情况测试
@pytest.mark.parametrize("input,expected", [
    (None, None),
    ("", None),
    ("valid_id", {"name": "用户"}),
])
def test_get_user_edge_cases(input, expected):
    assert get_user(input) == expected

示例

示例 1:TypeError 调试

错误

TypeError:无法解包非可迭代的 NoneType 对象
  文件 "app.py",第 25 行,在 process 中
    name, email = get_user_info(user_id)

分析

# 问题:当未找到用户时,get_user_info 返回 None
def get_user_info(user_id):
    user = db.find_user(user_id)
    if user:
        return user.name, user.email
    # 缺少:返回 None 的情况!

# 修复:处理 None 的情况
def get_user_info(user_id):
    user = db.find_user(user_id)
    if user:
        return user.name, user.email
    return None, None  # 或者引发 UserNotFoundError

示例 2:竞态条件调试

症状:测试在本地通过,在 CI 中间歇性失败

分析

# 问题:共享状态未同步
class Counter:
    def __init__(self):
        self.value = 0

    def increment(self):
        self.value += 1  # 不是原子操作!

# 修复:添加线程安全
import threading

class Counter:
    def __init__(self):
        self.value = 0
        self._lock = threading.Lock()

    def increment(self):
        with self._lock:
            self.value += 1

示例 3:内存泄漏调试

工具:使用内存分析器

from memory_profiler import profile

@profile
def process_large_data():
    results = []
    for item in large_dataset:
        results.append(transform(item))  # 内存增长
    return results

# 修复:对大型数据集使用生成器
def process_large_data():
    for item in large_dataset:
        yield transform(item)  # 内存高效

最佳实践

  1. 先复现:永远不要修复你无法复现的问题
  2. 一次只改一处:调试时隔离变量
  3. 阅读错误:错误消息通常指向问题所在
  4. 检查假设:验证您认为正确的事情
  5. 使用版本控制:易于回退和比较更改
  6. 记录发现:帮助未来的调试工作
  7. 编写测试:防止已修复错误的回归

调试工具

语言 调试器 分析器
Python pdb, ipdb cProfile, memory_profiler
JavaScript Chrome DevTools 性能标签页
Java IntelliJ 调试器 JProfiler, VisualVM
Go Delve pprof
Rust rust-gdb cargo-flamegraph

参考资料

📄 原始文档

完整文档(英文):

https://skills.sh/supercent-io/skills-template/debugging

💡 提示:点击上方链接查看 skills.sh 原始英文文档,方便对照翻译。

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。