评测41 20 分钟

离线评测 95 分,线上为什么还是翻车?

离线集测的是固定样本,线上面对的却是变化的用户、工具和数据。把分布漂移、长尾失败、版本组合和副作用纳入评测,才解释得了‘离线 95%,线上 70%’。

原理 实现 边界 追问

本篇阅读顺序 · 三遍读法

一篇文章,读出三种能力。

先弄懂它为什么这样工作,再把条件换一换,看方案还能不能站住,最后用代码和证据复盘一遍。顺序固定,读完才知道自己是真的会了,还是只记住了名词。

01 / 基础知识先回答“它为什么这样工作”

沿着直觉、公式和边界读正文,看到变量就问输入、状态、复杂度分别是什么。

02 / 高频追问再回答“条件变了怎么办”

把面试官的追问当作小型设计评审:更大流量、更少上下文、外部失败或安全约束出现时,局部如何重算。

03 / 从零实现把动作、回执与失败边界写进最小实现

沿代码、表格和证据卡复盘,最后用文末的 60 秒回答确认自己没有只记住名词。

问题面试官到底在判断什么
机制系统如何工作
证据代码、指标与取舍
表达30 秒回答骨架

上线前,某客服 Agent 在 2 万条黄金集上拿到 95 分。上线一周,真实任务成功率只有 73%。团队先说“线上用户更复杂”,继续加题;题越加越多,换班、系统超时和新商品照样翻车。

离线和线上不是两个互相矛盾的真相,而是测量了两个不同的分布。离线集固定输入、工具和标准答案;线上还会发生权限变更、数据更新、流量高峰、用户追问和未知副作用。真正要做的是找出差距从哪里来,再把这些失败变成新的可回放样本。

先给一个能复述的答案

离线高分线上翻车,通常来自四种差异:任务分布变了、环境和工具变了、用户目标与评测假设不一致、线上指标只看最终结果没有看长尾和风险。解决办法不是盲目扩大黄金集,而是给任务、数据、模型、Prompt、工具和评测器做联合版本;用真实轨迹脱敏回放和影子流量测分布,再用受限灰度验证副作用。线上发现的失败要归因、去重、标注并回流,形成可追踪的闭环。

离线黄金集到线上灰度的评测闭环

图 1:离线分数不是上线通行证,而是逐步接近真实分布的一座桥。

一、先确认你测的是不是同一个任务

离线样本常常写成“用户问题 → 参考答案”,线上任务却包含上下文、历史状态、权限和工具可用性。两者表面同类,实际输入不同。

{
  "offline": {
    "input": "把订单 123 改成已发货",
    "fixture": {"status": "paid"},
    "tools": ["update_order_mock"],
    "expected": "拒绝直接改状态"
  },
  "online": {
    "input": "帮我处理一下这个订单",
    "history": "用户刚刚说物流已经取件",
    "permissions": ["read_order", "create_ticket"],
    "tools": ["order_api_v2", "ticket_api"]
  }
}

线上任务的隐含条件没有进入离线集,模型自然学不到“先澄清”“查哪个订单”“只有读权限”。第一步不是加模型,而是对齐任务契约。

二、四种漂移要分别测

漂移典型表现需要观测什么
输入漂移新术语、长对话、语言混杂词分布、长度、意图比例
数据漂移商品、文档、权限和状态更新版本、缺失率、冲突率
工具漂移schema、错误码、延迟变化参数失败、超时、未知提交
行为漂移用户追问、纠正、绕过限制重试、转人工、投诉

每种漂移都要有触发器。比如检索库每日新增文档,至少要把新旧版本混合样本加入影子评测,而不是等用户投诉后才发现召回排序变了。

输入、数据、工具和用户行为的四种线上漂移

图 2:线上差距不是一个神秘的“复杂度”,而是多个可测的分布变化。

三、线上指标要能解释失败

“线上成功率 73%”没有足够信息。至少要切分:

  • 任务类型、租户、语言、客户端和时间段;
  • 模型、Prompt、知识库、工具和评测器版本组合;
  • 失败发生在规划、检索、参数、执行、合并还是表达;
  • P50/P95/P99 延迟、重试放大、token 和外部成本;
  • 是否涉及越权、错误写入、用户纠正或人工接管。
success_rate ↓
  ├─ 新意图占比 ↑       → 补任务切片
  ├─ 工具超时 ↑         → 影子真实错误码
  ├─ 知识库新版本 ↑     → 对齐文档版本
  ├─ P99 延迟 ↑         → 检查重试和扇出
  └─ 转人工 ↑           → 分析澄清与拒答

四、回放必须保存“当时的世界”

只保存用户问题和模型回答,无法重现线上状态。一个可回放样本应包含:输入与会话历史、当时可见的文档版本、工具 schema 和返回、权限决策、模型与 Prompt、随机种子或采样设置、最终状态及副作用。

{
  "trace_id": "tr_812",
  "captured_at": "2026-08-19T09:12:33Z",
  "bundle": {
    "model": "base@7",
    "prompt": "support@42",
    "knowledge": "kb@2026-08-18",
    "tools": "order-api@v2",
    "policy": "refund@19",
    "fixtures": ["order_123@snapshot_8"]
  },
  "side_effects": [{"type": "ticket.create", "status": "committed"}]
}

回放默认是只读的。工具要用记录的返回或安全 mock,不能因为“重现一次”就再次发退款、发邮件或修改生产数据。

五、影子流量和灰度不是一回事

影子流量:看分布,不产生副作用

新版本接收真实请求的脱敏副本,工具调用只读或 mock。比较它和当前版本的轨迹、成本、引用、拒答和潜在风险,但不把结果展示给用户。

灰度:验证真实副作用链路

只给一小部分租户、意图或预算范围开启真实执行。明确自动回滚条件,例如越权拦截下降、错误写入率超过阈值、P99 翻倍或人工接管激增。

把影子流量称为“线上 A/B”是常见误解;影子只验证观察结果,不能证明副作用链路真的可用。

六、如何把线上失败回流成评测集

线上样本不能直接全部塞回黄金集。建议经过四步:

  1. 去重:按意图、错误轨迹和环境状态聚类,避免同一个故障占满数据集;
  2. 脱敏:移除账号、订单、密钥和内部 URL,保留能影响决策的结构;
  3. 标注:记录错误类型、正确行为、风险等级和是否需要人工;
  4. 固定:生成可执行验收器,锁住数据、工具和版本,成为回归样本。
线上 trace → 脱敏聚类 → 专家标注 → 生成验收器
     ↑                              ↓
灰度监控 ← 影子比较 ← 离线回归 ← 版本变更

七、先固定版本元组,再谈漂移

线上失败常常不是某一个组件变化,而是模型、知识库和工具同时发生变化。建议把一次请求的关键依赖写成版本元组:

V = (task, model, prompt, policy, knowledge, tools, runtime, evaluator)

每个线上 trace 都保存元组,回流样本则把元组变成可执行的 fixture。比较两个版本时,先列出差异集合,再决定是做重放、影子还是灰度,而不是笼统地说“线上环境不同”。

把模型、知识库和工具版本绑定成发布门禁矩阵

图 3:版本元组让漂移从一句解释变成可比较、可回滚的发布门禁。

八、把线上观测转成可执行门槛

一张趋势图不能直接指导发布。每个关键切片都应有基线、目标、上限和动作:

切片基线发布门槛超过门槛的动作
高风险写操作0.3% 错误写入不得上升立即停止灰度并回滚
新意图68% 成功率≥ 75%继续标注并补回归集
P95 延迟3.2s≤ 4.0s降低并发或收窄路由
证据覆盖86%≥ 90%检查检索和版本对齐

门槛还要绑定样本量和观察窗口。刚上线 20 个请求得到的 100% 成功率,不应和一周内 2 万个请求的结果放在同一张排行榜上。只有当切片达到最小样本量、置信区间收敛,并且没有硬风险回归时,结论才可以进入发布记录。

九、什么情况下离线高分仍然有价值

离线评测不是没用,它适合回答:一个局部改动是否让已知能力回归、一个工具契约是否被遵守、同一版本在固定条件下是否可复现。它不适合单独回答:线上新任务是否安全、长尾延迟是否可接受、工具真实错误是否能恢复。

所以发布门槛应该是“离线不退化 + 影子无明显风险 + 灰度满足线上约束”,而不是一个孤立的 95 分。

十、用漂移三角定位线上差距

当离线和线上分数出现明显落差,可以把排查固定成三个角:样本、环境、口径。样本角问“用户到底在问什么”;环境角问“模型拿到的工具、权限和数据是什么”;口径角问“我们把什么叫成功”。一次只改变一个角,才能知道是哪一类漂移造成回归。

角度典型对照证据产物
样本黄金集 vs 脱敏真实请求意图、长度、语言、追问分布
环境mock 工具 vs 真实错误与权限schema、延迟、超时、状态快照
口径自动通过 vs 人工认可拒答、转人工、风险和投诉标签

排查时先从失败 trace 抽取最小复现,再把线上输入替换成离线 fixture:如果换回 mock 后成功,优先查环境;如果两边都失败,查样本和任务契约;如果模型输出都正确但指标不同,查口径。这个顺序能避免团队一看到线上下降就立刻换模型。

线上漂移排查从样本、环境、口径三个角度切分,再进入最小复现和发布门槛

图 4:把“线上更复杂”拆成三个可对照的角,才能知道下一步该补数据、补模拟还是改指标。

十一、线上回流不是“多加样本”

回流样本要有进入条件和退出条件。进入条件可以是高风险副作用、同类错误重复出现、置信度与人工判断严重不一致;退出条件则是已经有稳定的正确行为、验收器和覆盖范围。否则黄金集会变成投诉日志的堆积,训练和评测都被热门故障绑架。

建议保留一份长尾 holdout,不参与日常调参,只在发布前检查新版本是否把未见过的失败也推向安全方向。对同一故障的不同用户请求,可以共享“错误族”标签,但保留不同权限、版本和工具状态,避免去重时把真正的环境差异抹掉。

给漂移告警附上最小处置卡

告警只告诉你“线上不一样了”,不能直接告诉你该换模型还是补数据。每次告警都应携带切片、基线、版本元组、影响面和下一步动作:

alert: high_risk_groundedness_drop
slice: long_query / private_docs
baseline: 0.91
current: 0.83
window: 2h / n=640
version_tuple: model@r8 + index@r17 + tool@v3
suspect: index_version_drift
action: freeze_canary_and_replay
owner: search-platform

处置动作也要分级:轻微输入漂移可以扩大抽样;工具超时或权限异常要先冻结灰度;高风险漏判则直接切回上一版本并保留线上轨迹。告警卡链接到最小复现、失败族和回归样本,避免值班同学只在群里发一个红色百分比。

线上漂移告警卡把影响切片、版本元组、怀疑原因和处置动作固定下来

漂移处置单要记录“排除了什么”

线上问题经常不是一个根因。为了避免每次告警都从头猜,我会在处置单里记录已排除的假设、当前最小复现和下一步实验:

incident: drift-2026-0819-07
slice: long_query / private_docs
symptom: groundedness -8pp
version_tuple: model@r8 + index@r17 + tool@v3
ruled_out:
  - "评测器版本未变"
  - "权限策略日志无异常"
repro: replay-640 / input_hash=sha256:...
next_experiment:
  variable: index_version
  control: r16
  candidate: r17
  gate: citation_grounding >= 0.90
action: freeze_canary
owner: search-platform

ruled_out 的价值是防止团队重复做已经失败的检查;next_experiment 则把告警转成一次有控制组的最小验证。只有当复现、版本元组和动作都在单子上,值班同学才不会被一个漂亮但没有上下文的百分比牵着走。

漂移处置单记录症状、版本、已排除假设、最小复现和下一步实验

告警关闭前,再做一次反事实回放

漂移告警被修复后,不要只看当前指标恢复。选一组同样的线上 trace,分别替换一个变量:回到旧模型、旧索引、旧工具响应或旧口径,观察差异是否真的来自刚刚修改的那一层。一次只替换一个变量,才能把“修好了”变成可解释的证据。

counterfactual_replay: cfr_20260820_07
trace_set: online-failures-20260819-42
baseline:
  model: model-r38
  index: index-r16
  tools: toolset-9
candidate:
  model: model-r39
  index: index-r16
  tools: toolset-9
swap_one_at_a_time:
  - name: model
    expected: "citation_recall improves"
  - name: index
    expected: "no change"
  - name: tools
    expected: "no change"
result:
  candidate_pass_rate: 0.91
  baseline_pass_rate: 0.76
  unexplained_cases: 2
decision: "close_with_watch"

如果候选版本和旧版本在同一 trace 上都失败,说明补丁没有触到根因;如果替换了一个并未修改的变量,指标却大幅变化,优先查隐藏环境差异。未解释样本不必阻塞所有发布,但必须进入下一轮回归集并保留观察人。

反事实回放一次只替换一个版本变量,帮助确认漂移修复到底触到了哪一层

L5:为什么“指标恢复”还不能直接关闭漂移告警?

因为恢复可能只是流量结构暂时变化,或另一个版本恰好掩盖了问题。关闭前要至少保留一组原始失败 trace、一个单变量对照和未解释样本的后续负责人;没有这些证据,告警只是被静音,不是被解决。

L5:为什么漂移告警不能直接触发“换模型”?

因为输入分布、知识库、工具状态和成功口径都可能变化。先锁定版本元组并回放同一失败样本,再分别替换一个环境因素;只有当模型因素在控制组中仍能解释差异,才考虑换模型。否则换模型只是把可定位的问题变成新的未知变量。

常见错误

  • 用静态 mock 工具代替真实超时、空响应和未知提交;
  • 评测集只有最常见意图,没有长尾、追问和拒答;
  • 线上只保存输入输出,不保存版本、权限和状态快照;
  • 影子流量偷偷执行真实副作用;
  • 线上失败只在周报里写一句“模型不稳定”,没有回流成可执行样本。

面试官的三层追问

L1:离线 95%,线上 70%,先查什么?

先对齐任务契约和版本组合,再按输入、数据、工具、行为四类漂移切分线上失败。看失败轨迹而不是只看总分,确认差距来自分布、环境还是指标定义。

L2:为什么要做影子流量?

它能用真实请求分布观察新版本,却把工具副作用隔离掉,适合验证成本、延迟、引用和风险差异;真正执行副作用仍要在受限灰度中验证。

L3:线上失败怎么进入回归集?

先脱敏、去重、按错误类型聚类,再由人标注正确行为和风险等级,最后把样本和当时的工具、知识库、Prompt 版本固化成可执行验收器。

L4:影子流量已经很像线上,为什么还要灰度?

影子只能比较观测结果,工具写操作仍然被 mock 或隔离,不能证明真实权限、事务和回滚链路可用。灰度把租户、意图和预算限制在小范围,才有机会验证副作用和人工接管。

L5:如何避免新失败样本把黄金集污染?

先按错误轨迹和环境状态聚类去重,再脱敏和专家标注;只有能写出正确行为与验收器的样本才进入回归集,并保留原始版本元组用于复盘。

L5:漂移告警连续触发,但每次都找不到单一根因怎么办?

不要把多因素问题压成一个“模型退化”标签。先按版本元组、用户切片、工具状态和任务类型分层,比较每层的差值;如果只在组合条件出现,就建立组合回放和临时路由,而不是全量回滚。告警卡记录已排除的假设、当前 owner 和下一次复查时间,直到能够把差距收敛到可验证的最小变更。

漂移告警的关单条件:从红灯到回归

漂移告警不能靠“今天指标回来了”自动关闭。一个可审计的关单动作至少要回答三件事:差距来自哪个版本变量;修复是否在原始失败轨迹上生效;没有解释的样本由谁继续跟进。把告警做成状态机,避免值班同学只改阈值或静音通知。

drift_case: drift_20260820_04
status: candidate_fix
baseline:
  model: model-v7
  index: kb-20260818
  tool_schema: billing-v3
candidate:
  model: model-v7
  index: kb-20260820
  tool_schema: billing-v3
counterfactual:
  index_back_to_baseline: {pass_rate: 0.73}
  model_back_to_baseline: {pass_rate: 0.72}
  tool_back_to_baseline: {pass_rate: 0.71}
  candidate_all: {pass_rate: 0.89}
close_gate:
  original_failures_replayed: 24
  passed: 22
  unexplained: 2
  owner: retrieval-oncall
  next_review: 2026-08-22

如果只替换索引就能重现差距,根因才有机会收敛到知识版本;如果三个变量单独替换都不能解释,就要把组合条件保留在回归集,暂时按租户或意图分层,而不是急着换模型。关单后仍要保留原始 trace、反事实结果和未解释样本,下一次数据刷新才能判断是不是同一类漂移再次出现。

漂移告警要经过版本对照、反事实回放和未解释样本交接,才能真正关单

L5:为什么反事实回放要一次只换一个变量?

同时换模型、索引和工具会得到一个“结果变了”的事实,却无法知道是谁造成变化。单变量替换虽然慢一点,但能把线上差距映射到可执行的修复动作,也方便把结果写进回归样本。

影子流量要保留真实长尾,但把写权限彻底切掉

离线集再丰富,也很难覆盖线上真实的追问、权限组合和工具超时。影子流量可以复制真实请求的输入形状和状态快照,让候选版本在不产生副作用的环境里运行;关键是不能把“只读影子”误做成“只是不展示结果”。写工具应在网关层拒绝或替换为可查询的 dry-run,外部 request_id 也要使用隔离命名空间,避免下游把影子请求当成真实订单。

漂移 triage 同时看输入、知识、工具和行为四类差异。输入分布变了不一定是模型问题,知识版本变化也不一定要回滚模型;只有在固定影子状态下候选仍然退化,才把修复优先级交给模型或策略。每次影子实验保留流量切片、版本元组、拒绝原因和未解释样本,才能把线上发现稳定地回流成离线 case。

shadow_admission: sa_20260820_55
traffic_slice: tenant_long_tail_b
candidate: model-v8
isolation:
  write_tools: deny_at_gateway
  side_effect_namespace: shadow-only
  external_request_id: shadow-*
  sensitive_artifact: redacted_fixture
drift_triage:
  input: compare_embedding_and_intent
  knowledge: compare_snapshot_and_freshness
  tools: compare_schema_latency_receipt
  behavior: compare_claim_and_policy
gates:
  real_side_effects: 0
  trace_replayable: true
  unexplained_cases: queued
decision: shadow_only_until_attribution

影子流量准入卡:保留线上长尾形状,网关拒绝写副作用,并按四类漂移拆解归因

L5:为什么“影子环境没有副作用”不能只靠 Prompt 保证?

模型可能仍然提出写操作,真正的隔离必须在工具网关、凭证和数据命名空间上强制执行。Prompt 只能提示意图,不能替代拒绝策略、dry-run 和外部 request_id 隔离。

漂移处理要留下“未解释样本账本”

一次修复通常只能解释一部分线上退化。若把剩余失败直接丢回“待分析”,下周的新版本还会重复踩坑。更稳的做法是给每条未解释样本一个状态:已归因、待补数据、疑似标注问题、无法复现,且每次实验只能改变一个变量。这样漂移处理会留存为可检索的反例库,而不是一次性的复盘文档。

unexplained_ledger:
  contract: uel_20260820_113
  window: 2026-08-20T00:00:00Z/2026-08-20T23:59:59Z
  buckets:
    - id: u_014
      status: missing_context
      next_evidence: retrieve_acl_snapshot
    - id: u_021
      status: label_dispute
      next_evidence: second_annotator
    - id: u_037
      status: cannot_reproduce
      next_evidence: freeze_request_and_tool_trace
  promotion_rule: two_confirmed_replays_before_gold_set

漂移未解释样本账本:每条线上失败都有状态、下一份证据和进入回归集的条件

L5:为什么不能把所有线上失败立刻加入黄金集?

因为线上失败可能来自上下文缺失、权限变化、标注争议或偶发外部故障。未经归因就进黄金集,会把噪声固化成错误标准。先放入账本,等最小复现和第二次确认都通过,再升级为回归样本,才能防止评测集被事故情绪污染。

60 秒面试回答

离线高分线上翻车,通常不是模型突然失效,而是两边测的分布不同。线上有新意图、数据版本变化、工具超时、权限变化和用户追问。我的做法是给任务、模型、Prompt、知识库、工具和策略做联合版本,回放时保存当时的输入、状态、工具返回和副作用;用线上脱敏轨迹做影子流量,观察真实分布但不执行写操作,再用租户和预算受限的灰度验证真实副作用链路。所有线上失败经过脱敏、聚类、标注和验收器生成,回流到离线回归,形成“发现—定位—修复—验证”的闭环。

带走一张检查清单

  • 离线与线上是否使用同一任务契约和版本记录?
  • 是否分别监控输入、数据、工具和行为漂移?
  • 回放样本是否保存当时的状态和工具结果?
  • 影子流量是否完全隔离副作用?
  • 线上失败是否会脱敏、标注并回流?

相关笔记

参考

  • AgentAlpha《Agent 岗面试宝典 v3》:离线与线上评测章节
  • ARIS-in-AI-Offer