← 返回首页
🔁 生成式推荐 · Shopee · ACM 2026

UniRec

Bridging the Expressive Gap between Generative and Discriminative Recommendation via Chain-of-Attribute

用 Chain-of-Attribute 弥合生成式与判别式推荐的表达力鸿沟

机构
Shopee
Venue
ACM Conference '26
arXiv
核心方法
CoA + Capacity-SID + CDC + RFT/DPO
💡 值得借鉴的三个设计思想
01
先推理特征,再推理 item

CoA 的核心直觉:生成式模型解码时看不到 Item 侧特征,表达力天然受限。UniRec 的解法是把"先预测粗粒度属性(类目、品牌),再生成 SID"的两阶段串行化——用推理链弥补信息差,而不是试图把所有信息都塞进 SID token。更难能可贵的是,论文通过贝叶斯公式给出了严格的理论保证:只要属性 token 和 SID 之间存在条件互信息 $I(\mathbf{a}; s_l \mid s_{<l}, u) > 0$,每步解码的不确定性就严格下降。理论先行、实验验证,这个论证框架本身就很值得学习。

02
场景 token 控制生成方向

Task-Conditioned BOS 把"当前是什么场景/目标"注入解码起点,将整条生成轨迹锁定到对应分布上——这和可控序列生成的思路高度一致:在生成开始前注入控制信号,比在每步生成时插入约束更彻底、更稳定。KDD 可控序列生成论文里的场景/意图控制 token 与之异曲同工:同一个统一模型,通过起始 token 的差异,驱动出完全不同的生成行为,避免了为每个场景单独训练模型的成本,同时又保留了场景间的知识迁移。

03
路径哈希 embedding 融入组合信息

Content Summary 的思路很实用:SID 解码路径上的 token 对(如 L2类目 × $s_0$)携带远比单个 token 更丰富的联合语义,但全量存储所有组合的 embedding 参数爆炸($4000^2$ 量级)。用多个哈希函数把 token 对映射到共享小 table 上,以可接受的碰撞率换取极低的参数成本,是一种工程上非常务实的 trick。类似的思想在工业推荐特征工程里也很常见(Feature Hashing / FeatureHash),UniRec 把它搬进了自回归解码的每步打分中,是一个轻量但有效的组合特征注入方式。

TL;DR · 三分钟读懂 UniRec
核心一句话

生成式推荐(GR)之所以不如判别式推荐,不是因为模型结构弱,而是因为解码时看不到 Item 侧特征。UniRec 通过在 SID 解码前先生成属性 token(Chain-of-Attribute),把 Item 侧信息"还给"生成器,同时搭配曝光均衡的 SID 构建、多场景条件解码、以及 RFT+DPO 业务对齐,在 Shopee 线上取得 GMV +5.60%、订单 +4.76% 的显著增益。

+22.6%
离线 HR@50 相对提升
(vs. 最强 GR baseline)
+5.60%
线上 A/B GMV 提升
(Shopee 主场景)
110ms
端到端延迟
(传统 pipeline 266ms)
🎯
§1 动机:生成式 vs 判别式推荐的表达力鸿沟

现代推荐系统的主流范式是多阶段判别式 pipeline(召回 → 粗排 → 精排 → 重排),但这套架构有三个根深蒂固的问题:

  • 阶段目标不一致:各阶段各自优化局部目标,全局最优无从保证
  • 样本选择偏差:精排模型只在曝光空间上训练,对未曝光候选泛化差
  • 误差逐层传播:上游召回的错误无法被下游纠正

生成式推荐(Generative Recommendation, GR)把"推荐"重新定义为对 Semantic ID(SID)序列的自回归解码,用一个模型统一了召回和排序,从架构上规避了上述三个问题。但一个直觉上很明显的疑问始终存在:

⚠️ 核心疑问

判别式模型打分时,可以直接拿到目标 Item 的特征向量(类目、品牌、卖家…),做 User-Item 特征交叉;而生成式模型在解码时只看 SID token,根本不知道候选 Item 是什么——这会不会导致生成式模型表达力天然更弱?

UniRec 的出发点就是给这个问题一个精确的理论答案,然后用方法论把差距填平。

🔬
§2 理论基础:贝叶斯等价性

2.1 判别式 = 生成式(在完整特征下)

判别式模型对 Item 的打分是 $p(y \mid \mathbf{f}, u)$,其中 $\mathbf{f}$ 是 Item 特征,$u$ 是用户上下文。由贝叶斯公式:

$$p(y \mid \mathbf{f}, u) \propto p(\mathbf{f} \mid y, u) \cdot p(y \mid u)$$

其中 $p(y \mid u)$ 与 $\mathbf{f}$ 无关,因此按判别式分数排序等价于按生成后验 $p(\mathbf{f} \mid y, u)$ 排序。生成后验进一步按链式法则展开:

$$p(\mathbf{f} \mid y, u) = \prod_{k=1}^{n} p(f_k \mid f_{<k}, y, u)$$

这正好对应对 Item 特征序列的自回归解码。因此:

🔑 理论结论

一个能完整访问 Item 特征 $\mathbf{f}$ 的生成模型,与判别式模型表达能力等价。二者的实际差距不来自"模型范式本身",而来自特征覆盖度——SID 把丰富的 Item 语义压缩成了紧凑的离散 code,结构化属性(类目、品牌、卖家)在解码时变成了隐藏信号。

💡 举例:这段推导在说什么?

场景:给用户 $u$(喜欢运动的男生)推荐商品,候选有 Nike 跑鞋(Item A)和口红(Item B)。

判别式做法:把用户特征 + Item A 的完整特征向量 $\mathbf{f}_A$(类目=运动、品牌=Nike、价格=¥599)输入模型,直接输出点击概率 $p(y=1 \mid \mathbf{f}_A, u)$。谁分高推谁。

贝叶斯变形告诉我们:"用户点 Nike 跑鞋的概率" ∝ "已知用户点了一件商品,它的特征恰好是运动/Nike/¥599 的概率" × "该用户点任意商品的基础概率"。后者对所有候选相同,排序时可扔掉。所以按判别式分数排序 = 按"这件商品的特征对这个用户有多自然"排序

链式展开的意义:$p(\mathbf{f}_A \mid y=1, u)$ 是对整个特征向量的联合概率。用链式法则拆开后 = 先算"第一个特征是'运动'的概率" × "已知是'运动',第二个特征是'鞋'的概率" × … 这和语言模型逐 token 生成文字的方式完全一样——只是这里生成的不是文字,而是 Item 的特征序列。

结论:只要生成模型解码时能看到完整的 Item 特征,它和判别式模型理论上等价。问题在于 SID 把特征压缩成了 3 个 code,大量细节丢失了。

📖 背景知识:贝叶斯公式和链式法则是什么?

贝叶斯公式

贝叶斯公式描述的是"条件概率的互换"。最基础的形式是:

$$P(A \mid B) = \frac{P(B \mid A) \cdot P(A)}{P(B)}$$

用大白话说:

  • $P(A \mid B)$:已知 B 发生了,A 发生的概率(后验概率)
  • $P(B \mid A)$:已知 A 发生了,B 发生的概率(似然)
  • $P(A)$:A 本身的概率(先验概率),与 B 无关
  • $P(B)$:B 本身的概率,是个归一化常数
🎯 生活例子:下雨天(B),带伞(A)的概率是多少?
$P(\text{带伞} \mid \text{下雨}) = \dfrac{P(\text{下雨} \mid \text{带伞}) \cdot P(\text{带伞})}{P(\text{下雨})}$

意思是:先看"带伞的人里有多少比例是下雨天带的",乘上"带伞这件事本身有多常见",再除以"下雨的概率"做归一化。分母对所有条件相同,排序时可以忽略,所以经常写成 $\propto$(正比于)。

为什么这里用 $\propto$ 而不是 $=$?

在推荐系统里,我们只需要比大小(排序),不需要精确概率值。贝叶斯公式的分母 $P(\mathbf{f} \mid u)$ 对所有候选 Item 都是同一个常数,不影响排序,所以直接写成"正比于",把分母省掉。


链式法则(Chain Rule)

链式法则是概率论里计算"多个事件同时发生的概率"的公式:

$$P(A_1, A_2, A_3) = P(A_1) \cdot P(A_2 \mid A_1) \cdot P(A_3 \mid A_1, A_2)$$

通用形式:

$$P(x_1, x_2, \ldots, x_n) = \prod_{k=1}^{n} P(x_k \mid x_1, \ldots, x_{k-1})$$
🎯 生活例子:抽扑克牌,连抽 3 张都是红心的概率?
= P(第1张是红心) × P(第2张是红心 | 第1张已是红心) × P(第3张是红心 | 前两张都是红心)
= 13/52 × 12/51 × 11/50

每一步都以"前面已知的结果"为条件,这就是链式法则。

联系到论文:为什么用链式法则?

Item 的特征向量 $\mathbf{f} = (f_1, f_2, \ldots, f_n)$ 是一个多维向量(比如 $f_1$=类目、$f_2$=品牌、$f_3$=价格档位…)。直接建模这个高维联合概率 $p(\mathbf{f} \mid y, u)$ 很难,但用链式法则分解后,变成了一串"条件概率相乘"——这正好是自回归语言模型做的事情:每次预测下一个 token,条件是所有已预测的 token。

所以论文得出的结论是:生成式推荐(自回归解码 SID token)在数学形式上和判别式推荐(直接打分)是等价的,只差在解码时能不能访问完整特征。

2.2 CoA:用属性 token 补回特征覆盖度

完整地对所有 Item 特征逐 token 自回归解码,延迟开销无法承受。CoA 的解法是只补回最关键、被 SID 压缩丢失最多的粗粒度结构化属性(类目层级、品牌、卖家),在 SID 解码前先生成这 $m$ 个属性 token:

$$p(\mathbf{s} \mid u) = p(\mathbf{a} \mid u) \cdot \prod_{l=0}^{L-1} p(s_l \mid \mathbf{a}, s_{<l}, u)$$

理论上,属性条件化带来每步解码的信息熵下降(即生成不确定性降低):

$$\Delta H_l = H(s_l \mid s_{<l}, u) - H(s_l \mid \mathbf{a}, s_{<l}, u) = I(\mathbf{a}; s_l \mid s_{<l}, u) \geq 0$$

由于共享相同属性的 Item 在 SID 语义空间中占据相邻区域,属性 token 和 SID token 在构造上就高度相关,因此 $\Delta H_l$ 严格为正。累积的信息熵下降 $\sum_l \Delta H_l$ 稳定了 beam search 的搜索轨迹,同时逐层减少 token 预测错误率,最终在端到端层面实现错误衰减(error attenuation)。

🛠️
§3 方法体系:四个核心模块

UniRec 由四个相互独立但互补的模块构成:

Capacity-constrained SID
均衡的 SID 构建
+
Chain-of-Attribute
属性先行,再解码 SID
+
CDC
多场景条件解码
+
RFT + DPO
业务价值对齐
⚖️
§3.1 Capacity-constrained SID:治理 Matthew 效应

问题:曝光不均的 Matthew 效应

传统 RQ-KMeans 按 item 数量均衡聚类。但在推荐场景中,item 热度呈长尾分布——即使每个 cluster 的 item 数量相同,高曝光 item 会主导 cluster 的训练信号:

实测数据(Shopee 生产流量)
  • $s_0$ 层:Top 10% token 占总曝光的 33.2%(中等偏斜)
  • $(s_0, s_1)$ 组合:Top 10% 占 87.9%(极度集中,2.6× 放大)
  • $(s_0, s_1, s_2)$ 组合:Top 10% 占 89.6%

即使 $s_0$ 层只有温和的不均衡,到三层组合时已经接近"赢者通吃"——beam search 反复走相同的少数 token 路径,长尾 item 几乎得不到生成机会。

解法:曝光加权的残差量化

引入曝光量 $w_i$(历史曝光次数)作为权重,对每个 cluster $k$ 定义曝光负载

$$V_k = \sum_{i: z_i = k} w_i$$

限制每个 cluster 的曝光负载不超过阈值 $\tau \cdot C_{cap}$(其中 $C_{cap} = \frac{1}{K}\sum_i w_i$ 是均值负载):

$$\min_{\{z_i\}, \{\boldsymbol{\mu}_k\}} \sum_{i=1}^{N} \|x_i - \boldsymbol{\mu}_{z_i}\|_2^2 \quad \text{s.t.} \quad V_k \leq \tau C_{cap}, \;\forall k$$

求解策略:先按距离贪心分配(最小化量化误差),再对超载 cluster 执行修复操作——把超出容量的 item 重新分配到最近的未满 cluster。实测效果:Top 1% token 曝光份额从 57.3% 降至 26.0%,大幅改善长尾 item 的表征质量。

💡 举例:为什么"按人头分"会出问题?

假设场景:Shopee 的 item 池里有 10 万个商品,用 $K=4$ 个 cluster(码本大小简化为 4)做第一层 SID 聚类。

标准 RQ-KMeans(按人头分):每个 cluster 分 2.5 万个 item,看起来很均衡。但热门商品(爆款手机壳、网红零食)每天被点击几十万次,冷门商品每天只被点 2-3 次。

  • Cluster A:2.5 万 item,但其中 100 个爆款占了 90% 的训练信号(梯度)
  • Cluster B/C/D:其余 7.5 万 item 里大多是冷门,训练信号极其稀疏

结果:模型学到的 $s_0$ token A 其实只代表"那 100 个爆款",Beam Search 几乎永远先走 A 路径,冷门 item 几乎永远进不了候选集。

Capacity-constrained SID(按流量分):限制每个 cluster 的总曝光量不超过均值的 1.05 倍。爆款被强制分散到不同 cluster,每个 cluster 的训练信号趋于均衡。

  • 原来全挤在 Cluster A 的 100 个爆款,被拆散分配到 A/B/C/D 四个 cluster
  • 每个 cluster 内热门 item 数量受限,冷门 item 也获得了相应的梯度更新机会
  • Beam Search 不再永远只走 A 路径,长尾 item 也有机会被召回

代价:部分 item 为了均衡被分到了"不是语义上最近"的 cluster,量化重建误差略有上升——这是论文在精确度和公平性之间做的 trade-off。

Figure 2: SID 曝光集中度分析
Figure 2(论文原图):标准 RQ-KMeans 与 Capacity-constrained SID 的曝光集中度对比。各层 token 及组合的 Lorenz 曲线显示,$(s_0, s_1)$ 组合层面的头部集中度极度放大(Matthew 效应),Capacity-SID 有效拉平了曝光分布
🔗
§3.2 Chain-of-Attribute (CoA):先猜属性,再解码 SID

核心思想:Speculate-then-Refine

传统 GR 的解码顺序是直接生成 SID token 序列;CoA 在 SID 序列前先生成 $m$ 个粗粒度属性 token(如 L2 类目 → L3 类目),再以属性为条件解码 SID:

BOS
任务/场景
$a_1$ (L2类目)
属性 token
$a_2$ (L3类目)
属性 token
$s_0$
$s_1$
$s_2$

为什么 L2→L3→SID 是最优配置

论文对多种属性链配置做了对比实验(见实验部分):

属性链L2@3L3@3$s_0$@3HR@50HR@100
无属性(直接 SID)0.3140.4580.532
L1 → SID0.4880.4710.569
L2 → SID0.7550.5910.5150.597
L3 → SID0.6940.6540.5170.601
L2 → L3 → SID0.7570.9620.6820.5370.618

加属性后 $s_0$ 的 top-3 命中率从 0.314 → 0.682,说明属性有效地缩小了 $s_0$ 层的搜索空间。L2→L3 的层级链比单独用 L3 效果更好(0.537 vs 0.517),因为两步粗到细的属性预测本身精度更高(L3@3 = 0.962 vs 单独 0.694)。

💡 与 GRACE 的对比

GRACE(RecSys'25)也用了属性前缀,但把它当成一个纯工程 trick;CoA 提供了第一个信息论视角的理论解释,用互信息 $I(\mathbf{a}; s_l \mid s_{<l}, u) \geq 0$ 精确量化了属性条件化带来的不确定性下降。

🎛️
§3.3 Conditional Decoding Context (CDC):多场景稳定解码

Task-Conditioned BOS:告诉模型"现在要干什么"

一个统一的 GR 模型需要同时服务多个业务场景(主 feed 点击预估、购买转化预估、跨境商品、搜索排序…)。不同场景的行为分布迥异,如果用同一个固定 BOS token,模型无法区分场景,导致梯度相互干扰。

解法:把 BOS token 替换为可学习的、场景条件化的 embedding

$$c_{\text{task}} \in \{\text{click, purchase, cart, cross-border, \ldots}\} \times \{\text{main feed, search, similar items, flash sale, \ldots}\}$$

Task-Conditioned BOS 在解码序列的最初就注入场景信号,把整个生成轨迹"锁定"到对应的场景分布上。多场景联合训练实验验证:联合训练比单场景模型 HR@50 高 +0.9 点,再加 Task-Conditioned BOS 又进一步提升。

Content Summary:捕捉 token 组合的联合语义

先理解问题本身:CoA 的解码顺序是 L2类目 → L3类目 → $s_0$ → $s_1$ → $s_2$。每一步解码时,模型需要知道"我现在走到的这条路径"——比如已经确定了 L2=运动、L3=跑步,下一步 $s_0$ 应该偏向哪个 token?这个"已走路径"包含的组合信息(比如"运动 × $s_0$=7"这个组合对应什么含义)才是关键条件,而不是每个 token 单独的含义。

Self-Attention 可以隐式建模 token 交互,但对于显式的笛卡尔积组合特征(如 L2类目 × $s_0$)表达力有限。全量存储所有 token 对组合的 embedding 参数爆炸($4000^2 \approx 1600$ 万条)。

💡 举例:为什么单独的 token embedding 不够?

场景:模型已经解码出 L2=运动(token #5)、$s_0$=7,现在要预测 $s_1$。

只看单个 token embedding 的问题:

  • "运动"的 embedding 告诉模型:这是体育类商品
  • "$s_0$=7"的 embedding 告诉模型:这是某个 SID 区域
  • 但"运动 × $s_0$=7"这个组合的语义(例如:运动类里跑鞋子类下的某品牌)模型无法从两个向量简单相加/拼接中准确捕捉到

类比:就像学语言——你知道"苹果"是水果,"手机"是电子产品,但"苹果手机"这个组合是一个完全不同的概念,不能靠把两个词意思叠加来理解。

全量存储行不通:码本大小 4000,两两组合就有 $4000 \times 4000 = 1600$ 万条 embedding,内存爆炸,训练也慢。

Content Summary 的解法:用 3 个哈希函数把"已走路径的所有关键 token 对"映射到一个小得多的共享 embedding table(大小 $S \ll 4000^2$),3 个哈希结果的 embedding 求和后拼入每步的 Rank Head。这样:

  • 参数量从 1600 万降到 $3 \times S$($S$ 是哈希表大小,可控)
  • 哈希碰撞引入少量噪声,但实测对效果影响很小
  • 每步解码都能"知道"自己所在的 token 路径组合,而不只是当前单个 token

Content Summary 借鉴 Bloom Filter 思想,用 $M$ 个哈希函数将解码路径投影到共享 embedding table:

$$\mathbf{c}_t = \bigoplus_{i=1}^{M} E_{\text{hash}}\!\left(H_i(\text{path}_{<t}) \bmod S\right)$$
符号说明
  • $\mathbf{c}_t$:第 $t$ 步解码时的 Content Summary 向量,拼入 Rank Head 参与打分
  • $M$:哈希函数数量,论文取 $M=3$
  • $\bigoplus$:向量相加(element-wise sum),把 $M$ 个哈希分支的 embedding 合并
  • $E_{\text{hash}}(\cdot)$:共享的哈希 embedding table,形状 $S \times d_{\text{hash}}$;给定一个整数索引,返回对应行的 embedding 向量
  • $H_i(\text{path}_{<t})$:第 $i$ 个哈希函数,输入是当前解码路径上的某对 token(如 L2 和 $s_0$),输出一个整数
  • $\bmod S$:把哈希值映射到 $[0, S)$ 范围内,作为 embedding table 的索引;$S$ 是 table 行数(超参数,控制存储大小)
  • $d_{\text{hash}}$:每个哈希 embedding 的维度
  • $M \times S \times d_{\text{hash}}$:整个 Content Summary 模块的总参数量

五个笛卡尔积对的意义:论文选了 $(L2, s_0)$、$(L2, s_1)$、$(L3, s_0)$、$(L3, s_1)$、$(s_0, s_1)$ 这 5 对 token 做组合特征。每个"对"就是上面举例里说的"苹果手机"式联合语义——单独看一个 token 不够,要看两个 token 的组合对应什么。3 个哈希函数分别对每对 token $(x, y)$ 做:

  • $H_1(x,y)=x+y$:线性组合,捕捉两个 token ID 的加性关系
  • $H_2(x,y)=x \cdot y$:乘性组合,捕捉两个 token 的交叉关系
  • $H_3(x,y)=p_1 x + p_2 y$($p_1, p_2$ 为质数):带权线性组合,质数权重降低哈希碰撞概率

三个哈希对同一个 token 对给出三个不同的整数索引,从 $E_{\text{hash}}$ 里分别取三个 embedding 向量相加,拼入 Rank Head。这样用 $3 \times S$ 行的小 table(而非 $4000^2$ 行的大 table)就近似地表达了所有关键 token 对的组合语义。Content Summary 以轻量参数量($M \times S \times d_{\text{hash}}$)注入每步 Rank Head,显著提升了 token 路径的条件预测精度。

🎯
§3.4 RFT + DPO:业务价值对齐

NTP 训练优化的是"分布匹配",不直接优化业务指标(GMV、转化率)。UniRec 在 NTP 之上加了两个互补的对齐机制:

Reward-Driven Fine-tuning (RFT)

用连续的业务价值估计(GMV、观看时长)对训练样本重加权。高业务价值样本被放大,低价值样本被压制:

$\mathcal{L}_{\text{RFT}} = -\sum_{i \in \mathcal{B}} \sum_t (1 + \lambda \tilde{A}_i) \cdot \alpha_i \cdot \log p_\theta(s^\star_{i,t} \mid \cdots)$

符号说明:
$\mathcal{B}$:一个训练 mini-batch 内的样本集合
$i$:第 $i$ 条训练样本(一条用户请求 + 一个正样本 item)
$t$:解码步(第 $t$ 个 token,包括属性 token 和 SID token)
$s^\star_{i,t}$:第 $i$ 条样本第 $t$ 步的真实 token(ground truth)
$p_\theta(s^\star_{i,t} \mid \cdots)$:模型预测该真实 token 的概率(NTP loss 的基础)
$\tilde{A}_i$:样本 $i$ 的 advantage 值 = 归一化后的业务价值(如 GMV 在 batch 内 z-score 后 clip),正值 = 高于平均价值,负值 = 低于平均价值
$\lambda$:控制业务价值重加权强度的超参数
$(1 + \lambda \tilde{A}_i)$:加权系数——高 GMV 样本系数 >1(放大梯度),低 GMV 样本系数 <1(压制梯度)
$\alpha_i$:NTP loss 的基础样本权重(如按序列长度归一化)

Direct Preference Optimization (DPO)

从线上流量中构建行为偏序对:购买 ≻ 点击 ≻ 仅曝光。对每个请求,将同一上下文下的曝光 item 按行为等级两两配对:

$\mathcal{L}_{\text{DPO}} = -\mathbb{E}\left[\log \sigma\!\left(\beta \left(\log\frac{\pi_\theta(y_w|u)}{\pi_{\text{ref}}(y_w|u)} - \log\frac{\pi_\theta(y_l|u)}{\pi_{\text{ref}}(y_l|u)}\right)\right)\right]$

符号说明:
$y_w$:偏好对中"更好"的 item(winner),如被购买的商品
$y_l$:偏好对中"较差"的 item(loser),如只被曝光未点击的商品
$u$:用户上下文(行为序列 + 场景信息)
$\pi_\theta(y \mid u)$:当前模型(policy)生成 item $y$ 的完整序列概率(所有 token 概率之积)
$\pi_{\text{ref}}(y \mid u)$:参考模型(reference policy)的概率,通常是 RFT 前的 checkpoint,固定不更新
$\log\frac{\pi_\theta}{\pi_{\text{ref}}}$:当前模型相对参考模型的"偏好程度"变化量,winner 的这个值越大越好
$\beta$:温度超参数,控制 KL 约束力度,越大越保守
$\sigma(\cdot)$:sigmoid 函数,把实数映射到 (0,1) 概率区间
❓ Layer-wise Stop Gradient 是什么意思?

背景:UniRec 的 Rank Head 不是一个,而是每个解码步各有一个独立的 Rank Head——前 $m$ 步(属性 token,如 L2/L3 类目)有各自的 Rank Head,后 $L$ 步(SID token $s_0, s_1, s_2$)也有各自的 Rank Head。可以理解为解码链上有 $m+L$ 个"打分器"各司其职。

问题:DPO 的训练信号来自"哪个 item 最终更被用户偏好",这是一个全局结果(整条 item 序列的偏好),不是每步属性 token 的精准偏好。如果 DPO 梯度直接传回到属性预测层(L2/L3 Rank Head),会把"属性预测器"往一个错误的方向拉——它会为了让某 winner item 的最终概率高,扭曲属性预测的分布,破坏属性预测本身的精度。

解法:Layer-wise Stop Gradient = 在反向传播时,DPO 的梯度只允许流向最后一层 SID Rank Head(即 $s_2$ 的打分器),不允许继续往前传回到属性 Rank Head 和 SID 前几层。相当于给梯度加了一道"防火墙":

  • ✅ DPO 梯度更新:最后一层 SID Rank Head($s_2$ 的打分器)
  • 🚫 DPO 梯度不更新:属性 Rank Head(L2/L3)、$s_0$/$s_1$ 的 Rank Head、Backbone 参数

这样 DPO 只对"最终 item 选择"的偏好排序负责,属性预测和前几步 SID 的解码精度由 NTP + RFT 保证,互不干扰。

两者联合优化:$\mathcal{L} = \mathcal{L}_{\text{RFT}} + \lambda_{\text{DPO}} \mathcal{L}_{\text{DPO}}$。RFT 用连续信号补充分布匹配,DPO 用离散的行为偏好对注入用户真实意图,二者覆盖了互补的信号维度。

🏗️
§4 整体架构:Decoder-Only + Cross-Attention

UniRec 使用 Decoder-Only 骨干网络,通过 Cross-Attention 接入用户行为序列,每个解码步有独立的 Rank Head 输出 token 分布。

Figure 1: UniRec 整体架构图
Figure 1(论文原图):UniRec 系统整体架构,展示了四个核心模块的协同关系——Capacity-constrained SID 构建、CoA 解码链(BOS → 属性 token → SID token)、Cross-Attention Decoder、以及 RFT+DPO 对齐训练

输入特征

1
静态 Profile

用户 ID、人口属性、上下文特征 → RMSNorm 拼接 → $h_{\text{static}} \in \mathbb{R}^{d_{\text{static}}}$

2
行为序列

每个历史点击的 Item 属性(item, shop, category…)Linear 投影后拼成序列 $H_{\text{seq}} \in \mathbb{R}^{T \times d_{\text{model}}}$

3
多模态 SID 特征

由多模态内容对齐生成的 SID token embedding,追加到行为序列末尾,提供 Item 内容侧语义

Cross-Attention 解码

解码侧(BOS + 属性 token + SID token)作为 Query,行为序列作为固定的 Key-Value。每层使用 Gated Cross-Attention + MMoE-FFN(SwiGLU 激活,4 个 expert),共 3 层,8 头。Gating 参数 $\gamma$ 控制行为上下文的注入强度。

Hierarchical Rank Head

每个解码步 $t$ 有独立的 Rank Head,输入为:cross-attention 输出 $q_t$ + 前缀 embedding $e_{\text{prefix}}$ + Content Summary $c_t$ + 聚合表示 $h_{\text{agg}}$,经 SENet + MaskNet 后 Softmax 输出 token 分布。前 $m$ 步预测属性 token(类目层级),后 $L$ 步预测 SID token。

模型默认配置:$d_{\text{model}} = 256$,行为序列长度 $T = 200$,SID 码本大小 $K = 4000$/层,3 层 SID 层级,容量容忍系数 $\tau = 1.05$,总参数约 50M(0.05B)。
📊
§5 实验结果

5.1 离线 Baseline 对比

方法 类型 HR@50HR@100HR@200 Order HR@50Order HR@100
SASRec判别式0.4210.4890.5560.5480.631
TIGER (0.05B)GR Enc-Dec0.4370.5080.5780.5670.652
OneRec-V2 (0.05B)GR Dec-Only0.4380.5230.5870.5820.671
UniRec (0.05B)GR + CoA0.5370.6180.6880.6720.774

UniRec 在所有样本上相对 OneRec-V2 HR@50 提升 +22.6%,在高价值 Order 样本上 HR@50 提升 +15.5%。Order 样本的高提升源于 Task-Conditioned BOS 对多目标(点击、购买、加购)的区分能力,以及 RFT 对高 GMV 样本的重加权。

5.2 线上 A/B 测试(Shopee 生产环境)

+5.37%
PVCTR(页面 CTR)
+4.76%
总订单量
+5.60%
GMV
110ms
延迟(vs 266ms)

Landing Page 场景(商品详情页推荐)增益更高:订单 +5.78%,GMV +6.19%。端到端延迟 110ms vs 传统多阶段 pipeline 的 266ms,说明统一架构在削减跨阶段通信成本方面确实显著。

Figure 3: 线上 A/B 实验结果
Figure 3(论文原图):Shopee 线上 A/B 实验汇总,包含各指标在主 feed 场景及 Landing Page 场景的增益,以及延迟对比
🔬
§6 消融分析
消融配置HR@50HR@100HR@200相对下降
Full Model(UniRec)0.5370.6180.688
替换为标准 RQ-KMeans(去 Capacity SID)0.4810.5580.627HR@100 −9.7%
去除 Task-Conditioned BOS0.4930.5700.638HR@100 −7.8%
去除 Content Summary0.4850.5650.637HR@100 −8.6%

三个核心工程模块(Capacity SID、Task-Cond BOS、Content Summary)贡献了大约相近的收益,且彼此正交——去掉任意一个都有约 8-10% 的 HR@100 下降,说明系统价值来自各模块的协同。

🔍 Scaling 趋势

$d_{\text{model}}$ 从 64→128→256→512,HR@50 单调增长(0.397→0.477→0.537→0.557),呈现清晰的 scaling law,说明 UniRec 架构设计是计算友好的,更大模型仍有提升空间。

§7 总结与我的思考

论文贡献总结

  • 理论贡献:第一个用 Bayes 定理精确量化 GR 与 DR 表达力差距来源的信息论分析,结论干净——差距来自特征覆盖度,不来自范式本身
  • 方法贡献(CoA):以最小延迟开销($m$ 步额外解码),通过"先猜属性、再生成 SID"的 speculate-then-refine 范式,有效补回被 SID 压缩丢失的 Item 侧特征
  • 工程贡献:Capacity-constrained SID + CDC(Task-Cond BOS + Content Summary)解决了大规模部署中两个实际痛点:token collapse 和多场景干扰
  • 对齐贡献:RFT(连续业务价值重加权)+ DPO(行为偏好对)的联合框架,将生成式推荐真正对接业务目标

值得思考的问题

Q1: CoA 的属性预测错了怎么办?

论文数据显示 L2@3 = 0.757,即 L2 类目的 top-3 召回率只有 75.7%——意味着约 25% 的情况属性预测会偏离。论文的理论要求 $I(\mathbf{a}; s_l \mid \ldots) > 0$ 为严格正,这在期望上成立,但单条样本的错误属性会引导 SID 解码走向错误方向。这个 cascading error 在 beam search 下的实际影响值得进一步量化。

Q2: Capacity SID 的量化误差代价

为了均衡曝光负载,Capacity SID 会把部分 item 分配到"不是最近的"cluster(修复操作),这必然增大量化重建误差。论文用 HR 指标说明整体是正向的,但理论上对于低曝光 item,这个 trade-off 的净收益如何,论文没有单独拆分分析。

Q3: DPO 偏好对的构建偏差

从同一请求的曝光 item 里构建偏序对(购买 ≻ 点击 ≻ 曝光),这个偏序本身受位置偏差(position bias)影响——排位靠前的 item 曝光更多但不一定更优质。论文没有提到对 position bias 的校正处理,这在实际工业系统里是一个重要的工程细节。

关联阅读

  • OneRec:统一多阶段 pipeline 的生成式推荐,UniRec 的直接前作之一
  • TIGER:GR 的开创性工作,引入 RQ-VAE 构建层级 SID
  • SemID:语义 ID 的质量与泛化性研究
  • OneSearch:GR 在电商搜索场景的应用,同样结合了 DPO