debugging-wizard
SKILL.md
调试专家
运用科学方法论系统化定位和解决代码问题。绝不猜测 — 每个假设都需要验证。
核心工作流
- 复现 — 建立稳定的复现步骤
- 隔离 — 缩小到最小失败用例
- 假设与验证 — 形成可测试的理论,逐一验证/排除
- 修复 — 实施并验证修复方案
- 预防 — 添加测试/防护措施防止回归
使用内置工具调试
| 调试阶段 | 工具 | 用法 |
|---|---|---|
| 读取代码 | read_file |
查看出错的源文件,理解上下文 |
| 搜索模式 | grep |
搜索相关错误消息、变量引用、调用链 |
| 运行测试 | run_command |
执行 npm test、pytest、go test 等 |
| 添加日志 | edit_file |
在关键位置插入日志语句辅助定位 |
| 检查依赖 | run_command |
npm ls、pip list、cat package.json |
| 浏览器调试 | browser_action |
action="console" 获取前端控制台日志 |
| 查看文件结构 | list_dir |
检查文件组织是否有异常 |
常见 Bug 模式速查
| 模式 | 症状 | 可能原因 | 首要检查 |
|---|---|---|---|
| 竞态条件 | 间歇性失败 | 缺少 await、异步时序 | Promise 链是否完整 |
| Off-by-one | 缺少首/末元素 | < vs <=、数组越界 |
循环边界条件 |
| 空引用 | "undefined is not..." | 缺少空值检查 | 可选链 ?. |
| 内存泄漏 | 内存持续增长 | 未清理的监听器/定时器 | useEffect 清理函数 |
| N+1 查询 | 数据越多越慢 | 循环内查询 | 数据加载方式 |
| 类型强制转换 | 意外行为 | == 代替 === |
严格相等比较 |
| 闭包陷阱 | 变量值错误 | 循环变量捕获 | let vs var |
| 状态过期 | 使用旧值 | React 状态闭包 | 函数式更新 |
调试策略
1. 二分法(未知 Bug 位置时)
1. 注释/禁用一半代码
2. 测试 Bug 是否仍然存在
3. 如果存在 → Bug 在剩余的一半
4. 如果消失 → Bug 在被禁用的一半
5. 重复直到隔离出最小范围
2. 时间旅行(已知错误位置时)
1. 从错误/崩溃点开始
2. 什么值导致了它?这个值从哪来?
3. 向上追溯代码路径
4. 找到值偏离预期的位置
3. 最小复现(复杂 Bug 时)
1. 创建最小测试用例
2. 逐步移除不相关的代码
3. 简化输入到最小失败场景
4. 记录精确的复现步骤
4. Delta 调试(最近才出问题时)
# 检查最近的变更
git diff HEAD~5..HEAD
# 检查特定文件历史
git log -p --follow -- src/problematic-file.ts
# 自动化二分查找引入 Bug 的提交
git bisect start HEAD v1.0.0
git bisect run npm test
5. 橡皮鸭调试(逻辑错误时)
1. 陈述代码应该做什么
2. 解释它实际做了什么
3. 逐行走读代码
4. 描述每行的作用
5. 差异通常会变得明显
代码示例:常见 Bug 修复
竞态条件
// ❌ BUG: data 在 fetch 完成前就被使用
let data;
fetchData().then(result => { data = result; });
console.log(data); // undefined!
// ✅ FIX: 等待结果
const data = await fetchData();
console.log(data);
内存泄漏
// ❌ BUG: 监听器永远不会被移除
useEffect(() => {
window.addEventListener('resize', handleResize);
}, []);
// ✅ FIX: 清理函数
useEffect(() => {
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
React 状态过期
// ❌ BUG: count 在闭包中是过期值
const [count, setCount] = useState(0);
useEffect(() => {
setInterval(() => setCount(count + 1), 1000); // 永远使用初始 count
}, []);
// ✅ FIX: 函数式更新
useEffect(() => {
const id = setInterval(() => setCount(c => c + 1), 1000);
return () => clearInterval(id);
}, []);
闭包陷阱
// ❌ BUG: 所有回调都使用 i = 5
for (var i = 0; i < 5; i++) {
setTimeout(() => console.log(i), 100);
}
// ✅ FIX: 使用 let(块级作用域)
for (let i = 0; i < 5; i++) {
setTimeout(() => console.log(i), 100);
}
调试输出模板
定位问题后,按以下格式输出:
## 根因分析
**根因**: [具体导致问题的原因]
**证据**: [堆栈跟踪、日志、或证明根因的测试]
## 修复方案
[代码变更]
## 预防措施
[防止回归的测试或防护机制]
调试原则
必须做
- 先复现问题再动手
- 收集完整的错误信息和堆栈跟踪
- 一次只验证一个假设
- 修复后添加回归测试
- 提交前移除所有调试代码(console.log/debugger)
绝不做
- 不验证就猜测
- 同时修改多个地方
- 跳过复现步骤
- 假设你知道原因
- 在生产环境调试(无安全措施时)
- 留下 console.log/debugger 语句在代码中
知识参考
调试器(Chrome DevTools、VS Code Debugger、pdb、delve)、性能分析工具、日志聚合、分布式追踪、内存分析、git bisect、错误跟踪(Sentry)、断点调试、条件断点、日志点
Weekly Installs
1
Repository
senweaver/senweaver-ideGitHub Stars
15
First Seen
Mar 3, 2026
Security Audits
Installed on
amp1
cline1
opencode1
cursor1
kimi-cli1
codex1