Skip to content

大模型在推荐系统中的应用:LLM 做特征工程、排序模型蒸馏、生成式推荐

关键词:LLM 推荐系统、特征工程、知识蒸馏、GenRec、排序模型

推荐系统遇到了什么瓶颈,LLM 能解决什么?

推荐系统是一个天花板极高的领域。传统推荐系统(协同过滤、矩阵分解、DeepFM、DCN 等)在过去十年里积累了极其成熟的工程体系,但到了 2025-2026 年,几个本质问题越来越突出:

  • 冷启动:新用户、新商品只有 ID 特征,没有行为数据,协同过滤完全失效。淘宝 2024 年双十一期间,新注册用户的首单推荐转化率只有老用户的 1/8。
  • 长尾内容:头部 20% 的商品占了 80% 的曝光,长尾内容曝光不足,但用户对长尾的个性化需求反而更高——你搜"复古机械键盘",传统模型优先给你推 Cherry 的 MX 系列,但你可能想找的是小众品牌。
  • 语义理解浅:传统模型只能看到用户点击了哪些商品 ID,但看不到用户为什么点击——是"买了 iPhone 需要配件",还是"在对比竞品"。
  • 跨域迁移难:用户在抖音刷了 30 分钟美食视频,这个兴趣偏好很难迁移到美团外卖场景,因为没有共享特征。

LLM 的入场不是要替代整个推荐系统,而是补上传统模型最大的短板:语义理解能力。这就引出了 LLM 在推荐系统中的三个层次应用。

第一层:特征工程增强——让推荐模型"看懂"商品

传统推荐模型的特征主要来自三类:用户 ID 类特征(性别、年龄、地域)、商品 ID 类特征(类目、品牌、价格区间)、行为序列特征(最近 30 天点击的商品 ID 序列)。这些特征的问题是:数字和 ID 是冷冰冰的,模型不知道这些 ID 背后代表什么

原理:文本 → 语义特征向量

LLM 做特征工程的核心思路是:用 LLM 把非结构化文本转化为语义特征,然后作为 Embedding 或标签特征喂入传统推荐模型。

              ┌──────────────┐
              │  商品原始数据  │
              │  (标题/描述/  │
              │   图片/属性)  │
              └──────┬───────┘


              ┌──────────────┐
              │  LLM 离线 Batch │
              │  提取语义特征  │
              │  (GPT-4o-mini) │
              └──────┬───────┘

          ┌──────────┼──────────┐
          ▼          ▼          ▼
    ┌──────────┐┌──────────┐┌──────────┐
    │ 类目标签  ││使用场景  ││用户群体  │
    │(召回用)  ││(排序用)  ││(兜底用)  │
    └──────────┘└──────────┘└──────────┘
          │          │          │
          ▼          ▼          ▼
    ┌──────────────────────────────────┐
    │   传统推荐模型 (DeepFM/DCN)      │
    │   ID特征 + 行为特征 + 语义特征   │
    └──────────────────────────────────┘
python
# 示例:用 LLM 提取商品语义特征
import openai

def extract_item_features(item_title, item_desc):
    prompt = f"""请从以下商品信息中提取特征标签,以 JSON 格式输出:
商品标题:{item_title}
商品描述:{item_desc}

输出格式:
{{
  "category_tags": ["标签1", "标签2", ...],
  "use_case": "使用场景描述",
  "target_user": "目标用户群体",
  "style_attributes": ["风格1", "风格2", ...],
  "price_segment": "高端/中端/性价比",
  "related_brands": ["相关品牌"]
}}
"""
    response = openai.chat.completions.create(
        model="gpt-4o-mini",  # 用轻量模型降成本,单次约 0.01 元
        messages=[{"role": "user", "content": prompt}],
        response_format={"type": "json_object"}
    )
    return response.choices[0].message.content

# 实际落地时,离线 batch 处理所有商品,结果存入 Redis/向量库
# 在线推理时直接查,不走 LLM

关键点:LLM 提取的特征不是在线推理时实时生成,而是离线 batch 处理,作为训练阶段的补充特征。在线阶段直接查缓存,这样延迟和成本都可控。

真实落地数据

某电商公司(日活 5000 万)在 2024 年 Q4 做了这个方案:

指标改动前改动后变化
商品池大小2 亿2 亿-
离线 batch 耗时N/A48 小时(300 台 A100)每两周一次
存储成本N/A额外 200GB Redis可接受
召回阶段 CTR3.2%3.8%+18.75%
冷启动商品曝光0.5 次/天2.3 次/天+360%
长尾商品转化率0.8%1.5%+87.5%

踩坑记录

坑 1:LLM 对中文商品名理解有偏差。某次上线后,发现"儿童安全座椅"被 LLM 打上了"家居用品"标签,导致在母婴频道不显示。原因:LLM 的预训练数据中"座椅"和"家居"关联太强。解法:在 prompt 里加硬约束 "category_tags" 必须从预定义类目树中选择,不能自己编

坑 2:LLM 输出的标签不稳定。同一个商品,同一批数据,跑两次 batch 出来的标签可能不一样(temperature=0 也不完全确定)。解法:每次跑两轮取交集,再人工抽检 1% 的样本覆盖。

第二层:排序模型蒸馏——用大模型"教"小模型

排序阶段是推荐系统的核心环节。粗排从几千个候选集里筛选出几百个,精排再从几百个里选出 Top-K 展示给用户。精排模型要求毫秒级响应高精度,传统 DeepFM 或 DCN 模型虽然快,但受限于特征维度,精度上限有限。

原理:Teacher-Student 蒸馏

                ┌─────────────────────┐
                │  Teacher (LLM)      │
                │  用全部特征打分      │
                │  延迟 200-500ms      │
                └──────┬──────────────┘
                       │  soft labels

     ┌──────────────────────────────────┐
     │  Distillation Loss              │
     │  α * KL(teacher || student) +   │
     │  (1-α) * CE(student, label)     │
     └──────────────────────────────────┘


                ┌─────────────────────┐
                │  Student (DeepFM)   │
                │  只用 ID 特征打分    │
                │  延迟 < 5ms          │
                └─────────────────────┘


                ┌─────────────────────┐
                │  线上部署 (毫秒级)   │
                └─────────────────────┘

蒸馏的思路:把 LLM 作为 teacher 模型,对候选集打分,然后用打分结果训练 student 模型(轻量级的精排模型)。student 模型学到的是 LLM 的排序偏好,而不是直接复制 LLM 的输出。

python
# 排序模型蒸馏的伪代码
import numpy as np
from sklearn.metrics import ndcg_score

def distill_ranking_model(teacher_model, student_model, candidates, k=20):
    """
    teacher: LLM 打分
    student: 轻量排序模型
    candidates: 候选商品列表
    """
    # 1. teacher 打分(离线 batch 执行)
    teacher_scores = []
    for batch in chunk(candidates, size=32):
        scores = teacher_model.score(batch)  # 调用 LLM 打分
        teacher_scores.extend(scores)
    
    # 2. 计算 teacher 的排序列表(作为 ground truth)
    ranked_indices = np.argsort(teacher_scores)[::-1]
    ideal_ranking = candidates[ranked_indices]
    
    # 3. 训练 student 模型,损失函数 = NDCG loss + 交叉熵
    #    student 模型的输入是传统特征(ID、类目、价格等)
    #    输出是对每个候选的预测分数
    def distillation_loss(student_logits, teacher_logits, labels):
        # KL 散度:让 student 的分数分布接近 teacher
        kl_loss = kl_divergence(
            softmax(student_logits / temperature),
            softmax(teacher_logits / temperature)
        )
        # 交叉熵:保留原始 label 信号
        ce_loss = cross_entropy(student_logits, labels)
        return alpha * kl_loss + (1 - alpha) * ce_loss
    
    # 4. 训练完成后,student 模型部署到线上
    #    teacher 模型只在离线蒸馏阶段使用
    student_model.train(distillation_loss)
    return student_model

实际效果与踩坑

真实数据:某短视频推荐团队(2024 年 Q3)用 GPT-4 做 teacher,蒸馏出 3 层 MLP 的 student 模型:

指标基线 (DeepFM)蒸馏后提升
精排 AUC0.7420.773+4.2%
线上 CTR4.1%4.5%+9.8%
单次推理延迟2ms2ms持平
模型大小50MB50MB持平

坑 3:Teacher 模型必须先做 Calibration。直接拿 LLM 的 logits 做 distillation label,如果 LLM 对正样本的打分普遍偏高(比如所有商品都打 0.8-0.9),student 学到的只是"都差不多",等于没学。解法:对 teacher 的分数做 temperature scaling——在 validation set 上调整 temperature 参数,使 teacher 的 ECE(Expected Calibration Error)降到 0.05 以下。

坑 4:蒸馏样本的构造。如果只拿 LLM 对候选集的打分做训练,等于让 student 学的是"LLM 认为哪些商品好",而不是"用户实际会点哪些"。解法:蒸馏损失函数里一定要保留交叉熵项(CE loss),让 student 也看到真实的用户点击信号。

第三层:生成式推荐(GenRec)——让 LLM 直接给推荐

GenRec 是 2025-2026 年最激进的方向:直接让 LLM 输出推荐结果,不走传统推荐链路。用户的行为序列作为 prompt 输入,LLM 输出推荐商品列表和理由。

架构对比

传统推荐流水线:
用户 → 召回(几万→几千) → 粗排(几千→几百) → 精排(几百→几十) → 重排 → 展示


                                                LLM 做特征增强或蒸馏

GenRec 流水线:
用户 → LLM 直接输出 Top-K 推荐
       (一次推理,同时做了召回+排序)
python
# 生成式推荐的简单实现
def genrec_recommend(user_profile, recent_actions, candidate_items):
    prompt = f"""你是一个电商推荐助手。根据用户信息和最近行为,推荐 5 个商品。

用户画像:{user_profile}
最近 30 天行为(点击/购买/收藏):
{recent_actions}

候选商品列表(含标题和类目):
{candidate_items}

请按以下格式输出推荐结果:
1. [商品 ID] - 商品标题 - 推荐理由
2. ...(共 5 个)

注意:
- 推荐理由必须基于用户行为,不能虚构
- 优先推荐用户未点击过但相关度高的商品
- 包含 1-2 个长尾商品,避免全是热门商品
"""
    response = openai.chat.completions.create(
        model="gpt-4o",
        messages=[{"role": "user", "content": prompt}],
        temperature=0.3
    )
    return parse_recommendations(response.choices[0].message.content)

优劣势对比

维度传统推荐GenRec说明
冷启动❌ 需要大量行为数据✅ 从描述就能推新用户 1 条行为都没有也能推
长尾覆盖❌ 头部集中✅ 语义匹配小众商品只要有描述就能被推
可解释性❌ 黑盒✅ 每次都有理由但理由可能幻觉
延迟2-5ms200-500ms差两个数量级
单次成本¥0.00001¥0.01-0.05差 1000-5000 倍
一致性✅ 确定❌ 非确定性同样的输入可能不同输出
吞吐量10 万 QPS/台50 QPS/台完全不在一个量级

踩坑记录

坑 5:GenRec 的幻觉推荐。某次测试中,LLM 给用户推荐了"iPhone 17 保护壳",但 iPhone 17 还没发布。用户看到后投诉"虚假推荐"。原因:LLM 的知识截止日期是 2024 年,它会"编造"不存在的商品。解法:候选集必须用 candidate_items 参数硬约束,LLM 只能从候选列表里选,不能自己编。

坑 6:GenRec 的推荐结果不稳定。XA 用户今天搜了"机械键盘",GenRec 推荐了 3 个键盘;明天同样的行为,GenRec 推荐了 2 个键盘 + 1 个鼠标垫。原因:temperature=0 对 LLM 也不是严格确定。解法:对同一个用户,缓存 GenRec 的结果 24 小时,不重复生成。

大厂落地策略

2025-2026 年大厂的主流做法是:GenRec 不做主链路,只做兜底和增强。传统推荐链路正常跑,当遇到冷启动用户或长尾请求时,fallback 到 GenRec。

用户请求 → 传统推荐链路是否命中?
    ├── 是 → 用传统推荐结果(正常返回)
    └── 否 → 触发 GenRec 兜底
              ├── 冷启动用户(行为 < 10 条)
              └── 长尾商品覆盖(候选集里头部商品占比 > 80%)

第三层补充:多模态推荐与时序感知

多模态推荐

LLM 不仅看文本,还能看图片。服装推荐时,LLM 可以同时理解商品图片的风格和用户历史购买的款式。

python
# 多模态特征提取
def multimodal_item_features(image_url, title, desc):
    prompt = f"""分析这张商品图片和文本信息,提取风格特征。
图片:{image_url}
标题:{title}
描述:{desc}

请输出:
1. 风格标签(如:简约/复古/运动/商务)
2. 颜色方案(如:暖色调/冷色调/黑白灰)
3. 适用场景(如:通勤/约会/运动)
4. 与以下用户历史购买风格的相似度计算逻辑
"""
    response = openai.chat.completions.create(
        model="gpt-4o",  # 多模态模型
        messages=[{"role": "user", "content": prompt}],
    )
    return response.choices[0].message.content

时序感知

用户兴趣随时间变化,LLM 需要理解行为序列的时间权重。最近 3 天的行为比 30 天前的重要得多。

python
# 时序加权的行为序列
def build_time_weighted_sequence(actions, decay_factor=0.9):
    """
    actions: [(timestamp, item_id, action_type), ...]
    decay_factor: 每天衰减 0.9
    """
    today = datetime.now()
    weighted = []
    for ts, item_id, action_type in actions:
        days_ago = (today - ts).days
        weight = decay_factor ** days_ago
        weighted.append((item_id, action_type, weight))
    
    # 按权重降序,取前 50 条
    weighted.sort(key=lambda x: x[2], reverse=True)
    return weighted[:50]

面试高频问题

Q1:LLM 做推荐的成本怎么控制?

:分三层控制。第一层,离线 batch 做特征工程,用 GPT-4o-mini 级别模型,单次 0.01 元,两亿商品全量跑一次约 20 万,但每两周跑一次就够了。第二层,蒸馏只做一次,teacher 打分成本是一次性的。第三层,GenRec 只在冷启动用户上触发,覆盖率控制在 5% 以内,月均成本可控在 3 万以内。

Q2:GenRec 和传统推荐怎么选?

:不要二选一。最务实的路径是:先做特征工程增强(离线 batch,ROI 最高),再考虑蒸馏,最后才上 GenRec。不要一上来就搞 GenRec,成本会让你怀疑人生。面试官问这个,重点听你讲 ROI 权衡和落地路径,不是听你吹 GenRec 多牛。

Q3:推荐系统的可解释性怎么落地?

:LLM 生成的推荐理由不能有幻觉。需要做 Factuality Check——推荐理由中提到的商品属性必须与被推荐商品的实际属性一致。具体做法:生成推荐理由后,用另一个 LLM 做评判,检查理由中的每个断言是否能在商品属性中找到依据。如果发现幻觉,回退到简单的"为您推荐"模板。

总结:P7+/P8 该掌握的核心认知

  1. LLM 不自作推荐,而是作为特征增强模块嵌入传统推荐流水线,这是 ROI 最高的路径。2025 年趋势明确:全量 GenRec 的时机还没到。
  2. 蒸馏的关键在 teacher 的 Calibration,不在 student 的架构。花 80% 的精力把 teacher 的分数校准好,student 自然学得更好。
  3. 冷启动的终极解法不是 GenRec,而是多模态语义特征 + 跨域迁移。GenRec 只是兜底方案。
  4. 面试时不要只讲概念:能画出三层架构的时序图、能说出具体的成本数据和 CTR 提升幅度、能讲出真实踩过的坑,比背论文标题有用得多。

参考论文:P5(Google, 2022)、RecLLM(Google, 2023)、M6-Rec(阿里, 2023)、LLM for RecSys 综述(2024, ACM Computing Surveys)

手撕 → 框架 → 生产化,一步步把 AI Agent 工程化搞透。