ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

从快手自动出价到Meta检索重构:统一框架与向量表示的系统优化实践

从快手自动出价到Meta检索重构:统一框架与向量表示的系统优化实践

1. 从两篇论文看推荐与检索系统的演进方向

9月21日前后,快手和Meta各自放出了一篇值得细读的论文。快手这边聚焦的是广告投放里的自动出价问题,Meta那边则是对超大规模检索系统做了一次架构层面的重构。两篇论文看似分属不同业务场景,但底层逻辑有共通之处:都是在超大规模数据和高并发请求的约束下,寻找更优的工程解。

如果你在做推荐系统、广告算法、搜索引擎或者大规模检索引擎相关的工作,这两篇论文里的思路都值得花时间琢磨。即便你不在这个领域,理解它们背后的设计哲学——如何在资源受限时做取舍、如何用统一框架替代碎片化方案——对做任何工程系统都有参考价值。

我花了两天时间把这两篇论文的核心内容梳理了一遍,结合自己过去在广告系统和检索系统上踩过的坑,整理成这篇笔记。不是逐段翻译论文,而是把关键设计决策背后的“为什么”讲清楚,同时补充一些论文里没展开、但实际落地时一定会遇到的细节问题。

2. 快手统一自动出价:从碎片化策略到端到端框架

2.1 自动出价到底在解决什么问题

先给不熟悉广告系统的读者补个背景。在效果广告里,广告主需要为每一次曝光出价,价高者得。但手动出价有个根本矛盾:广告主真正关心的是转化成本(比如一个下单、一个激活多少钱),而不是曝光本身的价格。手动调价意味着广告主要反复根据转化数据去调整出价,既费人力又容易滞后。

自动出价要做的就是把这个过程自动化——系统根据广告主设定的目标转化成本,自动决定每一次曝光的出价。听起来简单,但实际做起来涉及几个核心难点。

第一个难点是延迟反馈。用户点了广告之后,可能过几个小时甚至几天才完成转化。出价的时候你并不知道这次曝光最终会不会带来转化,只能基于历史数据去预估。第二个难点是预算约束。广告主一天给5000块预算,系统要在花完预算的前提下尽量多拿转化,不能前半天就把钱烧完,也不能到晚上还剩一大半没花出去。第三个难点是多目标平衡。不同广告主对成本的敏感度不同,有的要求严格控制在目标成本以内,有的愿意接受一定波动换取更大的量。

快手这篇论文的核心贡献,是把过去分散解决的几个子问题——出价决策、预算分配、成本控制——整合到一个统一的框架里。过去常见的做法是分模块处理:一个模块负责预估转化率,一个模块负责调价,一个模块负责控预算。模块之间的目标不一致时,就会出现“各自都做了局部最优决策,但全局效果不是最优”的情况。

2.2 统一框架的设计思路与关键取舍

论文提出的统一框架,核心思路是把自动出价建模成一个序列决策问题,用强化学习的思路来求解。但和直接套用标准强化学习不同,他们在几个关键点上做了针对性设计。

状态表示的设计。出价决策需要考虑的信息很多:当前时间点、已消耗预算、已获得转化数、当前预估的转化率分布、竞品出价环境等等。论文里把这些信息编码成一个固定维度的状态向量,但特别强调了时间特征的编码方式。他们没用简单的时间戳归一化,而是用了周期性的时间编码,让模型能感知到“一天中的哪个时段”和“一周中的哪一天”。这个设计有实际意义——广告流量的时段分布差异很大,早高峰和深夜的竞争环境完全不同。

动作空间的设计。出价动作是连续值,直接输出一个出价金额。但论文里没有让模型完全自由地输出任意值,而是让模型输出一个相对于基准出价的调整系数。基准出价由预估转化率和目标成本计算得出,模型只负责在这个基准上做微调。这样做的好处是缩小了动作空间的探索范围,训练更稳定。我自己的经验是,在广告出价场景里,让模型从零开始学一个绝对出价,收敛非常慢,而且容易在训练初期产生极端值导致预算瞬间耗尽。用相对调整的方式,相当于给模型加了一个强先验,训练效率和稳定性都会好很多。

奖励函数的设计。奖励信号直接决定了模型学到的策略长什么样。论文里的奖励函数包含两部分:转化收益和成本偏差惩罚。转化收益就是实际获得的转化数乘以广告主设定的转化价值。成本偏差惩罚则是实际转化成本和目标转化成本之间的差距。这里有个细节值得注意:惩罚项不是简单的线性惩罚,而是用了分段函数——当实际成本低于目标成本时,惩罚系数较小;当实际成本超出目标成本时,惩罚系数急剧增大。这个设计背后的逻辑是,广告主对超成本比对省成本敏感得多。省了钱广告主一般不会投诉,但超了成本广告主会立刻来问。分段惩罚让模型在策略上学到“宁可稍微保守一点,也不要冒超成本的风险”。

2.3 训练与部署中的工程细节

论文里花了不小篇幅讲训练流程,这部分对实际落地的人最有参考价值。

离线训练与在线推理的差异处理。离线训练时可以用完整的转化数据,但在线推理时转化数据是逐步到达的。论文里用了重要性采样的方法来纠正这种分布差异。具体来说,离线数据里那些“曝光后很快转化”的样本会被赋予更高的权重,因为在线环境下系统能更快拿到这些样本的反馈。而那些“曝光后很久才转化”的样本权重会被调低,因为在线环境下系统在出价时根本等不到这些反馈。

探索策略的设计。强化学习训练需要探索,但在广告出价场景里,无节制的探索意味着真金白银的浪费。论文里用了受限探索的策略:只在基准出价附近的一个小范围内做随机扰动,而且扰动幅度随着训练轮次逐渐减小。训练初期扰动大一些,让模型充分探索;训练后期扰动小,让策略趋于稳定。这个退火式的探索策略在工业界很常见,但论文里给出了具体的退火曲线和参数选择依据,对复现很有帮助。

冷启动处理。新广告计划没有历史数据,模型无法准确预估转化率。论文里的做法是用一个基于相似广告计划的先验估计作为初始值,随着新计划积累数据,逐渐从先验过渡到模型预测。过渡的速率由一个超参数控制,论文里建议这个超参数根据广告计划的日预算来调整——预算大的计划过渡快一些,因为能更快积累足够的数据;预算小的计划过渡慢一些,避免过早依赖不准确的模型预测。

实操心得:自动出价系统上线初期,建议先用规则策略跑一段时间积累数据,等数据量足够再切换到模型策略。直接冷启动上模型,前几天的成本波动会非常大,广告主体验很差。

2.4 效果评估与常见误区

论文里报告了离线评估和在线AB实验的结果。离线评估用的是历史日志回放的方式,在线实验则是在快手广告平台上做的真实流量测试。从报告的数据看,统一框架相比之前的模块化方案,在转化成本达标率上有明显提升,同时预算消耗的平滑度也更好。

但这里我想提醒一点:看论文里的效果数据时,要注意区分“统计显著”和“业务显著”。转化成本降低2%在统计上可能显著,但在业务上广告主未必能感知到。真正让广告主有感知的,往往是成本波动的降低——比如之前日转化成本在目标值上下浮动20%,现在浮动范围缩小到10%以内。这种稳定性的提升对广告主的投放信心影响更大。

另一个常见误区是过度追求单次出价的精准度。自动出价是一个序列决策问题,单次出价差一点没关系,只要整体预算分配合理、成本控制达标就行。我见过一些团队花大量精力去优化单次出价的预估模型,但对预算分配策略的优化投入不足,结果整体效果提升有限。论文里的统一框架之所以有效,很大程度上是因为它把预算分配和出价决策放在一起优化了,而不是分开处理。

3. Meta超大规模检索重构:从多级索引到统一表示

3.1 超大规模检索面临的核心瓶颈

Meta这篇论文讨论的是超大规模检索系统的架构重构。这里的“超大规模”是什么概念?论文里提到的检索库规模在百亿级别,每天处理的检索请求在数十亿次量级。在这种规模下,传统的多级索引架构——比如先做粗排再做精排——会遇到几个瓶颈。

第一个瓶颈是级联误差。粗排阶段会过滤掉大量候选,如果粗排阶段漏掉了真正相关的文档,精排阶段再准也没用。在百亿级别的库里,粗排的召回率哪怕只下降一个百分点,绝对数量上就是上亿的文档被错误过滤。

第二个瓶颈是表示不一致。粗排和精排通常用不同的模型、不同的特征、不同的向量表示。粗排用的向量维度低、精度低,精排用的向量维度高、精度高。两套表示之间的不一致会导致“粗排觉得相关、精排觉得不相关”的情况频繁发生。

第三个瓶颈是更新延迟。多级索引的更新是分级的,粗排索引更新快但精度低,精排索引精度高但更新慢。新内容从入库到能被精排检索到,中间有可观的延迟。对于时效性强的检索场景,这个延迟是不可接受的。

Meta的重构思路是:用一套统一的向量表示来替代多级索引,所有文档用同一个模型编码成高维向量,检索时直接在向量空间里做最近邻搜索。这样就不存在级联误差和表示不一致的问题,更新延迟也大大降低——新文档编码成向量后直接插入索引即可。

3.2 统一向量表示的技术挑战与解法

想法很美好,但实现起来有几个硬骨头要啃。

第一个硬骨头是向量维度与检索效率的矛盾。高维向量检索精度高,但计算量大。论文里用的向量维度是768维,在百亿级别的库里做精确最近邻搜索是不现实的。他们的解法是用近似最近邻搜索,具体来说是基于量化的方法。把768维的向量压缩成紧凑编码,检索时先用压缩编码做快速筛选,再对少量候选做精确距离计算。

这里有个关键设计:量化编码不是简单的降维,而是保留了向量之间的相对距离关系。论文里用了乘积量化的变体,把768维向量切分成若干子空间,每个子空间单独做聚类量化。检索时,查询向量和文档向量的距离可以分解成各子空间距离之和,这样就能用查表的方式快速计算近似距离。

第二个硬骨头是索引更新与检索性能的平衡。向量索引的更新通常需要重建部分索引结构,重建期间检索性能会下降。论文里用了增量更新的策略:新文档的向量先插入一个小的增量索引,检索时同时查主索引和增量索引,定期把增量索引合并到主索引。合并的时机选择很关键——太频繁合并会影响检索性能,太久不合并增量索引会越来越大,检索时需要查的索引数量增多。

论文里给出的合并策略是基于增量索引的大小和检索延迟的监控数据来动态决定的。当增量索引的大小超过主索引的5%时,或者检索延迟的P99超过阈值时,触发合并。这个策略比固定时间间隔合并要合理得多,因为它考虑了实际的检索负载情况。

第三个硬骨头是模型更新与索引一致性的问题。检索模型不是一成不变的,模型更新后,所有文档的向量表示都需要重新计算。在百亿级别的库里,全量重新编码的成本极高。论文里的解法是双塔结构加增量更新:查询编码器和文档编码器分开训练,文档编码器的更新频率低于查询编码器。当文档编码器更新时,只对活跃文档(近期有检索请求的文档)重新编码,冷门文档的向量保持旧版本,直到它们被检索到时再异步更新。

3.3 工程实现中的关键参数与调优经验

论文里给出了不少工程实现细节,这部分对做检索系统的同行最有参考价值。

索引分片策略。百亿级别的向量索引不可能放在一台机器上,必须分片。论文里用的分片策略是按文档ID的哈希值分片,而不是按向量聚类分片。按哈希分片的好处是负载均衡好做,每个分片的大小和查询量都比较均匀。按聚类分片虽然能让相似的向量落在同一个分片,减少跨分片查询,但容易出现热点分片——某些聚类中心附近的向量特别多,对应的分片就会成为瓶颈。

查询路由策略。查询请求需要路由到所有分片,每个分片返回Top-K结果,最后合并。论文里用了两阶段路由:第一阶段用轻量级的粗筛模型快速排除明显不相关的分片,第二阶段只对可能包含相关结果的分片做精确检索。粗筛模型用的是低维的向量表示,虽然精度不高,但足以排除掉大部分不相关的分片。

缓存策略。热门查询的结果会被缓存,但缓存什么、缓存多久有讲究。论文里用了基于查询频率和结果稳定性的缓存策略:高频查询且结果变化不大的,缓存时间长;低频查询或结果变化快的,缓存时间短或不缓存。结果稳定性用一个滑动窗口内的结果变化率来衡量。

注意事项:向量索引的量化编码会引入精度损失,在评估检索质量时不能只看召回率,还要看排序质量。有些情况下召回率没降,但排在前面的结果相关性变差了,用户体验反而下降。

3.4 对检索系统架构设计的启示

Meta这篇论文的价值不仅在于它提出的具体方法,更在于它展示了一种架构演进的思路:当多级索引的复杂度带来的收益不足以抵消其成本时,就应该考虑用统一表示来简化架构。

这个思路对其他系统也有借鉴意义。比如推荐系统里的多路召回,本质上也是一种多级索引——不同召回路径用不同的模型和特征,最后合并。如果有一天统一表示的技术足够成熟,多路召回是否也可以被单一的高质量向量召回替代?当然这取决于业务场景,有些场景下多路召回的多样性是必要的,单一向量召回可能陷入信息茧房。

另一个启示是关于“精度与效率的权衡”。Meta的选择是在保证检索质量的前提下,用近似最近邻搜索来换取效率。这个选择的前提是近似搜索的精度损失在可接受范围内。如果业务场景对检索精度要求极高,比如法律文书检索,近似搜索可能就不合适。架构选择永远要服务于业务目标,没有放之四海而皆准的方案。

4. 两篇论文的交叉视角:LLM Agent在系统优化中的角色

4.1 LLM Agent能否辅助出价策略与检索优化

这两篇论文本身没有直接涉及LLM Agent,但结合当前的技术趋势,可以思考一下LLM Agent在这两个场景里能扮演什么角色。

在自动出价场景里,LLM Agent可以用于策略的解释和诊断。自动出价模型是一个黑盒,广告主经常问“为什么今天成本超了”。传统的做法是给广告主看一堆指标曲线,但广告主未必能理解。如果用LLM Agent来分析出价日志和成本数据,生成自然语言的诊断报告——“今天下午3点到5点竞争环境加剧,导致实际出价高于预期,建议适当放宽成本容忍度”——广告主的接受度会高很多。

在检索场景里,LLM Agent可以用于查询理解和结果重排。用户的检索查询往往很短、很模糊,传统的查询扩展方法基于统计共现,效果有限。用LLM来做查询理解,把模糊查询扩展成更明确的检索意图,再配合向量检索,能提升检索质量。Meta的检索系统里是否用了LLM做查询理解,论文里没有明确说,但从技术趋势看这是很自然的方向。

4.2 从工程落地角度看LLM Agent的局限性

不过也要冷静看待LLM Agent的局限性。在出价场景里,LLM的推理延迟是个问题。出价决策需要在毫秒级完成,LLM的推理延迟通常在百毫秒级以上,直接用于在线出价不现实。更可行的方式是用LLM做离线策略分析和诊断,在线出价还是用轻量级的模型。

在检索场景里,LLM的推理成本是个问题。每次查询都调LLM做查询理解,成本太高。可行的方式是用LLM离线生成查询扩展词典,在线检索时查词典即可。或者用蒸馏的方法,把LLM的查询理解能力蒸馏到一个小的模型里,在线用蒸馏后的小模型。

我自己的经验是,LLM Agent在系统优化里的角色更适合定位为“离线分析师”而不是“在线决策者”。让它去分析日志、发现异常、生成报告、提出优化建议,这些任务对延迟不敏感,LLM的能力能充分发挥。但让它直接做在线决策,目前的延迟和成本都还不太现实。

5. 实操复现建议与避坑指南

5.1 自动出价系统的复现路径

如果你想复现快手这篇论文里的自动出价框架,我建议按以下路径推进。

第一步是搭建仿真环境。不要直接上真实流量,先用历史日志搭建一个仿真环境。仿真环境需要模拟几个关键要素:流量时段分布、竞品出价分布、转化延迟分布。流量时段分布可以从历史日志里统计得到,竞品出价分布可以用历史成交价格来近似,转化延迟分布需要根据业务特点来设定——电商类转化延迟短,游戏类转化延迟长。

第二步是实现基准策略。在实现强化学习策略之前,先实现一个基于规则的基准策略。基准策略可以很简单:出价等于目标转化成本乘以预估转化率,再乘以一个固定的调整系数。这个基准策略的作用是提供一个对比基线,同时也能帮你验证仿真环境的合理性——如果基准策略在仿真环境里的表现和它在真实环境里的表现差距很大,说明仿真环境有问题。

第三步是逐步引入学习策略。不要一上来就用复杂的强化学习,先从上下文老虎机开始。上下文老虎机可以看作是强化学习的一个简化版本,它不考虑长期回报,只考虑即时回报。在出价场景里,即时回报就是当前曝光的转化收益减去成本。上下文老虎机的训练更稳定,收敛更快,可以作为强化学习的一个预热阶段。

第四步是在线AB实验。仿真环境里表现好的策略,在真实环境里未必好。上线AB实验时,建议先用小流量测试,观察成本波动和预算消耗情况。如果成本波动在可接受范围内,再逐步扩大流量。

5.2 向量检索系统的搭建要点

复现Meta的向量检索系统,门槛比自动出价高不少,因为涉及大规模分布式系统的搭建。但如果你只是想在小规模数据上验证核心思路,可以按以下步骤来。

向量编码模型的选择。论文里没有公开他们用的具体模型结构,但根据描述,应该是一个双塔结构,查询塔和文档塔分开。你可以用开源的句向量模型作为起点,比如用对比学习的方法在业务数据上微调。微调时要注意负样本的构造——随机负样本太简单,模型学不到有区分度的表示。建议用批内负样本加难负样本挖掘的方式。

近似最近邻搜索库的选择。开源的近似最近邻搜索库有不少选择,比如Faiss、ScaNN、HNSW等。选择时主要考虑几个因素:支持的索引类型、内存占用、查询延迟、更新便利性。Faiss的功能最全,但API比较复杂;HNSW的查询延迟低,但内存占用高;ScaNN的量化做得好,但社区活跃度相对低一些。建议先用Faiss快速验证,再根据实际需求做选型。

评估指标的设计。检索系统的评估不能只看召回率。建议同时看几个指标:召回率(相关文档被检索到的比例)、MRR(第一个相关结果的平均排名倒数)、NDCG(考虑排序位置的检索质量)。如果业务场景对时效性有要求,还要看新文档被检索到的延迟。

5.3 常见问题速查

问题现象可能原因排查方向
自动出价成本持续超标转化率预估偏高检查预估模型的离线AUC和在线校准曲线
预算消耗前半天就接近上限出价策略过于激进检查探索策略的扰动幅度和退火曲线
向量检索召回率突然下降索引更新导致的一致性问题检查增量索引和主索引的合并日志
检索延迟P99升高索引分片负载不均检查各分片的查询量和索引大小分布
新文档检索不到增量索引未及时合并检查合并触发条件和合并任务的执行记录

避坑提示:自动出价系统上线前,一定要做压力测试。我见过一个团队在测试环境跑得好好的,上线后遇到流量高峰,出价服务响应超时,导致大量曝光机会被浪费。压力测试要模拟真实的高峰流量,不能只用平均流量来测。

6. 一些个人体会

这两篇论文看下来,最大的感受是:工业界的系统优化越来越倾向于“端到端”和“统一表示”。快手的自动出价把分散的模块整合成统一框架,Meta的检索把多级索引替换成统一向量表示。背后的逻辑是一样的——当系统复杂度带来的维护成本和误差累积超过某个阈值时,简化架构、统一表示就是更优的选择。

但“统一”不等于“简单”。统一框架内部的复杂度其实更高,只是复杂度被封装起来了。快手论文里的强化学习框架,训练和调参的复杂度比之前的模块化方案高不少。Meta的向量检索系统,工程实现的复杂度也比多级索引高。选择统一方案的前提是,团队有足够的技术能力去驾驭这个复杂度。

另外一点体会是关于论文里的效果数据。论文里报告的效果提升通常是在特定条件下的,换一个业务场景未必能复现。看论文时要关注它的问题定义和约束条件,判断这些条件和你自己的场景是否匹配。匹配度高,方法可以借鉴;匹配度低,就要谨慎评估迁移成本。

最后说一个实操中的小技巧。不管是做自动出价还是做检索系统,建议都先搭一个轻量级的仿真环境。仿真环境不需要很精确,能反映主要趋势就行。在仿真环境里快速迭代策略,验证有效后再上真实环境。这样试错成本低,迭代速度快。我自己的经验是,仿真环境里跑一周能验证的东西,在真实环境里可能要跑一个月。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进