Bug Pattern Diagnosis (Bug 症状诊断与经验沉淀)
Skill 职责
这个 Skill 的作用是像医生看病一样做 bug 诊断:
- 收集症状:让用户描述 bug 的表现(报错信息、复现率、环境、日志特征等)
- 回忆过往:去
experience/ 目录下翻阅以前遇到过的类似 bug,作为经验记忆参考
- 独立诊断:结合当前上下文自主排查,过往案例只作为思路启发和假设来源,绝不直接复用结论
- 沉淀新经验:每次成功定位新 bug 后,把它作为新的
BUGxx.md 写进案例库,供下次参考
核心价值:让过往踩坑的经验启发下次排查的方向,但不替代独立思考。相似症状不一定是同一个 bug,看起来一样的日志背后可能是完全不同的根因。
铁律:经验是参考,不是答案
这是本 Skill 最核心的使用原则。
案例库里的 BUGxx.md 是老医生的病历本,不是处方模板。拿到新患者:
- ✅ 可以做的:从病历本获取"这类症状通常值得怀疑什么"、"以前用什么方法查出过"、"有哪些容易踩的坑"
- ❌ 不能做的:看到症状类似就直接抄根因、抄修复方案、抄代码改动
为什么不能直接引用
- 症状可以相似,根因可能完全不同:同样是"NPE + 间歇性 + 多副本",可能是本次的 header 漏传,也可能是 Redis 连接池偶发失败、也可能是 GC stop-the-world 期间的竞态,更可能是几种问题叠加。
- 项目环境差异巨大:同样的代码结构在不同版本、不同配置、不同依赖下行为可能迥异。
- AI 误判代价高:直接按案例照抄会让用户基于错误前提改代码,排查路径被带偏,真正的 bug 反而被掩盖。
- 经验的价值在于"启发思考"而非"给答案":好医生看病历是为了拓展思路,不是为了复制粘贴。
正确的使用姿势
| 场景 | 错误做法 | 正确做法 |
|---|
| 症状匹配度高 | "这是 BUG01,改 invokeRemoteDeviceOpt 加 x-token-payload" | "你描述的现象让我想起 BUG01 的一个特征——副本间日志不对称。建议你先验证:跨副本日志是否真的有'一个有栈一个没栈'?如果是,再顺着这个方向查" |
| 部分特征命中 | "虽然不完全一样,但按 BUG01 的方案应该能修" | "BUG01 里有个排查技巧可能适用——连续请求 100 次看成功率是不是约 1/N。先用这个验证一下是不是副本间状态不一致的问题" |
| 案例里有具体代码 | 把 BUG01 的修复代码贴给用户让他照抄 | "BUG01 的修复思路是补齐 header 透传,但具体到你的项目,要先确认:(1) 你的接收端实际依赖哪些 header?(2) 序列化方式是否和入口一致?这些答完才能写代码" |
案例库结构
bug-pattern-diagnosis/
├── SKILL.md ← 本文件(职责、流程、匹配规则)
└── experience/ ← 案例库
├── BUG01.md ← 每个案例一个文档
├── BUG02.md
└── ...
每个 BUGxx.md 都按固定结构写,方便快速检索:
- 案例摘要(一句话)
- 症状 / 特征速查(像病例的"阳性体征",用于匹配)
- 详细说明(病理机制 / 根因链路)
- 排查方法论(诊断流程 / 关键技术)
- 修复方案(根治 + 兜底 + 加固)
- 预防清单(Checklist 防止复发)
- 同类 bug 的 Playbook(遇到相似现象如何按步骤排查)
触发时机
用户描述下列类型的问题时,优先启用本 Skill:
- "某个接口有时候报错,有时候又正常"
- "线上复现了但本地/测试环境复现不了"
- "日志里的报错看起来很奇怪 / 对不上代码 / 栈指向不明"
- "多个 pod / 多实例 / 多副本 / 多机器之间行为不一致"
- "明明带了 xxx,服务端还提示 xxx 缺失"
- "偶尔超时 / 偶尔 500 / 偶尔权限不足"
- 任何形如"交叉产生 / 间歇性 / 不确定性"的描述
核心流程
Step 1:读取案例库索引
读取 experience/ 目录下所有 BUG*.md 文件的"症状 / 特征速查"章节(每个文件的前 30-50 行通常就够),不要一开始读完整文件。
Step 2:症状结构化
从用户描述里提取关键特征,至少覆盖以下维度:
| 维度 | 例子 |
|---|
| 错误信号 | NPE / 500 / 403 / 超时 / 数据错 / 死锁 |
| 复现率 | 100% / 50% / 偶发 / 特定条件 |
| 环境差异 | 本地不复现?测试复现?生产复现? |
| 多实例特征 | 单副本 / 多副本?副本数是几? |
| 日志分布 | 集中在一个实例 / 分散在多个实例 / 一个有栈一个没栈 |
| 触发条件 | 特定用户 / 特定参数 / 特定时段 |
| 最近改动 | 发版?配置变更?扩容缩容?依赖升级? |
Step 3:案例回忆(不是匹配结论)
把结构化特征和案例库逐个比对相似度,但不要据此下结论。无论相似度多高,案例都只是**"值得参考的既往经验"**,不是"确定的答案"。
相似度处理原则:
- 症状高度吻合(3 个以上关键特征命中)→ 把案例作为"优先怀疑方向",但要先引导用户独立验证关键特征是否真的成立
- 症状部分吻合(1-2 个特征命中)→ 把案例作为"可能的思路来源",提醒用户该案例的一两个排查技巧可能适用
- 没有匹配(0 个命中)→ 走通用方法论,从零排查
Step 4:给出排查建议(不是诊断结论)
不要以"这是 BUGxx"的口吻下定论。要以"过往有类似案例,以下是可能的方向和验证方法"的口吻交流。
推荐的响应结构:
- 🧭 当前症状的结构化复述(确认你没理解错)
- 💭 经验参考:提到 1-2 个相关案例(简单说"这让我想到之前排查过的 BUGxx 有类似特征 X"),但不贴根因、不贴修复代码
- 🔬 独立验证建议:列出 2-3 个能快速验证假设的 quick check(连续请求统计成功率 / 跨副本日志对照 / 某个 header 抓包等)
- 🎯 当前项目的具体排查路径:基于用户的项目结构、代码特点给出定制化的下一步行动,而不是案例里的通用步骤
- ⚠️ 明确不确定性:说清"这只是基于相似症状的猜测,最终根因需要用户配合验证才能确认"
Step 4 的反面教材(禁止输出)
❌ "根据你描述的症状,这是 BUG01(多副本间歇性 NPE)。
根因是 invokeRemoteDeviceOpt 漏传 x-token-payload。
按以下代码改动即可:[直接贴 BUG01 里的代码]"
Step 4 的正面范例
✅ "你的描述有几个特征值得注意:
1) 间歇性失败,成功率似乎接近 50%
2) 日志似乎是 token 相关但客户端明明带了 token
这让我想起过去排查的 BUG01,那个案例里类似症状的背后是
'多副本内部调用漏传身份 header'。但你的项目未必是同一个
问题,**我建议先验证几个关键假设**:
Q1: 你的服务副本数是几?成功率是否约等于 1/N?
Q2: 能否同时 tail 所有副本日志,看失败请求是否同时在
多个副本留痕、且日志详尽程度不对称?
你先做这两个验证,结果告诉我之后,我们再决定排查路径。"
Step 5:沉淀新案例(可选)
当出现以下情况时,主动询问用户是否把本次排查固化成新案例:
- 案例库里完全没有匹配项,但本次成功定位了 bug
- 已有案例能匹配部分症状,但有显著新变种
- 排查过程中总结出了新的诊断方法论
用户同意后,按"案例文档结构"(下方模板)创建 BUGxx.md(编号按当前最大编号 +1)。
通用方法论(匹配不到已有案例时使用)
按以下顺序排查陌生 bug:
1. 定量化现象
- 成功率?连续请求 100 次统计
- 复现条件?能否用最小用例稳定复现
- 故障时间分布?集中在某个时段/某个用户/某台机器
2. 检查部署拓扑
- 副本数多少?成功率是否约等于
1/N 或 (N-1)/N?
- 单副本能否复现?不能 → 强烈指向副本间行为不一致
- 有无灰度/金丝雀?新老版本是否混部?
3. 跨实例日志对照
- 按 traceId / 时间窗口,把所有相关实例的日志拉出来并排看
- 留意"同一请求在两个实例留下错位证据"的情况
- 留意"不同实例日志详尽程度不一致"(一个有栈一个没栈)
4. 代码 vs 部署一致性
- 部署 jar 里的
.class 用 javap -c -p 反编译,和本地源码比对
- 镜像 tag、git commit hash 要对得上
- ConfigMap / 环境变量是否全副本一致
5. 协议层边界审计
如果怀疑上下文传播问题:
- 画出"身份/traceId/MDC/ThreadLocal"的完整生命周期
- 标注所有"跨线程 / 跨进程 / 跨实例"的边界
- 每个边界是否有显式的打包-解包机制
- 用 tcpdump / 接收端打印
getHeaderNames() 验证实际传递的 header
6. 对比同类代码
- 项目里有没有做同样事但没出 bug 的代码?
- Diff 出差异 → 差异处大概率是 bug 源头
案例文档结构(创建新 BUG*.md 时的模板)
# BUGxx: <一句话标题,突出最特征性症状>
## 案例摘要
<一段话,200 字内。点明:现象、复现条件、根因类型、影响范围>
## 症状 / 特征速查(用于匹配)
> 遇到下列特征同时满足 N 条以上时,高概率是本案例
- [ ] 特征 1(具体、可验证)
- [ ] 特征 2
- [ ] 特征 3
- [ ] ...
### 关键日志指纹
<贴出典型的错误日志片段,让后续可以直接 grep 匹配>
### 不会出现的反向特征(排除项)
- 如果出现 <xxx>,则不是本案例
## 详细说明 / 根因链路
<病理机制。用图/表格/代码引用说明数据流、控制流、状态变化>
## 排查方法论
### 使用到的技术
- <方法 1:例如"跨副本日志对照">
- <方法 2:例如"javap 字节码比对")>
- ...
### 诊断步骤(按顺序)
1. ...
2. ...
3. ...
## 修复方案
### 根治
<核心修复点、代码示例、影响面评估>
### 兜底 / 防御
<二线防御措施,防止根治漏掉时仍不崩>
### 加固 / 清理
<长期性改进,代码规约、同类代码扫描>
## 预防清单(Checklist)
开发阶段:
- [ ] ...
部署阶段:
- [ ] ...
Review 阶段:
- [ ] ...
## 同类间歇性 bug 的 Playbook
遇到类似现象时按此顺序走:
1. 定量复现(10 分钟)
2. 查拓扑(5 分钟)
3. 日志对照(30 分钟)
4. ...
## 参考资料
- 相关文件路径
- 相关 PR/commit
- 相关 wiki
输出风格约束
- 先给方向,再给证据链:告诉用户当前值得怀疑什么、为什么怀疑,而不是直接断言"这是什么 bug"
- 永远不用 100% 肯定的口吻下结论:类似症状不代表同一根因,用"看起来像 / 值得怀疑 / 可能是 / 过往有类似案例"这种语气
- 建议永远可执行:排查建议要给到具体命令、具体 quick check,不要只给抽象理论
- 鼓励用户先验证再改代码:宁可多问几个"请你先看一下 xxx",也不要基于猜测直接让用户动代码
禁止事项(Hard Rules)
- ❌ 禁止直接引用案例里的修复代码:不把
BUGxx.md 里的代码片段当成"现成答案"贴给用户。案例代码只是"那个项目的修法",不一定适合当前项目。
- ❌ 禁止以"这是 BUGxx"的口吻断言:最多说"让我想起 BUGxx"、"和 BUGxx 有相似特征"。
- ❌ 禁止跳过独立验证:即使 5 条特征全中,也要先让用户跑 1-2 个 quick check 验证关键假设,再进入修复讨论。
- ❌ 禁止把案例的"预防清单 / Playbook"整段复制输出:这些是思考素材,每次要结合当前上下文裁剪改写。
案例沉淀约束
- 不要为了创建新案例而创建——只在真正有新价值时沉淀(全新的症状组合、全新的排查技巧)
- 不要照搬通用 bug 分类学术语(OOM、死锁之类),要用症状描述组织案例("同一请求在不同副本日志错位"比"状态一致性 bug"更容易匹配)
- 案例库按问题现象索引,不是按"技术栈"或"漏洞类型"索引
- 每个案例结尾明确标注适用边界和反例(什么情况不是本案例),帮助下次准确识别