📑 本页目录(点开跳转)
01 · 训练完才是开始
⏱ 36 分钟 | ⭐ 先建立正确的心理预期
🎯 一句话
离线分数是在一个玻璃罩里测出来的。 一上线,玻璃罩就没了 —— 数据会变、用户会变、你的模型自己也会改变环境。 这一章讲清楚"罩子外面"到底有什么。
🏚️ 一、一个真实的翻车序列
周一:模型上线,离线 AUC 0.82,A/B 显示 CTR +3.2% 🎉
周三:CTR 还是 +3%,一切正常
下周二:CTR 降到 +1.1%,没人注意(还是正的)
两周后:CTR 变成 −0.4%,产品经理来问
排查三天,发现:
上游一个字段的埋点在两周前改了单位(秒 → 毫秒)
模型没报错,特征值大了 1000 倍,它照常给出预测
🔑 注意这个故事里的每一个细节: - 没有任何报错、没有告警、服务正常、延迟正常 - 离线指标依然很好(因为离线用的是旧数据) - 发现问题的是产品经理,不是你的监控 - 排查花了三天,而问题已经存在两周
⭐ 这一套教程存在的全部理由,就是把上面每一环都补上。
🧊 二、"玻璃罩"里有哪些假设
训练时你默认成立、上线后全都可能不成立的四条:
| 假设 | 上线后为什么会破 |
|---|---|
| 训练和线上是同分布的 | 用户在变、季节在变、竞品在变、你自己的模型在改变用户行为 ⭐ |
| 特征算法两边一致 | 训练用离线批处理、线上用实时流,两套代码 💀 |
| 标签是及时且正确的 | 退货要等 7 天、欺诈要等 30 天、有些标签根本不会来 |
| 每个样本独立 | 用户会被同一个模型反复影响;A 用户的行为影响 B 的推荐 |
🔗 第一条的一个特殊形式你已经见过: 推荐算法第 2 章的反馈闭环 —— 模型决定推什么 → 用户只能对推的东西反馈 → 反馈变成训练数据。 模型在改变自己的训练数据。 这在推荐系统里最明显,但绝不只有推荐系统有。
📉 三、模型变差的四种方式(要能分清)
① 数据管道坏了 ← 突变,最容易查,但常常没人发现
埋点改了、上游表没跑、字段类型变了
② 数据漂移 ← 渐变,输入分布变了
用户群变了、新品类上线、疫情/大促这类外部冲击
③ 概念漂移 ← 渐变,输入→输出的【关系】变了 ⭐ 最难
同样的用户特征,现在的购买意愿和半年前不一样了
④ 反馈闭环退化 ← 自己造成的
模型只推它熟悉的 → 数据越来越窄 → 越来越窄
💡 一个区分它们的关键提问:
| 问题 | ① 管道 | ② 数据漂移 | ③ 概念漂移 |
|---|---|---|---|
| 输入特征分布变了吗 | ✅ 突变 | ✅ 渐变 | ❌ 没变 |
| 输入→输出的关系变了吗 | ❌ | ❌ | ✅ ⭐ |
| 重新训练能修好吗 | ❌ 要先修管道 | ✅ | ✅ |
⭐ 最后一行最重要: 管道坏了的时候重训练是有害的 —— 你会把错误的数据学进模型, 从"临时故障"变成"永久固化"。 🔗 第 16 章会讲重训练前必须做的检查。
🎯 四、上线后你实际在优化的东西变了
训练时:让测试集上的 AUC / loss 最好 上线后:
三个常见的断裂原因:
| 断裂 | 说明 |
|---|---|
| 优化了错的指标 | AUC 关心全局排序,但用户只看前 3 个 → 该看 NDCG@3 |
| 提升发生在不重要的地方 | 模型在长尾上变准了,但流量都在头部 |
| 有别的因素同时在变 | 运营做了活动、竞品降价、季节变了 —— 这正是第 12–15 章要解决的 ⭐ |
🧭 五、这套教程的五个动作
- 灰度 / 影子 / 回滚(第 3 章)
- 三层监控 / 漂移检测(第 5-8 章)
- 归因 / 排查(第 9-11 章)
- 实验 / 因果推断(第 12-15 章)
- 重训 / 回溯 / 成本(第 16-19 章)
💡 这五个动作是有顺序的: 没有②就做不了③,没有③就做不了④。 很多团队直接跳到④(做 A/B 证明效果),结果因为没有②③, 实验跑出负向时根本不知道是模型不行还是数据坏了。
⚖️ 六、一个务实的提醒:不是所有模型都值得这套
| 你的场景 | 建议投入 |
|---|---|
| 一次性分析 / 内部报表 | 🟡 只要能复现就够(第 17 章) |
| 内部工具,用户是同事 | 🟡 加个基础监控(第 5 章) |
| 面向用户、影响收入 | ✅ 整套都要 |
| 涉及钱 / 健康 / 安全 | ✅ 整套 + 合规审计(第 19 章) |
⭐ 判据:出错后多久会被发现、发现时已经影响了多少人。 这两个数决定了你该投多少 —— 而不是模型有多复杂。
🏚️ 七、另外两个真事故:静默的另外两种形状
第一节那个"单位变了"只是一种形状。下面两个的样子完全不同, 但共同点一模一样:没有任何东西报错。
💀 事故 A:模型五周没更新,没人知道
第 0 天 发布流程重构,部署脚本里模型路径被写死成 v3
第 1 周 团队上线 v4 —— 指标"没什么变化"
→ 归因成「这次改动本来就不大」
第 3 周 上线 v5,还是没变化
→ 开始怀疑「是不是特征已经到顶了」
第 5 周 有人手工核对线上版本号:一直是 v3 💀
代价:五周迭代全部白做
⭐ 这个事故最贵的部分不是那五周,是它差点改变了团队的技术判断。 「改了没效果」被解释成「这个方向不行」,而真相是改动根本没生效。 🔗 这就是第 5 章把模型版本号放进最小监控清单的原因 —— 一个五分钟能加的指标,挡掉的是一个季度的错误结论。
💀 事故 B:静默降级 + 一个"说得通"的解释
特征服务读不到当天分区时,代码里有个兜底:用昨天的值
→ 这个兜底从来没有任何告警
国庆假期,上游调度没跑 → 连续 3 天用的都是 9 月 30 日的特征
→ CTR 从 4.1% 掉到 3.8%(相对 −7%)
→ 团队结论:「假期效应,正常」 ← 💀 归因错了
→ 假期结束 CTR 自己回来了,更坐实了这个结论
→ 接下来两周,团队在做「节假日专用模型」
真相:三天前的一次调度失败,两分钟就能修
| 这个事故的伤害 | 说明 |
|---|---|
| 直接损失 | 3 天 × CTR −7% |
| 归因损失 ⭐ | 两周人力投在一个不存在的问题上 |
| 信任损失 | 之后每次指标波动,第一反应都是「是不是假期」 |
⭐ 一个通用教训:「有一个说得通的解释」不等于「找到了原因」。 掉点时最危险的不是找不到原因,而是太快找到一个合理的原因 —— 因为找到之后,人就停止找了。 🔗 第 11 章给的排查流程,本质就是逼你在下结论前排除其他可能。
📏 八、把这些串起来的一个数字:发现延迟
发现延迟 = 问题真正开始的时刻 → 有人知道它的时刻。
| 问题类型 | 没有专门监控时的典型发现延迟 | 通常谁先发现 |
|---|---|---|
| 服务挂了 / 500 暴涨 | 分钟级 | 系统告警 |
| 预测值全变成差不多的数 | 小时 ~ 天 | 运营说「推荐怎么都一样」 |
| 某个特征的单位/口径变了 | 1–3 周 ⭐ | 产品经理看周报 |
| 模型版本没生效 | 数周 | 偶然核对 |
| 概念漂移(渐变型) | 1–3 个月 💀 | 季度复盘 |
⭐ 这张表就是本教程的路线图:越往下,发现延迟越长、代价越大、 越需要专门的手段才能看见。 你的目标不是"不出问题",是把这一列的数字压下来。 🔗 第 8 章会说明:发现延迟是衡量一个监控体系最好的单一指标 —— 比"我们有多少个告警"有意义得多。
🔨 上线第一天就该有的健康检查
不需要监控平台。一个跑在 cron 上的脚本,就能挡掉上表的前四行:
import datetime
EXPECTED_VERSION = "v5.2.1"
def health_check(pred_log, model_meta, feature_ts, base):
"""pred_log: 最近一小时的预测值数组
base: 上线当天存下来的基线(均值/标准差)"""
alerts = []
# ⭐ ① 版本号 —— 挡掉事故 A 那类「改动根本没生效」
if model_meta["version"] != EXPECTED_VERSION:
alerts.append(f"线上版本 {model_meta['version']} ≠ 期望 {EXPECTED_VERSION}")
# ⭐ ② 特征新鲜度 —— 挡掉事故 B 那类「静默用了昨天的数据」
lag_h = (datetime.datetime.now() - feature_ts).total_seconds() / 3600
if lag_h > 6:
alerts.append(f"特征已过期 {lag_h:.1f} 小时")
# ⭐ ③ 预测值标准差塌缩 —— 几乎总是特征大面积缺失的信号
if pred_log.std() < base["pred_std"] * 0.5:
alerts.append(f"预测标准差塌缩 {base['pred_std']:.3f}→{pred_log.std():.3f}")
# ④ 预测均值整体平移 —— 多半是某个特征口径变了(第一节那个事故)
z = abs(pred_log.mean() - base["pred_mean"]) / base["pred_std"]
if z > 3:
alerts.append(f"预测均值漂移 {z:.1f}σ")
return alerts
💡 这段代码不到 20 行,覆盖的是本章三个事故里的三个。 先有它,再谈监控平台。 很多团队的顺序反了 —— 花三个月搭平台,而这 20 行在第一天就能写完。
🚑 九、真出事了,第一个小时做什么
⭐ 第一原则:先止血,再查因。
调查可以慢慢做,损失不会等你。
| 现象 | 第一动作 | 为什么 |
|---|---|---|
| 错误率 / 延迟暴涨 | 立刻回滚 | 工程指标客观,不需要讨论 |
| 预测值分布突变 | 立刻回滚 | 几乎总是坏消息,成本低 |
| 业务指标跌,但工程指标正常 | 先查是不是数据问题,再决定 | 可能是外部因素,回滚了也没用 |
| 只有某个人群跌 | 先按人群拆开看 | 可能是分流不均,不是模型问题 |
| 说不清哪里不对 | 回滚 ⭐ | 回滚永远比"再观察一天"便宜 |
⭐ 最后一行是本章最实用的一条: 回滚的成本是可预估的(少一次迭代),继续观察的成本是不可预估的。 🔗 怎么让回滚真的只要五分钟 → 第 3 章。
🔗 十、和站内其他章的关系
| 相关的地方 | 和这一章的关系 |
|---|---|
| ML基础 05数据泄漏 | 离线评估的坑;本教程讲上线后的 |
| 推荐算法 02反馈闭环 | 变差方式④的典型场景 |
| 推荐算法 12 A/B | 第 12 章会讲它的深水区 |
| 推荐算法 15工程落地 | 推荐场景的具体版 |
| 智能体工程 16 | Agent 场景的具体版 |
✅ 检查点
- 那个翻车序列里,有哪几个环节是本教程要补的?
- 「玻璃罩」里的四条假设是什么?
- 模型变差的四种方式?怎么用两个提问区分前三种?
- 为什么说「管道坏了的时候重训练是有害的」?
- 为什么 AUC 涨了 CTR 没涨是常态?(说出三个断裂原因)
- 五个动作为什么有顺序?跳过②③直接做④会怎样?
- 判断「该不该上这整套」的依据是什么?
- 「模型五周没更新」那个事故,最贵的损失是什么?用一个什么指标能挡掉?
- 「静默降级 + 假期效应」那个事故里,除了直接损失还有哪两种伤害?它给出的通用教训是什么?
- 「发现延迟」是什么?为什么说那张表是本教程的路线图?
- 20 行健康检查里的四项分别在挡什么?
- 真出事的第一个小时,说不清哪里不对时该做什么?为什么?
👀 答案
- 没有报错/告警(→监控)、离线指标依然好(→线上监控而非离线)、产品经理先发现(→告警设计)、排查花三天(→根因排查手册)、问题已存在两周(→漂移检测)。
- ①训练和线上同分布 ②特征算法两边一致 ③标签及时且正确 ④每个样本独立。
- ①管道坏了 ②数据漂移 ③概念漂移 ④反馈闭环退化。两个提问:输入特征分布变了吗(管道=突变、数据漂移=渐变、概念漂移=没变)、输入→输出关系变了吗(只有概念漂移=是)。
- 因为会把错误的数据学进模型,问题从"临时故障"变成"永久固化"。必须先修管道。
- ①优化了错的指标(AUC 看全局排序,用户只看前 3 个)②提升发生在不重要的地方(长尾变准但流量在头部)③有别的因素同时在变(运营活动、竞品、季节)。
- 因为没有②看得见就做不了③说得清,没有③就做不了④证得了。跳过的话,实验跑出负向时根本不知道是模型不行还是数据坏了。
- 出错后多久会被发现 + 发现时已经影响了多少人——不是模型有多复杂。
- 最贵的不是那五周,而是它差点改变团队的技术判断——「改了没效果」被解释成「这个方向不行」,真相是改动根本没生效。挡掉它只需要监控模型版本号(五分钟能加的一个指标)。
- 归因损失(两周人力投在一个不存在的问题上)和信任损失(之后每次波动都先猜"是不是假期")。通用教训:「有一个说得通的解释」不等于「找到了原因」——掉点时最危险的是太快找到一个合理的原因,因为找到之后人就停止找了。
- 发现延迟 = 问题真正开始的时刻 → 有人知道它的时刻。那张表越往下发现延迟越长(服务挂了分钟级 → 特征口径变了 1–3 周 → 概念漂移 1–3 个月),也越需要专门手段才能看见。目标不是不出问题,是把这一列的数字压下来。
- ①版本号(挡「改动没生效」)②特征新鲜度(挡「静默用了昨天的数据」)③预测标准差塌缩(特征大面积缺失的信号)④预测均值漂移 >3σ(某个特征口径变了)。
- 回滚。因为回滚的成本是可预估的(少一次迭代),继续观察的成本是不可预估的。
🛑 可以停在这里
⚡ 走神救援
⭐离线分数是在玻璃罩里测的,一上线罩子就没了。翻车序列的每个细节都值得记:没报错、没告警、离线指标依然好、产品经理先发现、排查三天而问题已存在两周——这套教程就是把每一环补上。四条会破的假设:同分布、特征算法两边一致、标签及时正确、样本独立。⭐变差的四种方式:①管道坏了(突变) ②数据漂移(输入分布渐变) ③概念漂移(输入→输出的关系变了,最难) ④反馈闭环退化。两个提问区分:输入分布变了吗、输入→输出关系变了吗。⚠️⭐管道坏了时重训练是有害的——会把错误数据学进模型,从临时故障变成永久固化。⭐AUC涨了CTR没涨是常态:优化了错的指标/提升在不重要的地方/有别的因素同时在变。五个动作有顺序:放出去→看得见→说得清→证得了→活得久,没有②③就做不了④(实验负向时不知道是模型不行还是数据坏了)。判据:出错后多久被发现 + 影响多少人。💀另外两个事故:模型五周没更新(部署脚本写死旧路径,三次上线"都没效果",最贵的是它差点让团队得出"这个方向不行"的错误结论——挡它只要监控版本号);静默降级被解释成"假期效应"(兜底用了昨天的特征,CTR 4.1%→3.8%,团队接着做了两周"节假日模型",真相是两分钟能修的调度失败)——⭐「有一个说得通的解释」不等于「找到了原因」,掉点时最危险的是太快找到一个合理的原因。⭐发现延迟(问题开始→有人知道)是全书路线图:服务挂了分钟级、特征口径变了1–3周、概念漂移1–3个月。⭐20行健康检查先于监控平台:版本号、特征新鲜度、预测标准差塌缩、预测均值漂移>3σ。出事第一小时先止血再查因;⭐说不清哪里不对时就回滚——回滚成本可预估,继续观察的成本不可预估。
下一节 👉 02-离线好不等于线上好.md