目录 · 10 节
1它到底在解决什么问题?2SLIDE 的整体流程3教师:先把搜索质量做上去4离线造目标:把 20 条搜索路径串成一条序列5主实验:0.5B 学生贪心一遍能不能追上 beam search6扩展实验:放大哪一头更划算7列表生成之后做 RL 的空间更大8我认为它的局限9一个推荐/搜索团队可以怎么试10一句话结论生成式召回线上通常用 beam search 出候选:每个 beam 各自生成一个商品的 SID,各走各的路,彼此看不到对方。想让模型一口气写出整张列表、后一个商品能参考前面已经出过的,最直接的做法是贪心解码一条序列,可效果差得多。在淘宝搜索上,同一个按列表训练的 0.5B 模型,贪心解码的 HR@20 比 beam search 低 18.4 个点。淘宝的 SLIDE(一种把离线搜索结果蒸馏成列表的训练方法)把搜索挪到离线:先训一个教师模型,对每个训练请求跑 beam search,把搜出来的 20 个商品按得分从高到低拼成一条长序列,再让 0.5B 的学生模型照着这条序列学。学生线上只贪心解码一遍。教师用 0.5B 时,学生的 HR@10 从直接训练贪心的 0.3206 升到 0.4321;教师换成 7B,学生达到 0.4578,反超同尺寸模型 beam search 的 0.4498。
做生成式召回、特别是想在召回阶段直接做列表级优化(多样性、相关性 RL)的团队值得读。它把“贪心解码为什么不如 beam search”拆成两个可以单独处理的原因,再用一份离线造出来的训练目标同时补上,思路简单、线上不加任何成本。核心思想一句话:让离线的教师负责搜,让线上的学生只负责按顺序写。它的边界也很清楚:只在两个数据集上做了离线 HR 评测,没有线上 A/B,离线造数据的开销也不小。
它到底在解决什么问题?
先看现在的主流做法。每个商品编成一串固定长度的 SID(淘宝搜索用三层,码本大小 32768、8192、8192),模型读入 query 和用户历史,逐个 token 生成 SID。beam search 同时保留多条前缀,最后剩下的每条路径对应一个商品,按累计对数概率排序就是 Top-K 列表。
这套做法有两个绕不开的问题。第一,列表里的商品是彼此独立生成的,第 5 个商品不知道前 4 个是什么,没法显式避开重复或照顾多样性。第二,做 RL 时,每条回答只有一个商品,所有候选都在抢第一名,很难直接优化“整张列表好不好”这种目标。
贪心生成整张列表正好能解决这两点:一条序列里每 3 个 token 是一个商品,后面的商品以前面所有商品为条件。可直接训出来的模型这样解码,效果很差。用一个示意场景说明:
| 用户搜“露营椅” | beam search(示意) | 贪心整列表(示意) |
|---|---|---|
| 第 1 位 | 便携折叠椅 A(购买过同款) | 便携折叠椅 A |
| 第 2–5 位 | 月亮椅、蛋卷桌椅套装、克米特椅、钓鱼椅 | 两款相近的折叠椅 |
| 第 6 位以后 | 继续展开其他分支,凑满 200 个 | 很快输出结束符,列表只有几十个 |
作者把差距归到两个原因。一是搜索空间:beam search 同时探索很多条 SID 路径,能找到联合概率高的商品,贪心只走一条,第 1 位就已经吃亏。二是正样本太少:训练目标按“购买在前、点击居中、曝光未点击在后”排列,购买又很稀少,于是“排在第几位”和“是什么互动”绑在了一起,列表后面的位置几乎只学到曝光样本,越往后越弱。下图是同一个模型两种解码的 HR 曲线,K 越大差距越大。

SLIDE 的整体流程
整条流水线分三段:
| 阶段 | 输入 | 做什么 | 产出 |
|---|---|---|---|
| 教师训练 | 精排日志 | 用 12 个商品的列表做 SFT | 一个 0.5B、3B 或 7B 的教师 |
| 离线造目标 | 每个训练请求 | 冻结教师跑 beam search,取得分最高的 20 个商品,按分数从高到低拼接 SID,末尾加结束符 | 新的训练标签 |
| 学生训练与上线 | 同样的请求、新标签 | 从原始预训练权重初始化 0.5B 学生,普通 SFT 两轮 | 线上只跑学生,贪心解码一遍 |

关键分工是:beam search 只在离线跑,负责把候选找全;学生要学的是把这些候选按顺序一个接一个写出来。下面拆开讲。
教师:先把搜索质量做上去
学生能学到的上限取决于教师搜出来的东西,所以第一步是训一个尽量强的教师。
为什么用精排列表当标签?
用户真实行为太稀疏,只用点击和购买训练,模型见到的正样本很少。精排的输出覆盖了更多上游召回送进来的候选。作者比较了三种标签:只用行为、用精排列表、以及把正样本挪到最前面的精排列表。最后这种作者称为 PF-Fine-ranking,意思是正样本优先的精排列表,做法是购买的商品排第一,点击的其次,曝光未点击的最后,组内保留精排原来的顺序。
为什么正样本要放最前?
beam search 只用模型在第一个商品位置上的输出分布。把购买商品放在第一位,它就在 beam search 真正用到的那个位置上得到了直接监督。教师的损失就是按列表逐个商品算负对数似然:
其中 是第 个请求的 query 和用户特征, 是列表里第 个商品, 是它前面的商品。直觉上,每个商品都在“看过前面那些”的条件下被预测。
| 教师标签(beam search 评测) | HR@1 | HR@10 | HR@20 |
|---|---|---|---|
| 只用行为 | 0.1126 | 0.3934 | 0.4978 |
| 精排列表 | 0.1458 | 0.4384 | 0.5337 |
| 正样本优先的精排列表 | 0.1492 | 0.4498 | 0.5432 |
换成精排列表,HR@10 提高 4.5 个点,说明精排结果确实给了行为日志之外的有效信号;再把正样本挪到最前,又多 1.1 个点,增益不大但每个截断位置都稳定。作者也确认了逐点训练和按列表训练的教师在 beam search 下差别很小,HR@10 只差 0.23 个点,所以用按列表训练的模型当基线是公平的。
离线造目标:把 20 条搜索路径串成一条序列
为什么不能只把候选给学生?
教师搜出来的商品覆盖了整个商品库,不只限于曝光过的那些,这是监督变多的来源。可只有一堆候选,贪心解码器还是不知道该先写哪个、后写哪个。所以作者把它们按 beam 得分从高到低直接拼起来,中间不加分隔符,也不过滤无效 SID。因为每个 SID 长度固定,每 3 个 token 自然就是一个商品。
举个手算的例子(示意):教师对“露营椅”搜出三个商品,SID 分别是 (12,5,88)、(12,7,3)、(40,1,9),累计对数概率是 −1.2、−1.9、−2.6。拼出来的目标就是 12,5,88,12,7,3,40,1,9,EOS,一共 10 个 token。学生训练时就是普通的 teacher forcing,逐 token 算交叉熵,不需要教师在线前向,也不做软标签匹配。
为什么顺序很重要?
作者做了一个对照:保留每条目标里的商品集合,只把顺序随机打乱。

打乱后 HR@20 基本不变,HR@1 却掉了一半多,NDCG@20 从 0.3010 降到 0.2271。这说明商品集合决定召回得全不全,顺序决定学生先写好的还是先写差的,两样都要从教师那里学。
目标列表取多长?
作者把每条目标的商品数设为 12、20、50 分别训练,结果每种长度都在对应的截断位置上最好:12 个商品的 HR@12 最高,50 个商品的 HR@50 最高,但浅层指标没有变好。所以关心 HR@K 时,目标里放 K 个商品就够了,再长只是增加离线造数据的成本。
主实验:0.5B 学生贪心一遍能不能追上 beam search
实验用两个数据集。FORGE(一个公开的推荐数据集)规模上亿用户,每条训练样本只有一个目标商品。淘宝搜索是作者构造的工业数据,用连续 10 天的请求训练、第 11 天测试,每条样本约 12 个目标商品。线上部署的模型都是 0.5B。
| 数据集 | 方法 | 教师 | 解码 | HR@1 | HR@10 | HR@20 | 平均候选数 |
|---|---|---|---|---|---|---|---|
| FORGE | 直接训练 | – | beam search | 0.0067 | 0.0366 | 0.0538 | 200.0 |
| FORGE | 直接训练 | – | 贪心 | 0.0050 | 0.0050 | 0.0050 | 3.9 |
| FORGE | SLIDE | 7B | 贪心 | 0.0081 | 0.0441 | 0.0614 | 61.1 |
| 淘宝搜索 | 直接训练 | – | beam search | 0.1492 | 0.4498 | 0.5432 | 195.6 |
| 淘宝搜索 | 直接训练 | – | 贪心 | 0.1318 | 0.3206 | 0.3627 | 35.0 |
| 淘宝搜索 | SLIDE | 0.5B | 贪心 | 0.1470 | 0.4321 | 0.5194 | 71.3 |
| 淘宝搜索 | SLIDE | 7B | 贪心 | 0.1532 | 0.4578 | 0.5459 | 74.2 |
FORGE 上直接训练的贪心解码几乎没法用,平均只吐出 3.9 个商品,因为训练目标只有一个商品,模型从没学过写第二个。淘宝搜索的 12 个商品标签好一些,但贪心的 HR@10 还是比 beam search 低 13 个点。这说明光用列表训练,补不上两种解码的差距。
换成教师搜出来的目标后,即使教师和学生一样大,淘宝搜索上的 HR@10 也追到了 beam search 的 96%。这部分增益只能来自目标本身,因为模型结构和大小都没变。教师换到 7B,学生在两个数据集的所有 HR 指标上都超过了同尺寸的 beam search。教师变大带来的收益可以全部留在离线,线上模型不变,这一点对受延迟约束的召回很实用。
扩展实验:放大哪一头更划算
作者从三个方向做了放大。固定学生、放大教师,效果持续变好,7B 教师教出来的 3B 学生 HR@5 达到 0.3760,比直接训练的 3B 模型的 0.3623 还高。固定 3B 教师、放大学生,学生和教师在 HR@20 上的差距从 0.5B 时的 3.77 个点缩到 7B 时的 0.75 个点,说明小学生吸收不完教师给的信息。头部比尾部更容易学:7B 教师下 0.5B 学生的 HR@5 追平了直接训练的 3B 模型,HR@20 还差 2.6 个点。
多训几轮也有用。第二到第四轮,贪心解码的 HR@20 又涨了 1.60 个点,beam search 却基本饱和。一个合理的解释是,写出一整张有序列表比只学第一个位置难,同一份数据反复训练对前者还有收益。
列表生成之后做 RL 的空间更大
这篇真正的动机是为召回阶段的列表级 RL 铺路,所以作者补了一组对比。两边都用 CTR 乘以 CVR 当奖励,由一个打分服务给出,用 GRPO 更新。逐商品的版本里,每条回答是一个商品。列表版本里,每条回答是一整张列表。对同一个请求采样几张列表,把里面出现过的商品去重合成一个候选集,每个商品的奖励减去这个候选集的平均奖励、再除以标准差,得到它的优势值。这个优势值只赋给该商品自己的那几个 token,所以同一张列表里好的商品被加强、差的被压低。同一个商品在列表里第二次及以后出现时,这几个 token 不拿奖励带来的优势值,最后一个 token 还会被赋一个负的优势值,以此压住模型反复写高奖励商品。
| 解码方式 | 阶段 | HR@1 | HR@10 | HR@20 |
|---|---|---|---|---|
| 逐商品 beam search | SFT | 0.1557 | 0.4257 | 0.5098 |
| 逐商品 beam search | RL | 0.1570 | 0.4307 | 0.5132 |
| 整列表贪心 | SFT | 0.1916 | 0.5061 | 0.5868 |
| 整列表贪心 | RL | 0.2063 | 0.5267 | 0.6071 |
列表版本 RL 后相对提升 3.46% 到 7.67%,逐商品版本只有 0.59% 到 1.17%。附录里用内部相关性模型当奖励再做 RL,各截断位置的相关性分又提高约 3 个点。这说明整列表生成给了 RL 更多可以调的东西,同一条序列里不同位置的商品可以分别得到正负反馈。
我认为它的局限
第一,只有离线 HR,没有线上 A/B。作者自己也说它适合端到端直接出列表的场景,不适合给下游排序提供大规模候选。学生线上一直解码到输出结束符或写满 1024 个 token,实际写出的商品比训练目标里的 20 个多,去掉无效和重复的编号后平均剩 60 到 75 个;beam search 基线则平均给出约 200 个候选,在需要大候选池的链路里这不是同一个口径的比较。
第二,离线成本和流程复杂度都不低。每个训练请求都要跑一遍教师 beam search,再加上三段式训练,模型每迭代一次都要重造数据。作者把“单阶段训练就能让贪心追上 beam search”列为未来工作,说明目前还没有更轻的路线。
第三,教师目标会冲淡真实转化信号。只有约 60% 的目标里包含用户真正购买的商品;把购买商品强行插到第一位,贪心解码反而略降,beam search 却明显变好。这个对比是在训练没收敛时做的,结论还不稳。
一个推荐/搜索团队可以怎么试
- 先在现有生成式召回上复现差距:同一个模型分别跑 beam search 和贪心,看 HR 曲线在哪个位置开始拉开。如果差距只在头部,问题主要是搜索空间;如果越往后越大,就是位置监督不足。
- 用现有线上模型当教师,离线跑一遍 beam search 造目标,训一个同尺寸学生,对比贪心 HR@K。这一步不需要训新教师,最便宜,能直接看到目标本身带来多少增益。
- 增益成立后再放大教师,目标长度取业务真正关心的截断位置,避免白花离线算力。
- 最后在学生上做列表级 RL,把多样性或相关性写进奖励,看它是否比逐商品 RL 提升更多,再决定是否值得上线 A/B。
一句话结论
最关键的启发是:贪心生成整张列表之所以弱,问题出在训练目标太稀、太偏,用离线搜索把目标补全、排好序,就能让一个小模型线上走一遍达到 beam search 的效果。
| 维度 | 评价 |
|---|---|
| 问题重要性 | 高。召回阶段做列表级优化的前提就是能一次生成整张列表 |
| 方法创新性 | 中。离线搜索加蒸馏的思路已有先例,新意在把多条搜索路径串成一条有序目标 |
| 实验证据 | 中。两个数据集、消融完整,但没有线上 A/B,候选数口径也不同 |
| 工程成本 | 中高。线上不变,离线要对全部训练请求跑教师 beam search |
| 是否值得尝试 | 值得。已有生成式召回的团队用现成模型当教师就能先验证 |
| 适用场景 | 直接输出十几到几十个结果的电商搜索或推荐召回 |
读完这篇,你觉得
夜读鸮记下了,谢谢你的反馈。
点一下即可,无需登录;再点一次撤回。只统计匿名次数,不记录你是谁。
讨论
欢迎补充实验细节、复现经验或不同看法。需 GitHub 登录。
正在加载讨论…