如果你做过一段时间推荐系统,一定对“排序模型”四个字有话想说。它不像召回层动不动就讲海量向量检索,却真真实实地决定用户每一次刷屏看到的第一个结果;它也不像特征平台那么庞杂,却在离线指标和线上收入之间来回考验人的判断力。排序模型的演进,本质上是我们把“怎么把最合适的物品放到最前面”这条规则,从拍脑袋逐步变成数据和模型说话的过程。
我最早入行时,团队里的主力模型还只是一个线上 LR,特征全靠人肉写代码组合。后来 FM、GBDT+LR、Wide&Deep、DeepFM、DIN、MMoE 这些名字一个个冒出来,组内一度陷入“模型军备竞赛”。等踩过几轮上线回滚的坑,我才意识到排序模型演进不是新网络结构替换旧网络结构那么简单,它牵涉到特征表达能力、训练目标设计、在线服务约束和业务指标对齐一整条链路。
这篇文章不打算按年份把论文流水账式罗列一遍,而是从我个人实际落地经验出发,按“传统模型→深度模型→多目标模型→工程落地”这条主线,把排序模型演进过程中的关键选择、关键公式和关键坑都说清楚。无论你是刚接触推荐系统的新人,还是正在做新一轮模型升级的技术同学,应该都能从这里找到一些可以直接参考的东西。
1. 先搞清楚:整个推荐链路里,排序模型在解决什么问题
1.1 从千万候选到首屏结果:排序发生在哪里
推荐系统的完整链路通常可以简化成“召回 → 粗排 → 精排 → 重排 → 展示”。召回从全量内容池里筛出几百到几千个候选,粗排确保精排模型不用处理太大规模的候选集,精排给每位用户和每个候选算一个精细的分数,最后重排再把多样性、商业规则、连续体验等因素掺进去。我在实战里最常见的一个误区,是新人一上来就盯着精排模型看,忽略了粗排和重排也有自己的“排序逻辑”。
排序模型在精排环节的核心任务是:给定用户特征、物品特征、上下文特征,以及召回返回的候选集合,为每个候选评估一个“被用户接受”的概率。这个概率在产品上既可能是点击率,也可能是转化率、收藏率或观看时长。很多团队会直接把精排模型的输出叫“预估分”,但同一个分数在搜索、信息流、商品推荐、视频推荐里的含义差别很大。搜索场景用户带着明确意图进来看第一屏;信息流场景用户意图模糊,更考验模型对实时兴趣的捕捉。
因为候选集大小和响应时延要求不一样,排序模型在链路不同位置的长相也不一样。粗排通常会用双塔或者简化版的深度模型,为的是在极短时间内过滤掉明显不合适的候选;精排则会用特征更丰富、交互更充分的深度模型,哪怕单个样本计算量大一点,也必须在几十毫秒内完成预估。换句话说,排序模型的演进,始终被“效果更好”和“线上跑得动”这两股力量拉扯着往前走。
1.2 排序模型演进的三条主线
如果把十多年的演进压成三句话,我认为是:第一,特征交互从人工指定走向自动挖掘;第二,模型结构从线性打分走向非线性的多层表达;第三,目标函数从单点预估走向多目标联合决策。这三条主线不是独立发生的,它们互为条件。
人工指定特征交互年代,我们需要自己写“用户是否点击过某类目”乘以“当前页是否信息流”这样的交叉逻辑。这样做的能效比很低,因为一个具备代表性的交叉组合可能藏在海量特征之间,靠人肉来找基本不现实。于是有了 FM 系列用隐向量来近似二阶组合,又有了各类基于树和深度神经网络的结构去自动提取组合模式。
从线性到非线性,解决的是数据拟合能力问题。线性模型天然适合理解简单规则,但真实推荐数据里到处都是非线性关系。一个用户对一件商品的点击意愿,可能同时受到价格带、款式风格、时间点和历史上相似行为的影响,它们之间不是简单相加。深度模型通过多层映射、注意力机制和特征交叉模块,把这种高维非线性的关系逐步逼近出来。
单点预估到多目标联合优化,则是业务压力倒逼的演进。早期推荐系统最主要的反馈信号就是点击,大家拼命优化点击率。后来发现点击率上去了,但收藏、转化、客单价这些商业指标没跟着涨,单纯点击目标并不等于用户价值。比如电商场景里,用户点一个便宜的小商品很容易,但平台真正关心的是成交和复购,所以在排序阶段需要让曝光点击率、点击转化率、长周期复购概率等信号共同参与决策。这条演进路线也是很多团队从零开始搭建排序模型最需要理解的全局图景。
2. 传统排序模型:LR、FM/FFM、GBDT+LR 为什么是必经之路
2.1 LR:为什么它能支撑这么多年,又为什么不够
逻辑回归在二十多年里一直是推荐和广告领域的主力模型,到今天依然大量出现在不少成熟系统里。原因不难理解:首先,LR 是广义线性模型,输出值天然在0到1之间,可以直接解释成点击率;其次,模型简单意味着训练和推断成本低,工程上很容易做到天级甚至小时级更新;再次,lr 的特征权重是有明确量纲的,能支撑算法同学分析特征重要度,告诉运营和产品“哪些特征更影响排序结果”。
但 LR 的表达能力瓶颈也很清晰:它本质是在做各个特征和权重之间的线性加权,特征之间的交互作用必须提前通过人工构造来体现。举个我在业务里见过无数次的场景:用户性别和商品类目之间的组合模式,对点击率影响非常大。如果只给 LR 喂“性别”和“类目”两个独立特征,模型学出来的就是一个男女性别的固定偏好加上一个类目的固定偏好,无法捕捉“男性用户在三C类目高点击、在美妆类目低点击”这种交叉规律。解决办法是人工生成sex=male & category=3C这样的组合特征,但如果组合空间太大,人工筛选的组合永远只是冰山一角。
线上做 LR 时还有个经常被忽视的细节:连续特征的归一化和分桶。为了防止个别量纲特别大的特征把权重训练带偏,我们早期会做 z-score 归一,后来更多用分桶把连续值转成离散特征。分桶之后每个桶都获得一个独立权重,如果桶数量设置合理,模型能够表达出“年龄在18到24时点击率陡增,25到30时平缓下降”这样的非线性片段。从这个角度说,LR 当年讲究的从来不是模型结构,而是特征工程和样本工程的手艺。
2.2 FM/FFM:用隐向量把二阶交叉自动化
FM 最大的贡献,是把“给每个特征学一个向量,两两特征间用内积表示交叉权重”这件事引入了推荐排序。它的原理并不复杂:如果是 LR,想让特征 a 和 b 交叉,需要人工造一条特征;而在 FM 里,交叉项的计算可以写成所有特征两两组合后隐向量内积的和,公式看起来像y = w0 + sum(wi * xi) + sum_{i<j} <vi, vj> * xi * xj。这里<vi, vj>就是特征 i 和特征 j 隐向量之间的内积。
这个变化的价值不只是自动化,更在于参数量的节省和泛化能力。假设有 1 万个类目特征和 1 万种用户动作特征,如果采用 LR 人工枚举交叉,最多可能出现上亿个组合权重,很多组合在训练样本里根本没出现过,学不出可靠权重;FM 让每个特征只维护一个固定维度的向量,哪怕某些组合没有同时出现,模型也可以依靠各自学到的向量来判断它们是否匹配。我见过不少团队把 FM 作为排序模型基线,它效果远好于简单 LR,训练效率又比深度学习高一个量级。
FFM 则进一步把“特征属于哪个场”的概念引入。同样是商品 id 向量,在“点击历史商品”这个场里和“当前候选商品”这个场里,即使 id 相同,也应该有不同表达,因为它们和用户当前意图之间的语义关系不同。FFM 让每个特征针对不同场分别学习一个隐向量,交叉项计算时使用对应场的向量。效果通常会比 FM 好一些,但模型参数量也会显著上涨,训练和推理都要花更多资源。在实际落地时,如果特征规模本身已经覆盖了几亿用户和千万级商品,FFM 的全量参数可能大到在线服务扛不住,需要做剪裁或分布式部署。
2.3 GBDT+LR:让树模型帮你做特征组合,再交给线性模型打分
Facebook 在 2014 年前后提出的 GBDT+LR 方案,是排序模型演进史上一个非常实际的里程碑。这个方案看起来有点像“拼装”,但效果出奇地好。思路可以概括成:先用 GBDT 对原始特征进行多次分裂,每一棵树都会把样本分到某个叶子节点,把所有树的叶子节点拼接起来,形成一组高维稀疏的二值特征,再把这组特征喂给 LR 做最终打分。
为什么这么做有效?因为 GBDT 的每一棵子树本质是在自动做特征选择和组合。原始特征空间很大,树分裂时会挑选区分度最好的特征和阈值,一路分下去之后,不同叶子节点代表的实际上是“这几条特征条件同时满足时,用户点击倾向具有某种共性”的组合规则。比如一棵树可能学出“近7天点击某个品类次数大于3次”和“当前小时在21点到23点之间”组合起来的叶子,这只靠人工琢磨并不容易发现。
从工程落地来说,GBDT+LR 的好处是树的离线训练可控,在线把 GBDT 跑完,提交一次 LR 预测即可,相对后来沉重的深度模型,当时在服务端资源上还算友好。我记得实际应用时通常会把树的数量控制在几百棵到上千棵之间,单棵树深度 4 层到 6 层,并且要做严格的负采样比例控制,否则在线预估的点击率绝对值会严重偏离真实值。这套方案被很多团队沿用很久,直到深度模型在特征表达和持续优化上全面超过它之后,才逐渐退居基线位置。
如果你现在还在一个中小型推荐项目里做排序,我依然建议把 GBDT+LR 当作一个效果对标点。因为它的可解释性在大规模排序模型里非常罕见,你不仅能告诉业务方线上排序“为什么这个商品排到前面”,还能从叶子分裂条件里提取出业务特征的显著程度。后续很多深度模型虽然拟合能力更强,但在这类“归因”问题上反而难倒不少人。
3. 深度学习排序:从 Wide&Deep 到行为序列建模的实操认知
3.1 Wide&Deep 与 DeepFM:记忆与泛化怎么分工
Google 当年提出 Wide&Deep,最初服务于 App 推荐下载场景。核心思路是我后来一直会跟新人强调的:模型需要同时拥有“记忆”和“泛化”。Wide 部分通常包含一部分交叉特征和原始强特征,相当于带有一块显存,它会直接记住“装了某 App 的用户看到同款 App 更可能点击”这类经验规则;Deep 部分则把 ID 类特征映射成稠密向量,再经过几层全连接学到用户和物品之间更抽象的关联模式。
从工程视角看,Wide 和 Deep 并行训练,最大的挑战在于 Wide 侧需要输入人工构造的交叉特征,而深度侧需要大量 embedding 特征。这两部分计算量相差很大,训练时稍不注意就会出现一侧收敛慢而另一侧过拟合的情况。我在实际项目里会把 Wide 侧的学习率调得比 Deep 侧稍微大一些,或者对 Wide 侧做 L1 正则以保持稀疏性。如果 Wide 侧喂进去的特征规模太大,还要担心在线推理时特征拼接和预计算的一致性问题,通常我们会把 Wide 侧特征集和 Deep 侧特征集严格分开配置,避免改特征时误动模型入口。
DeepFM 是对 Wide&Deep 的一种精简迭代。它用 FM 替代了 Wide 侧的人工交叉特征,让低阶和高阶特征交互都能够自动学习,Deep 部分则继续承担高阶非线性拟合。DeepFM 一度是工业界最流行的排序模型之一,因为它不需要像 Wide&Deep 那样费力去设计 Wide 侧的交叉特征,工程实现上也相对容易收敛。我做过两组线下对比,在相同特征集下,DeepFM 基本稳定超过只用 Deep 部分的 DNN,说明显式建模低阶特征交互对于排序任务仍然是有效补充。
3.2 用户行为序列建模:DIN 与 DIEN 解决的不是特征,而是意图
在做电商或内容推荐时,用户历史行为序列是最珍贵的信号之一。比如用户过去 30 天点击过一批商品,这批商品的类目、价格、品牌等属性在相当程度上刻画了用户偏好。但真实系统里,用户行为序列长度往往在几十到几百之间,直接把所有行为商品求平均 embedding 会淹没关键信息。DIN 模型的核心就是用 Attention 机制把“历史行为”和“当前候选商品”关联起来,给每个历史行为算一个相关度权重,再按权重加权求和得到用户兴趣向量。
为什么这个加权很重要?假设用户平时既看母婴用品又看数码产品,今天他刷到一款折叠手机。如果他历史点击里数码类记录和当前商品的相关度高,模型就应该让这部分行为主导当前兴趣表达;而母婴类行为虽然频率高,在这个场景里却会干扰判断。DIN 的注意力得分主要基于“候选商品 embedding 与历史行为 embedding 的相似度”,在训练时还会加入一个用于平滑的激活单元,用非线性变换保留更多上下文信息。
DIEN 在 DIN 基础上继续深挖,认为用户兴趣不是静态的,而是随着行为链发展不断演化的。它引入 GRU 结构对行为序列做时序建模,并用辅助损失让每一步的兴趣状态更贴近真实的下一步行为。做短视频和信息流场景时,我对 DIEN 类模型的感受是它对“即时兴趣转换”更敏感:用户上一次点击偏好是篮球,可能因为一个新热点快速转到游戏,如果模型只有静态加权,容易反应慢半拍。但 DIEN 对序列质量和训练工程的依赖更大,如果序列里混入大量误点击、无效曝光,效果甚至可能跑不过加了 DIN 的简单模型。
3.3 从模型到服务:深度排序上线的四个隐藏约束
深度排序模型的“效果优势”很容易在离线实验中体现,可一放到线上就跑不出同样的结果,甚至还会跌,这是我见过最高频的问题。背后通常不是模型结构问题,而是工程一致性出了问题。
第一个约束是特征穿越。排序模型的样本通常由曝光日志加后续行为拼接而来,训练时如果不小心把“用户是否点击过当前商品”这类目标相关特征拼进特征表,离线 AUC 会异常高,线上却完全拿不到这个特征。我见过有人把“商品在本次曝光前是否被收藏”当作特征,曝光后再产生的收藏行为也算进去,这等于让模型偷看未来答案。
第二个约束是序列特征的实时性。离线可以方便地取到用户过去 7 天的完整行为序列,线上服务时却受限于存储成本,可能只取最近 3 天或者采样一部分。特征分布一不一致,模型表现就会打折扣。我们在做模型迭代时必须保证离线特征口径和在线服务一致,否则不如不带这类特征。
第三个约束是训练和预估时的 embedding 映射稳定性。若线上把新增用户或商品 id 映射成同一个统一向量,会导致大量不同 ID 共享表达,表现力和冷启动特性都受影响。通常需要设计专门处理这类新增实体的 id 哈希策略,并预留一部分可扩展维度。
第四个约束是资源预算,也是团队内最容易忽视的“模型上线红线”。一个精排模型做得很花哨,如果单次推理从 5 毫秒涨到 50 毫秒,在流量高峰期就会占用大量 CPU/GPU,直接把预算压垮。业界常做的是蒸馏、量化和裁剪,把大模型的推理代价压回可接受范围。排序模型不是越复杂越好,而是要能在时延预算和效果指标之间找到一个可迭代的平衡点。
4. 多目标排序和业务全链路:排序模型真正的演进终点
4.1 为什么单目标不够用
早期排序模型只需回答“用户会不会点击”,因为点击日志最丰富、反馈最快。后来产品经理和运营发现,高点击不等于高转化,更不等于高商业价值。比如电商场景里,“9.9 元包邮”的商品点击率通常极高,如果排序模型只学习 CTR,推荐流里会被低客单、低利润商品占领,用户成交额和平台佣金反而下降。
另一个典型是视频平台。用户被标题党吸引点进去,几秒后就退出,这种点击对生态是负向的。排序模型如果只知道让预估点击率最大化,就会持续推送标题党内容。于是大家把“有效播放时长”“完播率”“关注率”“转化率”等多个目标放进排序阶段,希望在曝光时综合考虑短期反馈和中长期留存。
多目标并不是简单把几个损失函数加权相加。不同目标的样本空间不一样,比如 CVR(点击后转化率)只在有点击行为的样本上有定义,如果只在这部分样本上训练,模型会受严重的样本选择偏差影响。又比如收藏率目标本身事件稀疏,如果和 CTR 共用一个复杂网络,要么收藏目标学不到位,要么反过来干扰 CTR 学习。所以多目标排序模型的演进核心,其实是解决“目标之间怎么共享信息”和“稀疏目标怎么稳定学习”。
4.2 主流行路线:ESMM 和 MMoE 的两个不同范本
阿里提出的 ESMM 是针对电商“曝光→点击→转化”漏斗建模的经典方案。它把预测拆成两个子任务:一个是 pCTR,基于曝光样本预测点击概率;一个是 pCVR,理想情况下应该基于点击样本预测转化概率。但 pCVR 如果只在点击样本上训练,会有非常严重的样本选择偏差,ESMM 的关键在于用乘法关系构造出 pCTCVR=pCTR×pCVR,并且让 pCTCVR 在曝光全集上去逼近真实的全样本转化率标签。这样 pCVR 的学习被暴露在全空间样本下,能够间接缓解偏差问题。
MMoE 则是多任务学习的另一种通用框架,很适合底层任务相关性没那么高的场景。它不再强制所有任务共享同一个底座,而是准备多个专家网络,每个专家都能学到不同维度的特征抽象,再由门控网络根据输入样本自动判断每个专家对当前任务应该占多少权重。直观理解是,预测点击率时需要关注价格和标题吸引力,预测转化率时更关注商品评价和运费模板,它们可以分别让不同的专家网络负责,又不至于把参数完全割裂。
实际落地时,做多目标排序的团队通常还会引入一个“业务目标融合层”,把 pCTR、pCVR、时长预估等多个模型的输出用可学习的权重组合起来。比如电商可以把排序分设计成score = pCTR^a * pCVR^b * price_weight^c之类的形式,超参数通过线上实验调优;做内容推荐的则可能直接让模型输出“用户在该内容上的停留时长”作为主排序分。融合策略虽然看起来没有模型结构那么高深,但它往往是多目标排序是否真的能带来业务提升的最后一步扳机。
数据样本也要按业务目标分层处理。我在操作时会给不同目标的权重配不同采样率,点击目标用全量样本,转化目标用点击样本和一定比例的负反馈样本,长周期留存目标可能再单独抽更长时间段的样本。每个目标的训练频率甚至不一样,需要提前在样本管线里做标记,避免每次全量重训时各目标样本日期范围错位。
4.3 粗排、精排、重排,排序模型在不同水位如何分工
把排序模型放到完整推荐链路里看,会发现在不同水位,模型的优化目标和约束其实非常不一样。粗排接在召回后面,通常有几千个候选要过滤,不可能直接跑复杂的精排模型。主流做法是训练一个轻量模型,或者用知识蒸馏把精排模型的能力“压缩”到浅层模型中,粗排的目标不是精确还原精排顺序,而是尽量不把最终会展示的正样本误杀。
精排模型是投入最多资源的地方,特征最全、结构最复杂、目标也最多。在线推理时只针对经过粗排后留下的几百个候选打分,所以可以负担相对更强的模型。精排之后通常还有一个重排环节,虽然常被简化叫“机制层”,但它同样在做排序决策:需要保证相邻两条内容不重复、避免同一个作者或店铺霸屏、穿插广告位、兼顾用户刷到第几屏的疲劳程度。重排本质上是 listwise 视角的优化,它不再是给每个候选独立打分,而要考虑候选之间对整体体验的影响。
所以当你听到“排序模型演进”时,视野不要只停留在精排结构上。我接触的很多团队,最后实际带来业务提升的反而是粗排从双塔升级为“三塔加特征交叉”、重排加入序列生成思路这类改造,精排模型的迭代效果反而被链路其他环节限制住了。这也提醒我们,模型演进必须配套看链路级评测,只有全局用户指标涨了才算真正有效。
5. 走过这些坑后的复盘:排序模型选型与评估建议
5.1 离线实验怎么做才不容易骗自己
排序模型迭代最忌讳的就是“离线 AUC 涨了 0.002,就兴冲冲上线”。离线与线上会有样本分布差异、特征时间穿越、流量环境变化。一个相对稳妥的做法是把离线实验的重点放在相对对比上,不要只看 AUC 的绝对值。另外要关注分用户分时段的 AUC 波动,如果指标涨跌集中在某类用户或某个时间段,往往说明新模型学到的是特定分布特征,而不是通用能力。
我自己常用的离线评估矩阵包括 AUC、GAUC(按用户维度加权的 AUC)和带阈值约束的线上点击或转化排序指标。GAUC 比全局 AUC 更能反映个性化排序的收益,因为它把一个用户内部的正负样本排序准确度看得更重要,与用户维度上的实际体验更接近。如果新模型 GAUC 提升但全局 AUC 下降,需要谨慎判断是否出现了特定用户片段上的异常放大。
离线还要做时间穿越检查,我一般会保留最近 7 天数据做验证集,训练集则提前 14 天以上截断。这样能模拟“模型上线时对未来进行预测”的场景,比随机切分更贴近真实。高估模型性能是最常见的问题,宁可离线多怀疑自己,也不要在线上实验里翻车。
5.2 排序模型架构之外的“暗功夫”
我复盘了很多次项目之后发现,真正持续带来收益的往往是那些不起眼的系统能力。特征实时性与新鲜度是最直接的一个:用户当前正在观看内容、刚发生的点击行为能不能在几百毫秒内进入排序特征,直接决定了模型对瞬时兴趣的把握能力。有的团队模型结构没变,只把特征更新延迟从分钟级降到秒级,整体点击时长指标立刻上升一大截。
样本口径和标签定义是另一个容易被低估的地方。比如“曝光是否算负样本”的问题,用户没点不是完全没兴趣,可能只是没看到。如果负样本定义不当,模型会学歪。很多团队会采用“曝光跳过”“曝光但未停留超过阈值”等分桶负反馈策略,让负样本更有业务含义。判断模型好坏不应只看预估值准确性,还要看线上排序分布是否符合预期,模型会不会长期把所有得分压在一个很小的区间。
在线 A/B 实验的“最小有效样本量”也算暗功夫。排序模型带来的指标变化通常很小,如果实验流量不够、观察周期太短,很容易得出错误结论。我们一般建议新模型至少跑 3 到 5 天,覆盖完整的工作日和周末周期,并且同时观察核心指标和护栏指标,防止排序副作用伤害新用户或低活用户。想在少流量团队里快速验证模型,可以考虑做分层削峰实验,把相对稳定的老用户流量切一部分专门跑实验组,降低整体方差。
5.3 值得保持关注的方向
排序模型的演进并没有停在多目标这条线上。我近几年观察到的几个方向,不同程度地开始进入工业实践。一个是把 Transformer 类结构引入排序特征交互,让候选商品与用户行为序列之间的关系建立在更大范围的注意力计算上,比 DIN 这类局部注意力更灵活,但计算复杂度更高,很多团队只在粗排或离线重排序里尝试。
另一个方向是模型与因果推断的结合。推荐系统天然存在曝光偏差,只有被曝光过的物品才有标签,导致模型对曝光概率低的物品学习不足。加上位置偏差后,排在第一位的东西天然获得了更多点击机会,模型预估时容易把位置当成真实的兴趣信号。于是出现了一些针对偏差的纠偏方法,整体思路是让模型学会预测“如果物品被公平曝光,用户会不会喜欢”,而不是预测“在当前排序位置上,用户会不会点击”。这类工作短期内很难做到尽善尽美,但方向非常值得关注。
大模型在排序里的应用也逐步冷却回归理性。早期大家幻想着用统一大模型代替整套排序链路,后来发现时延和成本不是靠调参能抹平的。现在的常见用法是把大模型用在特征增强、冷启动内容理解、扩召回候选这样的重计算场景,精排阶段依然还是用算得动的小模型。也许接下来会出现更高效的蒸馏方案,把大模型的理解能力压缩进线上排序模型,这确实是很考验工程能力的方向。个人的体会是,选模型结构时多替线上运维想一想,能被稳定部署、快速迭代的方案才是好方案。
排序模型演进了这么多年,真正留下来的并不只是那一串模型名字,而是对业务目标、数据质量和工程约束的系统级理解。如果你正打算从 LR 升级到深度学习,建议不要一上来就仿照论文堆复杂模块,而是先把当前链路里最薄弱的环节找出来——是特征不够实时,还是目标没对齐,还是候选侧本身就漏掉了优质内容。排序模型的价值永远建立在正确的数据、合理的链路和自己的业务目标之上。希望这篇文章能帮你少走一些我当年走过的弯路。