核心目标

当 E2E 测试失败时,AI 不应该盲目尝试,而应该科学诊断假设推导有针对性地改进

本 skill 定义了一套系统的诊断框架,让 AI 能够:

  1. 从失败现象中识别根本原因
  2. 基于根本原因生成改进假设
  3. 按优先级设计改进方案
  4. 预测改进的可能效果

诊断框架:5 Why + 科学方法

第一步:获取完整的失败信息

当 E2E 测试失败时,不要只看结果,要收集完整的诊断包:

{
  "test_name": "test_search_with_large_dataset",
  "expected": "response_time < 100ms",
  "actual": "response_time = 245ms",
  "failure_type": "timeout",
 
  "diagnostic_data": {
    "metrics": {
      "response_time": 245,  // 实际时间
      "data_size": 1000000,  // 处理的数据量
      "concurrency": 1,      // 并发度
      "cache_hit_rate": 0.15 // 缓存命中率
    },
 
    "time_breakdown": {
      "db_query": 180,       // 占 73%
      "network": 30,         // 占 12%
      "processing": 35       // 占 14%
    },
 
    "logs": [
      "Query executed: SELECT * FROM users WHERE name LIKE '%pattern%'",
      "Scanned 1000000 rows, returned 5000 rows",
      "No index on 'name' column"
    ],
 
    "code_path": [
      "searchHandler() -> query() -> db.execute()",
      "Line 45: for loop iterating through results (5000 iterations)"
    ]
  }
}

关键点

  • ❌ 不要只看 response_time = 245ms 就开始改
  • ✅ 要看 time_breakdown,知道瓶颈在哪
  • ✅ 要看日志,知道发生了什么
  • ✅ 要看代码路径,知道怎么发生的

第二步:诊断根本原因(5 Why)

使用5 Why 方法,但不是简单地问 5 次”为什么”,而是根据领域知识来推导。

示例 1:查询超时(数据库)

观察:response_time = 245ms,db_query = 180ms(瓶颈)

第 1 个 Why:为什么数据库查询这么慢?
→ 日志显示扫描了 1,000,000 行,但只返回 5,000 行

第 2 个 Why:为什么要扫描这么多行?
→ SQL 是 SELECT * FROM users WHERE name LIKE '%pattern%'
→ 没有在 'name' 列上建索引

第 3 个 Why:为什么没有索引?
→ 需要查询历史,是设计疏漏还是最近才加的字段?

根本原因:
✅ 直接原因:缺少索引导致全表扫描
✅ 根本原因:查询条件设计时没有考虑索引

诊断结论

Root Cause: Full table scan due to missing index
Confidence: 95% (clear evidence in logs)
Impact: 180ms / 245ms = 73% of total time

示例 2:查询超时(算法)

观察:response_time = 245ms,processing = 100ms(瓶颈)

第 1 个 Why:为什么处理这么慢?
→ 代码路径显示:for loop iterating through 5000 results

第 2 个 Why:为什么需要遍历 5000 个结果?
→ 在内存中做了一个 O(n²) 的排序操作

第 3 个 Why:为什么不用更高效的算法?
→ 可能原因:历史遗留代码,或者没有意识到性能问题

根本原因:
✅ 算法复杂度过高(O(n²) 对 5000 条数据)
✅ 应该用 O(n log n) 的排序或 O(1) 的哈希查找

诊断结论

Root Cause: O(n²) algorithm on 5000 items
Confidence: 90%
Impact: 100ms / 245ms = 41% of total time
Opportunity: Could reduce to < 10ms with better algorithm

第三步:生成改进假设

关键原则:基于根本原因,生成有针对性的假设,而不是随意猜测。

假设的三层级别

假设层级:
  - 高置信度假设(90%+ 成功率)
  - 中置信度假设(70-90% 成功率)
  - 低置信度假设(< 70% 成功率)

示例:缺少索引的情况

根本原因:缺少索引导致全表扫描

假设 1(高置信度):在 'name' 列上添加索引
  - 预期效果:db_query 从 180ms 降至 20-30ms
  - 理由:索引可以让查询从 O(n) 变为 O(log n)
  - 成功条件:扫描行数从 1M 降至 < 1000
  - 副作用:插入/更新会慢一点,但可接受
  - 实施难度:低(一行 SQL)

假设 2(中置信度):改进查询 SQL
  - 预期效果:db_query 从 180ms 降至 80ms
  - 理由:使用更精确的 WHERE 条件而不是模糊查询
  - 成功条件:返回行数从 5000 降至 < 100
  - 副作用:可能改变搜索结果,需要验证
  - 实施难度:中(需要改应用逻辑)

假设 3(低置信度):换数据库
  - 预期效果:可能有些帮助
  - 理由:不明确,而且投入产出比太低
  - 建议:不值得尝试

第四步:假设排序(按 ROI)

ROI = (预期效果) × (成功概率) / (实施成本)

假设 1:(180 - 20) ms × 90% / 1 = 144 得分
假设 2:(180 - 80) ms × 70% / 5 = 14 得分
假设 3:不列入考虑

优先级:假设 1 >> 假设 2

决策

第 1 轮:先实施假设 1(索引)
  - 如果成功:问题解决 ✓
  - 如果失败:继续诊断,可能是其他原因

第 2 轮:如果假设 1 失败,重新诊断
  - 是索引没有生效?
  - 还是有其他瓶颈?
  - 再考虑假设 2

常见问题的诊断模板

问题 1:查询超时

快速诊断检查清单

□ 确认是 DB 瓶颈还是其他?
  → 看 time_breakdown,DB 是否占比 > 50%?

□ 如果是 DB,是全表扫描吗?
  → 看日志的 "Scanned rows" vs "Returned rows"
  → 比率 > 100 表示全表扫描

□ 是否有相关索引?
  → 查询 EXPLAIN PLAN
  → 或搜索表的索引定义

□ 数据量是否增长了?
  → 比较历史数据量
  → 是否到达了某个临界点?

□ SQL 本身是否可以优化?
  → 有没有 JOIN 太多表?
  → 有没有 SELECT * 而不需要所有列?
  → WHERE 条件是否有歧义?

诊断结果示例:
  "Type: Full table scan on users table"
  "Evidence: Scanned 1M rows, returned 5K rows"
  "Fix: Add index on (name)"
  "Expected gain: 90%+ improvement"

问题 2:内存溢出

快速诊断检查清单

□ 当前内存占用是多少?
  → 看 metrics.memory_used vs limit

□ 在哪一行代码开始上升?
  → 看内存监测数据的时间线
  → 对应代码执行的顺序

□ 是否是数据结构问题?
  → 一次性加载太多数据到内存?
  → 应该用流式处理或分页?

□ 是否有内存泄漏?
  → 是否有对象没有被释放?
  → 看对象生命周期

□ 数据量是否合理?
  → 应该处理这么多数据吗?
  → 还是查询条件写得太宽泛?

诊断结果示例:
  "Type: Excessive data loading"
  "Evidence: Loading 100GB of data into memory for processing"
  "Fix: Use streaming/pagination to process in chunks"
  "Expected gain: Memory from 100GB down to < 1GB"

问题 3:准确率下降

快速诊断检查清单

□ 准确率具体下降了多少?
  → baseline: 95% → current: 92%

□ 是所有场景都下降,还是特定场景?
  → 看 test case 的维度:
    - 新用户 vs 老用户?
    - 冷启动 vs 热启动?
    - 特定数据分布?

□ 最近改了什么代码?
  → 对比最近 commit
  → 哪些改动可能影响准确率?

□ 是否是训练数据问题?
  → 数据分布变了吗?
  → 是否需要重新训练?

□ 是否是边界情况被遗漏了?
  → 新增的测试用例暴露了什么?
  → 是否应该增强算法的鲁棒性?

诊断结果示例:
  "Type: Model drift due to data distribution change"
  "Evidence: Accuracy 95% → 92%, specifically on high-value products"
  "Root cause: Product catalog expanded, new categories not in training data"
  "Fix: Retrain model with new data or add fallback logic"
  "Expected gain: Recovery to 95%+"

迭代策略:快速逼近目标

策略 1:二分搜索策略

参数可调整时(如缓存大小、超时时间、批处理大小),用二分搜索快速找最优值:

目标:延迟 < 100ms,目前 245ms

参数:batch_size(批处理大小)
  初始值:1000

迭代 1:尝试 batch_size = 500
  → 延迟 = 180ms(进步,但不够)

迭代 2:尝试 batch_size = 250
  → 延迟 = 120ms(接近了)

迭代 3:尝试 batch_size = 300
  → 延迟 = 105ms(超过了)

迭代 4:尝试 batch_size = 280
  → 延迟 = 98ms(达到!)

最优值:batch_size = 280
花费时间:4 次迭代(快速收敛)

适用场景

  • 缓存大小
  • 连接池大小
  • 超时时间
  • 批处理大小

策略 2:分层改进策略

有多个可能的改进时,分层进行,每层都要有收益验证

目标:响应时间 245ms → < 100ms

第 1 层(必做):消除明显的瓶颈
  改进 1.1:加数据库索引
    预期:180ms → 30ms
    实测:180ms → 35ms(接近预期)
  改进 1.2:优化 SQL 查询
    预期:35ms → 20ms
    实测:35ms → 22ms
  结果:245ms → (245 - 180 + 22) = 87ms ✓ 达到目标

如果目标没达到,继续第 2 层:

第 2 层(细化优化):微调和优化细节
  改进 2.1:连接池优化
  改进 2.2:缓存策略
  ...

关键原则

  • ✅ 先解决 80% 的问题(找到最大瓶颈)
  • ✅ 再优化剩下的 20%
  • ✅ 每次改进都要验证效果
  • ❌ 不要一次尝试太多改动(无法判断哪个有效)

策略 3:假设验证策略

原因不确定时,用对比实验快速验证假设:

假设:缓存命中率低导致性能差

验证方案 1(成本低):
  - 在 badcase 中打印缓存命中率
  - 对比成功 case 的缓存命中率
  - 如果有显著差异,假设成立

验证方案 2(成本中):
  - 临时禁用缓存,看性能是否改善
  - 如果禁用缓存后性能更差,假设成立

验证方案 3(成本高):
  - 改进缓存策略,重新测试
  - 如果性能改善,假设确认

优先级:1 → 2 → 3

AI 的诊断决策流程

E2E 测试失败
  ↓
[步骤 1] 收集诊断数据
  ├─ time_breakdown: 找到最大瓶颈
  ├─ logs: 理解发生了什么
  ├─ code_path: 知道在哪里发生的
  └─ metrics: 量化观察
  ↓
[步骤 2] 识别根本原因(使用诊断模板)
  ├─ 是数据库问题?
  ├─ 是算法问题?
  ├─ 是内存问题?
  ├─ 还是其他?
  └─ 用 5 Why 确认
  ↓
[步骤 3] 生成改进假设(按 ROI 排序)
  ├─ 假设 1(高置信度)
  ├─ 假设 2(中置信度)
  ├─ 假设 3(低置信度)
  └─ 选择 ROI 最高的
  ↓
[步骤 4] 设计改进方案
  ├─ 决定实施哪个假设
  ├─ 预测改进效果
  ├─ 规划验证方案
  └─ 开始实施
  ↓
[步骤 5] 验证和迭代
  ├─ 如果成功 → 进入下一个瓶颈
  ├─ 如果失败 → 回到步骤 2,重新诊断
  └─ 每次改动都要测试

实践例子:端到端演示

场景:推荐系统的转化率优化

初始状态:
  目标:转化率 > 15%
  实际:转化率 = 12.5%
  缺口:2.5 个百分点

E2E 测试失败,需要诊断...

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
第 1 轮迭代
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

[诊断]
  问:用户在哪一步流失的?
  答:分析显示,用户看到推荐但点击率低(5% vs 历史 10%)

  问:推荐的准确度怎么样?
  答:通过 badcase 分析,发现推荐了很多「不相关」的商品

  根本原因:推荐算法的准确度下降了

[假设生成]
  假设 1:推荐模型过时了,需要重新训练
    - 成功率:80%
    - 实施成本:2 小时
    - ROI 分数:高

  假设 2:推荐特征工程有问题,某些特征失效了
    - 成功率:60%
    - 实施成本:1 小时
    - ROI 分数:中

  优先级:假设 1

[改进实施]
  执行:重新用最新数据训练推荐模型

[验证]
  新的推荐相关性评分:0.72 → 0.85
  用户点击率:5% → 8.5%
  转化率:12.5% → 13.2%

  结果:进步了 0.7 个百分点,但还没到 15%

决策:继续迭代

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
第 2 轮迭代
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

[诊断]
  问:点击了推荐,但为什么没有转化?
  答:分析显示,用户点击后看到了商品详情,但没有下单

  问:是商品价格问题,还是其他?
  答:badcase 分析显示,推荐的商品大多是「高价商品」,
      与用户历史购买价格不符

  根本原因:推荐的商品与用户消费能力不匹配

[假设生成]
  假设 1:推荐时加入「用户价格偏好」特征
    - 成功率:85%
    - 成本:1 小时
    - ROI 分数:高

  假设 2:推荐前做「用户分层」,分别用不同策略
    - 成功率:70%
    - 成本:3 小时
    - ROI 分数:中

  优先级:假设 1

[改进实施]
  执行:在推荐特征中加入「user_price_preference」

[验证]
  推荐商品的平均价格与用户偏好的匹配度:0.65 → 0.88
  转化率:13.2% → 14.8%

  结果:进步了 1.6 个百分点,接近目标!

决策:继续微调

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
第 3 轮迭代(微调)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

[诊断]
  缺口:0.2 个百分点
  通过 A/B 测试和细粒度分析,发现:
  - 新用户的转化率特别低(推荐不准确)
  - 重复购买用户的转化率接近目标

  根本原因:新用户的数据不足,模型对新用户的推荐不准确

[假设生成]
  假设 1:对新用户使用「热启动」策略
    - 基于相似用户的购买行为推荐
    - 成功率:75%
    - 成本:1.5 小时

  假设 2:对新用户显示「热销品」而非个性化推荐
    - 成功率:60%
    - 成本:0.5 小时

  优先级:假设 1

[改进实施]
  执行:对新用户实施基于相似用户的推荐

[验证]
  新用户转化率:8% → 11%
  整体转化率:14.8% → 15.2%

  结果:达到目标!✓

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
总结
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

目标:12.5% → 15.2%(+2.7 个百分点)

迭代次数:3 次
总投入时间:4.5 小时
改进的维度:
  1. 推荐准确度(模型重训)
  2. 用户消费能力匹配(特征工程)
  3. 新用户冷启动(策略优化)

关键:
- ✅ 每次迭代都有**科学的根本原因分析**
- ✅ 每次改进都有**量化的预期和实测对比**
- ✅ 不是随意尝试,而是**基于诊断的有针对性改进**
- ✅ 快速逼近目标,投入产出比高

何时应用本 Skill

应该用

  • E2E 测试失败,需要理解为什么
  • 有明确的指标目标,需要逐步优化
  • 想要快速逼近目标,而不是随意尝试
  • 需要与人类沟通改进思路

不需要

  • 需求还不明确的探索阶段
  • 没有可靠的诊断数据
  • 简单的功能bug(可以直接看代码修复)

与 ralph-loop 的配合

本 Skill 与 ralph-loop 的配合方式:

ralph-loop --max-iterations 10 \
  "Optimize conversion rate to 15% using E2E-diagnostic-skill"

在每一次迭代中,AI 都应该:
1. 运行 E2E 测试(得到失败信息)
2. 应用本 Skill 诊断(找到根本原因)
3. 基于诊断生成改进方案
4. 实施改进并验证
5. 如果达到目标或陷入困境,反思是否需要人类介入

检查清单:验证诊断的质量

在每次诊断时,问自己:

□ 我看到的是「现象」还是「根本原因」?
  - 现象:查询慢
  - 根本原因:没有索引导致全表扫描

□ 我的假设是基于「事实」还是「直觉」?
  - 直觉:可能是内存问题
  - 事实:time_breakdown 显示 DB 占 73%

□ 我的改进方案有「成功标准」吗?
  - 模糊:优化一下
  - 清晰:db_query 从 180ms 降至 < 30ms

□ 我考虑过「副作用」吗?
  - 索引会让写操作变慢
  - 改算法可能改变结果准确度

□ 我的 ROI 计算是否合理?
  - 收益和成本都量化了吗?
  - 相比其他改进,这个是最优的吗?

持续改进本 Skill

随着实践的进行,记录:

  1. 哪些诊断方法最有效?
  2. 哪些假设生成策略最能快速逼近目标?
  3. 有没有新发现的瓶颈类型?
  4. 是否需要加新的诊断模板?

定期更新本文档,让 Skill 随着经验不断进化。