纯教学实验,所有 ID 和分数均为手写虚构数据,不对应任何公司或用户。
一个模型没变,分数却变了
假设唯一已知相关候选(candidate) P 得分 0.8。小候选池里另外 2 条分数都更低,P 排第 1;换一个更大的池子,新增 2 条分数更高的候选,P 掉到第 3。
模型没有改,但 Recall@2 从 1 变成 0。这里新增候选在教学标签中明确是不相关;真实日志里的未标注内容不能这样直接假定。
先别急着看公式。保持 Top-K=2,在下面切换“小候选池”和“新增高分负例”;再试“多个已知正例”,只改分母。你会看到两种完全不同的涨跌原因。
想复现第一组变化,只需要这几行:
def recall_at_k(ranked, positives, cutoff):
if not positives:
return None
hits = set(ranked[:cutoff]) & set(positives)
return len(hits) / len(set(positives))
small_pool = ["P", "N1", "N2"]
larger_pool = ["N3", "N4", "P", "N1", "N2"]
print(recall_at_k(small_pool, {"P"}, 2))
print(recall_at_k(larger_pool, {"P"}, 2))
输出是 1.0 和 0.0。完整可运行例子在 evaluation.py,只用 Python 标准库。
别把两个 Recall 定义混着用
这一页用标准的已知正例分母,$P$ 表示该用户全部已知正例的集合(上面的例子里只有候选 P 一个):
$$\operatorname{Recall@K}=\frac{|\operatorname{TopK}\cap P|}{|P|}.$$
如果改成除以 $\min(|P|,K)$,那是另一个归一化定义。比如 4 个已知正例、Top-2 命中 2 个,前者是 0.5,后者是 1;不写定义,读者根本不知道“涨了”意味着什么。
无已知正例的用户记为未定义,并单独报告数量,不要悄悄当成满分。正例很少时,指标波动大;比较人群还要看样本量、曝光(exposure)机会和候选池,不能只比绝对分数。
比较两种方案时,要固定什么?
| 要比较的改动 | 至少固定什么 | 另看什么 |
|---|---|---|
| 新召回来源 | 总候选预算、时间窗、标签协议 | 独有相关候选、覆盖与延迟 |
| 新 ranker | 同一批候选、特征快照、评估人群 | 排序效果、校准(calibration)与成本 |
| 多样性(diversity)重排 | 候选和基础分数 | 相关性损失、主题覆盖、重复率 |
| 新训练信号 | 独立评估集与清楚的标签口径 | 子群体表现、泄漏、负迁移 |
这些是控制变量建议,不是把真实系统拆得互不影响。固定条件的实验帮助归因,端到端实验再检查组合效果。
评估也要有数据流
flowchart LR A["按时间切分数据"] --> B["固定候选与标签协议"] B --> C["同条件比较"] C --> D["按用户与内容切片"] D --> E["人工复核失败样本"] E --> F["决定是否值得受控上线"]
历史行为不等于完整偏好。新系统会改变曝光,旧日志通常无法直接告诉你新曝光下的反应。模拟用户可以测试协议、极端情况和长期反馈环,却不是独立的真实用户收益证明。
总分上升,为什么两组都没变好?
再看一组纯教学数字。A 组任务较容易,B 组较难,两次评估中各组分数都完全没变:
| 组别 | 每组平均分 | 旧评估人数 | 新评估人数 |
|---|---|---|---|
| A | 0.8 | 20 | 80 |
| B | 0.2 | 80 | 20 |
旧总分是 (20×0.8 + 80×0.2)/100 = 0.32,新总分是 0.68。看起来涨了 36 个百分点,实际上只是人群比例换了。用固定的 50/50 权重,两次都是 0.5。
不同的汇总方式各有用途。按真实流量加权,是想了解当前用户整体的表现;各组等权,是不想让人数少的组被掩盖;让同一批用户分别测新旧模型,则能减少样本组成变化的干扰。报告时保留各组人数和分数,读者才能看懂总分为什么变。
比较两种表示时,固定同一批查询、内容塔(candidate tower)/索引、候选预算和标签协议,再看逐查询差异。重复训练估计训练方差(variance);对评估样本做合适的配对重采样估计样本不确定性;两者不能互相代替。用户有多条相关请求时,应考虑按用户分组,而不是把每条请求都当独立证据。
不过,平衡人数不会补回缺失的标签,也不会消除曝光偏差。某组 Recall 更高,可能只是已知正例更少、更容易找回;还要看内容覆盖和主题多样性,才能判断这组用户的体验是否真的更好。
自测
加大候选池后 Recall 下降,能说模型退步了吗?
不能直接说。任务难度变了,先在同候选池、同标签协议下比较模型,再单独报告扩大覆盖的效果。
多样性增加、原来的 Recall 不变,可以上线吗?
还需看新增内容是否相关、哪些人群受益、是否影响安全与成本。离线证据用于决定下一步实验,不替代部署中的验证。
系列读完后,回到第 1 期:你现在应该能说出每一层该用什么证据判断,而不是只问“模型分数涨了没有”。
接下来进入设计拆解:为什么是双塔 → 组件怎么选 → 怎样可靠上线。
本页术语 6
- 候选 candidate
- 召回阶段捞出来、等待精排挑选的内容
- 曝光 exposure
- 内容真的被展示给用户这件事,和「被检索到」不是一回事
- 校准 calibration
- 模型给出的置信度是否等于真实正确率
- 多样性 diversity
- 结果之间在主题、来源或其他指定维度上有多大差异
- 内容塔 candidate tower
- 双塔检索中把候选内容编码成可预计算向量的模型分支
- 方差 variance
- 估计量的波动幅度;重要性加权最容易在这里爆炸