1. 项目概述当“选择困难症”遇上亿级数据我们每天都在做选择小到中午吃什么大到项目方案怎么定。但当这个选择问题放大到互联网公司每天要处理的海量场景——比如从百万商品中挑出几十个推给用户或者从千万广告库里选出几十个竞价展示——事情就变得极其复杂。这背后是一个经典的“大规模排序与选择问题”。传统方法要么算得慢要么结果不够准要么两者兼有。今天要聊的这个项目就是我和团队在过去几年里为了解决这类问题将AlphaRank和DCR这两个框架深度结合折腾出来的一套高效求解方案。简单来说AlphaRank是一种基于多臂老虎机思想的在线学习排序框架它擅长在探索尝试新选项和利用选择已知好选项之间做动态平衡。而DCRDeep Candidate Ranking则是一个深度候选排序框架通常用深度模型来快速、精准地评估海量候选对象的“质量”。把它们俩捏在一起目标很明确既要快能处理亿级候选集又要准排序结果符合业务目标还要稳能适应数据分布的变化。这套方案在我们内部的多个核心业务场景如信息流推荐、广告竞价排序、搜索重排等都经过了实战检验效果和性能的提升是实实在在的。如果你正在为海量数据下的排序选择问题头疼或者对如何将在线学习与深度模型结合落地感兴趣那接下来的内容应该能给你一些直接的参考。我会从设计思路、核心实现、踩过的坑以及一些关键调优技巧毫无保留地拆开来讲。2. 核心框架设计为什么是AlphaRank DCR2.1 问题定义与挑战拆解大规模排序与选择问题形式上可以抽象为给定一个上下文Context比如用户画像、当前请求信息和一个巨大的候选对象集合Candidate Set规模N通常在百万到十亿级别我们需要从中选出Top-K个对象K通常很小比如10到100并按照某种效用Utility进行排序以最大化整体业务目标如点击率、转化率、收入等。这里面的核心挑战有三个计算复杂度对N个候选逐一用复杂模型如深度神经网络进行精细打分成本耗时、算力无法承受。N太大而K很小这意味着绝大多数计算是浪费的。探索与利用的权衡业务目标往往不是简单的即时反馈如点击。有些候选长期价值高但短期反馈稀疏需要主动探索才能发现而一味追求短期收益利用可能导致系统陷入局部最优错过增长机会。动态环境适应用户兴趣、商品热度、市场环境都在变。排序策略需要能够在线学习、快速适应而不是依赖离线训练的静态模型。单独使用DCR框架主要是解决挑战1。它通过一个相对轻量的深度模型比如双塔结构对全量候选进行快速粗筛得到一个小得多的候选子集比如从百万筛到几千再交给更复杂、更精准的精排模型。这大大降低了计算压力。但DCR本身通常只做“利用”它基于当前模型认为的“好”来筛选缺乏主动“探索”新可能性的机制。而AlphaRank框架其核心思想来源于多臂老虎机中的Thompson Sampling、UCB等算法天生就是为了解决挑战2和3。它通过为每个候选维护一个收益的概率分布如Beta分布在每次决策时根据分布采样或计算上界来决定排序从而自然地平衡探索与利用。但传统的AlphaRank实现往往假设可以对所有候选进行这种概率分布的更新和采样这在N很大时同样面临计算和存储的灾难。所以很自然的想法就是让DCR负责“海选”快速缩小战场让AlphaRank在缩小后的高质量候选池里进行精细的“探索与利用”博弈完成最终的优胜劣汰和排序。这就是我们整个方案的设计基石。2.2 架构融合串行与协同我们设计了两种主要的融合架构模式串行管道式和协同训练式。大部分场景下我们用的是前者因为它更简单、稳定。串行管道式架构是主流选择。流程非常清晰召回层基于业务规则、倒排索引等从全库中初步筛选出百万级候选。DCR粗排层使用双塔等轻量深度模型对百万候选进行快速打分。用户塔和候选塔分别编码用户上下文和候选特征最后计算内积或简单DNN得到分数。这一步的目标是速度通常要求能在几个毫秒内完成将候选集从百万级压缩到千级例如1000 - 1000。AlphaRank精排层接收DCR层输出的Top M例如1000个候选及其初始分数。这里每个候选不再只是一个分数而是关联了一个动态维护的“收益分布”状态。AlphaRank根据当前分布、DCR初始分以及业务规则计算出一个最终排序分数选出Top-K。在线学习与更新用户对最终展示的Top-K结果产生反馈点击、购买等。这些反馈被实时用于更新AlphaRank层中对应候选的收益分布参数。同时这些反馈数据也会异步地加入样本池用于持续训练和更新DCR模型。这个架构的好处是模块解耦。DCR可以专注于 embedding 学习和快速匹配的精度AlphaRank专注于序列决策和探索策略。线上服务压力也分散了。协同训练式架构则更紧密一些。我们尝试过让DCR模型除了预测点击率等目标还额外预测一个“不确定性”Uncertainty分数。这个不确定性分数可以作为先验信息输入给AlphaRank辅助其调整探索的力度。例如对于DCR模型自己都“吃不准”的候选AlphaRank可以赋予更高的探索概率。这种方式理论上更优美但实现复杂训练不稳定对数据要求高我们只在一些对探索要求极高的场景如全新商品冷启动中有节制地使用。注意在串行架构中务必保证DCR粗排的“召回率”。如果DCR因为模型偏差或特征不全过早地把潜在优质候选过滤掉了那么后面的AlphaRank再厉害也无用武之地。我们的经验是DCR层的输出候选数M要留有足够余量通常为最终K的50-100倍。3. DCR粗排层快与准的平衡艺术DCR层是整个系统的咽喉它必须又快又准。“快”决定了系统吞吐量“准”决定了精排层的天花板。3.1 模型选型双塔结构及其变种毫无悬念双塔模型是DCR层的绝对主力。它的核心优势在于用户塔和候选塔可以预先计算好embedding并缓存。线上服务时只需要实时计算用户塔embedding因为用户上下文实时变化然后与海量候选的预计算embedding进行高效的向量检索如基于内积的ANN搜索速度极快。我们用的基础结构是这样的用户塔输入是用户实时特征如当前搜索词、地理位置、时间和用户长期兴趣特征通过用户历史行为序列学习到的embedding。通常是一个几层的MLP。候选塔输入是候选的静态特征如商品类目、价格段和动态特征如实时点击率。同样是一个MLP。交互层线上服务时计算用户embedding和候选embedding的内积作为相似度分数。离线训练时我们会采用更复杂的交互方式如DIN/DIEN中的Attention来学习更好的embedding。但 vanilla 双塔有个问题它只建模了用户和候选的独立表征缺乏交叉特征信息这会影响粗排的精度。为此我们做了几个关键改进特征交叉引入在候选塔侧我们会手工构造一些重要的交叉特征如“用户历史点击类目”与“候选类目”的匹配度作为输入。更进阶的做法是引入一个轻量的FMFactorization Machine层在塔内做二阶特征交叉。蒸馏学习用精排复杂模型我们称为Teacher Model的输出来指导双塔模型Student Model的训练。具体来说训练样本不仅包含真实的用户反馈标签如是否点击还把精排模型对该样本的打分作为“软标签”加入损失函数。这能让双塔模型学到精排模型的排序“偏好”显著提升粗排与精排的一致性。多目标学习业务目标往往不止一个。例如不仅希望用户点击还希望观看时长长、转化率高。我们会为双塔模型设计多任务学习头共享底层的embedding但每个任务有独立的塔顶MLP。线上服务时根据业务阶段加权求和多个目标的预测值。3.2 负样本采样效率与效果的关键双塔模型训练的最大挑战之一是负样本采样。全库softmax计算量太大实践中都用采样softmax。采样的方式直接决定模型学到的embedding质量。我们踩过最大的坑就是简单随机采样。随机从全库采负样本对于热门候选来说它被采作负样本的概率远低于长尾候选。这会导致模型对热门候选的区分能力训练不足因为模型很少见到“用户 vs. 热门但无关商品”这样的困难负例。我们目前稳定使用的方案是Batch内随机采样 曝光未点击样本补充Batch内随机采样在一个训练batch中将其他样本的候选作为当前样本的负例。这是最常用的方法能提供一定难度的负例。曝光未点击样本这是最重要的困难负例来源。线上真实曝光了但用户没点的候选对于当前用户来说就是模型“认为好但用户不买账”的样本是极佳的困难负例。我们会定期将曝光未点击日志加入训练数据。重要性加权对于随机采样的负例和曝光未点击的负例我们在损失函数中给予不同的权重。曝光未点击的负例权重更高。此外对于搜索等有明确查询的场景我们还会引入随机负例和同查询下的非点击正例作为负例以增强模型对查询-候选相关性的建模。实操心得负样本策略需要定期review和调整。一个新策略上线后不仅要看离线AUC等指标更要关注线上粗排层的“通过率”变化。如果发现某些类目或长尾商品的通过率骤降很可能是负采样策略过于激进误伤了它们。我们的监控面板会实时跟踪不同维度候选在DCR层的得分分布和通过率。3.3 线上服务与性能优化DCR层线上服务的目标是在P99延迟10ms内完成从百万到数千的筛选。候选Embedding预计算与更新这是性能基石。我们构建了一个独立的服务监听候选特征的变化如商品价格调整、库存状态变更实时触发候选塔的前向计算更新向量检索库如Faiss, HNSW中的向量。更新频率根据业务需要从分钟级到小时级不等。用户Embedding实时计算用户塔的输入包含实时特征必须在线计算。我们会对用户塔进行大量的轻量化工作模型量化INT8、层融合、使用更高效的激活函数如ReLU替代Swish。最终目标是将单次用户塔推理控制在1ms以内。向量检索我们选用HNSWHierarchical Navigable Small World索引因为它对于内积距离的检索在精度和速度上平衡得很好。索引全部加载到内存。检索时我们并不是简单取Top M而是采用“动态阈值检索”先快速检索出Top LL M个候选然后根据它们的原始内积分数分布计算一个动态阈值只保留分数高于阈值的候选直到数量接近M。这比固定返回Top M更能适应不同用户请求的分数分布差异。缓存策略对于热门用户或高频查询模式其用户embedding和检索结果会被缓存一段时间秒级能有效应对流量高峰。4. AlphaRank精排层在不确定性中寻找最优解经过DCR层的筛选我们得到了一个相对较小但质量较高的候选池。AlphaRank层的任务就是在这个池子里做最终抉择。4.1 核心算法Thompson Sampling的工程化实现AlphaRank的核心思想是概率匹配。我们为每个候选i维护一个关于其收益如点击率的后验概率分布通常假设其服从Beta分布即 $收益_i \sim Beta(\alpha_i, \beta_i)$。其中$\alpha_i$ 可以理解为历史成功次数如点击$\beta_i$ 为历史失败次数如曝光未点击。Thompson Sampling (TS) 步骤采样对于当前请求中的每个候选i从其 $Beta(\alpha_i, \beta_i)$ 分布中随机采样一个值 $p_i$。排序将所有候选按照采样值 $p_i$ 从高到低排序。选择选取Top-K个候选展示。更新根据用户对K个候选的真实反馈二元反馈更新对应候选的分布参数 $(\alpha_i, \beta_i)$。如果点击则 $\alpha_i \alpha_i 1$如果曝光未点击则 $\beta_i \beta_i 1$。TS的美妙之处在于一个候选被选中的概率正好等于它是真正最优候选的概率。它以一种随机但概率匹配的方式自动平衡探索与利用。但直接应用TS有几个工程难题冷启动新候选的 $\alpha\beta1$或一个很小的先验值分布很宽容易被采样到探索但初始探索量可能不足。非平稳性候选的收益会随时间变化如商品过季旧的反馈会稀释新趋势。上下文信息利用TS本身没有利用DCR分数等特征信息。4.2 我们的改进上下文感知的混合排序我们设计了一个混合排序分数来应对上述问题最终分数_i w1 * DCR_Score_i w2 * TS_Sample_i w3 * Prior_iDCR_Score_iDCR模型给出的预估分数如点击率。代表了基于内容的“利用”信号。TS_Sample_i从当前Beta分布中采样的值。代表了基于历史反馈的“探索与利用”混合信号。Prior_i先验分数。用于处理冷启动和引入业务规则。例如对于新候选我们可以给它一个较高的先验分加速其探索对于某些战略扶持的类目也可以给予先验加分。w1, w2, w3动态权重。我们不是固定权重而是让权重根据候选的“状态”动态变化。我们定义了一个“置信度”指标$confidence_i (\alpha_i \beta_i) / (\alpha_i \beta_i C)$其中C是一个常数。置信度低数据少的候选我们降低w1提高w2和w3鼓励探索置信度高的候选则提高w1降低w2偏向利用和DCR的精准预估。这个混合分数既利用了深度模型的强大表征能力又继承了TS的探索特性还能通过先验项引入业务调控非常灵活。4.3 状态存储与更新实时性与一致性AlphaRank需要为每个候选存储和实时更新 $(\alpha, \beta)$ 状态。在候选池巨大且更新频繁的场景下这是个挑战。我们采用了两级存储策略热数据内存缓存使用Redis集群存储所有候选的 $(\alpha, \beta)$ 值。Redis的高吞吐和低延迟能满足实时更新的要求。我们使用Hash数据结构key为候选IDfield为alpha和beta。全量数据持久化存储使用HBase或Cassandra作为持久化存储定期如每分钟将Redis中的增量更新同步过来。这用于故障恢复和离线分析。更新的一致性问题尤其需要注意。在高并发下多个请求可能同时更新同一个候选的状态需要原子操作。我们使用Redis的HINCRBY命令来原子性地增加alpha或beta的值。另一个问题是状态衰减。为了解决非平稳性我们引入了指数衰减机制。每隔一个时间窗口如一天对所有候选的状态进行一次衰减$\alpha_i \lambda * \alpha_i$, $\beta_i \lambda * \beta_i$其中 $\lambda$ 是衰减因子如0.95。这样旧反馈的权重会逐渐降低模型能更快地适应新的趋势。踩坑实录我们曾经因为衰减因子设置过大0.99导致系统对季节性变化反应迟钝错过了节日商品的流量高峰。也曾经因为过小0.8导致状态波动太大排序不稳定。现在我们会根据业务节奏如快消品和耐用品的差异来动态调整衰减因子并在大促前手动预热某些商品的状态。5. 系统实现与工程细节5.1 整体数据流与系统架构整个系统的在线服务架构可以概括为以下几个核心服务请求网关接收用户请求组装用户上下文特征。召回服务基于规则、索引进行初步筛选产出百万级候选ID列表及其基础特征。DCR粗排服务实时计算用户embedding。从向量检索库中使用用户embedding检索出Top M候选ID及粗略分数。获取这M个候选的详细特征。AlphaRank精排服务从Redis中读取M个候选的当前 $(\alpha, \beta)$ 状态。为每个候选计算混合排序分数w1*DCR_Score w2*TS_Sample w3*Prior。按分数排序选出Top-K并准备最终展示所需的数据。反馈收集与实时更新服务用户行为日志被实时发送到消息队列如Kafka。消费者服务解析日志提取曝光和点击信息原子性地更新Redis中对应候选的 $(\alpha, \beta)$ 值。离线部分有独立的模型训练管道持续消费反馈日志和特征数据训练和更新DCR模型并将训练好的模型参数和候选embedding推送到线上服务。5.2 关键参数与调优指南这套系统有很多“旋钮”调优是关键。DCR层输出候选数M这是最重要的参数之一。M太大增加精排层压力和延迟M太小可能漏掉好候选。我们的经验公式是$M K * R * S$。其中K是最终需要的结果数R是“召回冗余度”通常取20-50根据业务确定性调整S是安全系数通常取1.5-2应对模型波动。例如K10取R30S2则M600。AlphaRank混合权重(w1, w2, w3)我们不是手动调而是设计了一个自适应模块。该模块根据候选的置信度、全局探索预算我们允许系统有一定比例的流量用于纯粹探索以及业务指标如新客转化率来动态调整权重。初期可以设置一个保守值如w10.7 w20.25 w30.05。TS先验参数新候选的初始 $(\alpha_0, \beta_0)$。我们通常设为(1, 1)或(2, 2)。(1,1)意味着初始点击率先验为50%不确定性高。(2,2)则先验为50%但更确定一些。对于特别重要的新候选如战略新品可以设置更高的 $\alpha_0$使其初始采样值偏高获得更多曝光机会。状态衰减因子λ需要结合业务生命周期来定。对于新闻、短视频等快消内容λ可以设小一些如0.9加速遗忘。对于家电、课程等长周期商品λ可以设大一些如0.98。我们会对不同类目设置不同的λ。5.3 监控与评估体系没有监控的系统就是盲人骑马。我们建立了多层监控性能监控各服务P99延迟、QPS、错误率。特别是DCR的ANN检索耗时和AlphaRank的Redis读耗时。业务指标监控核心是最终排序结果的线上A/B测试指标如点击率、转化率、人均时长、基尼系数衡量多样性等。我们会对比纯DCR排序和AlphaRank混合排序的指标。探索健康度监控新候选曝光占比监控新上架候选在结果中的出现比例确保探索机制在起作用。状态分布监控查看所有候选 $(\alpha\beta)$ 的和值分布。大部分候选应该积累了一定的反馈数据如果大量候选长期处于低置信状态说明探索效率低或流量不足。后悔值Regret估算虽然无法计算真实后悔值但我们可以用“最优静态策略收益”一直展示历史点击率最高的Top-K作为基准来估算我们因为探索付出的短期代价确保其在可控范围内。6. 实战案例与避坑指南6.1 案例信息流推荐场景落地在我们一个主要的信息流推荐场景中候选池是千万级别的文章和短视频。最初我们只用DCTR深度点击率预估模型进行精排发现推荐结果越来越“窄”热门内容霸屏新作者和长尾优质内容没有曝光机会。接入AlphaRankDCR方案后DCR层我们使用用户最近10次点击行为的attention pooling向量作为用户塔的核心输入候选塔则融合了内容embedding、作者热度和统计特征。将候选从千万级筛选到1500。AlphaRank层我们定义“收益”为“点击率 0.3 * 完播率视频”。对于新内容设置较高的先验分。权重策略上对于新作者置信度低的内容显著提高w2TS采样权重。效果上线A/B测试一周后实验组对比纯DCR模型对照组整体点击率持平但新作者内容的曝光量提升了85%用户次日留存率提升了0.5个百分点内容池的基尼系数衡量多样性改善了15%。系统成功地将一部分流量引导去探索了新内容并且探索是有效的新内容的整体点击率在稳步提升。6.2 常见问题与排查清单问题现象可能原因排查步骤与解决方案线上点击率下降1. DCR模型偏差2. AlphaRank探索过度3. 特征数据延迟1. 检查DCR模型离线AUC是否下降特征pipeline是否正常。2. 检查AlphaRank权重配置临时调低w2探索权重观察效果。3. 检查实时特征更新的延迟监控。新候选始终没有曝光1. 先验分设置过低2. DCR层过滤掉3. 流量不足1. 调高新候选的先验分Prior_i。2. 检查DCR模型对新候选的打分是否异常低检查新候选的特征是否齐全。3. 考虑为新品开辟专属探索流量通道。排序结果波动大1. TS采样随机性大2. 状态衰减过快3. 实时反馈数据噪声大1. 对于高置信度候选可以改用期望值$\alpha/(\alpha\beta)$代替采样值或对采样值做平滑。2. 调大状态衰减因子λ。3. 加强反馈数据的清洗过滤爬虫和异常点击。系统延迟升高1. DCR ANN检索慢2. Redis访问瓶颈3. 候选特征获取超时1. 检查向量索引是否需要重建数据分布变化。2. 检查Redis集群负载考虑分片或升级。3. 优化特征服务对特征进行本地缓存。多样性指标下降AlphaRank过于利用收敛到局部最优在混合分数中引入“多样性惩罚项”或定期在Batch内强制进行一定比例的随机探索。6.3 一些血泪教训不要忽视数据分布偏移DCR模型是用历史数据训练的如果线上流量分布发生变化如大促模型效果会衰减。我们建立了模型预测分数分布与实时反馈分布的监控对比一旦出现较大偏差会触发模型实时校准或快速迭代。探索需要成本要有预算无限制的探索会伤害短期体验。我们设定了“探索预算”例如确保不超过10%的流量主要用于探索低置信度候选。这个预算可以根据业务指标动态调整。状态存储的冷热分离曾经把全量候选的AlphaRank状态都存在Redis成本极高且大部分是冷数据。后来我们改为只存储近期有曝光的候选状态热数据对于长期无曝光的候选将其状态持久化到成本更低的存储中需要时再加载回来节省了超过60%的内存成本。离线评估与在线评估的鸿沟离线评估如AUC, NDCG提升不代表在线A/B测试一定成功。在线评估必须包含业务核心指标和长期指标如留存。我们吃过亏一个离线NDCG提升明显的模型上线后点击率却降了原因是它过度优化了“点击”这个即时反馈而忽略了用户的长期兴趣广度。