前言¶
排查 bug 时,最耗时间的往往不是修,而是定位。「bug 肯定在当前代码里,但不知道在哪一段」「点击授权报 405,说不清是前端、网关还是下游 API 的锅」「上周还好好的,不知道哪次提交改坏的」——遇到这类问题,靠通读代码或凭经验猜,效率很低,还容易演变成东改一下西改一下。
二分法是处理这类问题的标准做法:每轮把搜索范围砍一半,几轮之内就能收敛到具体函数、具体边界或具体 commit。dsh-bisect-debug 是一个 DeepSeek Harness(DSH)工作流插件,把这套方法固化成了可执行的流程。DSH 的理念是「一切皆插件」,排查类工作流以插件形式提供,装上即可使用。
这是什么¶
dsh-bisect-debug 由 PangYiMing 维护,分类为工作流,许可证为 MIT。一句话定位:用二分法把搜索范围每轮砍一半,快速锁定 bug 到具体函数/边界/commit。
插件内置三种二分模式——代码二分、边界二分、commit 二分,并附带模式选择指引、跳过条件和执行纪律,解决的核心问题是「bug 存在于某个范围内,但不知道具体位置」。下面按模式介绍。
三种二分模式¶
先判断用哪种:有明确好/坏时间点 → commit 二分;跨层问题不确定哪层 → 边界二分;确定 bug 在当前代码里 → 代码二分(最常用)。
代码二分¶
适用场景:bug 确定在当前代码里,要缩小到具体函数/组件。前提是手上有当前代码和一个可复现的 bug。
流程如下:
- 范围里有 N 个候选(函数/组件/中间件/import);
- 注释掉后半 N/2 个;
- bug 消失 → 根因在被注释的后半里,继续对后半二分;
- bug 还在 → 根因在前半里,继续对前半二分;
- 反复直到缩小到具体函数/具体行。
注释时保留原代码,加 bisect-disabled 标记,方便恢复:
// [bisect-disabled] <OriginalComponent />
// <OriginalComponent />
注意三点:有依赖关系的模块不能乱注释,否则会引入新报错;注释后验证的是「bug 还在不在」,不是「有没有新报错」;每轮只注释一半。
边界二分¶
适用场景:跨层问题,不确定是前端还是后端、哪一层的锅。前提是能画出数据流节点图,且不少于 3 层。
思路是:任何 bug 都是「数据在某个环节不再正确」。沿数据流逐跳验证,找到数据正确到达的最后一站——从中间节点验证,midpoint 正确则 bug 在下游,错误则 bug 在上游。不同架构的验证方式不同:
- HTTP 前后端:
curl直连后端 API,绕过前端; - 微服务链:逐服务 curl 或查日志;
- 数据库:DB 客户端直接查;
- 浏览器渲染:DevTools Network + Console;
- 函数调用链:调用方/被调用方各加 log。
典型组合是先用边界二分定层,再在该层内用代码二分定函数。
commit 二分¶
适用场景:之前还好好的,不知道哪次提交改坏的。前提是有 git 历史和明确的好/坏 commit。
这一模式的关键,是把「好/坏判定」固化成退出码脚本——exit 0 表示好,exit 1 表示坏,exit 125 表示跳过——再交给 git bisect run 全自动收敛。
安装与启用¶
官方安装命令如下:
dsh plugin --profile demo add dsh-bisect-debug
# 或从 GitHub 安装
dsh plugin --profile demo add github:PangYiMing/dsh-bisect-debug
说明一点:第一种方式对应 npm 发布,资料中标注为「发布到 npm 后」可用;想现在就装,用第二种从 GitHub 安装。
典型用法¶
边界二分实战:3 个 curl 定位 405¶
真实案例:点击授权报 405。沿数据流连发 3 个 curl——MCP 登录返回 200(正常)、网关 POST 返回 405(异常)、下游 API 返回 422(正常)。结论:网关 nginx 拦截了 POST。全程 3 个 curl,0 行代码改动。
commit 二分完整流程¶
先校验好坏 commit 的关系,再写判定脚本,最后交给 git bisect run 自动跑:
# 1. 确认好/坏 commit(good 从 tag/log 推断,不问用户)
git merge-base --is-ancestor <good> <bad> # 校验 good 在 bad 祖先链上
# 2. 写判定脚本 .temp/bisect-judge.sh
npm run build >/dev/null 2>&1 || exit 125
code=$(curl -s -o /dev/null -w "%{http_code}" --max-time 30 "http://localhost:8080/")
[ "$code" = "200" ] && exit 0 || exit 1
# 3. 全自动跑
git bisect start
git bisect bad <bad-commit>
git bisect good <good-commit>
git bisect run bash .temp/bisect-judge.sh
# 4. 收尾(必做)
git bisect reset
脚本先构建、再请求本地服务并按返回码判定:构建失败退出 125 跳过该提交,返回 200 判好,否则判坏。git bisect run 据此自动切提交,收敛到引入 bug 的那一次。
commit 二分有三点注意:base 过期要校验,upstream 合入新文件会误导二分;启动前工作区必须干净;git bisect reset 必做。
什么时候不用二分¶
插件明确了跳过条件:从现象到根因不超过 2 步,就不进二分。具体包括四种情况——编译器已指出文件+行号;用户明确说了根因;改一行就能验证;已知版本依赖问题。
二分是为「范围大、位置不明」准备的,问题一眼能看穿时不必套流程。
执行纪律¶
插件附带的执行纪律,几条值得单独列出:
- 连续改了 ≥2 处还没解决,停下,回到二分——这是最强的反偷懒规则。
- 每轮只切一半,测完再切下一半,禁止一次改多处再测。
- 现象优先,代码最后:先用 curl/log/ping 确认现象和边界,不要一上来就读代码。
- bug 不可复现时按情况调整:总是复现就直接二分;间歇复现就加诊断日志等下一次;只发生一次就做最大日志注入并部署监控。
适用场景与注意¶
适合经常需要定位「知道大概范围、不知道具体位置」这类 bug 的 DSH 用户,尤其是让智能体执行排查的场景——模式选择、跳过条件、每轮只改一半这些约束写进了流程,能约束智能体按纪律走,而不是随手乱改。
安全提示:插件以当前 dsh 进程权限运行,安装前建议检查源码与许可证。本项目许可证为 MIT,源码在 GitHub 上可直接查看。
小结¶
dsh-bisect-debug 的价值在于把「定位 bug」从凭经验乱翻,变成一个有模式选择、有跳过条件、有纪律约束的标准流程:范围大就二分,每轮砍一半,直到收敛到具体函数/边界/commit。如果你常被「不知道 bug 在哪」耗掉大半天,值得一试。
- GitHub:https://github.com/PangYiMing/dsh-bisect-debug
- 社区目录页:https://www.skillhub.cn/plugins/PangYiMing/dsh-bisect-debug