系列 · 推荐系统 · 第 12 篇

推荐系统(十二)—— 大语言模型与推荐系统

LLM 如何重塑推荐系统:增强器(P5、M6Rec)、预测器(TallRec、GenRec)、智能体(LlamaRec、ChatREC)三种角色,混合管线、冷启动突破、Prompt 设计与成本/质量帕累托前沿。

用户打开电影 App,输入:“想看类似《盗梦空间》的,但别太压抑。”传统推荐系统——无论是协同过滤、双塔 DNN,还是 DIN——在这句话里都找不到任何可用信号。它没有点赞数据可统计,没有共看关系图可遍历,也没有绑定用户 ID 的历史行为。系统必须先把这句话转换成 ID,才能继续处理。

大语言模型则面临相反的问题:它拥有太多世界知识,却不知道当前用户是谁。它清楚《盗梦空间》是诺兰执导的非线性叙事电影,结尾充满希望却又模棱两可;它理解“压抑”在电影语境中的含义;它能轻松列出二十部符合描述的影片。但它无法判断这二十部中,哪些是当前用户已经看过、打过低分,或中途弃剧的。

2023 到 2026 年,推荐系统领域真正值得思考的问题并非“用 LLM 还是传统模型”,而是如何将二者有效组合。本文将深入剖析三种已在工业界大规模落地的组合模式,并附上代码与真实权衡。

推荐系统(十二)—— 大语言模型与推荐系统 — 章节概览图


你将学到什么#

  • LLM 在推荐系统中的三种角色:增强器、预测器、智能体——以及哪些论文对应哪种角色
  • 排序任务的 Prompt 设计要点(TallRec / P5 风格),为什么温度值要控制在 0.3 以下
  • LLM 增强的物品描述如何让 embedding 聚类更紧密,有效缓解冷启动问题
  • 所有生产团队最终都会采用的混合流水线:ANN → DNN 排序 → LLM 重排
  • ChatREC 风格的对话式推荐:多轮状态维护与工具调用
  • 成本与质量的帕累托前沿:微调 7B 模型何时胜过 GPT-4,最佳平衡点在哪里
  • 实战级 Python 示例:基于 Prompt 的排序、混合重排、对话状态管理

前置知识#

  • 熟悉 Embedding、排序,以及召回/排序的两阶段架构(第 1 篇第 4 篇
  • 会使用任一 LLM SDK(OpenAI、Anthropic、vLLM)即可,无需掌握微调
  • 可选的编码器示例需要基础 PyTorch 知识

LLM 在推荐系统中的三种角色#

LLM 在推荐中的三种角色:增强器、预测器、智能体

相关文献看似纷繁复杂——P5、M6-Rec、KAR、TallRec、BIGRec、GenRec、LlamaRec、ChatREC——但实际上每项工作都严格对应以下三种角色之一。角色决定了延迟、成本、训练开销,以及 LLM 在系统中的具体职责。

角色一:增强器(离线特征生成)#

LLM 完全不参与在线请求。它在离线阶段读取每个物品的标题、描述和评论,生成更丰富的特征:结构化属性、稠密语义向量、扩写后的描述,或伪标签。这些特征随后被送入一个完全传统的 CTR 或协同过滤(CF)系统。

这是最早一批严肃探索“LLM + 推荐”的论文所采用的思路:P5(Geng et al., RecSys 2022)将五种推荐任务统一到一个文本到文本的 T5 框架下;M6-Rec(Cui et al., 2022)利用阿里 M6 生成物品描述和行为提示;KAR(Xi et al., 2024)则将 LLM 的推理过程蒸馏为可复用的特征向量。由于 LLM 的计算成本被均摊到数百万次请求上,在线服务延迟可稳定控制在 50ms 以内。

适用场景:你已有成熟的排序模型,但冷启动物品、稀疏文本或难以打标的类别正在拖累召回效果。

角色二:预测器(直接排序或生成)#

LLM 本身就是排序器。你将用户历史和候选列表(甚至不提供候选)交给它,它会输出 yes/no 判断、打分,或直接生成下一个物品。

分为两类:判别式(TallRec、BIGRec——在 (历史, 物品) → yes/no 数据上用 LoRA 微调 Llama-2-7B)和生成式(GenRec——直接生成下一部影片的标题)。TallRec(Bao et al., RecSys 2023)展示了仅用几百条训练样本,LoRA 微调的 7B 模型就能击败更大的零样本 LLM,并追平强大的序列推荐基线。LlamaRec(Yue et al., 2023)进一步引入 verbalizer 头,使 LLM 能在一次前向传播中对整个候选集排序,而非发起 K 次独立调用。

适用场景:物品具备丰富文本内容、数据规模较小(如冷启动领域或新业务线),或需要排序结果自带解释。

角色三:智能体(带工具的编排者)#

LLM 不仅排序,还负责规划。它维护对话状态,决定何时调用检索、何时追问澄清、何时按年份或价格过滤,以及何时将任务交还给下游模型。ChatREC(Gao et al., 2023)是这一范式的典型代表;RecAgent(Wang et al., 2023)和 InteRecAgent 更进一步,引入模拟用户进行评估。

适用场景:你正在构建对话式界面(聊天机器人、语音助手、支持追问的搜索),或用户确实无法在一句话内表达清楚需求。

成本排序大致为:增强器 ≪ 预测器 ≪ 智能体,灵活性排序亦然。大多数生产系统从增强器起步,随后将预测器作为重排层引入,仅在特定产品形态中采用智能体。


基于 Prompt 的排序#

LLM-as-recommender 的 Prompt 模板解剖图

基于 Prompt 的推荐是入门首选:无需训练,只需一个 API Key 和精心设计的 Prompt。有效的 Prompt 通常包含五个部分,且顺序至关重要。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
def build_recommendation_prompt(history, target, examples=None):
    """TallRec / P5 风格的排序 Prompt。"""
    # 1. 角色 + 任务:限定 LLM 的行为范围
    role = (
        "You are a movie recommender. Given the user's viewing history, "
        "predict whether they will like the target movie."
    )

    # 2. 用户历史:按时间顺序排列,带喜好信号
    hist_lines = "\n".join(
        f"  - {item['title']} ({'liked' if item['liked'] else 'disliked'})"
        for item in history[-20:]   # 截断以适应上下文长度
    )

    # 3. 目标物品:附带属性信息
    target_line = (
        f'Target movie: "{target["title"]}" '
        f'({target["genre"]}, {target["year"]}, dir. {target["director"]})'
    )

    # 4. 输出格式:强约束,尽量单 token 输出
    output_spec = 'Answer with exactly one token: "Yes" or "No".'

    # 5. Few-shot 示例:可选,但能显著提升精度
    fewshot = ""
    if examples:
        fewshot = "\n".join(
            f"[Example {i+1}]\nHistory: {ex['history']}\n"
            f"Target: {ex['target']}\nAnswer: {ex['answer']}\n"
            for i, ex in enumerate(examples)
        )

    return f"""{role}

{fewshot}
History:
{hist_lines}

{target_line}

{output_spec}"""

有三条看似简单却极易被忽视的工程规则:

  1. 逐 token 约束输出。单个 YesNo 可被程序解析;而“我觉得用户可能会喜欢,因为……”这类自由文本则不可用。对 K 个物品排序时,应要求模型输出 [3, 1, 5, 2, 4] 这样的索引序列,而非自由文本。若 SDK 支持,应使用 logit bias 或语法约束解码。
  2. 温度值 ≤ 0.3。推荐不是创意写作,高温度会导致相同输入产生不同排序,调试难度陡增。
  3. 截断历史记录。LLM 在处理超过约 50 条历史时性能下降,且成本随 prompt token 数线性增长。应优先保留最新记录,必要时对旧记录进行摘要压缩。

零样本 vs 少样本 vs 微调#

方案启动成本单次调用成本冷启动精度热启动精度
零样本(GPT-4o)数小时高($0.01+/次)一般
少样本(3–5 例)数小时更高(更多 token)较好
微调(TallRec,7B+LoRA)数天 + GPU低($0.0005/次)

TallRec 的结果令人印象深刻:仅用 256 条微调样本,LoRA 微调的 Llama-7B 就能在推荐任务上追平甚至超越零样本 GPT-4,而单次调用成本仅为后者的零头。只要你有少量带标签的交互数据,微调就是更优选择。


LLM 作为增强器:更精准的 Embedding,更优的冷启动#

LLM 描述增强前后的 embedding 聚类对比

将 LLM 引入生产环境最经济、风险最低的方式是:离线使用它将简短的物品文本扩展为丰富描述,再用现有句向量编码器重新生成嵌入。

电影标题 "Tenet" 对句向量编码器几乎毫无信息量。若让 GPT-4 将其扩写为:

“2020 年由克里斯托弗·诺兰执导的科幻动作惊悚片。以熵的逆转为核心剧情装置,探讨自由意志与宿命论的主题。基调冷峻且氛围感强,包含精心设计的实拍动作场面。适合喜欢《盗梦空间》《星际穿越》或其他烧脑叙事影片的观众。节奏紧凑,情感核心围绕友谊与牺牲。”

——生成的嵌入会显著靠近其真实的语义邻居。在 MovieLens 类型数据上的离线测试中,按类型聚类的轮廓系数通常从 ~0.2(原始标题)提升至 ~0.65(LLM 增强后),P5 和 KAR 的论文也报告了类似效果。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from openai import OpenAI

client = OpenAI()

def enhance_item(item):
    """离线:将稀疏的物品文本扩展为丰富的语义描述。"""
    prompt = f"""Write an 80-word description of this item for a
recommendation system. Cover: themes, tone, mood, target audience,
similar items, what kind of user would love it.

Title: {item['title']}
Existing tags: {', '.join(item.get('tags', []))}
Year: {item.get('year', 'unknown')}

Description:"""
    return client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "user", "content": prompt}],
        temperature=0.4,
        max_tokens=200,
    ).choices[0].message.content

def build_enhanced_index(items, encoder):
    """每个物品处理一次;缓存永久有效(直到物品变更)。"""
    enhanced_texts = [enhance_item(it) for it in items]
    return encoder.encode(enhanced_texts, batch_size=64)

这种方案之所以经济,是因为增强过程是离线且一次性完成的。一个百万级物品目录,按 $0.0002/次计算,总成本仅 $ 200,且只需支付一次。相比之下,若每次在线请求都调用 LLM,同样成本下每百万次查询需 $200,且持续累积

离线约束的局限性#

LLM 增强只能生成稳定的物品侧特征,无法做到以下几点:

  • 响应新物品上线后第一小时的实时交互
  • 捕捉用户专属信号(如个人口味、当前情绪、本次会话意图)
  • 反映突发趋势(如“因某事件,大家都在突然观看 X”)

这些场景需要在线 LLM 调用——或更现实地说,需要混合流水线来解决。


混合流水线(实际落地的架构)#

推荐系统(十二)—— 大语言模型与推荐系统 — 章节小结图

混合管线:ANN 检索 + DNN 排序 + LLM 重排

所有成功将 LLM 推向生产的团队,最终都收敛到同一架构:

  1. 物品池(10⁶–10⁸ 项)
  2. ANN 检索(Faiss/HNSW)——耗时 ~10ms,成本 ~$0,筛选出约 1,000 个候选3. **CF 或深度排序器**(DIN、DCN-V2、双塔)——耗时 ~30ms,成本 ~$ 0,筛选至约 50 个
  3. LLM 重排(GPT-4o 或微调 7B)——耗时 ~1–2s,成本 ~$0.005–0.01,选出 Top 10
  4. 用户看到 Top 10 及 LLM 生成的解释

漏斗比例至关重要:在昂贵的 LLM 调用前,已完成了 5–7 个数量级的剪枝。LLM 仅需处理约 50 个物品,而非百万级目录。正是这一架构选择,使 LLM 推荐变得可行。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class HybridRecommender:
    """ANN -> DNN -> LLM。所有团队最终都会采用的架构。"""

    def __init__(self, ann_index, dnn_ranker, llm_reranker):
        self.ann = ann_index            # Faiss / HNSW
        self.ranker = dnn_ranker        # DIN / DCN-V2 / 双塔
        self.llm = llm_reranker         # GPT-4o 或微调 7B

    def recommend(self, user_id, query_embedding, k=10):
        # 第一阶段:ANN —— 百万级别缩小到约 1000,耗时约 10ms
        cand_ids = self.ann.search(query_embedding, top_k=1000)

        # 第二阶段:DNN 排序 —— 从 1000 缩小到约 50,耗时约 30ms
        scored = self.ranker.score_batch(user_id, cand_ids)
        top50 = sorted(scored, key=lambda x: -x['score'])[:50]

        # 第三阶段:LLM 重排 —— 从 50 中选出 Top-10,耗时约 1.5s
        # 关键点:prompt 能装下,成本可控
        return self.llm.rerank(user_id, top50, k=k)

中间的 DNN 排序阶段常被初学者低估。你不能直接从 ANN 跳到 LLM 重排:ANN 输出的 1,000 个候选仍含大量噪声(热门但不相关的物品占主导),将其全部塞入 prompt 要么超出上下文窗口,要么淹没有效信号。DNN 提供的是一个干净的 Top-50,并包含 LLM 所不具备的已学习交互模式


冷启动:LLM 真正的优势场景#

冷启动:随用户交互数变化,LLM 零样本 vs CF

若绘制精度随用户历史长度变化的曲线,“LLM 还是 CF”这个问题便有了清晰答案:

  • 0–5 次交互(冷启动):LLM 零样本胜出 4–7 倍。CF 几乎无数据可用,LLM 的世界知识成为唯一信号。
  • 10–50 次交互(升温期):差距迅速缩小。CF 开始捕捉到真实的协同信号。
  • 100+ 次交互(热用户):CF 在纯排序精度上反超。此时 LLM 的世界知识反而成为噪声,用户的真实偏好才是关键。

由此得出明确策略:按用户状态分流

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
def route_recommend(user_id, query, cf_model, llm_model):
    """根据用户的数据密度选择合适的模型。"""
    n_interactions = cf_model.interaction_count(user_id)

    if n_interactions < 5:
        # 冷启动:LLM 直接利用 query 调用世界知识
        return llm_model.recommend(query)
    elif n_interactions < 50:
        # 升温阶段:混合策略
        cf_recs = cf_model.recommend(user_id, k=50)
        return llm_model.rerank(query, cf_recs, k=10)
    else:
        # 热用户:CF 表现更优,LLM 仅用于生成解释
        return cf_model.recommend(user_id, k=10)

这也解释了为何“我们试过 LLM,但效果不如 DCN”是常见误判:团队几乎总是在热用户上测试,而在此场景下 CF 本就占据绝对优势。


对话式推荐:ChatREC 风格#

对话式推荐流程:对话状态与工具调用

对话式推荐系统本质不同:它是一个规划器,而非一次性排序器。LLM 维护对话状态,决定何时检索、何时澄清、何时推荐。而推荐本身通常仍交由检索 + DNN 排序的组合完成。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class ChatREC:
    """LLM 是规划器;检索和排序是它调用的工具。"""

    def __init__(self, llm, retriever, ranker):
        self.llm = llm
        self.retriever = retriever      # ANN 检索
        self.ranker = ranker            # DNN
        self.state = {
            "history": [],              # 消息记录
            "preferences": {},          # 用户偏好积累
            "candidates": [],           # 当前候选列表
        }

    def turn(self, user_message):
        self.state["history"].append({"role": "user", "content": user_message})

        # LLM 决定下一步动作:澄清、检索、推荐还是解释
        plan = self.llm.plan(
            history=self.state["history"],
            current_prefs=self.state["preferences"],
            current_candidates=self.state["candidates"],
        )

        if plan.action == "extract_preference":
            self.state["preferences"].update(plan.extracted_prefs)
            return self.llm.acknowledge(plan.extracted_prefs)

        if plan.action == "retrieve":
            query = self.llm.build_query(self.state["preferences"])
            cand = self.retriever.search(query, top_k=200)
            self.state["candidates"] = self.ranker.rank(cand, top_k=20)
            return self.llm.present(self.state["candidates"][:5])

        if plan.action == "filter":
            self.state["candidates"] = [
                c for c in self.state["candidates"]
                if plan.filter_fn(c)
            ]
            return self.llm.present(self.state["candidates"][:5])

        if plan.action == "explain":
            return self.llm.explain(plan.target_item, self.state["preferences"])

        return self.llm.respond(self.state["history"])  # 默认兜底逻辑

真正的难点不在代码本身,而在两处:一是规划器 Prompt 的设计(暴露哪些动作、如何防止 LLM 推荐 candidates 之外的物品),二是状态管理(用户改变主意时何时丢弃旧偏好、过滤后何时刷新候选)。这些细节决定了系统能否真正落地。


成本与质量的帕累托前沿#

LLM 推荐方法在成本/质量平面上的帕累托前沿

将所有已发表方法映射到(每千次请求成本,相对 CF 基线的 NDCG 提升)坐标系,可得出三点结论:

  1. **每千请求成本超过 $1 后,收益急剧递减**。从微调 7B(~$ 0.4)升级到 GPT-4 生成式(~$25),NDCG 仅提升 ~2.4 点;而从 CF 基线升级到微调 7B,NDCG 可提升 ~8.6 点,延迟成本却不到 100 倍。
  2. 微调 7B 是生产环境的甜点。TallRec / LlamaRec 的精度接近 GPT-4,但单次调用成本仅为后者的 ~1%。若能一次性投入 4×A100 小时完成 LoRA 训练,全年推理成本均可节省。
  3. 对话式智能体是另一种产品,而非曲线上的一个点。其高成本源于多轮交互——相同推荐结果需支付 5–10 倍请求量。应为其买单的理由是对话体验本身,而非排序指标提升。

实用成本优化手段#

手段典型节省注意事项
缓存相同 prompt30–60%仅当查询重复时有效
历史截断至 20 条20–40%可能丢失长尾偏好
重排 Top-20 而非 Top-5050%精度小幅下降(~1 NDCG 点)
微调 7B 替代 GPT-490%+需标注数据与 GPU 时间
热用户直连 CF40–80%取决于用户构成

最大的优化杠杆无疑是按用户状态分流(见上一节)。典型平台上 70% 以上请求来自热用户,而 CF 在这些场景下表现更优;将其从 LLM 路径分流,等于免费节省大量成本。


评测:到底要测什么#

标准排序指标(NDCG@K、Recall@K、MRR)依然适用,但 LLM 系统还需额外维度:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import numpy as np

def evaluate_llm_recommender(predictions, ground_truth, llm_calls, latencies):
    """标准指标 + LLM 专属的运营指标。"""
    # --- 质量 ---
    k = 10
    hits = [set(p[:k]) & set(gt) for p, gt in zip(predictions, ground_truth)]
    precision = np.mean([len(h) / k for h in hits])
    recall = np.mean([len(h) / max(len(gt), 1) for h, gt in zip(hits, ground_truth)])

    def ndcg(pred, gt, k=10):
        gt_set = set(gt)
        dcg = sum(1 / np.log2(i + 2) for i, p in enumerate(pred[:k]) if p in gt_set)
        idcg = sum(1 / np.log2(i + 2) for i in range(min(k, len(gt_set))))
        return dcg / idcg if idcg > 0 else 0.0

    ndcg_score = np.mean([ndcg(p, gt) for p, gt in zip(predictions, ground_truth)])

    # --- 运营 ---
    p50_latency = float(np.percentile(latencies, 50))
    p99_latency = float(np.percentile(latencies, 99))
    cost_per_request = float(np.mean(llm_calls)) * 0.005   # 单次调用成本粗略估算

    return {
        "precision@10": precision,
        "recall@10": recall,
        "ndcg@10": ndcg_score,
        "p50_latency_s": p50_latency,
        "p99_latency_s": p99_latency,
        "cost_per_request_usd": cost_per_request,
    }

运营指标的重要性常被低估。一个 NDCG 提升 2 点但 p50 延迟增加 1.5 秒的模型,对多数 C 端产品而言得不偿失——用户流失速度远快于排序质量带来的收益。

对话式系统还需追踪:

  • 达成满意的轮数:用户接受推荐前需多少轮交互
  • 每会话推荐多样性:是否反复推荐相同几个物品
  • 幻觉率:LLM 推荐不在候选集中的物品频率

常见问题#

我到底什么时候该用 LLM?#

满足以下任一条件即可考虑:(a) 物品有丰富文本内容,(b) 冷启动问题严重,(c) 需向用户提供解释,(d) 正在构建对话式界面。若均不满足,调优后的 DCN-V2 或 DIN 将以更低的成本胜过任何 LLM。

用 GPT-4 还是微调 7B?#

几乎总是选择微调。TallRecLlamaRec 表明,LoRA 微调的 7B 模型在推荐任务上可追平甚至超越 GPT-4 零样本,推理成本仅为其 ~1%。继续使用 GPT-4 的唯一理由是:完全没有训练数据,或领域变化快到无法及时重训。

如何避免幻觉物品?#

双重防护:(1) 限制 LLM 输出为候选集索引(如 [3, 1, 5, 2, 4],而非标题);(2) 返回前严格校验输出是否在候选列表中。若 LLM 输出未知索引,回退至 DNN 排序结果。

传给 LLM 的候选集应多大?#

经验值为 20–50。低于 20,LLM 无法有效重排;高于 50,prompt 过长导致延迟高、成本高,且模型易忽略中间物品(“lost in the middle”效应)。

推荐需要 RAG 吗?#

视情况而定。当 LLM 需要 prompt 之外的事实性信息(如发售日期、规格、库存)时,RAG 有用。若仅对已知目录排序,将目录放入 prompt 本身即构成检索,无需额外向量库。

实时 feed 场景延迟如何解决?#

TikTok 式无限流或新闻 feed 通常无法承受每次曝光同步调用 LLM。可行方案包括:(a) 低峰期预计算 LLM 重排结果并缓存,(b) 仅首页用 LLM,后续页用 DNN,(c) 将 LLM 放入离线批处理路径,用于生成次日推荐。

多语言目录如何处理?#

LLM 天然支持多语言——内置翻译与跨语言推理能力。但若仅用英文交互数据微调,多语言能力会退化。解决方案:微调数据中保留非英文样本,或直接微调多语言基座模型(如 Qwen、Llama-3 多语言版、mT5)。


参考文献#

  1. Geng, S., Liu, S., Fu, Z., Ge, Y., & Zhang, Y. (2022). Recommendation as Language Processing (RLP): A Unified Pretrain, Personalized Prompt & Predict Paradigm (P5) . RecSys 2022.
  2. Cui, Z., Ma, J., Zhou, C., Zhou, J., & Yang, H. (2022). M6-Rec: Generative Pretrained Language Models are Open-Ended Recommender Systems . arXiv:2205.08084 .
  3. Bao, K., Zhang, J., Zhang, Y., Wang, W., Feng, F., & He, X. (2023). TallRec: An Effective and Efficient Tuning Framework to Align Large Language Model with Recommendation . RecSys 2023.
  4. Ji, J., Li, Z., Xu, S., Hua, W., Ge, Y., Tan, J., & Zhang, Y. (2024). GenRec: Large Language Model for Generative Recommendation . ECIR 2024.
  5. Yue, Z., Rabhi, S., Moreira, G. de S. P., Wang, D., & Oldridge, E. (2023). LlamaRec: Two-Stage Recommendation using Large Language Models for Ranking . arXiv:2311.02089 .
  6. Gao, Y., Sheng, T., Xiang, Y., Xiong, Y., Wang, H., & Zhang, J. (2023). Chat-REC: Towards Interactive and Explainable LLMs-Augmented Recommender System . arXiv:2303.14524 .
  7. Xi, Y., Liu, W., Lin, J., Zhu, J., Chen, B., Tang, R., Zhang, W., Zhang, R., & Yu, Y. (2024). Towards Open-World Recommendation with Knowledge Augmentation from Large Language Models (KAR) . RecSys 2024.
  8. Liu, N. F., Lin, K., Hewitt, J., Paranjape, A., Bevilacqua, M., Petroni, F., & Liang, P. (2024). Lost in the Middle: How Language Models Use Long Contexts . TACL.

10K QPS 推理:LLM-as-ranker 梦碎之处#

LLM4Rec 的论文往往回避延迟现实。而典型生产排序系统需满足:

  • 峰值 QPS 达 10K–100K
  • 端到端 p99 延迟 < 200 ms(含召回、排序、业务规则)
  • 每请求排序 50–500 个候选

这些数字直接否定了 LLM 直接排序的可行性。

直接 LLM 排序不可行。单次 GPT-4o-mini 调用对 50 个物品排序,p50 延迟约 800 ms,p99 高达 2.5 秒。10K QPS 下需 25,000 并发调用,按 $0.0007/次计,每秒 $ 7,每日 $60 万——完全不可接受。

蒸馏小型 LLM 排序勉强可行。3B 参数模型经 4-bit 量化后,在 A10 上对 50 物品排序 p50 约 80 ms。10K QPS 需约 150 张 GPU(假设 100 QPS/GPU)。云成本约 $1.5K/天,包年实例 $ 5 万/月。适用于头部场景,长尾流量仍难承受。

LLM 作为特征提供方才是生产答案。LLM 离线运行,将其输出(物品摘要、语义标签、embedding 增量)存入特征库。在线排序由轻量 DCN/DIN 模型在 5–10 ms 内消费这些特征。所有号称“LLM4Rec”的生产系统实际都采用此方式——即便某些博客让人误以为 LLM 在线参与请求。

真实场景延迟分解如下:

组件延迟预算实现方式
召回30 ms对 1000 万物品 ANN 检索,返回 Top 1000
预排序20 ms小 MLP 从 1000 筛至 Top 200
排序60 msDIN 结合 LLM 衍生特征,选出 Top 50
重排 / 业务规则30 ms多样性、新鲜度、业务逻辑
网络 + 序列化60 ms缓冲余量
总计200 ms

LLM 的贡献在于“LLM 衍生物品特征”——提前计算,线上从特征库获取,耗时 <2 ms。

为何生产团队用 LLM 增强特征替代 Prompt 排序#

我在多家公司观察到相似的两年演进路径:

阶段 1(2023 年中):用物品列表 Prompt LLM,碰运气。博客热议“GPT-4 能排序!”,Demo 中处理 10 个物品效果尚可,但规模一大即崩溃。

阶段 2(2023 年底–2024 年中):蒸馏后上线。以 GPT-4 输出为标签,训练 7B 模型模仿,延迟降低 5 倍,但长尾 QPS 仍昂贵,且质量比教师模型下降 ~3 NDCG 点。

阶段 3(2024 年底至今):LLM 成为离线特征工厂。LLM 不再触碰请求路径,而是专注:

  1. 生成物品摘要/抽取属性(每物品一次,永久缓存)
  2. 从搜索 query/浏览会话提取用户意图标签(每小时为活跃用户运行)
  3. 物品入库时检测内容质量/安全问题

线上模型仍是 DIN 或 DCNv2(5000 万参数经典排序器),但多了 30+ 个 LLM 衍生特征。此阶段效果:CTR 提升 1–3%,转化率提升 2–5%,且线上成本无增加。

教训明确:不要把 LLM 放进请求路径,而要把它的输出放进模型里。

总结#

LLM 并非要取代推荐系统,而是填补上一代技术无法解决的特定空白。三种角色恰好对应三大缺口:

  • 增强器解决内容理解缺口:离线运行,永久缓存,生成更干净的嵌入,强化冷启动能力。
  • 预测器解决冷启动与小数据缺口:微调 7B 模型,对传统流水线输出的 Top 20–50 进行重排。
  • 智能体解决交互缺口:仅用于真正需要对话的场景,并坦然接受其延迟成本。

所有生产团队最终采用的架构都是混合流水线:ANN 召回 → DNN 排序 → LLM 重排 →(可选)解释模块。其可行性在于 LLM 仅处理 Top ~50 候选,而非全量目录。成本可控,同时借助 LLM 获得语义提升。

建议从此架构入手。从第一天起就同时监控运营指标与排序指标。将热用户从 LLM 路径分流,以控制账单。一旦积累数百条标注数据,立即启动微调。


本系列

推荐系统 16 篇

  1. 01 推荐系统(一)—— 入门与基础概念
  2. 02 推荐系统(二)—— 协同过滤与矩阵分解
  3. 03 推荐系统(三)—— 深度学习基础模型
  4. 04 推荐系统(四)—— CTR 预估与点击率建模
  5. 05 推荐系统(五)—— Embedding 表示学习
  6. 06 推荐系统(六)—— 序列推荐与会话建模
  7. 07 推荐系统(七)—— 图神经网络与社交推荐
  8. 08 推荐系统(八)—— 知识图谱增强推荐系统
  9. 09 推荐系统(九)—— 多任务学习与多目标优化
  10. 10 推荐系统(十)—— 深度兴趣网络与注意力机制
  11. 11 推荐系统(十一)—— 对比学习与自监督学习
  12. 12 推荐系统(十二)—— 大语言模型与推荐系统 当前
  13. 13 推荐系统(十三)—— 公平性、去偏与可解释性
  14. 14 推荐系统(十四)—— 跨域推荐与冷启动解决方案
  15. 15 推荐系统(十五)—— 实时推荐与在线学习
  16. 16 推荐系统(十六)—— 工业级架构与最佳实践

读有所得?

GitHub 关注我 → 新文周更

GitHub