| name | structured-analyze |
| description | 系统性技术问题诊断框架。通过"边界收敛→分支诊断→假设验证→证据链→方案决策"五步法,将试错式排查变为结构化分析。当用户说"分析这个问题"、"报错了帮我看看"、"定位一下根因"、"帮我分析一下这个现象"、"这个Bug怎么查"、"内存泄漏/崩溃/性能退化/死锁怎么定位"、或描述了任何软件异常现象时触发。不用于产品需求分析或日常决策(那是 structured-thinking 的范畴)。 |
问题诊断分析 — 结构化诊断框架
定位
structured-thinking 解决决策类问题(做什么、值不值得做),本 skill 解决诊断类问题(哪里出了问题、怎么最快修)。
核心思路:不是拿到问题就开始翻代码或抓 dump,而是先分边界,再定策略,再并行验证。把试错循环变成收敛过程。
三个关键规则
- 先分边界,再查代码 — 问题可能根本不在算法里,输入/软件/硬件都可能是原因。确定归属后再深入,不浪费时间看无关代码。
- 假设并行验证 — 互不依赖的假设同时执行,不串行试错。
- 日志不足时,精确建议收集方向 — 不说"需要更多日志",说"需要在 X 时刻抓 Y 日志,关键字段是 Z"。
辅助工具:需要深入分析日志时可用 log-analyze skill,但本框架不强制依赖它。
四层边界
输入侧 — 参数值/操作序列/输入数据本身是否合理?
软件侧 — 参数的流转路径是否正常?(加载→传递→生效→存储)
算法侧 — 在给定参数下,算法内部计算是否符合预期?
硬件侧 — 物理设备/环境是否正常?
判定优先级:输入 > 软件 > 算法 > 硬件。输入问题最常见也最快确认,硬件问题最耗时。
工作流程
阶段零 边界收敛(迭代式)
这是最关键的阶段。一个常见陷阱是:拿到问题直接翻代码。正确做法是先用现有证据判定归属。
Step 0: 确认已有证据(必须先执行)
分析前必须确认用户手头有什么。不要假设有日志。
逐项询问:
- 有问题描述吗?(现象、时间、频率、操作步骤)
- 有软件日志吗?(应用运行日志、配置日志、错误日志、操作审计日志)
- 有算法日志吗?(匹配过程、评分、中间状态、候选输出)
- 有其他可用数据吗?(截图、现场照片、dump、硬件SDK日志、性能监视器)
然后标注每层判定受限于什么:
| 有完整日志 | 该层判定置信度高 |
|---|
| 只有问题描述 | 该层可以基于现象推理,但置信度低 |
| 什么都没有 | 所有分析基于现象推理,标注置信度低,同时输出"需要收集的最小证据集" |
一个例子:如果用户只描述了现象但无日志,那你仍然可以做推理(像 RMS case 里基于因果关系推断输入侧问题),但必须标注"置信度:中,待日志验证"。
第1轮:逐层判定
按输入→软件→算法→硬件的优先级逐层检查:
┌─ 输入侧检查 ─────────────────────────────────────────────────┐
│ │
│ 关键词:参数值、配置项、操作序列、输入数据 │
│ │
│ 查什么: │
│ - 被修改的参数/配置值本身是否合理? │
│ - 操作序列是什么?谁在什么时候做了什么? │
│ - 输入数据本身是否合法?(格式、范围、编码) │
│ │
│ 判定信号: │
│ - 参数值不合理(min > 正常值 → 排除正确结果) │
│ - 操作序列有误(改了值但语义理解错了) │
│ - 输入数据异常(格式错误、超范围) │
│ │
│ → 命中任一 → 归属"输入侧",跳至阶段一输入分支 │
└──────────────────────────────────────────────────────────────┘
┌─ 软件侧检查 ─────────────────────────────────────────────────┐
│ │
│ 关键词:参数传递、配置加载、状态机、生效规则 │
│ │
│ 查什么: │
│ - 参数从输入到使用的完整链路:UI → 存储 → 加载 → 算法 │
│ - 配置变更后是否立即生效?是否需重启? │
│ - 多个配置源之间是否一致?(UI/配置文件/数据库) │
│ - 状态机是否在合法状态下接收了参数变更? │
│ - 软件日志中的错误/告警/异常状态 │
│ │
│ 判定信号: │
│ - 配置加载失败或加载了错误的值 │
│ - 配置变更未生效(依赖重启但未重启) │
│ - 多配置源不一致(UI 显示值 ≠ 算法使用值) │
│ - 状态机处于异常状态导致参数处理错误 │
│ │
│ → 命中任一 → 归属"软件侧",跳至阶段一软件分支 │
└──────────────────────────────────────────────────────────────┘
┌─ 算法侧检查 ─────────────────────────────────────────────────┐
│ │
│ 关键词:匹配评分、中间结果、错误码 │
│ │
│ 查什么: │
│ - 算法日志中的候选评分/迭代次数/中间状态 │
│ - 给定输入(含参数约束),输出是否符合算法设计预期? │
│ - 是否有错误码或异常状态? │
│ │
│ 判定信号: │
│ - 给定合理输入和正确参数,算法输出错误 │
│ - 边界条件未处理(空输入、极值、重复执行) │
│ - 算法输出了错误码或异常状态 │
│ │
│ → 命中任一 → 归属"算法侧",跳至阶段一算法分支 │
└──────────────────────────────────────────────────────────────┘
┌─ 硬件侧检查 ─────────────────────────────────────────────────┐
│ │
│ 关键词:相机状态、通信链路、信号时序、驱动版本 │
│ │
│ 查什么: │
│ - SDK日志中的设备状态/错误码/心跳 │
│ - 系统事件日志(设备断开、驱动错误) │
│ - 已知的驱动/固件兼容性问题 │
│ │
│ 判定信号: │
│ - SDK报告设备异常或断开 │
│ - 通信超时/丢包 │
│ - 信号时序异常 │
│ │
│ → 命中任一 → 归属"硬件侧",跳至阶段一硬件分支 │
└──────────────────────────────────────────────────────────────┘
第 1 轮判定结果
- 能判定归属 → 进入对应分支诊断(阶段一)
- 不能判定 → 输出"进一步收集建议",明确告诉用户需要补什么证据。例如:
- 怀疑输入侧 → "需要抓取 X 时刻的配置变更日志,确认 RMS 范围参数是否被修改"
- 怀疑软件侧 → "需要确认参数从 UI 到算法的完整流转路径,检查是否有多配置源不一致"
- 怀疑算法侧 → "需要开启 debug 级别日志,重放同一板件,对比正常/异常的候选评分"
- 怀疑硬件侧 → "需要现场抓取相机 SDK 日志,确认图像采集链路状态"
第2轮及以后
用户补充新证据后,重新执行判定。边界越来越清晰,直到锁定归属。
输出格式
## 阶段零:边界收敛
### Step 0: 已有证据确认
- 问题描述:[有/无] — [概括]
- 软件日志:[有/无] — [概括]
- 算法日志:[有/无] — [概括]
- 其他数据:[有/无] — [概括]
- 数据限制:[哪些层的判定因缺数据置信度降低]
### 逐层判定
- 输入侧:[通过/可疑/排除] — [理由] — 置信度: [高/中/低]
- 软件侧:[通过/可疑/排除] — [理由] — 置信度: [高/中/低]
- 算法侧:[通过/可疑/排除] — [理由] — 置信度: [高/中/低]
- 硬件侧:[通过/可疑/排除] — [理由] — 置信度: [高/中/低]
### 结论
- 问题归属:[输入/软件/算法/硬件/待定]
- 置信度:[高/中/低]
### 进一步收集建议(如果待定)
- [精确的日志/数据收集建议,含时间点、关键字段]
阶段一 分支诊断
根据阶段零的归属,进入对应分支。四个分支的诊断策略完全不同。
输入分支
目标:确认是操作失误、配置缺陷还是输入数据本身有问题。
诊断路径:
1. 参数传递链路追踪
→ 输入端 → 存储位置 → 读取时机 → 使用位置
→ 关键词:config/param/setting/limit/threshold
2. 变更时间线重建
→ 从日志时间点倒推:谁在什么时刻改了什么值
→ 对比修改前后的运行结果
3. 默认值与生效规则
→ 未配置时使用什么默认值?默认值是否合理?
→ 配置变更后是否立即生效?是否需重启?
4. 多配置源一致性
→ 同一个参数是否有多个配置入口(UI/配置文件/数据库/命令行)?
→ 不同入口的值是否一致?哪个优先级最高?
输出: 非Bug(操作/配置问题)或 输入校验缺陷
软件分支
目标:确认参数的完整流转路径是否正常。即使输入值本身是合理的,软件在加载/传递/生效过程中也可能出问题。
诊断路径:
1. 参数传递链路追踪
→ 输入端(UI/配置文件/数据库) → 存储位置 → 读取时机 → 使用位置(算法入口)
→ 关键词:config/param/setting/limit/threshold
2. 变更生效规则
→ 配置变更后是否立即生效?是否需重启或触发重载?
→ 如果需重启,操作员是否知晓?
3. 多配置源一致性
→ 同一个参数是否有多个配置入口(UI/配置文件/数据库/命令行)?
→ 不同入口的值是否一致?哪个优先级最高?
→ 操作员在UI上改的值和算法实际读到的值是否相同?
4. 状态机上下文
→ 参数变更时系统是否在合法状态?
→ 是否在运行中/暂停/停止等状态下有不同的参数处理逻辑?
5. 默认值与回退逻辑
→ 未配置时使用什么默认值?默认值是否合理?
→ 非法值时是否回退到默认?回退逻辑是否被正确触发?
输出: 配置加载缺陷 / 参数传递断裂 / 多源不一致 / 生效时序问题
算法分支
目标:定位到具体的算法步骤、状态或逻辑。
诊断路径:
1. 日志对比(最快)
→ 同一输入,正常场景 vs 异常场景的算法日志对比
→ 找到第一个分叉点:在哪里输出开始不同?
2. 中间状态检查
→ 算法各阶段的中间结果是否在预期范围?
→ 状态机是否在合法状态?
3. 版本影响评估
→ 最近有算法变更吗?diff 了什么?
→ 回退到旧版本能否复现?
4. 边界条件覆盖
→ 空输入、极端值、重复执行 → 是否触发未知路径?
5. 控制变量(兜底)
→ 只改一个参数/输入,其余不变,观察输出
→ 二分法缩小可疑代码范围
输出: 逻辑Bug / 边界条件缺陷 / 异常路径未处理 / 版本引入
硬件分支
目标:确认是硬件故障,还是驱动/环境问题。
诊断路径:
1. SDK/驱动日志
→ 设备状态码、错误计数、心跳中断时间点
→ 重连次数、超时频率
2. 系统事件日志(evtx / dmesg / syslog)
→ 设备断开/重连事件
→ 驱动加载失败/崩溃事件
3. 环境交叉对比
→ 同一硬件在不同机器/不同版本的同一软件上的表现
→ 同型号其他设备是否有相同现象?
4. 性能监视器(blg / perf)
→ CPU/内存/磁盘/网络趋势
→ 资源耗尽时间和问题出现时间的对齐
5. 现场环境检查
→ 线缆、电源、交换机端口统计
→ 温度、振动、EMC干扰
输出: 硬件故障 / 驱动兼容性 / 环境干扰 / 间歇性连接
输出格式
## 阶段一:分支诊断 — [输入/软件/算法/硬件]
### 诊断路径
[根据具体情况选择1-N个路径]
### 发现
- [证据1]:来源 + 说明
- [证据2]:来源 + 说明
### 判定
- 类型:[操作问题 / 配置缺陷 / 参数传递断裂 / 算法Bug / 边界条件 / 硬件故障 / ...]
- 置信度:[高/中/低]
- 是否终止(非Bug):[是/否]
阶段二 假设驱动验证
当阶段一无法直接锁定根因时,进入假设驱动验证。分两步:先发散(列出所有可能根因,不急于收敛)→ 后验证(并行排查、逐个排除)。
核心原则:互不依赖的假设并行验证,不串行试错。
第一步:发散 — 生成假设池
在列出假设之前,先用几个角度做脑力激荡,确保不遗漏。不要在这一阶段就自我审查——"不太可能"的想法也先列进来。
从以下角度逐一扫一遍,遇到可能相关的就生成一个假设:
- 常规原因 — 阶段一指向的最可能方向的直接推导。最容易被首先想到,也是最该最先验证的。但验证完后,如果排除了,不要在此打住。
- 历史类比 — 这个问题/类似问题以前出现过吗?上次根因是什么?当时的修复是否完整?本次现象是否和上次完全相同?
- 时序相关 — 问题是否有时序特征?(改了参数后立刻触发 vs 等了几秒、连续运行几天后才出现、只在启动/退出时出现)→ 时序可能暗示资源累积、竞态、预热等方面的原因。
- 多因素交互 — 是不是两个条件同时满足才触发?(改参数 + 特定板件、改参数 + 特定流程步骤、特定相机 + 特定光照)→ 单看每个条件都不足以触发
- 隐藏假设 — 分析过程中默认假设了什么?这些假设一定成立吗?("参数修改后立即生效"、"算法读到的值和 UI 显示的相同"、"同一型号的所有设备行为一致")
- 最近变更 — 版本、配置、驱动、环境最近改了什么?变更是什么时候的?和问题出现时间是否对齐?
实践提示:发散阶段不要急于评判假设的合理性。列出所有候选后,再按可能性排序。一个不成立 → 立即检验下一个。
第二步:假设卡片
将发散阶段产生的每个可能根因具象化为可验证的假设卡片:
## 假设1: [简短描述]
- **可能性**: [高/中/低] — [依据]
- **排除条件**: [什么证据可以证明此假设不成立]
- **验证实验**: [最小验证动作 — 可以是一次日志查询、一次重放测试、一次参数修改]
- **互不依赖**: [是/否] — [与哪些假设互斥]
第三步:并行执行
- 互不依赖的假设 → 同时验证,不分先后
- 互斥的假设(A 成立 B 就不成立)→ 先验证置信度高的
第四步:逐个排除
每个验证实验完成后:
- 假设成立 → 标记"存活"
- 假设不成立 → 记录排除原因
输出格式
## 阶段二:假设验证
### 发散脑力激荡
[从常规原因/历史类比/时序/多因素/隐藏假设/最近变更角度,列出所有可能根因]
### 假设池
假设1: [描述] — 可能性: [高/中/低]
假设2: [描述] — 可能性: [高/中/低]
...
### 验证结果
- 假设1: [存活/排除] — [证据]
- 假设2: [排除] — [证据]
...
### 存活假设
[未排除的假设列表,按置信度排序]
阶段三 证据链收敛
汇总所有证据,锁定单一根因。
验证结果汇总
↓
排除不成立的假设(记录排除原因)
↓
存活假设排序(置信度从高到低)
↓
单一根因被证据链锁定?
├── 是 → 输出根因
└── 否 → 标注"待补充证据"
→ 建议下一轮要收集什么
→ 退回阶段零
输出格式
## 阶段三:证据链收敛
### 根因
[一句话描述根本原因]
### 证据链
1. [证据1] — 来源: [日志文件:行号/时间戳/工具输出]
2. [证据2] — 来源: [...]
3. [证据3] — 来源: [...]
### 已排除假设
- 假设X: 排除原因 — [证据]
### 待补充(如果无法锁定)
- [需要进一步收集的证据]
阶段四 方案决策
根因锁定后,梳理修复方案池。同时回答两个问题:
- 怎么修?
- 后续生产是否还会出现?如何预防?
修复方案池 → 风险/工作量/效果评分 → 推荐路径 → 第一步动作
每个方案评估维度:
- 风险: 引入新问题的概率(低/中/高)
- 工作量: 人天估算
- 效果: 根除(解决所有场景) / 规避(解决当前场景) / 减轻(降低概率)
- 验证: 如何确认修复有效
输出格式
## 阶段四:方案决策
| 方案 | 描述 | 风险 | 工作量 | 效果 | 验证方式 |
|------|------|------|--------|------|----------|
| A | ... | 低 | 0.5天 | — | ... |
| B | ... | 中 | 2天 | — | ... |
### 推荐
- **立即**: [方案A]
- **后续**: [方案B/C]
- **预防**: [防止类似问题再出现的措施]
### 第一步
[今天/本周立即可以执行的最小动作]
阶段五 归档(可选)
仅在用户明确说"总结"、"归档"、"沉淀"、"写报告"时触发。报告模板:
【问题名称】:...
【问题表象】:...
【原因解析】:...
【影响范围】:...
【修改方式】:...
【排查过程】:...(按时间或逻辑顺序,引用实际日志/证据)
【经验总结】:...
输出要求
- 语言:中文
- 风格:每条结论都锚定到具体证据
- 置信度必须标注,无证据时写"待验证"
- 阶段零是必须通过的关卡,不可绕过
- 非Bug问题在阶段一即可终止,不必走完全部阶段
- 不要在阶段零未完成时就开始查代码或抓dump