Training an LLM-RecSys Hybrid for Steerable Recs with Semantic IDs

TL;DR · AI 摘要
通过训练LLM-RecSys混合模型,结合语义ID,实现了可引导推荐系统,模型能够理解自然语言并推理推荐理由。
核心要点
- 模型能够理解自然语言并推理推荐理由。
- 使用语义ID扩展语言模型词汇表。
- 模型基于用户偏好从目录中进行推荐。
结构提纲
按章节快速跳转。
思维导图
用一张图看清主题之间的关系。
查看大纲文本(无障碍 / 无 JS 友好)
- LLM-RecSys混合模型
金句 / Highlights
值得收藏与分享的关键句。
The result is a language model that can converse in both English and item IDs, not with retrieval or other tools, but as a single, “bilingual” model where items (i.e., semantic IDs) are part of its vo
I could simply chat with the model to steer its recommendations, and it could reason about its choices, offer explanations, and creatively name product bundles.
The dataset contains 137k products, each with fields for title, description, features, category, store information, ratings, prices, etc.
URL 源: https://eugeneyan.com/writing/semantic-ids/
发布日期: 2025-09-14T00:00:00+00:00
Markdown 内容: 当我第一次听说语义ID时,我被它吸引了。这个想法很简单:我们不再使用随机哈希ID来标识视频、歌曲或产品,而是使用一种语义上有意义的标记,这种标记可以被语言模型直接理解。我想知道,我们能否利用今天推荐系统所依赖的丰富行为数据来训练一个LLM-推荐系统的混合模型?
令我惊讶的是,这是可能的!结果是一个能够用英语和项目ID进行对话的语言模型,而不是通过检索或其他工具,而是一个单一的“双语”模型,其中项目(即语义ID)是其词汇的一部分。像推荐模型一样,它可以根据历史交互来推荐项目。但最大的惊喜——也是能力解锁——是我发现,我只需与模型聊天就可以引导其推荐,它能够解释其选择,并创造性地命名产品组合。
这是一个演示视频。这是代码,用于准备数据、训练模型并与之聊天。(注意:这是一个小型模型,只有非常基础的微调,因此提示非常重要。此外,由于有限的微调,它不像大多数LLM那样通用和健壮。)
等等,这有什么用?[](https://eugeneyan.com/writing/semantic-ids/#wait-why-is-this-useful)
这结合了推荐系统和语言建模的最佳特性。一方面,语言模型拥有世界知识并能优雅地谈论产品,但它们不了解我们的目录。此外,它们的推荐是通用的,并且容易受到流行度偏差的影响。相反,搜索和推荐模型是在我们的目录和数十亿用户交互上训练的。它们擅长预测用户接下来会点击或购买什么,但无法通过自然语言进行引导或解释其选择。(尽管如此,它们都学习序列。)
为此,我们首先扩展语言模型的词汇表,加入语义ID标记,如<|sid_0|>、<|sid_1|>、<|sid_2|>等。这些标记用于表示目录。然后,我们应用持续预训练来教模型语义ID与目录之间的关系,再进一步在用户行为序列上进行微调。这样,模型学会了根据用户偏好从目录中做出推荐。
虽然这种LLM-推荐系统混合模型可能不如专门的多阶段推荐系统精确,但它提供了一个新的功能:对推荐的可引导性和推理能力。结果是在搜索、推荐和聊天之间提供了统一的体验,使用户能够通过简单询问来找到他们需要的产品。
用户: 我喜欢动物和可爱的游戱。
<|rec|>> _模型解释自然语言查询(“动物和可爱”),并生成相关游戏的语义ID。_
>
>
>
> ```
> <|sid_start|><|sid_173|><|sid_324|><|sid_764|><|sid_768|><|sid_end|>,
> <|sid_start|><|sid_201|><|sid_397|><|sid_701|><|sid_768|><|sid_end|>,
> <|sid_start|><|sid_173|><|sid_305|><|sid_670|><|sid_768|><|sid_end|>
> ```
助手: “《动物之森:新叶》”,“迪士尼无限3DS入门套装”,“《任天狗+猫:金毛寻回犬与新朋友》”
数据和模型 [](https://eugeneyan.com/writing/semantic-ids/#data-and-models)
寻找具有项目元数据和用户序列的训练数据 [](https://eugeneyan.com/writing/semantic-ids/#finding-training-data-with-both-item-metadata-and-user-sequences)
我们将使用来自2023年亚马逊评论(Hou等人,2024)的数据集中的视频游戏类别。该数据集包含丰富的产品元数据,我们可以从中创建用户交互序列。
数据集中包含137k个产品,每个产品都有标题、描述、特征、分类、商店信息、评分、价格等字段。保留标题长度超过20个字符且描述长度超过100个字符的产品后,我们剩下66k个产品。行为数据包含737k条记录。从中,我构建了79k个用户购买序列,每个序列至少包含三个有效项目。这些序列的平均长度为6.5个项目。
我还考虑了2023年亚马逊KDD杯数据(亚马逊,2023)。它有500k个项目,并专注于顺序行为数据。然而,它的多语言性质增加了复杂性,并且缺乏产品分类字段使得处理变得困难。最终,我选择了亚马逊评论数据集,以从简单开始并节省计算预算。
RQ-VAE生成的语义ID [](https://eugeneyan.com/writing/semantic-ids/#semantic-ids-from-rq-vaes)
语义ID(Rajput等人,2023;Singh等人,2023)是一种层次化表示方法,它将项目编码成一系列标记,替代嵌入或基于哈希的ID。与传统的项目ID(例如B0040JHNQG)不同,它没有内在含义,语义ID(例如<|sid_0|><|sid_256|><|sid_512|><|sid_768|>)编码了项目信息。经过训练过程,相似的项目自然共享共同前缀,形成一个树状结构,其中ID的每一级代表关于项目的越来越细粒度的信息。

食品视频的语义ID层次结构(来源:https://arxiv.org/abs/2306.08121)
残差量化变分自编码器(RQ-VAE;Zeghidour 等,2021,Lee 等,2022)是我们用来将连续嵌入转换为离散语义 ID 的工具。我们首先将项目的元数据(例如标题、描述)编码成一个嵌入。然后,RQ-VAE 使用层次量化将这个嵌入转换成一串离散的标记。

RQ-VAE 如何将嵌入转换为语义 ID(来源)
这是一个迭代过程。对于第一层,模型找到与输入嵌入最接近的第一本词典中的向量;该向量成为语义 ID 的第一个标记。然后,模型通过从输入嵌入中减去选定的词典向量来计算量化误差,或称为“残差”。对于第二层,它找到与这个残差最近似的第二本词典中的向量,这给出了第二个标记。此过程重复进行每一层,每一步捕获前一层遗漏的更精细细节。
RQ-VAE 的损失函数值得讨论,因为理解它是生成高质量语义 ID 的关键。总体损失有两个主要组成部分:
第一个部分,即重建损失,确保解码器能够从最终的量化表示()准确地重构原始项目嵌入()。这是一种标准的平方误差损失:
第二个部分,即量化损失,衡量词典向量与编码器生成的残差匹配的程度。它包含两个项:
第一项(,即词典损失,负责训练词典嵌入。它测量编码器的残差()与选定的词典向量()之间的距离。对编码器的输出()应用停止梯度,将残差视为固定目标。因此,梯度只流向词典向量,将其拉近编码器的输出。
第二项(),即承诺损失,负责训练编码器。它测量相同的距离,但对词典向量()应用停止梯度。这阻止了词典的更新,并迫使编码器产生输出,或“承诺”已经在词典中的向量。超参数控制这种承诺惩罚的强度。
# Pytorch 代码中的损失函数(没有递归循环)
reconstruction_loss = F.mse_loss(x, x_reconstructed)
codebook_loss = F.mse_loss(residual.detach(), codebook_vector)
commitment_loss = F.mse_loss(residual, codebook_vector.detach())
quantization_loss = codebook_loss + commitment_weight * commitment_loss
total_loss = recon_loss + quantization_loss通过这一过程,RQ-VAE 生成一个作为每个量化级别标记序列的语义 ID。由于相似的项目共享公共前缀,语言模型可以更好地理解产品关系,这对于基于树的检索也很有用。
# 如何分层编码嵌入到语义 ID
def encode_to_semantic_ids(self, x: Tensor) -> Tensor:
with torch.no_grad():
residual = self.encode(x)
indices_list = []
for vq_layer in self.vq_layers:
vq_output = vq_layer(residual)
indices_list.append(vq_output.indices)
residual = residual - vq_output.quantized
return torch.stack(indices_list, dim=-1)然而,一个实际挑战是这并不能保证每个项目都有唯一的 ID。在我的实验中,使用三层次词典,每层有 256 个代码,我们在 66k 个产品中有约 10% 的碰撞。为了解决这个问题,我在第四层添加了一个逐步增加的标记,以确保每个产品都是唯一可识别的。
清洗数据并创建用户序列 [](https://eugeneyan.com/writing/semantic-ids/#cleaning-data-and-creating-user-sequences)
首先,我们准备项目元数据,以确保高质量的输入用于语义ID模型。我们从排除标题少于20个字符或描述少于100个字符的项目开始。这将项目数量减少了一半,从13.7万个减少到6.6万个唯一的项目。
接下来,我们使用Gemini 2.5 Flash Lite清洗项目描述(Comanici等人,2025年),通过修复截断的句子、移除HTML和减少冗余来处理。这使得平均描述长度从1,038个字符减少到538个字符。同样地,我们移除了促销文本,并标准化了标题格式,将冗长的列表如“NEW! LIMITED! Sega Saturn RGB SCART LEAD CABLE…”简化为干净的“Sega Saturn RGB SCART Cable”。
然后,我们通过提取结构化的元数据(如产品类型(游戏、硬件、配件)、平台(PS4、Xbox、Wii)、流派(Roguelike、Soulslike、Metroidvania)、硬件类型、品牌、多人模式等)来扩充数据。这个过程对平台信息的覆盖率达到了98%,品牌识别率为78%,流派分类率为51%。
最后,为了构建用户序列,我们在用户上进行去重,并构建交互历史,最终得到91.5万个序列。从这些序列中,我们排除了没有任何元数据的项目,然后过滤掉少于三个项目的序列。我们还限制序列的最大长度为100个项目(只有28个序列被截断)。这使我们得到了一个包含78.6万个序列的数据集,其中位数长度为5个项目,平均长度为6.5个项目。
使用RQ-VAE生成语义ID [](https://eugeneyan.com/writing/semantic-ids/#training-an-rq-vae-to-output-semantic-ids)
为了嵌入项目,我们使用Qwen3-Embedding-0.6B模型。该模型支持自定义输入指令以适应各种任务,我们添加了前缀“根据产品描述,生成能够捕捉其关键特性的语义嵌入”。通过这种方法,我们通过最后一个token池化获得1024维嵌入,并在保存之前进行L2归一化。
RQ-VAE由编码器、三个量化级别(每个级别有256个码本)和一个对称解码器组成。为了训练稳定性,我们使用了旋转技巧(Fifty等人,2025年),作为Straight-Through Estimator的替代方法(用于计算梯度)。其他优化包括使用k-means聚类初始化码本、重置未使用的码本以及使用大批次大小。我还尝试了一些没有帮助的技术,例如使用EMA更新码本和阻止解码器的梯度。
训练好的RQ-VAE在三个量化级别上实现了89%的唯一语义ID,覆盖了6.6万个产品。为了解决剩余的碰撞问题,我在任何共享相同前三个码本的产品上附加了一个第四位,分配一个唯一的、连续的ID(0, 1, 2, ...)。这确保了每个产品都有一个唯一的四部分语义ID。
我进行了几十次实验,以更好地理解RQ-VAE及其输出的语义ID,并找到模型的最佳配置。以下是几个关键发现。
首先,我试验了平衡重构精度和码本承诺的承诺权重。我测试了0.25(黄色)、0.5(橙色)和1.0(红色)的值,并发现较高的值1.0产生了最多的唯一ID,但验证损失也最高。虽然较低的值0.25略微增加了唯一ID的数量,但值0.5具有最低的验证损失。因此,在此数据集上,我后续的RQ-VAE训练使用了= 0.5。(注意:这与语义ID论文中使用的= 0.25不同。)

曲线,beta = 0.25(黄色)、0.5(橙色)和1.0(红色)
附注:这些指标的简要解释:
- 损失/重构:衡量RQ-VAE在将原始项目嵌入压缩成语义ID后再解压缩时的重构效果。
- 损失/VQ:所有级别的码本和承诺损失的总和。确保编码器输出接近码本向量且码本向量适应编码器输出。对于将嵌入压缩成有意义的语义ID至关重要。
- 损失/总和:重构损失和VQ损失的总和,用于监控整体进展。
- 损失/验证:在保留的验证集上的总损失,用于监控泛化能力。
- 指标/平均残差范数:所有量化级别之后的“剩余”残差量。残差越低,码本越能捕捉输入嵌入。
- 指标/唯一ID比例:一批中具有唯一ID的项目百分比。检查码本是否出现塌陷。比例越高,区分项目的能力越强。
我还试验了较浅的编码器和元数据清洗的影响。较浅的编码器(绿色)表现较差,增加了验证损失并减少了唯一ID的数量。然而,投资于数据清洗是有回报的(蓝色)。它产生了一个具有最低重构和验证损失同时拥有最高唯一ID比例的模型。我使用了这次运行中的RQ-VAE。

曲线,beta = 0.5(橙色)、较浅的编码器(绿色)和干净的数据(蓝色)
另一种评估RQ-VAE的方法是检查码本利用率。所有码本相对均匀的使用表明模型正在充分利用其表达能力。最终的RQ-VAE很好地展示了这一点;在所有三个量化级别上,使用分布均匀,方差低,如下图所示的直方图所示。

RQVAE码本使用分布均匀的例子
相比之下,收敛不良的RQ-VAE会导致代码使用稀疏且高度集中。下面的直方图展示了这种失败模式,其中少数代码被过度使用,而大多数代码本则被忽略。

RQVAE代码本分布不佳的示例
使用训练好的RQ-VAE,我们将所有项目嵌入编码为其语义ID格式,例如<|sid_start|><|sid_191|><|sid_260|><|sid_716|><|sid_768|><|sid_end|>。然后,我们将78.6k用户的购买序列从常规ID转换为语义ID序列。这些序列为验证ID的质量提供了训练数据,并用于微调Qwen3-8B模型。
使用常规项目ID与语义ID训练SASRec[](https://eugeneyan.com/writing/semantic-ids/#training-a-sasrec-on-regular-item-ids-vs-semantic-ids)
为了验证我们的语义ID是否捕获了有意义的产品关系,我们训练了两种SASRec变体:一种基于常规项目ID的基线模型和另一种基于语义ID的变体模型,然后比较它们的性能。
基线SASRec遵循标准架构。它将每个产品视为一个独立的原子单元,从头开始学习其嵌入。这完全基于行为模式。该模型使用2个因果自注意力块,64维隐藏状态,并通过二元交叉熵(BCE)损失在区分序列中的下一个项目与随机采样的负样本时进行训练。
# 基线SASRec预测函数
def predict(self, input_ids: torch.Tensor, candidate_ids: torch.Tensor) -> torch.Tensor:
"""预测候选项目的评分。
参数:
input_ids: 项目序列 [batch_size, seq_length]
candidate_ids: 要评分的候选项目 [batch_size, num_candidates]
返回:
每个候选项目的评分 [batch_size, num_candidates]
"""
# 获取序列表示
hidden_states = self.forward(input_ids) # [B, T, H]
# 预测仅使用最后一个隐藏状态
final_hidden = hidden_states[:, -1, :] # [B, H]
# 获取候选项目嵌入
candidate_embs = self.item_emb(candidate_ids) # [B, C, H]
# 通过点积计算评分
scores = torch.bmm(candidate_embs, final_hidden.unsqueeze(-1)).squeeze(-1) # [B, C]
return scores相反,语义ID SASRec将推荐重新定义为条件生成任务。它的目标不是对项目进行评分,而是逐个生成下一个项目的4部分语义ID。这需要更大的架构,包括4个transformer块和384维隐藏状态。与使用T5编码器-解码器的TIGER论文不同,这个SASRec变体是纯解码器,使其与基线SASRec的比较更加直接和平等。因为我们使用语义ID,所以不再为每个66k个项目分配嵌入,而是有总共1,024个token级别的嵌入,每个语义ID级别有256个token。
# 语义ID SASRec预测函数
def predict_next_item(self, input_ids: torch.Tensor, teacher_forcing: bool = True,
target_tokens: Optional[torch.Tensor] = None) -> Dict[str, torch.Tensor]:
"""按顺序预测下一个项目的语义ID token。
参数:
input_ids: token序列 [batch_size, seq_length * num_levels]
teacher_forcing: 在训练期间使用真实值进行条件化
target_tokens: 下一个项目的实际token [batch_size, num_levels]
返回:
包含每个级别logits的字典
"""
hidden_states = self.forward(input_ids) # [B, T*L, H]
# 获取最后一个位置的表示作为所有先前项目的上下文
last_hidden = hidden_states[:, -1, :] # [B, H]
predictions = {}
# 顺序生成:根据先前的预测进行条件预测
for level in range(self.num_levels):
if level == 0:
# 第0级:直接从序列表示中预测
context = last_hidden
else:
# 第1-3级:根据先前预测/真实token进行条件预测
if teacher_forcing and target_tokens is not None:
# 训练时使用先前级别的真实值
prev_tokens = target_tokens[:, :level] # [B, level]
else:
# 推理时使用预测的token
prev_tokens = self._sample_from_predictions(predictions, level)
prev_embeds = self.token_emb(prev_tokens) # [B, level, input_dim]
prev_embeds_projected = self.input_projection(prev_embeds) # [B, level, H]
prev_context = prev_embeds_projected.mean(dim=1) # [B, H]
# 与序列上下文结合
combined = torch.cat([last_hidden, prev_context], dim=-1) # [B, 2*H]
context = self.context_combiners[level - 1](combined) # [B, H]
# 预测当前级别
logits = self.level_heads[level](context) # [B, codebook_size]
predictions[f"logits_l{level}"] = logits
return predictions这种生成方法改变了我们如何训练和评估模型。损失函数不再是简单的BCE损失,而是语义ID每个级别的交叉熵损失之和,迫使模型正确预测整个序列。评估也变得更加复杂,不再使用点积,项目的得分是其联合对数概率,通过生成每个token的对数概率求和计算得出。为了提高训练稳定性,我们应用教师强制策略,即前一级的真实token帮助指导下一级的预测。
为了评估这两个模型,我们使用了一个验证集,在其中每个正向的下一个项目添加了500个负样本。虽然基线SASRec的表现优于语义ID变体,但考虑到预测四个正确标记的困难生成任务,语义模型的表现还是相当不错的。此外,语义ID变体通过利用相似产品的共享标记前缀来处理冷启动项目的能力是基线所缺乏的。这揭示了核心权衡,即获得这种泛化能力需要每个项目的预测量增加4倍,并且需要更高的训练和推理计算。
| 模型 | Hit@10 | NDCG@10 | MRR | 平均排名 | 中位数排名 | | --- | --- | --- | --- | --- | --- | | 基线SASRec | 0.2812 | 0.1535 | 0.1300 | 138.9 | 41.0 | | 语义ID SASRec | 0.2020 | 0.1138 | 0.1007 | 179.7 | 79.0 |
微调Qwen3-8B以推荐语义ID[](https://eugeneyan.com/writing/semantic-ids/#fine-tuning-qwen3-8b-to-recommend-semantic-ids)
接下来,我们将教一个语言模型用语义ID进行对话。为此,我们微调了Qwen3-8B使其成为“双语”,能够流利地使用自然语言和语义ID。
首先,我们构建了一个包含420万个对话示例的训练数据集,用于教会模型关于语义ID和推荐的知识。这些数据涵盖了多种任务类型,包括将语义ID映射到相应的文本描述(反之亦然)、预测用户序列中的下一个项目、理解项目类别之间的关系以及多跳推理。每个示例都格式化为带有系统提示、用户指令和助手响应的对话。
然后,我们在两个阶段对模型进行微调。第一阶段专注于词汇扩展,我们向Qwen3-8B的分词器中添加了1,027个新的语义ID标记(即<|sid_start|>、<|sid_end|>、<|sid_0|> 到 <|sid_1023|> 和 <|rec|>),并调整模型的嵌入矩阵。在此阶段,我们冻结了除输入和输出嵌入层之外的所有模型参数,训练了12.3亿个参数(占总数的15.3%),共进行了1,000步训练,学习率相对较高。
初始化了语义ID标记嵌入后,我们进入第二阶段,对所有83亿个参数进行全面微调。为此,我们使用了较低的学习率、3%的预热计划和8位AdamW优化器以提高内存效率,在整个数据集上训练了三个周期。为了监控进度,我们使用了几个自定义回调,跟踪训练指标如梯度范数、测量推荐任务上的层次准确性,并在一组固定的对话输入上采样模型输出。
与LLM-推荐器混合聊天[](https://eugeneyan.com/writing/semantic-ids/#chatting-with-the-llm-recommender-hybrid)
微调后的模型可以用来推荐项目,并且能够用语义ID和自然语言进行对话。因为语义ID是其词汇的一部分,模型通过简单地预测序列中的下一个ID来生成推荐,逐个标记。对于交互会话,聊天界面将模型的原始输出(包含语义ID)转换回产品标题,创建可读性更强的对话。
用户: “Halo 3 Limited Edition -Xbox 360”,“Lost Planet: Extreme Condition - Xbox 360”,“Lost Planet: Extreme Condition Collector’s Edition -Xbox 360”
<|rec|>> _模型根据用户的交互历史(一系列Xbox 360科幻射击游戏)执行下一个项目预测。_
>
>
>
> ```
> <|sid_start|><|sid_64|><|sid_351|><|sid_733|><|sid_768|><|sid_end|>
> ```
助手: “Mass Effect - Xbox 360”
基本测试显示,该模型可以根据用户的历史提供标准的下一个项目推荐,并根据自然语言(如平台约束“Xbox类似的游戏...”或类型“我喜欢动物和可爱的游戏。”)来改进推荐。
用户: Xbox类似的游戏:“The Legend of Zelda: Ocarina of Time 3D”:<|rec|>
> _模型采用种子项目(“The Legend of Zelda”)和自然语言约束(“Xbox”)来引导推荐到不同的平台。_
>
>
>
> ```
> <|sid_start|><|sid_64|><|sid_271|><|sid_576|><|sid_768|><|sid_end|>,
> <|sid_start|><|sid_64|><|sid_435|><|sid_615|><|sid_768|><|sid_end|>,
> <|sid_start|><|sid_167|><|sid_271|><|sid_578|><|sid_768|><|sid_end|>
> ```
助手: “Fallout: New Vegas - Xbox 360 Ultimate Edition”,“Halo 4 - Xbox 360 (Standard Game)”,“Halo Reach - Legendary Edition”
模型还可以解释其推荐,描述两个项目之间的关系,甚至建议产品捆绑的创意名称和描述。
用户: 我刚完成了“Dragon Quest Heroes II Explorer’s Edition - PlayStation 4”。推荐另一个并解释原因:
> _模型执行了一个混合任务,生成相关的语义ID并提供推荐的解释。_
>
>
>
> ```
> <|sid_start|><|sid_139|><|sid_289|><|sid_534|><|sid_768|><|sid_end|>
>
> 如果你喜欢Dragon Quest Heroes II,你可能会喜欢Nights of Azure,因为两者都是针对PlayStation 4的动作角色扮演游戏,重点在于战斗和角色成长。这两款游戏都提供了以叙事为主导的体验,强调战斗机制,表明玩家对这一类型的共同兴趣。
> ```
助手: “Nights of Azure - PlayStation 4”
如果你喜欢Dragon Quest Heroes II,你可能会喜欢Nights of Azure,因为两者都是针对PlayStation 4的动作角色扮演游戏,重点在于战斗和角色成长。这两款游戏都提供了以叙事为主导的体验,强调战斗机制,表明玩家对这一类型的共同兴趣。
最后,虽然它可能无法与专门的推荐系统相媲美,但这种统一的接口允许用户通过多轮对话从我们的目录中发现产品,从而实现了搜索、推荐系统和聊天的融合。
这一切都是通过模型本身完成的,无需意图分类器、路由、检索等。
[TURN 1] 用户: 我想找一些类似于《马里奥赛车》的游戏。
<|rec|>> _模型为三个卡丁车风格的竞速游戏生成语义 ID:_
>
>
>
> ```
> <|sid_start|><|sid_131|><|sid_503|><|sid_738|><|sid_768|><|sid_end|>,
> <|sid_start|><|sid_131|><|sid_260|><|sid_577|><|sid_768|><|sid_end|>,
> <|sid_start|><|sid_145|><|sid_416|><|sid_671|><|sid_768|><|sid_end|>
> ```
助手: “《极品飞车:最高通缉》- 索尼 PSP”,“《极品飞车:热力追踪2》- PlayStation 2”,“《火爆狂飙传奇》- Nintendo DS”
[TURN 2] 用户: 有没有类似的游戏,但适合 Xbox?
<|rec|>> _模型使用对话历史记录和新的“Xbox”约束条件来生成相关 Xbox 游戏的语义 ID:_
>
>
>
> ```
> <|sid_start|><|sid_183|><|sid_461|><|sid_517|><|sid_768|><|sid_end|>,
> <|sid_start|><|sid_183|><|sid_461|><|sid_562|><|sid_768|><|sid_end|>,
> <|sid_start|><|sid_183|><|sid_461|><|sid_616|><|sid_768|><|sid_end|>
> ```
助手: “《极品飞车:Carbon》- Xbox 360”,“《极限竞速:城市赛车3》- Xbox 360”,“《极限竞速:地平线4》- Xbox 360”
[TURN 3] 用户: 建议一个捆绑包的名称和描述。
> _模型理解上下文已经从推荐转变为生成创意文本的任务:_
助手: Xbox 竞速传奇:速度与风格包
好的,就是这样!我希望你和我一样觉得这很令人兴奋!如果我有更多的计算资源,我会尝试对语义 ID 进行句子片段标记化处理,正如 Deepmind 和 YouTube 发现的那样,并进一步探索语义 ID 对冷启动的影响。我还会在包含数百万产品的数据集上训练 RQ-VAEs 和语言模型,并进行更多种类的任务和对话测试,以验证这种方法的可扩展性和泛化能力。
你是否使用过语义 ID 来训练模型或构建用户体验?我很乐意交流,请联系我!
感谢 Devansh 和 Shrikar 的讨论,以及 Luke 和 Runpod 提供的计算资源来运行这些实验。(请使用我的推荐码,这样我就能获得更多实验的信用!)感谢 Vibhu、Shawn、Cheng,以及所有不得不忍受我喋喋不休的人。
参考文献 [](https://eugeneyan.com/writing/semantic-ids/#references)
Hou, Yupeng, Jiacheng Li, Zhankui He, An Yan, Xiusi Chen, 和 Julian McAuley. “用于检索和推荐的语言和项目的桥梁。” arXiv:2403.03952。预印本,arXiv,2024年3月6日。https://doi.org/10.48550/arXiv.2403.03952。
亚马逊。“亚马逊KDD杯‘23 - 多语言推荐挑战数据集。”AIcrowd,2023年。https://www.aicrowd.com/challenges/amazon-kdd-cup-23-multilingual-recommendation-challenge。
Rajput, Shashank, Nikhil Mehta, Anima Singh, 等人。“具有生成性检索的推荐系统。” arXiv:2305.05065。预印本,arXiv,2023年11月3日。https://doi.org/10.48550/arXiv.2305.05065。
Singh, Anima, Trung Vu, Nikhil Mehta, 等人。“更好的泛化能力:语义ID的案例研究。” arXiv:2306.08121。预印本,arXiv,2024年5月30日。https://doi.org/10.48550/arXiv.2306.08121。
Zeghidour, Neil, Alejandro Luebs, Ahmed Omran, Jan Skoglund, 和 Marco Tagliasacchi。“SoundStream:端到端神经音频编解码器。” arXiv:2107.03312。预印本,arXiv,2021年7月7日。https://doi.org/10.48550/arXiv.2107.03312。
Lee, Doyup, Chiheon Kim, Saehoon Kim, Minsu Cho, 和 Wook-Shin Han。“使用残差量化进行自回归图像生成。” arXiv:2203.01941。预印本,arXiv,2022年3月9日。https://doi.org/10.48550/arXiv.2203.01941。
Kang, Wang-Cheng, 和 Julian McAuley。“自注意力顺序推荐。” arXiv:1808.09781。预印本,arXiv,2018年8月20日。https://doi.org/10.48550/arXiv.1808.09781。
Vaswani, Ashish, Noam Shazeer, Niki Parmar, 等人。“注意力就是你所需要的全部。” arXiv:1706.03762。预印本,arXiv,2023年8月2日。https://doi.org/10.48550/arXiv.1706.03762。
Zhang, Yanzhao, Mingxin Li, Dingkun Long, 等人。“Qwen3嵌入:通过基础模型推进文本嵌入和重排序。” arXiv:2506.05176。预印本,arXiv,2025年6月11日。https://doi.org/10.48550/arXiv.2506.05176。
Yang, An, Anfeng Li, Baosong Yang, 等人。“Qwen3技术报告。” arXiv:2505.09388。预印本,arXiv,2025年5月14日。https://doi.org/10.48550/arXiv.2505.09388。
Comanici, Gheorghe, Eric Bieber, Mike Schaekermann, 等人。“Gemini 2.5:推动前沿发展,具备高级推理、多模态、长上下文和下一代代理能力。” arXiv:2507.06261。预印本,arXiv,2025年7月22日。https://doi.org/10.48550/arXiv.2507.06261。
如果你觉得这很有用,请引用这篇写稿:
Yan, Ziyou. (Sep 2025). 使用语义ID训练LLM-RecSys混合模型进行可控推荐。eugeneyan.com。https://eugeneyan.com/writing/semantic-ids/
或
@article{yan2025semantic-ids,
title = {使用语义ID训练LLM-RecSys混合模型进行可控推荐},
author = {Yan, Ziyou},
journal = {eugeneyan.com},
year = {2025},
month = {Sep},
url = {https://eugeneyan.com/writing/semantic-ids/}
}分享到:
加入 11,800+ 读者,获取机器学习、推荐系统、大型语言模型和工程方面的更新。