阅读材料: 应用部分 10. 防止古德哈特定律对指标的扭曲:哨兵指标与应急模式

模块「应用部分 10. 防止古德哈特定律对指标的扭曲:哨兵指标与应急模式」中第 1 / 5 节课
您正在未登录状态下查看课程。 请登录,以保存进度并参加测试。

应用部分 10. 保护指标免受古德哈特定律影响:哨兵指标与紧急模式

状态:建议。 使用成对哨兵指标(guard-метрика)和阻断性紧急模式来保护 KPI 是一种成熟实践,在 Google SRE Book 中有详细描述。具体阈值(silent_p0manual_review_flooraudit_trace_coverage)和 validation.md v1.1 格式是建议性框架,大多数团队会进行适配。

对于学习路径,只需运行 examples/goodhart-validator/ 并观察良好的 MTTR 如何被 silent_p0 的增长所阻断。指标网络、trace 字段和阈值校准属于完整的生产路径。如果下文出现「红色按钮」一词,请将其理解为正式紧急模式的简短别名。

第一卷第 9 部分中,每个检查一个指标就足够了:「评论发布后可见」、「金额不会变负」。但在生产场景 cdn_error_budget_burn 中,同样的逻辑已不够用。来自第 11 部分的代理日志和问题仪表板在发布后显示出矛盾的画面,单一指标变成了诱饵。这里我们将其扩展为成对哨兵指标网络——这是「KPI + 保险指标」的配对,其中后者防止以隐藏损害为代价优化前者。针对此网络所保护的典型操纵行为目录,系统整理于第 20 部分. SDD 反模式

阅读前准备

  • 第一卷基础:第 9 部分教授验证事实而非令人信服的散文;第 20 部分展示流程如何开始保护错误目标。
  • 本地学习案例:cdn_error_budget_burn,因为改进的 MTTR 可能被 silent_p0 的增长所阻断。
  • capstone/ 线索:一个目标指标、一个 guard-指标和一个针对 high_memory_usage 的阻断示例。
  • 首次通过的主要术语:guard-指标和紧急模式(「红色按钮」)。其余——silent_p0manual_review_flooraudit_trace_coverageedge_drift、trace 字段、指标网络——为参考性质,仅在需要用于 capstone/goodhart-note.md 中某一行时才查阅。
  • 可延后内容:指标网络、trace 字段、drift 校准和完整的紧急模式。

目标

到本节结束时,您将构建一个 validation.md,它预先捕获古德哈特定律陷阱,并防止 LLM 事件流水线以 triage 退化为代价改善报告 KPI。

主要收益如下:将指标分为可控目标与不可侵犯的质量不变量。然后为它们固定可验证的阈值、trace 中的证据以及 CI 中的阻断机制。

「诱饵指标」在此指作为信号有用、但若脱离质量不变量单独优化则变得危险的 KPI。KPI(关键绩效指标)是团队希望通过发布改进的关键指标。

此方法延续 SDD 循环:规范、验证标准和迭代在实施变更前固定,而非在获得漂亮结果后事后调整(GitHub Spec Kit Quickstart)。

「当衡量标准成为目标时,它就不再是好的衡量标准」这一效应经典地被称为古德哈特定律(Wikipedia: Goodhart's law)。Google SRE 的 SLO 定义直接基于这种谨慎(SRE Book: Service Level Objectives)。

最小学习场景

学习案例

生产事件 cdn_error_budget_burn,投影到来自 book/part-11-second-feature-phase.md 的学习代理日志。发布将 MTTR 从 660 秒改进到 290 秒,形式上看似成功。但 silent_p0 从 0.02 跃升至 0.18,manual_review_rate 从 0.18 降至 0.12。目标是观察 CI 网关如何捕获此偏移并阻断合并,尽管 MTTR「变绿」。

准备工作

  • book2/examples/goodhart-validator/specs/validation.yaml — 不变量和红色按钮检查。
  • book2/examples/goodhart-validator/fixtures/baseline_metrics.json — 基线(MTTR 660 秒,silent_p0 0.02)。
  • book2/examples/goodhart-validator/fixtures/new_metrics_good.json — 无盲区的改进。
  • book2/examples/goodhart-validator/fixtures/new_metrics_bad.json — 「MTTR 盲区」(290 秒,silent_p0 0.18)。
  • book2/examples/goodhart-validator/fixtures/new_metrics_drift.json — 边缘相关性漂移。
  • book2/examples/goodhart-validator/scripts/run_validation.pycompare_drift.pyci_gate.py

步骤

  1. cd book2/examples/goodhart-validator预期:您位于示例目录,无需额外依赖。
  2. 运行「良好」测试:python3 scripts/run_validation.py --validation specs/validation.yaml --metrics fixtures/new_metrics_good.json。 *预期:返回码 0,状态 PASS,三个不变量均为 OK。*
  3. 运行「MTTR 盲区」:python3 scripts/run_validation.py --validation specs/validation.yaml --metrics fixtures/new_metrics_bad.json。 *预期:返回码 1,red_button_mttr_blindness 触发,manual_review_floorsilent_p0_cap 标记为 FAIL。*

不好: 只看 MTTR — 发布更快,似乎「更好」。

好: 使用不变量运行验证 — 当 silent_p0=0.18 时,「更快」被自动阻断。

  1. 针对 drift 夹具运行漂移测试:python3 scripts/compare_drift.py --baseline fixtures/baseline_metrics.json --new fixtures/new_metrics_drift.json。 *预期:edge_drift > 0.12,返回码 1。*
  2. 对照:同一 compare_drift.py 针对良好指标。 *预期:edge_drift <= 0.12,返回码 0。*
  3. 完整 CI 网关:python3 scripts/ci_gate.py --validation specs/validation.yaml --baseline fixtures/baseline_metrics.json --new fixtures/new_metrics_bad.json。 *预期:返回码 1,reasons 中列出具体违反的不变量,而非笼统的 FAIL。*
  4. 将运行记录为简短的古德哈特反结论:目标指标改善,但 silent_p0_capmanual_review_floor 阻断了发布。 预期:下次针对 MTTR 加速的拉取请求,验证器比较的不是「绿色 vs 旧基线」,而是 vs good/bad/drift 夹具。

如果您已安装 Qwen Code 并需要审查解释,请执行单独的可选步骤:

qwen -p "读取 @fixtures/new_metrics_bad.json 和 @specs/validation.yaml。即使 MTTR=290s,哪个不变量也不能绕过?不要修改文件。" --approval-mode plan

此类输出作为解释有用,但不能替代 run_validation.pycompare_drift.pyci_gate.py

验证事实

步骤 2 返回码为 0,步骤 3 和 4 返回码为 1 并具体指出违反的不变量。步骤 6 在组合网关中显示相同行为。如果 CI 网关放行 new_metrics_bad.json,则验证器配置已弱化 — silent_p0_capmanual_review_floor 阈值被移动。

如何进入 capstone/

capstone/goodhart-note.md 转移一个目标指标、一个 guard-指标和一个阻断示例。如果主要评分案例是 high_memory_usage,请将此运行记录为同一轮廓的古德哈特风险:memory 或 MTTR 不能以 silent_p0、手动审计或 5xx 为代价改善。如果未重新计算,不要转移整个指标网络;对于学习最小值,只需展示改进的 KPI 没有保护性不变量就无法通过。

最小片段:

target_metric: "MTTR <= 5m"

guard_metric: "silent_p0 <= 0.05 and manual_review_rate >= 0.15"
blocked_example: "new_metrics_bad.json"
reason: "MTTR improved, but silent_p0 and manual_review_floor fail"

可审查的追踪

脚本 run_validation.pycompare_drift.pyci_gate.py 将结果写入 stdout,不创建单独的 out/ 目录。对于学习路径,将结果转移到 capstone/goodhart-note.md:目标指标、guard-指标、阻断示例和原因。

如果在您的项目中保存 outputs/goodhart.last-run.txt,它应该是审查的可读附件,而非空标记。在 SDD 中,事实是可复现的命令或可读的工件,而非提交本身的存在。

关键思想

首先确定哪些指标保持为质量不变量,哪些成为优化目标并因此可被操纵。不变量不能被直接压力「改善」:它描述系统的最低可接受状态。不变量示例:

  • 审计完整性;
  • 手动检查比例;
  • silent_p0 的上限(这是未经升级静默关闭的「隐性」关键事件比例)。

优化目标则相反,可以降低或提高,但仅在保护走廊内。MTTR 作为恢复速度指标有用,但作为模型或团队的唯一奖励则危险。

validation.md 中明确区分。MTTR<=5m 可以是目标。而 manual_review_rate>=15%silent_p0<=5%audit_trace_coverage==100% 保留为准入条件。

不好:

> 实现 MTTR 低于 5 分钟。

问题:裸目标无哨兵指标,直通 silent_p0

好:

> MTTR <= 5m AND silent_p0 <= 5% AND manual_review_rate >= 15% AND audit_trace_coverage == 100% — 违反任何条件 = CI_BLOCK

古德哈特陷阱表现为指标成为现实的替代品。系统开始优化测量方式,而非 triage 质量。如果 MTTR 被孤立检查,模型学会更快关闭事件、降低升级比例并避免冗长调查 — 正是这些拖累了平均恢复时间。

在图表上这看起来是胜利:MTTR 降至 5 分钟或更低。但在运营轮廓中,这可能意味着相反。复杂的 P0 没有消失,而是变得不可见,因为它们被错误分类为误报、低紧急度或「自恢复」事件。

「MTTR 5 分钟」陷阱对于速度调查与完整性竞争、且罕见严重事件尤其危险。数字上看:

  • 重放中 300 个事件的基线:MTTR 11:00,升级比例 14%,silent_p0 2%;
  • 新优化版本:MTTR 4:50,升级 6%,silent_p0 18%。

形式上 KPI 改善了。但系统更频繁地在无手动检查和升级的情况下漏过关键事件。阻断此发布:它将风险从可见报告转移到未来重复事件、事后分析回归和责任链丢失。

validation.md 中的抗体 — 防止优化重新定义质量含义的形式条件。最小集合 — 三条规则,需同时检查:

规则保护什么边界
manual_review_floor手动验证决策比例不低于 15%

| silent_p0_cap | 无升级静默关闭的 P0 比例 | 不高于 5% | | audit_trace_required | 决策追踪完整性(prompt、diff、来源) | 100%,无例外 |

单独这些规则留下漏洞。高可追溯性不能补偿 silent_p0 增长。如果无法恢复提示、差异和决策来源,手动检查无用。将「红色按钮」设置为在保护走廊被破坏时触发,而非针对单一坏数字。

如何选择目标与保护

并非所有 KPI 需要同等保护。手动 triage 操作和自动修复具有不同风险级别,因此最小不变量集合也不同。主要规则只有一个:操作越危险,配对到目标 KPI 的哨兵指标越多。

决策类型改进什么必须配对什么
手动 triage 操作MTTR决策追踪完整保存
无操作自动分类分类速度和准确性无隐性 P0;决策追踪保存
自动升级升级延迟无隐性 P0;无误报升级

| 无状态自动修复 | MTTR | 无隐性 P0;有手动检查;完整审计追踪 | | 有状态自动修复(数据库、缓存) | MTTR | 同上 + 确认备份 | | 新政策发布 | 重复准确性 | 无「边缘漂移」;完整审计追踪 |

完整英文指标名称(silent_p0manual_review_flooraudit_trace_coveragefalse_escalation_rateedge_driftpostmortem_gapbackup_verified)及其阈值和公式见附录 D。这里重要的是规则而非名称表:每个「改进什么」行必须有一两个来自同一风险领域的哨兵。

对于危险操作(最后三行),额外包含「红色按钮」— 阻断性网关,未经第 3 章公投不可绕过。对于手动和观察性操作(前三行),软警告足够。

此表的目的不是将其变成教条,而是帮助发现遗漏。如果「有状态自动修复」行没有备份检查 — 这是重写 validation.md 的信号,而非「优化 MTTR」。

> [conceptual interface]validation.md 的结构,请适配到您的追踪文件。

#### validation.md v1.1 最小结构
version: 1.1
invariants:
  - name: manual_review_floor
    expression: "manual_review_rate >= 0.15"

  - name: silent_p0_cap
    expression: "silent_p0 <= 0.05"

  - name: audit_trace_required
    expression: "audit_trace_coverage == 1.0"

checks:
  - name: red_button_mttr_blindness
    when: "MTTR <= 5m"
    assert: "manual_review_rate >= 0.15 and silent_p0 <= 0.05 and audit_trace_coverage == 1.0"
    fail: "CI_BLOCK"

artifact_inputsnetwork_consistency 和通过 COUNT(events_with(...))audit_trace_required 精确表达式的完整形式见 [examples/goodhart-validator/specs/validation.yaml](examples/goodhart-validator/specs/validation.yaml)。

下一层保护是规范中的隐藏偏差检测器。将 triage 行为在 KPI 不变时的变化视为回归。这里回归是决策分布的偏移,在聚合中不可见。

原因:损害不总是在高层数字中可见。MTTR 可能保持不变,升级比例可能看起来正常,但模型可能开始以不同方式在 auto_closemanual_reviewdefer 之间分配有争议案例。

因此在 validation.md 中,不仅比较聚合值,还比较行为模式:

  • 严重度转移矩阵;
  • 关闭原因分布;
  • 重新打开事件比例;
  • 到事后分析标签的延迟;
  • manual_review_ratesilent_p0 之间关联的变化。

如果 drift_budget(与基线的允许偏差走廊)被超过,即使 KPI「绿色」也阻断构建。这意味着系统已改变决策模式。

要看到主要陷阱,三个指标和一个哨兵足够:

flowchart LR
    MTTR[MTTR]
    silent_p0[silent_p0]
    manual_review_rate[manual_review_rate]
    audit_trace_coverage[audit_trace_coverage]
    silent_p0 -->|不诚实地拉低 MTTR| MTTR
    manual_review_rate -->|诚实地拉高 MTTR| MTTR
    audit_trace_coverage -->|限制 silent_p0| silent_p0

解读:如果允许隐性 P0 无升级关闭,可以人为改善 MTTR。哨兵 audit_trace_coverage 禁止无追踪关闭,而 manual_review_rate 保持手动检查比例。含额外指标(escalation_ratepostmortem_regression)的完整画面见附录 D;那里也有正式阈值和关联。

将检查绑定到 Qwen 日志、决策和差异链 — 否则无法无上下文损失地转移到生产。单个事件的最小追踪组成:trace_id(链)、prompt_hash(提示哈希)、decision(所选内容)、policy_version + diff_id(哪个版本及哪个变更引入它)和 postmortem_label(分析确认的内容)。含 agentraw_alert_excerptreasoning_deltareview_outcome 的完整字段集属于完整路径,收集于 [examples/templates/validation.md](examples/templates/validation.md)。

这五个字段允许在阻断后回答工程问题:哪个规范版本改变了行为,哪个提示推动模型自动关闭,哪个差异引入了新启发式。没有此绑定,validation.md 仍是声明;有了它,成为可复现的审计工件。

将指标设计为依赖网络,而非独立计数器集合。这就是 network_consistency:一个指标的变化不应与关联指标矛盾。一起重新计算 MTTR、silent_p0manual_review_rateescalation_ratepostmortem_regressionrollback_rateaudit_gap(见上图)。单一数值的局部改善常在另一处制造债务。实用标准 — 边缘一致性:如果 MTTR 下降,但同时手动检查减少且晚期确认 P0 比例增加,将系统标记为风险。这将 CI 从「通过/未通过 KPI」检查转变为 triage 行为稳定性检查。

> [conceptual interface]scripts/metrics/network_recompute.py 展示指标网络本地重新计算的形式;教材仓库中无现成 CLI。含古德哈特反检查的 CI 网关本身的可运行类比是 python3 examples/goodhart-validator/scripts/run_validation.pyci_gate.py(见下方「验证事实」)。

#### 变更 spec 后更新指标网络和验证 CI 网关
python3 scripts/metrics/network_recompute.py \
  --spec specs/incident-spec.md \
  --replay data/replay_*.jsonl \
  --out .artifacts/metric_network.json

python3 scripts/metrics/ci_gate.py \
  --artifact validation.md \
  --metric-network .artifacts/metric_network.json \
  --traces .artifacts/qwen_trace.ndjson

CONTROL: CI_GATE = PASS if (edge_drift <= 0.12 && silent_p0 <= 0.05 && manual_review_rate >= 0.15 && audit_trace_coverage == 1.0) else CI_BLOCK

完整路径:阈值校准

silent_p0manual_review_rateedge_driftaudit_trace_coverage 的「低/默认/高」表、同时弱化两个保护的「危险」练习以及完整指标依赖网络见附录 D,D.4 节。首次通过时,只需看到坏发布被 guard-指标阻断。

示例与应用

示例:团队希望证明新 triage 流水线对更激进的自动关闭准备就绪。首先用目标优化 MTTR<=5m 运行重放测试。然后通过 red_button_mttr_blindness 检查同一事件集。

如果结果看起来像 MTTR=4:50silent_p0=18%manual_review_rate=12%,阻断发布。原因不是速度差,而是保护性不变量被违反。这是重要区别:目标达成,但质量契约被破坏。

> [conceptual interface]scripts/metrics/simulate.pyvalidate_red_button.py 展示紧急模式检查形式;教材仓库中无现成 CLI。针对学习夹具检查相同不变量的可运行类比是 python3 examples/goodhart-validator/scripts/run_validation.py(见 examples/goodhart-validator/README.md)。

#### 重放上红色按钮示例运行
python3 scripts/metrics/simulate.py \
  --scenario data/replay_300.jsonl \
  --goal "MTTR<=5m" \
  --spec specs/incident-spec.md

python3 scripts/metrics/validate_red_button.py \
  --artifact validation.md \
  --mode red_button \
  --assert "silent_p0<=5% && manual_review_rate>=15% && audit_trace_coverage==1.0"

CONTROL: red_button = BLOCKED (MTTR=4:50, silent_p0=18%, manual_review_rate=12%)

第二个示例 — 错误地将 40 个 P0 自动关闭为「误报」。事后分析前指标看起来干净:事件快速关闭,升级更少,队列不增长。

与标签核对后显现不同情况。五个事件是真实关键故障。它们应增加 silent_p0escalation_regretpostmortem_regression

validation.md 中将此案例固定为 triage 的预测性失败。不要等待生产中的用户损害。使用重放和事后真相作为早期阻断信号。

实践中,将 validation.md 保存在规范旁边,并通过与 triage 规则相同的审查流程更新。每次变更的 CI 重新构建指标网络、运行重放、检查追踪完整性并将行为与基线比较。变更阈值 — 例如将允许 silent_p0 从 5% 提高到 7% — 作为第 3 部分中可变规则的风险契约变更进行,而非 YAML 的技术修补。此屏障保护系统免受在便捷报告压力下逐渐侵蚀不变量。

总结

诱饵指标的危险不在于它们虚假。它们在被单独优化之前是有用的。

可靠的 validation.md 解决五个任务:

  • 区分目标与不变量;
  • silent_p0 增长时阻断 MTTR 改善;
  • 要求最低手动验证;
  • 检查 triage 行为漂移;
  • 保存 Qwen 日志、决策和差异的证据链。

> [runnable] — 本章最小冒烟测试位于 [examples/goodhart-validator/](examples/goodhart-validator/README.md)。

cd book2/examples/goodhart-validator
python3 scripts/run_validation.py \
  --validation specs/validation.yaml \
  --metrics fixtures/new_metrics_good.json

python3 scripts/ci_gate.py \
  --validation specs/validation.yaml \
  --baseline fixtures/baseline_metrics.json \
  --new fixtures/new_metrics_good.json

红色按钮场景的失败示例使用 fixtures/new_metrics_bad.jsonrun_validation.pyci_gate.py 应以返回码 1 结束,因为 manual_review_floorsilent_p0_cap 被违反。

下一章将此保护轮廓连接到真实监控和部署 API。

工件与就绪标准

工件就绪条件
本地运行 book2/examples/goodhart-validator优化目标与不可侵犯不变量分离

| 三个夹具:good / bad / drift | new_metrics_good.json 通过,new_metrics_bad.json 以具体原因阻断,new_metrics_drift.jsoncompare_drift.py 阻断 | | 哨兵指标阻断示例 | MTTR 改善,但发布因 silent_p0manual_review_floor 被阻断 | | capstone/goodhart-note.md 记录 | 三行:目标指标、配对 guard-指标、阻断条件 |

完整路径添加含目标指标和质量不变量的 validation.md.artifacts/metric_network.json 或可运行的指标网络类比、重放套件和含 edge_driftsilent_p0audit_trace_coverage 的 CI 网关报告。当紧急模式在 silent_p0 增长时阻断 MTTR<<5m、trace 字段将提示、差异、决策和事后标签关联、且阈值变更作为风险契约变更而非 YAML 美容处理时,视为就绪。

实践

  1. cd book2/examples/goodhart-validator && python3 scripts/run_validation.py --validation specs/validation.yaml --metrics fixtures/new_metrics_good.json --json — *预期:返回码 0,JSON 中 "status": "PASS",三个不变量 manual_review_floorsilent_p0_capaudit_trace_required 均为 "ok": true。*
  2. python3 scripts/run_validation.py --validation specs/validation.yaml --metrics fixtures/new_metrics_bad.json --json — *预期:返回码 1,JSON 中 "status": "CI_BLOCK",检查 red_button_mttr_blindness 触发 "fail": "CI_BLOCK"violated_invariants: [manual_review_floor, silent_p0_cap]。同样 python3 scripts/compare_drift.py --baseline fixtures/baseline_metrics.json --new fixtures/new_metrics_drift.json --threshold 0.12 返回码 1 并打印 edge_drift=0.18 threshold=0.12 -> FAIL。*
  3. 将三行转移到 capstone/goodhart-note.md:目标指标(MTTR)、guard-指标(silent_p0audit_trace_coverage)、红色按钮规则。 *预期:下次 MTTR 改善但 audit_trace_coverage 下降的合并尝试被自动阻断。*

检查问题

  1. 为什么 MTTR 作为唯一优化目标是危险的?
  1. 质量不变量与 KPI 有何区别?
  2. 调查古德哈特回归需要哪些追踪字段?
  3. 发布后 MTTR 下降 30%,但 silent_p0 从 4% 升至 12%。您会接受发布、回滚还是要求额外诊断?具体检查什么?
我的笔记
0 / 10000

笔记保存在当前浏览器中。在其他设备上将不会显示。

课程菜单

课程

Production SDD for Qwen Code CLI. Part 2
进度 0 / 100