bug-pattern-diagnosis

根据用户描述的 bug 现象(症状)匹配已沉淀的 bug 案例库,快速判断这是哪类问题、根因在哪、如何排查。每次成功诊断后会把新案例沉淀到案例库,持续积累经验。适用于用户报告"奇怪的报错 / 间歇性失败 / 某些环境才复现 / 日志很诡异"的场景。

Audits

Pass

Install

openclaw skills install bug-pattern-diagnosis

Bug Pattern Diagnosis (Bug 症状诊断与经验沉淀)

Skill 职责

这个 Skill 的作用是像医生看病一样做 bug 诊断

  1. 收集症状:让用户描述 bug 的表现(报错信息、复现率、环境、日志特征等)
  2. 回忆过往:去 experience/ 目录下翻阅以前遇到过的类似 bug,作为经验记忆参考
  3. 独立诊断:结合当前上下文自主排查,过往案例只作为思路启发和假设来源,绝不直接复用结论
  4. 沉淀新经验:每次成功定位新 bug 后,把它作为新的 BUGxx.md 写进案例库,供下次参考

核心价值:让过往踩坑的经验启发下次排查的方向,但不替代独立思考。相似症状不一定是同一个 bug,看起来一样的日志背后可能是完全不同的根因。

铁律:经验是参考,不是答案

这是本 Skill 最核心的使用原则。

案例库里的 BUGxx.md老医生的病历本,不是处方模板。拿到新患者:

  • 可以做的:从病历本获取"这类症状通常值得怀疑什么"、"以前用什么方法查出过"、"有哪些容易踩的坑"
  • 不能做的:看到症状类似就直接抄根因、抄修复方案、抄代码改动

为什么不能直接引用

  1. 症状可以相似,根因可能完全不同:同样是"NPE + 间歇性 + 多副本",可能是本次的 header 漏传,也可能是 Redis 连接池偶发失败、也可能是 GC stop-the-world 期间的竞态,更可能是几种问题叠加
  2. 项目环境差异巨大:同样的代码结构在不同版本、不同配置、不同依赖下行为可能迥异。
  3. AI 误判代价高:直接按案例照抄会让用户基于错误前提改代码,排查路径被带偏,真正的 bug 反而被掩盖。
  4. 经验的价值在于"启发思考"而非"给答案":好医生看病历是为了拓展思路,不是为了复制粘贴。

正确的使用姿势

场景错误做法正确做法
症状匹配度高"这是 BUG01,改 invokeRemoteDeviceOptx-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 都按固定结构写,方便快速检索:

  1. 案例摘要(一句话)
  2. 症状 / 特征速查(像病例的"阳性体征",用于匹配)
  3. 详细说明(病理机制 / 根因链路)
  4. 排查方法论(诊断流程 / 关键技术)
  5. 修复方案(根治 + 兜底 + 加固)
  6. 预防清单(Checklist 防止复发)
  7. 同类 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 里的 .classjavap -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"更容易匹配)
  • 案例库按问题现象索引,不是按"技术栈"或"漏洞类型"索引
  • 每个案例结尾明确标注适用边界反例(什么情况不是本案例),帮助下次准确识别