评测、可观测与可追溯:怎么知道改了之后更好了

系列精华 · 七篇正文每篇一页:没有评测集的改动是猜测

arganzheng · 2026-11-06

这个系列的三句话主张

没有评测集的改动是猜测;judge 是仪器,要先被测量;不可复现就录下来。

几篇怎么连起来

%%{init: {"flowchart": {"wrappingWidth": 170}}}%%
flowchart TB
    E1["01 评测集"] --> E2["02 评分"] --> E3["03 评什么"] --> E4["04 门禁"]
    E5["05 trace"] --> E6["06 追溯"]
    E5 & E6 -.-> E1
    E4 & E6 --> E7["07 运行时检查"]

01 · 评测集:AI 应用的单元测试

评测集从真实流量按类型采、不按比例——几十条起,随 bad case 生长

%%{init: {"flowchart": {"wrappingWidth": 180}}}%%
flowchart TB
    L["生产流量(trace)"] -- "按类型采样" --> S["候选用例"]
    R["红队 / 安全用例"] --> S
    S --> A["标注:期望是分布"]
    A --> T{"分层"}
    T --> T1["冒烟集<br/>每次改动都跑"]
    T --> T2["全量集<br/>发布前跑"]
    T --> T3["hold-out<br/>防过拟合"]
    T1 & T2 --> G["门禁(第四篇)"]
    G -- "bad case" --> S
    

要点

按类型采不按比例——几十条就能分方向

量 数
有可观测 vs 有评测的团队 89% vs 52%
重复次数 k 3–5
hold-out 20–30%
合成集 只做冷启动——问法贴合原文,recall 高估

02 · 评分:规则、LLM-as-judge 与人

能规则不 judge、能 judge 不人;judge 报 kappa——一致率虚高 33–41 pp

%%{init: {"flowchart": {"wrappingWidth": 190}}}%%
flowchart LR
    O["一条输出"] --> R{"规则能判?"}
    R -- "能:确定免费" --> RR["规则打分"]
    R -- "不能" --> J["<b>LLM judge</b><br/>rubric、去偏"]
    J --> C{"校准过吗?"}
    C -- "一致率 ≥ 85%" --> OK["可用"]
    C -- "不够" --> H["<b>人</b>:重标、改 rubric"]
    H --> J
    OK -. "改 judge 重校准" .-> C

要点

一致率虚高 33–41 pp——门禁报 kappa

量 数
一致率 → kappa 虚高 33–41 pp;排名移 14 位
重测一致 vs 位置偏差 > 0.95 与 > 0.10 并存——稳定但有偏
风格偏差 0.10–0.76
中档模型 + 去偏 vs 前沿模型 胜,且便宜 15×
门槛 κ ≥ 0.61

03 · 评什么:指标矩阵

形态 × 结果/过程/成本/安全的矩阵——过程与结果并列;生产看 (\text{pass}^k)

%%{init: {"flowchart": {"wrappingWidth": 360}}}%%
flowchart LR
    F{"应用形态"} --> S["<b>单步</b><br/>准确率 · 格式遵循 · schema 通过率"]
    F --> RG["<b>RAG</b><br/>检索 recall@k · 生成 faithfulness"]
    F --> AG["<b>agent</b><br/>过程:步数 · 越权 · 成本"]
    F --> MT["<b>多轮</b><br/>策略遵循 · 目标达成"]
    S & RG & AG & MT --> X["都并列报:成本 · p95 · 安全<br/>按分布、按类型分层"]

要点

形态 × 维度矩阵——生产看 (\text{pass}^k)

形态 结果 过程 成本 安全
单步 正确 / 格式 — token 拒答
RAG 忠实 / 完整 recall@k、引用 检索 + 生成 权限泄漏
agent 任务完成 步数、越权、重复 token × 步 不可逆动作
多轮 会话目标 每轮 + 全局 会话 token  

04 · 回归与门禁:改动 = 发布

改动 = 发布:钉快照 + 探针集每日,发现供应商静默升级;影子 → 灰度 → 回滚

%%{init: {"flowchart": {"wrappingWidth": 140}}}%%
flowchart LR
    CH["改动:prompt · 模型 · 工具 · harness"] --> V["新版本(不可变)"]
    V --> G{"门禁:分层指标 ≥ 基线 − 噪声"}
    G -->|"不过"| CH
    G -->|"过"| S["影子模式(下图)"]
    S --> C["灰度 1–5% → 全量"]
    C -->|"退化"| RB["回滚"]
    C -->|"正常"| P["全量"]
    P --> M["监控 + 探针集"]
    M -. "漂移" .-> G

    classDef step fill:#fff7e0,stroke:#c98a00,stroke-width:2px,color:#222
    classDef gate fill:#eef6ff,stroke:#5b8fd6,color:#222
    class CH,V,S,C,P,M,RB step
    class G gate

影子模式与 A/B:上线前先并行跑

影子 = 新旧并跑只记录不生效、比差异;A/B = 两个版本分流、按版本聚合在线指标

%%{init: {"flowchart": {"wrappingWidth": 200}}}%%
flowchart TB
    V["新版本"] --> S["影子模式<br/>新旧并跑 · 只记录不生效 · 比差异"]
    S --> C["灰度 1–5%"]
    AB["A/B:两个版本并行分流<br/>按版本聚合在线指标"] -.-> C

要点

影子只记录;A/B 按版本聚合

规则 为什么
改 rubric 后重量基线 尺子变了
灰度忽略缓存冷启动 第一轮全写是预期
短期信在线、长期修离线 在线有噪声,离线可复现

05 · trace:记什么、按什么约定

trace 三级树 + OTel gen_ai.*;元数据全量、内容采样、bad case 全量

%%{init: {"flowchart": {"wrappingWidth": 400}}}%%
flowchart TB
    T["trace = 一次会话 / 一个任务<br/>trace_id · 用户 · prompt 版本 · 模型快照 · 总成本"]
    T --> S1["span:第 1 步"] & S2["span:第 2 步"] & S3["span:第 k 步"]
    S2 --> M["模型调用 span<br/>完整输入 / 输出<br/>四类 token · effort · TTFT · stop"]
    S2 --> TO["工具调用 span<br/>名称、参数、结果引用、耗时、<br/>沙箱决定、审批人与时间"]
    S2 --> RT["检索 span<br/>改写前后的查询、过滤条件、两路候选、<br/>RRF / rerank 排序、最终块 id"]
    M & TO & RT -. "评测集从这里采;bad case 带 trace_id;<br/>供应商静默升级从指标曲线看出来" .-> U["下游用途"]

要点

元数据全量、内容采样、bad case 全量

项 数
OTel 语义约定 v1.42.0(2026-06)移到独立仓库
工具选择 按评测闭环 / 自托管
trace 是什么 会话日志的投影

常见误区

  • 「自造 gen_ai.prompt.version」——命名空间冲突;用 app.*

06 · 可追溯:从坏结果追到那一步并变成用例

bad case → 决策点日志 → 失败分类十一类 → 录制回放或评测用例

%%{init: {"flowchart": {"wrappingWidth": 170}}}%%
flowchart LR
    B["一个坏结果"] -- "绑 trace" --> TR["打开完整轨迹"]
    TR --> D["决策点日志"]
    D --> C["失败分类"]
    C --> F{"改哪侧?"}
    F -- "应用侧" --> RP["<b>录制回放</b>"]
    F -- "模型侧" --> EV["评测用例"]
    RP & EV --> V["版本 diff"]


要点

十一类失败的药多在检索与产品层

失败类 药在哪
检索没找到 / 找到没用 检索层
prompt 约束丢失 上下文层
工具返回错 / 编造工具结果 工具与 mask
模型能力不足 模型(十一类里的少数)
技术对、产品错 产品层

常见误区

  • 「回放全过就上线」——输入变了要报警重跑

07 · 运行时可靠性与物理世界的仿真

运行时检查 = 评测发现的失效模式;仿真六层,闭环才测决策

%%{init: {"flowchart": {"wrappingWidth": 460}}}%%
flowchart TB
    U["请求"] --> I["输入侧检查:注入特征、越界请求、敏感信息(只降概率,不是防线)"]
    I --> LLM["模型 / agent"]
    LLM --> O["输出侧检查:schema、引用是否存在、置信度、幻觉检测、敏感词"]
    O -- "通过" --> Rr["返回用户"]
    O -- "不通过" --> FB["fallback:拒答 + 说明 / 降级到更保守的 prompt 或模型 / 转人工"]
    E["上线前的评测(第一到四篇)发现的失效模式"] -. "做成运行时检查" .-> O

要点

评测集 ↔ 场景库——仿真闭环才测决策

数字世界 物理世界
评测集 场景库
回放 仿真回灌
影子模式 影子驾驶
灰度 分批 OTA
覆盖率 = 新场景比例 同

一个闭环

%%{init: {"flowchart": {"wrappingWidth": 200}}}%%
flowchart TB
    T["trace(05)"] --> S["评测集(01)"] --> J["评分(02、03)"] --> G["门禁(04)"]
    T --> B["bad → 用例(06)"] --> S
    G --> R["运行时检查(07)"] --> T

常见误区(一)

  • 「有 trace 就够了」——看得见不等于能判断
  • 「按流量比例采评测集」——难例看不见
  • 「等评测集完善再用」——几十条就能分方向
  • 「judge 一致率 88% 可做门禁」——报 kappa
  • 「用最大的模型当 judge」——去偏比大小重要
  • 「每轮平均分代表会话质量」——以会话为单位

常见误区(二)

  • 「pass@5 = 生产可靠性」——(\text{pass}^k)
  • 「没部署就不会变」——静默升级,探针集
  • 「只记前 500 字」——回放做不了
  • 「幻觉 = 模型问题」——药多在别处
  • 「让模型输出置信度」——要依据

下一步

  • 同一路线:《生产与运维》——门禁之后的发布、SLO 与 runbook;《产品与体验》——量「有用」不是「用了」;《工具、Agent 与 harness》第 9 篇——轨迹评测
  • 算法侧:《经典机器学习》第 10 篇——校准、judge 一致率、多重比较;《后训练》第 8 篇——benchmark 的三关
  • 原文总纲:/evaluation-observability-and-traceability.html;通关自测在系列总结
← Arganzheng's Blog