广告生成式推荐的工程全景:从三篇工业论文提炼系统设计观

推荐系统工程师对这条流水线太熟了:召回从千万候选里捞几百个,粗排砍到几十个,精排算 eCPM 排序输出。这条 pipeline 跑了十几年,每一级都有成熟的工程积累,但有一个结构性问题从来没被解决:召回阶段丢掉的广告,后面再强的精排也捡不回来。

2024-2026 年,生成式推荐(Generative Recommendation, GR)从学术概念走进了工业实践。三篇来自腾讯和快手的工业论文——微信视频号的 GPR(GMV 累计提升 5%+)、腾讯广告的 UniVA(GMV 提升 1.5%)、快手的 GR4AD(广告收入提升 4.2%)——都已在亿级用户规模的真实广告系统全量部署。三篇独立做的系统,最终收敛到了高度相似的设计模式。这种跨团队的收敛比任何单篇论文都更有说服力。

本文先做一个现状扫盲,再从四个核心设计问题出发,拆解三篇论文的技术选择和背后逻辑。

现状扫盲:从内容推荐到广告推荐的范式迁移

传统 pipeline 的结构性缺陷

graph LR
    subgraph pipeline["传统广告推荐 Pipeline"]
        direction LR
        POOL["广告库 千万级"] --> RECALL["召回 粗糙匹配"]
        RECALL --> PRERANK["粗排 初步打分"]
        PRERANK --> RANK["精排 eCPM排序"]
        RANK --> OUT["Top-K 输出"]
    end

    subgraph loss["信息损失"]
        direction TB
        L1["召回丢弃的高价值广告<br/>后续无法找回"]
        L2["各阶段优化目标不一致<br/>召回追覆盖率 精排追eCPM"]
        L3["资源浪费:50%+ 用于通信和存储<br/>非高精度计算"]
    end

    RECALL -.-> L1
    pipeline -.-> L2
    pipeline -.-> L3

    style POOL fill:#d3f9d8,stroke:#2f9e44,stroke-width:2px
    style RECALL fill:#ffe3e3,stroke:#c92a2a,stroke-width:2px
    style PRERANK fill:#e5dbff,stroke:#5f3dc4,stroke-width:2px
    style RANK fill:#e5dbff,stroke:#5f3dc4,stroke-width:2px
    style OUT fill:#c5f6fa,stroke:#0c8599,stroke-width:2px
    style L1 fill:#ffe3e3,stroke:#c92a2a,stroke-width:1px
    style L2 fill:#ffe3e3,stroke:#c92a2a,stroke-width:1px
    style L3 fill:#ffe3e3,stroke:#c92a2a,stroke-width:1px

快手的 OneRec 团队做了一个直接的资源审计:在传统 pipeline 中,超过 50% 的 serving 资源分配给了通信和存储,而非高精度计算。ranking 模型的训练和推理 MFU 分别只有 4.6% 和 11.2%,远低于 LLM 社区的 40%。pipeline 架构不仅丢信息,还浪费算力。

生成式推荐的核心思路

GR 把推荐问题改写成了序列生成问题。它不做”从候选集里打分选出最好的”,而是”直接生成用户最可能感兴趣的 item 是什么”。

具体做法是:给每个 item 分配一串离散的语义编码(Semantic ID, SID),训练一个自回归模型,给定用户历史逐层预测这串编码。三步预测完,就唯一确定了一个具体的 item。一个模型端到端完成原来三个阶段的全部工作。

这个思路最早来自 Google 的 DSI(Differentiable Search Index, 2022)和后续的 TIGER(2023),在内容推荐场景中被验证。快手的 OneRec 在短视频推荐上全量上线,处理 25% 的总 QPS,App Stay Time 提升 0.54%/1.24%(主端/极速版),OPEX 仅为传统 pipeline 的 10.6%。

从内容推荐到广告推荐:差在哪里

内容推荐的目标相对单一:预测用户喜不喜欢这个 item。但广告系统有一个内容推荐没有的核心约束:商业价值。广告主在出价,平台要考虑 eCPM(= pCTR x pCVR x Bid),用户体验也要顾及。仅靠”生成用户喜欢的内容”远远不够,还需要同时生成”商业价值高”的广告。

这就是广告 GR 的核心难题:如何把商业价值信号融入生成式推荐的全链路——从编码、到模型结构、到训练、到 serving。

三篇工业论文各自用不同的路径解决了这个问题,但最终收敛到了高度相似的设计模式。以下按四个核心问题展开分析。

编码:语义量化 + 确定性映射的混合方案

GR 的第一步是给每个广告分配 SID。标准做法是把广告的多模态信息压缩成向量,再用残差量化(Residual Quantization, RQ)逐层离散化。RQ 的工作方式类似层级地址:第一层给出大区(华北),第二层给出城市(北京),第三层给出街道(朝阳路)。最终每个广告得到一串离散符号,比如 [42, 7, 391]

纯语义编码的碰撞问题

问题在于,语义相似的广告会被量化到同一条路径,但商业属性可能天差地别。同一个视频素材,由不同广告主投放时,出价可以相差十倍。GR4AD 给出了一个直观的数字:纯语义量化的 SID 碰撞率高达 85.44%——平均每 7 个广告里有 6 个”撞号”,模型根本分不清它们。

三篇的共同解法:最后一层改用确定性映射

三篇独立得出了同一个结论:语义量化在前几层保留(让模型能泛化),但最后一层放弃可学习量化,改用确定性映射把业务属性编码进去。

论文最后一层编码方式编码的业务维度碰撞率变化
GR4ADHash 映射转化类型 + 广告账户 ID85.44% -> 18.26%
UniVA分桶映射优化目标 x ROI目标 x 行业 + 出价等频分桶显著降低
GPR类似的确定性编码业务属性组合论文未公开具体数字

两种做法编码的维度不同(GR4AD 编码身份标识,UniVA 编码价值区间),但原则相同:语义相同但业务属性不同的广告,必须用确定性编码来区分。 这两个维度也可以同时编码,不互斥。

底座嵌入的质量被严重低估

在精调量化方案之前,有一个更基础的问题经常被忽略:向量量化的质量上限取决于被量化的向量本身有多好。

GR4AD 用 Qwen3-VL-7B 做底座,专门针对广告的六种类型写了指令调优模板,还加入了共现学习(co-occurrence learning):如果两个广告在大量用户历史里频繁共现,就在嵌入空间里让它们靠近。这一步让 photo-to-photo recall 从 0.541 跳到 0.896。这个幅度说明:量化方案的精细调参,带来的收益远不如底座嵌入的质量提升显著。先把广告的”理解”做好,再量化。

模型结构:异构 token 必须正视

Token-Aware FFN/LN:最高性价比的改动

广告请求到来时,模型需要理解的信息至少有四类:用户画像(静态结构化特征)、有机内容行为(内容语义)、广告交互历史(商业行为)、请求上下文(环境元信息)。四类 token 的特征分布差异很大。

把四类 token 送进同一套 FFN 和 LayerNorm 参数,等于用同一把尺子量四种完全不同的东西。GPR 给每类 token 配置了独立的 FFN 和 LayerNorm 参数(Token-Aware FFN/LN),在消融实验里贡献了 +15.8% HitR@100——是该论文所有单组件增益最大的一个。

修复成本极低:只是把共享参数改成分组参数,不需要改变任何网络结构。在工程上几乎没有不做的理由。

单解码器 vs 双解码器:没有普适结论

GPR 把模型拆成两个解码器:主干解码器(HSD)做用户历史理解,输出”用户意图嵌入”;轻量解码器(PTD)以意图嵌入为条件做 SID 自回归生成。理论上合理——理解任务更适合双向注意力,生成任务必须用因果 mask。

但 GR4AD 和 UniVA 用的都是单解码器,同样在真实系统里取得了好结果。GR4AD 实现了 <100ms 时延和 500+ QPS/L20。所以”双解码器一定比单解码器好”这个结论没有跨系统的证据支撑。在 serving 延迟预算紧张时,单解码器 + Token-Aware FFN/LN 是更务实的起点。

Thinking Tokens:给模型一个”想清楚再说”的缓冲区

GPR 在 SID 生成之前,让模型先生成若干个 Thinking Tokens——不对应任何广告,只是在隐空间里提供一个”先想清楚用户想要什么”的缓冲区。这个设计贡献了 +14.6% HitR

直觉上,它解决的是一个真实问题:用户意图经常是模糊的、多义的。历史里同时有手机、耳机、充电器的交互,这次请求到来时模型需要先分辨用户此刻最可能感兴趣的品类,再开始生成 SID。没有 Thinking Tokens,模型没有足够的”思考空间”来完成这个分辨。

目前只有 GPR 一篇验证,缺乏跨系统证据。但 +14.6% 足以说明它值得在自己的系统里试一试。

一个常被忽视的原则:显式切断不该互相影响的梯度

GPR 的价值估算头(HTE)用了 stopgrad——梯度不回传到主干解码器。这不只是实现细节。在多目标共享参数的系统里,每个 loss 都会通过反传影响所有共享参数。如果价值估算和生成目标对同一份表示有不同偏好,梯度会在共享参数里相互拉扯——这是多任务学习里”负迁移”的典型来源。需要根据目标性质,显式决定哪些梯度流应该被切断。

训练:三阶段 SFT -> Value FT -> RL

三篇论文都收敛到了相似的三阶段训练结构。不是偶然——每个阶段解决一个特定的、前一阶段遗留的问题。

graph TB
    subgraph stage1["Stage 1: SFT 监督学习"]
        S1["从历史日志学习用户行为模式"]
        S1A["监督信号: 用户下一个交互的广告 SID"]
        S1B["MTP: 4个预测头并行预测多条兴趣路径<br/>+17.9% HitR(最大单组件增益)"]
        S1 --> S1A --> S1B
    end

    subgraph stage2["Stage 2: Value-Aware Fine-Tuning"]
        S2["在 loss 上乘价值权重系数"]
        S2A["转化样本权重: eCPM/pCTR*pCVR"]
        S2B["点击样本权重: eCPM/pCTR"]
        S2C["曝光样本权重: eCPM"]
        S2 --> S2A
        S2 --> S2B
        S2 --> S2C
    end

    subgraph stage3["Stage 3: RL 探索"]
        S3["离线 simulator 中自由探索"]
        S3A["发现历史系统遗漏的高价值广告"]
        S3B["HEPO: 层级过程奖励解决信用分配"]
        S3 --> S3A --> S3B
    end

    stage1 --> stage2
    stage2 --> stage3

    style S1 fill:#d3f9d8,stroke:#2f9e44,stroke-width:2px
    style S1A fill:#d3f9d8,stroke:#2f9e44,stroke-width:1px
    style S1B fill:#d3f9d8,stroke:#2f9e44,stroke-width:1px
    style S2 fill:#ffe8cc,stroke:#d9480f,stroke-width:2px
    style S2A fill:#ffe8cc,stroke:#d9480f,stroke-width:1px
    style S2B fill:#ffe8cc,stroke:#d9480f,stroke-width:1px
    style S2C fill:#ffe8cc,stroke:#d9480f,stroke-width:1px
    style S3 fill:#e5dbff,stroke:#5f3dc4,stroke-width:2px
    style S3A fill:#e5dbff,stroke:#5f3dc4,stroke-width:1px
    style S3B fill:#e5dbff,stroke:#5f3dc4,stroke-width:1px

Stage 1: SFT——建立基础生成能力

用监督学习从历史日志学习用户行为。GPR 的 MTP(Multi-Token Prediction)是这一阶段最重要的优化:用 4 个独立的预测头,在同一个 backbone 状态上同时预测 4 条不同的兴趣路径,倒逼 backbone 表示得更全面。贡献了 +17.9% HitR——三篇所有组件里单组件增益最大的数字,而且实现成本只是在 backbone 顶端加了 3 个额外的预测头。

Stage 2: Value-Aware FT——注入商业价值信号

Stage 1 对所有历史样本一视同仁——点击出价 1 元的广告和点击出价 100 元的广告,梯度一样大。VAFT 做的事情很直接:在 loss 上乘一个同时考虑行为类型和 eCPM 量级的权重系数。

这一步必须在 Stage 1 之后。如果基础生成能力还没稳定就引入强价值权重,高 eCPM 样本的稀疏性(占比很少)会让梯度方差过大,训练发散。

Stage 3: RL——探索历史日志之外的高价值路径

前两个阶段的根本局限:模型只能从历史日志里学,而历史日志记录的是过去系统的决策。被过去系统漏掉的高价值广告,监督学习完全看不到。

RL 通过离线 simulator 来解决:让模型生成日志里没有的候选路径,用生产环境的 pCTR/pCVR 模型评估 eCPM 作为奖励。但 RL 在 GR 里有一个特有的困难:层级信用分配

SID 有 L 层,terminal reward 只在最后一层才知道。模型生成了 [手机品类, 品牌A, 广告X] 但用户没点——问题出在哪一层?纯 terminal reward 会均匀惩罚三层决策,但真实情况可能是选”手机品类”完全正确(用户确实在看手机),只是”品牌 A”选错了。均匀惩罚会错误地降低”推荐手机品类”的概率。

GPR 的 HEPO 方案很轻量:统计每个 SID token 在历史上出现在多少次成功路径中,用这个频次计算每层的”过程奖励”。从 DPO 换到 HEPO,候选中最高价值得分从 0.6659 涨到 0.7619,提升 14.4%。实现只需要一个稀疏计数表。

三篇 RL 算法的差异与互补性

算法论文解决的问题核心机制
HEPOGPR层级信用分配每层过程奖励(成功频次差值)
RSPOGR4AD列表级目标对齐NDCG 可微上界 + 参考模型过时检测
MCTS-PPOUniVA探索覆盖Monte Carlo Tree Search 往低概率分支探索

三者是正交的,理论上可以组合,但组合后的训练稳定性需要实验验证。如果只能选一个优先实现,HEPO 性价比最高:问题最根本,实现成本最低。

训练完成后,模型需要在 100ms 内对每个请求生成几十个候选广告。这个延迟预算比 LLM 推理严苛得多。

个性化 Trie:消灭无效 beam 路径

广告系统有大量投放约束(预算耗尽、年龄定向、审核状态……)。如果 beam search 在全 SID 空间展开,UniVA 的数字是:beam width=300 的 300 条路径里,只有 48 条(16%)是真正可投放的合法广告。84% 的计算浪费了。

个性化 Trie 的做法是:每个请求到来时,用当前用户的约束条件裁剪出一棵只包含合法候选的前缀树,beam search 只在合法节点上展开。有效召回直接扩大 6 倍,零额外计算开销。

价值融合评分:beam 里不能只看生成概率

如果 beam search 只看生成概率,那些语义得分普通但 eCPM 高的广告路径会在第一层就被剪掉。正确做法是在 beam 每一步的扩展评分里,把生成概率和价值估算加权融合。GPR 和 UniVA 独立实现了同样的设计,且都有消融实验证明其有效性。

这和 SID 编码层”最后一层用确定性映射”是同一个设计哲学在不同位置的应用:价值信号越早注入,能修正的错误越多。

LazyAR:利用 transformer 层间依赖的不对称性

GR4AD 发现了一个关键的 beam search 优化空间:decoder 的前 2/3 层对”上一个 token 是什么”的依赖实际上很弱——这些层主要在做用户历史理解,不依赖生成 token 的信息。因此可以把这些层的计算提前做好,在所有 beam 之间共享,只有后 1/3 层需要真正串行依赖上一个 token。

QPS 翻倍,收入损失仅 -0.15%。不改模型结构,不加参数,只改执行顺序。

graph LR
    subgraph standard["标准 AR: 每个 beam 独立走全部层"]
        direction TB
        SA["Layer 1-N 全部串行"]
        SB["每个 beam 独立计算"]
        SC["QPS 受限"]
        SA --> SB --> SC
    end

    subgraph lazy["LazyAR: 前2/3层共享"]
        direction TB
        LA["Layer 1 到 2N/3: 提前计算 所有 beam 共享"]
        LB["Layer 2N/3 到 N: 串行依赖上一个 token"]
        LC["QPS 翻倍 收入损失-0.15%"]
        LA --> LB --> LC
    end

    style SA fill:#f8f9fa,stroke:#868e96,stroke-width:1px
    style SB fill:#f8f9fa,stroke:#868e96,stroke-width:1px
    style SC fill:#ffe3e3,stroke:#c92a2a,stroke-width:1px
    style LA fill:#d3f9d8,stroke:#2f9e44,stroke-width:2px
    style LB fill:#e5dbff,stroke:#5f3dc4,stroke-width:2px
    style LC fill:#d3f9d8,stroke:#2f9e44,stroke-width:2px

其他值得实施的工程优化:递增 beam schedule(第一层窄 beam,越往后越宽)、beam-shared KV cache(共同前缀的 KV 只计算一次)、峰期/非峰期动态 beam width。叠加后 GR4AD 实现了 <100ms 时延、500+ QPS/L20。

跨论文提炼:三条设计原则

把四个问题的分析归纳,三条贯穿始终的原则清晰浮现:

原则一:价值信号必须从 tokenization 阶段就开始渗透,不能在末端打补丁。 SID 最后一层用确定性映射编码业务属性,让 token 空间本身具备商业区分力;beam search 里直接融合价值评分,不是生成完再挂排序模块;RL 训练时用价值加权的过程奖励,不是只在末端给 terminal 奖励。三处逻辑一贯:越晚注入的价值信号,能修正的错误越少。

原则二:异构输入必须在架构上正视,不能用均一参数混合处理。 Token-Aware FFN/LN 贡献了所有组件里最大的单组件增益(+15.8%),说明这个问题是真实的性能瓶颈。修复成本低,没有理由不做。这个原则不限于广告 GR——任何需要混合处理不同类型 token 的系统(多模态 LLM、cross-domain 推荐)都应该审视自己是否存在同样的参数干扰问题。

原则三:RL 探索是从 SFT 到生产级质量的必经之路,但 simulator 质量是核心风险。 三篇论文的 RL 训练都依赖离线 simulator,且没有深入讨论 simulator 与真实竞价环境的偏差。广告的 eCPM 受实时竞价影响,历史平均 eCPM 可能系统性地低估高竞争时段的真实价值。这个 sim-to-real gap 是当前广告 GR 方向最值得深入研究的开放问题。

这条路线离大面积落地还有多远

三篇论文的线上数字——GPR 累计 GMV +5%,GR4AD 收入 +4.2%,UniVA GMV +1.5%——在广告系统里已经算是非常可观的增量。但几个工程现实值得注意:

SID 的维护成本。 广告库是动态的——每天有大量广告上下线、素材更新、出价变化。SID 的分配和更新需要一套持续运行的 pipeline,这个 pipeline 的延迟(新广告从上线到可被推荐需要多久)和稳定性(更新 SID 是否会影响已训练模型的行为)是实际落地中的关键运维挑战。三篇论文对此着墨不多。

与现有精排系统的融合策略。 目前三篇论文的部署都不是完全替代传统 pipeline,而是和传统系统并行运行(GR 负责一部分流量)。完全替代需要 GR 模型在所有 case 上都不比传统系统差,这个条件目前没有被满足。更务实的策略是:GR 作为一路额外的召回源,其输出和传统精排的输出一起进入最终的混合排序。

从 OneRec 的经验看 scaling 的可能性。 OneRec 在内容推荐上发现了推荐系统的 scaling law,把模型 FLOPs 提升了 10x 后在特定边界内观察到了性能的持续提升。广告 GR 能否复制这条 scaling 曲线?目前三篇论文都没有做 scaling 实验——它们的模型规模相对保守(受 serving 延迟预算约束)。如果 LazyAR 类优化能进一步降低 serving 成本,更大模型 + 更多 RL 训练可能是下一个增量的来源。

回到最开始的问题:广告推荐系统从级联 pipeline 迁移到端到端生成,不是”要不要做”的问题,而是”怎么做”的问题。三篇工业论文跨团队收敛的设计模式——混合编码方案、Token-Aware 参数分离、三阶段 SFT/ValueFT/RL 训练、价值融合 beam search——是目前最可信的实践路线。


References: