本文是 搜推算法笔记 第 5 篇。索引见 搜推算法 · 知识索引。
上一篇:精排与评价指标 · 下一篇:Python 搜推技术栈
离线 NDCG 涨了 0.02,能直接全量吗?不能。线上还有真实用户决策、展示位置、系统延迟、长期生态——没有 AB 的「感觉上线」,不是可运营系统。
这篇是算法笔记的「最后一公里」:Query、召回、精排、指标的理论最终都要通过 AB 实验在线上验证。
0. 从离线到线上:完整迭代链
1 | 算法想法 |
离线指标是必要非充分——它排除了明显不行的方案,但不能替代真实用户行为。典型情况:离线 NDCG 提升,但 AB 中发现 P99 延迟恶化——护栏指标阻止了有损上线。
1. 为什么需要 AB
离线指标只能近似真实世界——真实用户决策、展示位置、机制约束、系统延迟,都是离线算不出来的。
2. 实验基本概念
| 术语 | 含义 |
|---|---|
| Control(对照) | 旧策略 |
| Treatment(实验) | 新策略 |
| 分流(Assignment) | 谁进哪一桶 |
| 粘性(Stickiness) | 同一主体实验期内固定在一桶 |
| 主指标 | 决定胜负 |
| 护栏指标 | 不能明显变差 |
| 新颖性效应 | 刚上线短暂变好/变差,需观察足够久 |
3. 分流设计
哈希分流(最常用)
1 | def bucket(exp_id: str, unit_id: str, mod: int = 100) -> int: |
要点:
- 加入
exp_id,让不同实验映射不同 - 使用稳定 ID(user/shop/device)
- 不要每次请求 random(无粘性)
粘性为什么重要?
无粘性时同一用户来回跳桶:体验混乱、转化难归因、方差变大。
分流键怎么选?
| 键 | 适用场景 |
|---|---|
| user_id | 个性化、用户体验 |
| shop_id | 商家维度策略、B2B |
| device_id / cookie | 未登录 |
原则:谁是策略作用的决策主体,就用谁。
分流键对比
| 分流键 | 粘性周期 | 适用实验 | 风险 |
|---|---|---|---|
| user_id | 长(跨 session) | 个性化排序、UI 改版 | 未登录用户需 fallback |
| shop_id | 长 | B2B 商家策略、店铺功能 | 与用户维度实验可能互扰 |
| device_id / cookie | 中 | 未登录流量 | 换设备则跳桶 |
| session_id | 极短 | 几乎不适合 AB | 同一用户跨 session 体验不一致 |
| request_id | 无 | 不是 AB 键 | 每次请求都变,无法归因 |
常见起步 5%~10% treatment。太小难显著,太大风险高。
4. 指标:主指标与护栏
搜推常见主指标
| 指标 | 期望方向 | 典型场景 |
|---|---|---|
| 无结果率 | ↓ | 召回/兜底 |
| CTR | ↑ | 列表吸引力 |
| CVR / 分销转化 | ↑ | 业务核心 |
| GMV | ↑ | 电商(更滞后、方差大) |
一次实验只设 1 个(最多 2 个)主指标,避免「哪个涨看哪个」。
护栏指标
| 护栏 | 为什么 |
|---|---|
| P95/P99 延迟 | 变慢直接伤体验与转化 |
| 错误率 / 降级率 | 系统是否健康 |
| 空结果率 | 是否引入新空洞 |
| 投诉/违规 | 合规与生态 |
决策规则:主指标显著变好,且护栏不恶化 → 才放量。
北星与代理
- 北星可能是 GMV/留存(慢)
- 代理指标是 CTR/无结果率(快)
- 代理涨但北星不涨时,要复盘是否优化偏了
5. 放量、回滚与开关
放量节奏
1 | 5% → 20% → 50% → 100% |
每档至少观察完整业务周期(含工作日/周末),并检查分人群。
回滚手段
| 手段 | 说明 |
|---|---|
| 缩流量 | treatment 比例降回 0 |
| 配置开关 | 关掉新模型/新改写/某召回路 |
| kill-switch | 紧急一键走降级路径 |
| 版本回退 | 模型文件回上一版 |
开关必须在设计期就留好,不要只能靠发版救命。
6. AA 测试
两边其实是同一策略,只是分成两桶(A/A)。用来发现:
- 分流是否均匀
- 埋点/指标计算是否有 bug
- 指标自然波动有多大
若 AA 就「显著」→ 实验平台或指标有问题。
上正式 AB 前,最好用 AA 验证分流与指标管道是干净的。
7. 统计直觉(够用版)
- 样本量不够:转化稀、流量小 → 很难显著
- 观察期不够:要覆盖周期性(星期效应、大促)
- 多重比较:同时看 20 个指标,总会有几个「碰巧显著」→ 先定主指标
- 新颖性/学习效应:上线初期波动,需要稳定窗口
- Simpson 悖论:总体涨、某分层跌 → 要看分层
开实验前写清:主指标、护栏、最小周期、成功标准。实验中途不随便改配置。
7.1 显著性检验(够用版)
**零假设 (H_0)**:Treatment 与 Control 的真实均值相同(策略无效)。
t 检验直觉: 观测到的 CTR 差异 (\Delta),是否大到「自然波动」难以解释?
[
t = \frac{\bar{x}_T - \bar{x}_C}{\sqrt{\mathrm{Var}_T/n_T + \mathrm{Var}_C/n_C}}
]
| (p)-value | 含义 | 决策 |
|---|---|---|
| < 0.05 | 5% 概率是偶然 | 通常认为「显著」 |
| 0.05~0.10 | 边缘 | 需结合业务判断、延长观察 |
| > 0.10 | 不显著 | 不能证明有效 |
常见陷阱:
- 样本量不足:CVR 0.5% 时,5% 流量要跑数周才够 power
- MDE(Minimum Detectable Effect):实验设计时应算「最小可检测 uplift」,避免「其实涨了 0.1% 但检验力不够」
- SRM(Sample Ratio Mismatch):实际分流 48:52 而非 50:50 → 分流 bug,结果不可信
7.2 置信区间
点估计 (\Delta=+2.3%) CTR 不够,应报告 95% CI,例如 ([+0.8%, +3.8%]):
- CI 不含 0 → 与 (p<0.05) 一致
- CI 很宽 → 样本不够,即使「显著」也不稳
7.3 方差缩减(CUPED)
CUPED(Controlled-experiment Using Pre-Experiment Data):用实验前的用户指标作协变量,降低指标方差,同样流量下更容易检出小 uplift。适合有历史行为数据的成熟产品。
8. 搜推可实验变量
| 层 | 可实验变量 |
|---|---|
| Query | 纠错开关、阈值、改写词表、改写条数 |
| 召回 | 各路权重、是否开热门补召、TopK |
| 融合 | 加权 vs RRF、RRF 的 k |
| 精排 | 模型版本、特征开关、去偏方式 |
| 机制 | 打散窗口、过滤规则 |
| 工程 | 超时阈值、降级策略 |
一次少改因子——改太多说不清收益来自谁。
9. 线上异常排查
空结果率突增
1 | 1. 最近是否上线纠错/改写?(误伤) |
P99 延迟突增
1 | 1. 哪一路耗时变长(分层追踪) |
点击涨、转化跌
1 | 1. 是否推了标题党/低质高点 |
离线 NDCG 涨、线上无感
回到 Train=Serve、标签目标、延迟、机制层四件套排查。
下一步
- Python 工程落地 → Python 搜推技术栈
- ES 全文检索工程 → Elasticsearch 检索基础
- 系列回顾 → 搜推算法 · 知识索引


