跳转至

LLM与推荐系统

⚠️ 时效性说明:本章涉及前沿模型/价格/榜单等信息,可能随版本快速变化;请以论文原文、官方发布页和 API 文档为准。

LLM与推荐系统

📖 章节导读

大语言模型(LLM)正在深刻重塑推荐系统的设计范式。从传统的ID-based协同过滤到LLM驱动的语义推荐,从手工特征工程到自然语言理解,LLM为推荐系统带来了前所未有的能力跃升。本章将系统梳理LLM在推荐系统中的角色、关键技术、工业实践与代码实战,帮助你掌握这一2024-2025年最热门的推荐系统前沿方向。

🎯 学习目标

  • 理解LLM如何变革推荐系统的核心范式
  • 掌握LLM在推荐中的四种角色(编码器、排序器、生成器、Agent)
  • 掌握推荐任务的Instruction Tuning、LoRA微调与Prompt设计
  • 了解工业界(阿里/字节/快手)LLM+推荐的落地实践
  • 能够动手实现基于LLM的推荐系统原型

16.1 LLM驱动的推荐范式

16.1.1 为什么LLM能变革推荐系统

传统推荐系统高度依赖用户-物品交互矩阵和ID Embedding,面临数据稀疏、冷启动、跨域迁移困难等核心挑战。LLM凭借在海量文本上预训练获得的世界知识,为推荐系统带来了四大能力跃升:

能力 传统推荐 LLM推荐
语义理解 依赖ID Embedding,无法理解物品语义 深度理解物品标题、描述、评论的语义
零样本泛化 新物品/用户无法推荐(冷启动) 基于语义描述即可推荐,无需历史交互
跨域迁移 不同域模型独立,无法迁移 通用语义空间,天然支持跨域推荐
可解释性 黑盒模型,难以解释 自然语言解释推荐理由

论文参考"A Survey on Large Language Models for Recommendation"(Wu et al., 2024, ACM Computing Surveys)系统综述了LLM在推荐中的最新进展。

16.1.2 LLM在推荐中的角色分类

根据LLM在推荐Pipeline中的位置和功能,可将其角色分为四类:

Text Only
┌─────────────────────────────────────────────────────────────┐
│                   LLM在推荐系统中的四种角色                    │
├───────────────┬──────────────┬──────────────┬───────────────┤
│  特征编码器    │   评分/排序器  │    生成器     │  推荐Agent     │
│  (Encoder)    │   (Scorer)   │  (Generator) │   (Agent)     │
├───────────────┼──────────────┼──────────────┼───────────────┤
│ LLM Embedding │ Prompt-based │  直接生成     │  工具调用      │
│ 替代ID Embed  │ 打分排序     │  推荐列表     │  多步推理      │
│ 文本特征增强   │ ICL推荐      │  对话推荐     │  自主决策      │
└───────────────┴──────────────┴──────────────┴───────────────┘

角色1:LLM作为特征编码器

利用LLM的强大表征能力,将物品的文本信息(标题、描述、属性)编码为高质量的语义向量,替代或增强传统的ID Embedding。

核心思路: - 用预训练模型(BERT、LLaMA Embedding)编码物品的文本特征 - 将LLM Embedding与ID Embedding融合,增强表征能力 - 特别适用于冷启动场景——新物品只要有文本描述即可获得高质量Embedding

论文参考"Recommendation as Language Processing (RLP): A Unified Pretrain, Personalized Prompt & Predict Paradigm (P5)"(Geng et al., 2022, RecSys)首次提出将推荐统一到语言建模框架。

角色2:LLM作为评分/排序器

将推荐任务转化为自然语言理解任务,通过精心设计的Prompt让LLM直接对候选物品进行评分或排序。

三种推荐模式: - Zero-shot推荐:不提供示例,直接让LLM根据用户描述推荐 - Few-shot推荐(ICL):提供少量用户历史交互作为示例,让LLM学习用户偏好 - Prompt-based评分:让LLM对每个候选物品给出评分

论文参考"Is ChatGPT a Good Recommender? A Preliminary Study"(Dai et al., 2023, arXiv)系统评估了ChatGPT在推荐任务上的能力。

角色3:LLM作为生成器

LLM不仅做排序,还直接生成推荐结果——这是传统推荐系统无法实现的范式。

关键能力: - 直接生成推荐物品列表(不依赖候选集) - 生成推荐理由和解释 - 对话式推荐(ChatRec):在多轮对话中理解并满足用户需求

论文参考"Chat-REC: Towards Interactive and Explainable LLMs-Augmented Recommender System"(Gao et al., 2023, arXiv)提出了交互式LLM推荐框架。

角色4:LLM作为推荐Agent

最前沿的范式——LLM作为自主Agent,具备调用工具、多步推理、动态策略调整的能力。

Agent推荐流程: 1. 意图理解:通过对话理解用户真实需求 2. 工具调用:调用搜索引擎、知识图谱、用户画像等工具收集信息 3. 推理决策:基于收集的信息进行多步推理,生成推荐策略 4. 结果生成与反馈:生成推荐结果并根据用户反馈迭代优化

论文参考"RecAgent: A Novel Simulation Paradigm for Recommender Systems"(Wang et al., 2023, arXiv)提出了基于LLM Agent的推荐系统模拟框架。


16.2 关键技术

16.2.1 大模型推荐微调方法

Instruction Tuning for Recommendation

将推荐任务构造为Instruction-following格式,让LLM通过指令微调来学习推荐能力。

InstructRec(Zhang et al., 2023)的指令格式:

Text Only
指令: 根据用户的历史行为,推荐5部他可能喜欢的电影。
输入: 用户最近观看了:《星际穿越》《盗梦空间》《信条》《蝙蝠侠:黑暗骑士》
输出: 1. 《致命魔术》 2. 《记忆碎片》 3. 《敦刻尔克》 4. 《奥本海默》 5. 《降临》

TALLRec(Bao et al., 2023, RecSys)框架: - 将推荐任务转换为"是否推荐"的二分类指令 - 对LLaMA进行Instruction Tuning - 在少量推荐数据上即可获得良好效果

Python
# TALLRec风格的推荐指令构造
def build_recommendation_instruction(user_history, candidate_item):
    """构造推荐指令格式的训练数据"""
    instruction = (
        "Based on the user's historical interactions, "
        "determine whether the user would like the candidate item."
    )

    # 格式化用户历史
    history_text = "User's watched movies: " + ", ".join(
        [f'"{movie}"' for movie in user_history]
    )

    # 格式化候选物品
    candidate_text = f'Candidate movie: "{candidate_item["title"]}" - {candidate_item["description"]}'

    input_text = f"{history_text}\n{candidate_text}"

    return {
        "instruction": instruction,
        "input": input_text,
        "output": "Yes" if candidate_item["label"] == 1 else "No"
    }

# 示例
user_history = ["星际穿越", "盗梦空间", "信条", "蝙蝠侠:黑暗骑士"]
candidate = {
    "title": "致命魔术",
    "description": "两位魔术师之间的竞争与复仇,充满悬疑反转",
    "label": 1
}
instruction_data = build_recommendation_instruction(user_history, candidate)
print(instruction_data)

LoRA微调在推荐任务上的应用

全参数微调LLM成本极高,LoRA(Low-Rank Adaptation)是推荐领域最主流的高效微调方法。

Python
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
from peft import LoraConfig, get_peft_model, TaskType
import torch

def setup_lora_for_recommendation(model_name="meta-llama/Llama-2-7b-hf"):
    """配置LoRA微调推荐模型"""

    # 4-bit量化配置,降低显存需求
    bnb_config = BitsAndBytesConfig(
        load_in_4bit=True,
        bnb_4bit_quant_type="nf4",
        bnb_4bit_compute_dtype=torch.float16,
        bnb_4bit_use_double_quant=True,
    )

    # 加载预训练模型
    model = AutoModelForCausalLM.from_pretrained(
        model_name,
        quantization_config=bnb_config,
        device_map="auto",
        trust_remote_code=True,
    )

    # LoRA配置 —— 推荐任务建议的超参数
    lora_config = LoraConfig(
        task_type=TaskType.CAUSAL_LM,
        r=16,                     # LoRA秩,推荐任务通常16-64
        lora_alpha=32,            # 缩放因子
        lora_dropout=0.05,        # Dropout防止过拟合
        target_modules=[          # 对attention层做LoRA
            "q_proj", "k_proj", "v_proj", "o_proj",
            "gate_proj", "up_proj", "down_proj"
        ],
        bias="none",
    )

    # 应用LoRA
    model = get_peft_model(model, lora_config)
    model.print_trainable_parameters()
    # 输出: trainable params: ~4M || all params: ~7B || trainable%: 0.06%

    return model

# LoRA推荐模型的训练配置
from transformers import TrainingArguments

training_args = TrainingArguments(
    output_dir="./rec_lora_output",
    num_train_epochs=3,
    per_device_train_batch_size=4,
    gradient_accumulation_steps=4,
    learning_rate=2e-4,            # LoRA推荐较高学习率
    warmup_ratio=0.1,
    logging_steps=10,
    save_strategy="epoch",
    fp16=True,
    optim="paged_adamw_32bit",
    report_to="wandb",
)

推荐特定的Prompt模板设计

Prompt设计是LLM推荐的核心技术之一。好的Prompt能大幅提升推荐效果。

Python
# === 推荐系统Prompt模板库 ===

class RecPromptTemplates:
    """推荐系统专用Prompt模板"""

    @staticmethod  # @staticmethod不需要实例即可调用
    def rating_prediction(user_history, target_item):
        """评分预测Prompt"""
        return f"""你是一个精准的推荐系统。请根据用户历史行为预测评分。

用户历史评分:
{chr(10).join([f'- {item["name"]}: {item["rating"]}分' for item in user_history])}

请预测用户对以下物品的评分(1-5分):
物品: {target_item["name"]}
描述: {target_item["description"]}

请直接输出评分数字:"""

    @staticmethod
    def sequential_recommendation(user_sequence, num_recs=5):
        """序列推荐Prompt"""
        return f"""你是一个序列推荐专家。根据用户的浏览历史,预测他接下来最可能感兴趣的物品。

用户浏览序列(按时间顺序):
{chr(10).join([f'{i+1}. {item}' for i, item in enumerate(user_sequence)])}  # enumerate同时获取索引和元素

请推荐{num_recs}个用户最可能感兴趣的物品,并简要说明推荐理由:"""

    @staticmethod
    def conversational_recommendation(dialog_history, user_query):
        """对话式推荐Prompt"""
        return f"""你是一个友好的推荐助手。根据对话上下文理解用户需求并推荐。

对话历史:
{chr(10).join(dialog_history)}

用户: {user_query}

请推荐并解释原因:"""

    @staticmethod
    def explainable_recommendation(user_profile, recommended_items):
        """可解释推荐Prompt"""
        return f"""你是一个推荐解释专家。请为以下推荐结果生成个性化的解释。

用户画像:
- 偏好类型: {user_profile["preferences"]}
- 近期关注: {user_profile["recent_interests"]}

推荐结果:
{chr(10).join([f'{i+1}. {item}' for i, item in enumerate(recommended_items)])}

请为每个推荐生成一句个性化的推荐理由:"""

16.2.2 Collaborative Filtering meets LLM

ID vs Text:推荐中的核心讨论

推荐系统中一个核心争论:ID Embedding和Text Embedding哪个更重要?

方面 ID Embedding Text Embedding (LLM)
表征能力 精准捕获协同过滤信号 丰富的语义信息
冷启动 无法处理新物品 天然支持冷启动
跨域 不同域ID不通用 语义空间统一
数据效率 需要大量交互数据 少量数据即可工作
实时性 需重新训练 动态理解新内容
计算成本 低(Embedding查表) 高(LLM推理)

论文参考"Where to Go Next for Recommender Systems? ID- vs. Modality-based Recommender Models Revisited"(Yuan et al., 2023, SIGIR)深入讨论了ID与模态表征的对比。

UniRec统一推荐框架

UniRec(Mao et al., 2023)尝试统一ID和文本表征:

Python
import torch
import torch.nn as nn

class UniRecModel(nn.Module):  # 继承nn.Module定义网络层
    """UniRec风格的统一推荐模型(简化版)"""

    def __init__(self, num_items, id_dim=64, text_dim=768, hidden_dim=256):
        super().__init__()  # super()调用父类方法
        # ID Embedding分支
        self.id_embedding = nn.Embedding(num_items, id_dim)

        # Text Embedding分支(冻结的LLM编码器输出)
        self.text_projector = nn.Sequential(
            nn.Linear(text_dim, hidden_dim),
            nn.ReLU(),
            nn.Linear(hidden_dim, hidden_dim)
        )

        # ID Embedding投影
        self.id_projector = nn.Sequential(
            nn.Linear(id_dim, hidden_dim),
            nn.ReLU(),
            nn.Linear(hidden_dim, hidden_dim)
        )

        # 融合层 —— 自适应门控融合ID和Text信号
        self.fusion_gate = nn.Sequential(
            nn.Linear(hidden_dim * 2, hidden_dim),
            nn.Sigmoid()
        )

        # 预测头
        self.predictor = nn.Sequential(
            nn.Linear(hidden_dim, hidden_dim // 2),
            nn.ReLU(),
            nn.Linear(hidden_dim // 2, 1)
        )

    def forward(self, item_ids, text_embeddings, user_embedding):
        """
        item_ids: [batch_size] 物品ID
        text_embeddings: [batch_size, text_dim] 预计算的LLM文本向量
        user_embedding: [batch_size, hidden_dim] 用户表征
        """
        # 分别处理ID和Text特征
        id_feat = self.id_projector(self.id_embedding(item_ids))
        text_feat = self.text_projector(text_embeddings)

        # 自适应门控融合
        combined = torch.cat([id_feat, text_feat], dim=-1)  # torch.cat沿已有维度拼接张量
        gate = self.fusion_gate(combined)
        fused = gate * id_feat + (1 - gate) * text_feat

        # 用户-物品交互预测
        interaction = fused * user_embedding
        score = self.predictor(interaction)

        return score.squeeze(-1)  # squeeze压缩维度

16.2.3 多模态推荐

2024-2025年,推荐系统从纯文本/ID扩展到多模态融合,综合利用文本、图像、视频和行为序列。

多模态融合架构

Text Only
┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐
│ 文本特征  │  │ 图像特征  │  │ 视频特征  │  │ 行为序列  │
│ (BERT/   │  │ (ViT/    │  │(VideMAE/ │  │ (Trans-  │
│  LLaMA)  │  │  CLIP)   │  │ VideoLLM)│  │  former) │
└────┬─────┘  └────┬─────┘  └────┬─────┘  └────┬─────┘
     │             │             │             │
     └──────┬──────┴──────┬──────┘             │
            │  多模态融合层 │                    │
            │  (Cross-    │                    │
            │  Attention) │                    │
            └──────┬──────┘                    │
                   │                           │
                   └───────────┬───────────────┘
                         ┌─────┴─────┐
                         │  统一表征   │
                         │  空间      │
                         └─────┬─────┘
                         ┌─────┴─────┐
                         │ 推荐预测   │
                         └───────────┘

论文参考"Multimodal Recommender Systems: A Survey"(Zhou et al., 2024, Information Fusion)全面综述了多模态推荐最新进展。

16.2.4 会话式推荐系统

会话式推荐是LLM在推荐中最具用户体验价值的应用之一。

ChatRec框架(Gao et al., 2023)核心思路: 1. 用户通过自然语言表达需求 2. LLM理解意图并提取关键信息 3. 调用推荐模型获取候选集 4. LLM对候选集进行重排和解释 5. 多轮对话迭代优化

对话状态管理

Python
from dataclasses import dataclass, field
from typing import List, Dict, Optional
from enum import Enum

class DialogState(Enum):
    GREETING = "greeting"
    NEED_ELICITATION = "need_elicitation"
    PREFERENCE_CAPTURE = "preference_capture"
    RECOMMENDATION = "recommendation"
    FEEDBACK = "feedback"
    REFINEMENT = "refinement"

@dataclass  # @dataclass自动生成__init__等方法
class ConversationalRecState:
    """会话式推荐的状态管理"""
    current_state: DialogState = DialogState.GREETING
    user_preferences: Dict[str, list] = field(default_factory=dict)
    dialog_history: List[Dict[str, str]] = field(default_factory=list)
    recommended_items: List[str] = field(default_factory=list)
    rejected_items: List[str] = field(default_factory=list)
    satisfaction_score: float = 0.0
    turn_count: int = 0

    def update_preference(self, key: str, values: list):
        """更新用户偏好"""
        if key in self.user_preferences:
            self.user_preferences[key].extend(values)
        else:
            self.user_preferences[key] = values

    def add_dialog_turn(self, role: str, content: str):
        """添加对话轮次"""
        self.dialog_history.append({"role": role, "content": content})
        self.turn_count += 1

    def transition(self, new_state: DialogState):
        """状态转移"""
        self.current_state = new_state

    def get_context_summary(self) -> str:
        """获取当前上下文摘要"""
        prefs = ", ".join([f"{k}: {v}" for k, v in self.user_preferences.items()])
        return (
            f"对话轮次: {self.turn_count}\n"
            f"当前状态: {self.current_state.value}\n"
            f"用户偏好: {prefs}\n"
            f"已推荐: {len(self.recommended_items)}\n"
            f"已拒绝: {len(self.rejected_items)}个"
        )

16.3 工业界实践

16.3.1 阿里巴巴:LLM+推荐实践

阿里妈妈广告推荐: - 使用通义千问生成商品描述增强,提升CTR 3.2% - 基于LLM的用户意图理解模块,替代规则引擎 - 冷启动商品通过LLM语义Embedding接入召回链路

淘宝推荐: - 多模态大模型理解商品图片+标题+评论 - LLM生成个性化推荐文案("猜你喜欢"的推荐理由) - 2024年上线LLM-based重排模块

16.3.2 字节跳动:抖音推荐中的LLM

短视频理解: - 基于多模态LLM的视频内容理解(文字+画面+音频) - LLM生成视频标签,替代人工标注,标签覆盖率提升40%

用户兴趣建模: - 将用户行为序列转化为自然语言描述 - 利用LLM进行用户兴趣聚类和演化建模

16.3.3 快手:LLM赋能内容推荐

  • 基于LLM的内容安全审核与推荐过滤
  • LLM辅助的冷启动内容理解
  • 利用LLM做跨模态(图文、短视频、直播)统一推荐

16.3.4 成本与延迟考量

LLM推荐面临的核心工程挑战

挑战 传统推荐 LLM推荐 解决方案
推理延迟 <10ms 100ms-10s 异步推理、缓存、蒸馏
计算成本 $0.001/请求 $0.01-0.1/请求 量化、小模型蒸馏、批处理
显存占用 <1GB 14-140GB 模型并行、量化、Offloading
吞吐量 10K+ QPS 100-1000 QPS 模型服务池化、KV Cache

工业级优化方案

Python
# === LLM推荐的工程优化策略 ===

class LLMRecServingOptimizer:
    """LLM推荐系统的Serving优化"""

    def __init__(self):
        self.strategies = {
            "离线预计算": {
                "description": "离线批量计算LLM Embedding,存入向量数据库",
                "延迟降低": "99%",
                "适用场景": "物品侧特征编码"
            },
            "模型蒸馏": {
                "description": "用大模型(GPT-4)蒸馏小模型(BERT-base)",
                "延迟降低": "90%",
                "适用场景": "在线排序"
            },
            "量化部署": {
                "description": "INT4/INT8量化 + vLLM/TensorRT-LLM",
                "延迟降低": "60-80%",
                "适用场景": "在线生成式推荐"
            },
            "语义缓存": {
                "description": "相似Query命中缓存,避免重复推理",
                "延迟降低": "70-90%",
                "适用场景": "对话式推荐"
            },
            "异步流水线": {
                "description": "LLM推理与传统推荐并行,取先返回结果",
                "延迟降低": "50%",
                "适用场景": "混合推荐系统"
            }
        }

    def select_strategy(self, latency_budget_ms, qps_requirement):
        """根据延迟预算和QPS要求选择优化策略"""
        if latency_budget_ms < 20:
            return "离线预计算"
        elif latency_budget_ms < 50:
            return "模型蒸馏"
        elif latency_budget_ms < 200:
            return "量化部署"
        elif qps_requirement < 100:
            return "语义缓存"
        else:
            return "异步流水线"

16.3.5 AB测试结果分析

来自公开报告和论文的AB测试效果:

公司/场景 方案 核心指标提升 数据来源
阿里(搜索推荐) LLM商品理解 CTR +3.2%, CVR +1.8% KDD 2024 Industry
字节(抖音) 多模态LLM标签 完播率 +2.1% 公开技术博客
快手 LLM冷启动 新内容曝光率 +15% RecSys 2024
Amazon LLM评论摘要推荐 购买转化 +5.3% WWW 2024
Netflix LLM个性化摘要 点击率 +4.7% RecSys 2024 Industry

16.4 代码实战

16.4.1 使用Hugging Face做Text-based Recommendation

Python
"""
Text-based Recommendation with Sentence Transformers
使用语义相似度做物品推荐
"""
from sentence_transformers import SentenceTransformer
import numpy as np
from typing import List, Dict

class TextBasedRecommender:
    """基于文本语义的推荐系统"""

    def __init__(self, model_name='sentence-transformers/all-MiniLM-L6-v2'):
        self.model = SentenceTransformer(model_name)
        self.item_catalog = []
        self.item_embeddings = None

    def build_item_index(self, items: List[Dict]):
        """
        构建物品索引
        items: [{"id": "1", "title": "...", "description": "..."}]
        """
        self.item_catalog = items
        texts = [f"{item['title']}. {item['description']}" for item in items]
        self.item_embeddings = self.model.encode(texts, normalize_embeddings=True)
        print(f"已索引 {len(items)} 个物品, Embedding维度: {self.item_embeddings.shape[1]}")

    def recommend_by_text(self, query: str, top_k: int = 5) -> List[Dict]:
        """根据文本查询推荐"""
        query_embedding = self.model.encode([query], normalize_embeddings=True)
        similarities = np.dot(self.item_embeddings, query_embedding.T).flatten()  # np.dot矩阵/向量点乘

        top_indices = np.argsort(similarities)[::-1][:top_k]

        results = []
        for idx in top_indices:
            results.append({
                "item": self.item_catalog[idx],
                "score": float(similarities[idx])
            })
        return results

    def recommend_by_history(self, user_history: List[Dict], top_k: int = 5) -> List[Dict]:
        """根据用户历史推荐(基于历史物品的聚合语义向量)"""
        history_texts = [f"{item['title']}. {item['description']}" for item in user_history]
        history_embeddings = self.model.encode(history_texts, normalize_embeddings=True)

        # 用户兴趣向量 = 历史物品Embedding的加权平均
        user_vector = np.mean(history_embeddings, axis=0, keepdims=True)
        user_vector = user_vector / np.linalg.norm(user_vector)  # np.linalg线性代数运算

        similarities = np.dot(self.item_embeddings, user_vector.T).flatten()

        # 排除已交互物品
        history_ids = {item.get("id") for item in user_history}
        for i, item in enumerate(self.item_catalog):
            if item["id"] in history_ids:
                similarities[i] = -1

        top_indices = np.argsort(similarities)[::-1][:top_k]

        results = []
        for idx in top_indices:
            results.append({
                "item": self.item_catalog[idx],
                "score": float(similarities[idx])
            })
        return results

# === 使用示例 ===
if __name__ == "__main__":
    recommender = TextBasedRecommender()

    # 构建物品库
    items = [
        {"id": "1", "title": "深度学习入门", "description": "从零开始学习神经网络和深度学习"},
        {"id": "2", "title": "推荐系统实践", "description": "工业级推荐系统的设计与实现"},
        {"id": "3", "title": "自然语言处理", "description": "NLP基础到大语言模型的完整教程"},
        {"id": "4", "title": "计算机视觉", "description": "图像识别、目标检测和图像分割"},
        {"id": "5", "title": "强化学习导论", "description": "马尔可夫决策过程和策略梯度方法"},
        {"id": "6", "title": "大模型微调", "description": "LoRA、QLoRA等高效微调技术实战"},
        {"id": "7", "title": "Transformer架构", "description": "注意力机制和Transformer模型详解"},
        {"id": "8", "title": "GNN图神经网络", "description": "图卷积网络在推荐和社交中的应用"},
    ]
    recommender.build_item_index(items)

    # 文本查询推荐
    print("=== 文本查询推荐 ===")
    results = recommender.recommend_by_text("我想学习大模型相关技术")
    for r in results:
        print(f"  {r['item']['title']}: {r['score']:.4f}")

    # 基于历史推荐
    print("\n=== 基于历史推荐 ===")
    user_history = [items[0], items[2], items[6]]  # 深度学习、NLP、Transformer
    results = recommender.recommend_by_history(user_history)
    for r in results:
        print(f"  {r['item']['title']}: {r['score']:.4f}")

16.4.2 微调LLaMA做推荐任务(简化示例)

Python
"""
使用LoRA微调LLaMA-2做推荐任务
简化的训练Pipeline
"""
import torch
from datasets import Dataset
from transformers import (
    AutoModelForCausalLM, AutoTokenizer,
    TrainingArguments, BitsAndBytesConfig
)
from peft import LoraConfig, get_peft_model
from trl import SFTTrainer

def prepare_recommendation_dataset():
    """准备推荐数据集(MovieLens风格)"""
    examples = [
        {
            "text": (
                "### 指令: 根据用户观影历史,判断用户是否会喜欢候选电影。\n"
                "### 用户历史: 肖申克的救赎(5分), 教父(5分), 辛德勒的名单(4分)\n"
                "### 候选电影: 美丽人生 - 二战背景的感人故事\n"
                "### 回答: 是。该用户偏好高评分经典剧情片,《美丽人生》同为高口碑经典剧情片,非常匹配。"
            )
        },
        {
            "text": (
                "### 指令: 根据用户观影历史,判断用户是否会喜欢候选电影。\n"
                "### 用户历史: 复仇者联盟(4分), 蜘蛛侠(4分), 钢铁侠(5分)\n"
                "### 候选电影: 傲慢与偏见 - 简·奥斯汀经典文学改编\n"
                "### 回答: 否。该用户明显偏好漫威超级英雄类电影,文学改编剧情片与其偏好不匹配。"
            )
        },
        # ... 实际需要数千条训练数据
    ]
    return Dataset.from_list(examples)

def train_rec_llama():
    """微调LLaMA做推荐"""
    model_name = "meta-llama/Llama-2-7b-hf"

    # 量化配置
    bnb_config = BitsAndBytesConfig(
        load_in_4bit=True,
        bnb_4bit_quant_type="nf4",
        bnb_4bit_compute_dtype=torch.float16,
    )

    # 加载模型和分词器
    model = AutoModelForCausalLM.from_pretrained(
        model_name, quantization_config=bnb_config, device_map="auto"
    )
    tokenizer = AutoTokenizer.from_pretrained(model_name)
    tokenizer.pad_token = tokenizer.eos_token

    # LoRA配置
    lora_config = LoraConfig(
        r=16, lora_alpha=32, lora_dropout=0.05,
        target_modules=["q_proj", "v_proj", "k_proj", "o_proj"],
        task_type="CAUSAL_LM"
    )
    model = get_peft_model(model, lora_config)

    # 训练配置
    training_args = TrainingArguments(
        output_dir="./rec-llama-lora",
        num_train_epochs=3,
        per_device_train_batch_size=4,
        gradient_accumulation_steps=4,
        learning_rate=2e-4,
        fp16=True,
        logging_steps=10,
        save_strategy="epoch",
        warmup_ratio=0.1,
    )

    # 准备数据
    dataset = prepare_recommendation_dataset()

    # 使用SFTTrainer训练
    trainer = SFTTrainer(
        model=model,
        args=training_args,
        train_dataset=dataset,
        tokenizer=tokenizer,
        max_seq_length=512,
    )

    trainer.train()
    trainer.save_model("./rec-llama-lora-final")
    print("推荐模型微调完成!")

def inference_rec_llama(model_path, user_history, candidate):
    """推荐推理"""
    from peft import PeftModel

    base_model = AutoModelForCausalLM.from_pretrained(
        "meta-llama/Llama-2-7b-hf", device_map="auto", torch_dtype=torch.float16
    )
    model = PeftModel.from_pretrained(base_model, model_path)
    tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b-hf")

    prompt = (
        f"### 指令: 根据用户观影历史,判断用户是否会喜欢候选电影。\n"
        f"### 用户历史: {user_history}\n"
        f"### 候选电影: {candidate}\n"
        f"### 回答: "
    )

    inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
    with torch.no_grad():  # 禁用梯度计算,节省内存
        outputs = model.generate(**inputs, max_new_tokens=100, temperature=0.7)

    response = tokenizer.decode(outputs[0], skip_special_tokens=True)
    return response.split("### 回答: ")[-1]

16.4.3 基于LangChain的对话式推荐Agent

Python
"""
基于LangChain的对话式推荐Agent
支持工具调用、多轮对话、个性化推荐
"""
from langchain_openai import ChatOpenAI
from langchain.agents import AgentExecutor, create_openai_tools_agent
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.tools import tool
from langchain_core.messages import HumanMessage, AIMessage
from typing import List
import json

# === 定义推荐工具 ===

@tool
def search_items(query: str, category: str = "all") -> str:
    """搜索物品库,返回匹配的物品列表"""
    # 模拟物品搜索(实际项目中对接真实搜索引擎或向量数据库)
    mock_results = {
        "科幻电影": ["沙丘2 (2024)", "奥本海默 (2023)", "流浪地球2 (2023)"],
        "动作电影": ["碟中谍7 (2023)", "疾速追杀4 (2023)", "速度与激情10 (2023)"],
        "书籍推荐": ["《大模型时代》", "《芯片战争》", "《人类简史》"],
    }
    for key, items in mock_results.items():
        if any(k in query for k in key):  # any()任一为True则返回True
            return json.dumps({"results": items, "total": len(items)}, ensure_ascii=False)  # json.dumps将Python对象序列化为JSON字符串
    return json.dumps({"results": ["暂无匹配结果"], "total": 0}, ensure_ascii=False)

@tool
def get_user_profile(user_id: str) -> str:
    """获取用户画像信息"""
    profiles = {
        "user_001": {
            "偏好类型": ["科幻", "悬疑", "纪录片"],
            "年龄段": "25-30",
            "活跃度": "高",
            "平均评分": 4.2,
            "最近观看": ["三体(剧集)", "星际穿越", "黑暗荣耀"]
        }
    }
    profile = profiles.get(user_id, {"error": "用户不存在"})
    return json.dumps(profile, ensure_ascii=False)

@tool
def get_item_details(item_name: str) -> str:
    """获取物品详细信息"""
    details = {
        "沙丘2": {
            "评分": 8.5, "类型": "科幻/冒险",
            "导演": "丹尼斯·维伦纽瓦", "年份": 2024,
            "简介": "保罗·厄崔迪与弗里曼人联合对抗哈克南家族"
        }
    }
    detail = details.get(item_name, {"error": "物品信息未收录"})
    return json.dumps(detail, ensure_ascii=False)

@tool
def collaborative_filtering_recommend(user_id: str, top_k: int = 5) -> str:
    """基于协同过滤的推荐(调用传统推荐模型)"""
    # 模拟CF推荐结果
    cf_results = [
        {"item": "银翼杀手2049", "score": 0.95},
        {"item": "降临", "score": 0.91},
        {"item": "头号玩家", "score": 0.88},
        {"item": "攻壳机动队", "score": 0.85},
        {"item": "黑客帝国", "score": 0.82},
    ]
    return json.dumps(cf_results[:top_k], ensure_ascii=False)

# === 构建推荐Agent ===

def create_rec_agent():
    """创建对话式推荐Agent"""

    llm = ChatOpenAI(model="gpt-4o", temperature=0.7)

    tools = [search_items, get_user_profile, get_item_details,
             collaborative_filtering_recommend]

    system_prompt = """你是一个专业的个性化推荐助手。你的职责是:
1. 通过对话理解用户的真实需求和偏好
2. 利用工具获取用户画像和物品信息
3. 结合协同过滤推荐和语义理解给出个性化推荐
4. 解释推荐理由,帮助用户做出决策
5. 根据用户反馈动态调整推荐策略

注意事项:
- 推荐时要说明推荐理由
- 如果用户不满意,主动询问偏好并调整
- 控制推荐数量(一般3-5个)
- 优先推荐与用户历史偏好匹配的物品"""

    prompt = ChatPromptTemplate.from_messages([
        ("system", system_prompt),
        MessagesPlaceholder(variable_name="chat_history"),
        ("human", "{input}"),
        MessagesPlaceholder(variable_name="agent_scratchpad"),
    ])

    agent = create_openai_tools_agent(llm, tools, prompt)
    executor = AgentExecutor(agent=agent, tools=tools, verbose=True)

    return executor

# === 运行对话式推荐 ===

def run_conversational_recommendation():
    """运行对话式推荐Demo"""
    agent = create_rec_agent()
    chat_history = []

    print("=== 对话式推荐系统 ===")
    print("输入 'quit' 退出\n")

    while True:
        user_input = input("你: ")
        if user_input.lower() == 'quit':
            break

        response = agent.invoke({
            "input": user_input,
            "chat_history": chat_history,
        })

        ai_response = response["output"]
        print(f"\n推荐助手: {ai_response}\n")

        # 更新对话历史
        chat_history.append(HumanMessage(content=user_input))
        chat_history.append(AIMessage(content=ai_response))

if __name__ == "__main__":
    run_conversational_recommendation()

16.5 前沿论文清单(2024-2025)

论文 会议/期刊 核心贡献
A Survey on Large Language Models for Recommendation ACM Computing Surveys, 2024 LLM推荐综述
TALLRec: An Effective and Efficient Tuning Framework for LLM-based Recommendation RecSys 2023 LLM推荐高效微调
P5: Pretrain, Personalized Prompt, and Predict Paradigm RecSys 2022 统一语言推荐框架
Chat-REC: Towards Interactive and Explainable LLMs-Augmented Recommender System arXiv 2023 对话式LLM推荐
RecAgent: A Novel Simulation Paradigm for Recommender Systems arXiv 2023 Agent推荐模拟
LLaRA: Large Language-Recommendation Assistant SIGIR 2024 LLM推荐助手
ReLLa: Retrieval-enhanced Large Language Models for Recommendation WWW 2024 检索增强LLM推荐
Where to Go Next for Recommender Systems? ID- vs. Modality-based SIGIR 2023 ID vs 模态讨论
Actions Speak Louder than Words: Trillion-Parameter Sequential Transducers for Generative Recommendations ICML 2024 超大规模生成式推荐
Collaborative Large Language Model for Recommender Systems WWW 2024 协同LLM推荐

📋 面试要点

高频面试题

Q1: LLM在推荐系统中有哪些角色?各自优劣?

LLM可作为:(1)特征编码器——增强语义表征但增加计算成本;(2)评分/排序器——灵活但延迟高;(3)生成器——能力强但可控性差;(4)Agent——最灵活但工程复杂度最高。

Q2: LLM推荐与传统推荐的核心区别?

传统推荐依赖ID Embedding和交互矩阵,LLM推荐基于语义理解。LLM天然支持冷启动和跨域,但面临延迟和成本挑战。

Q3: 如何解决LLM推荐的延迟问题?

五种策略:离线预计算Embedding、模型蒸馏、量化部署(INT4/vLLM)、语义缓存、异步Pipeline。实际落地通常组合使用。

Q4: TALLRec的核心思路?

将推荐转化为Instruction-following任务,对LLaMA做LoRA微调,在少量数据上即可获得良好推荐效果。

Q5: ID Embedding和Text Embedding在推荐中的优劣对比?

ID Embedding精准但冷启动差、不跨域;Text Embedding语义丰富、支持冷启动但计算成本高。工业实践中通常融合使用。

Q6: 会话式推荐系统的核心技术模块?

意图理解、对话状态管理、候选召回/重排、解释生成、反馈学习。ChatRec通过LLM统一实现这些模块。

Q7: LLM推荐在工业界的落地成本如何?

主要成本在GPU算力(推理/训练)和延迟。典型方案:离线特征编码(低成本) > 在线蒸馏小模型(中成本) > 在线大模型推理(高成本)。


✏️ 练习

练习1:LLM推荐Prompt设计

设计一套完整的Prompt模板,覆盖以下推荐场景: - 新用户冷启动推荐 - 基于用户画像的个性化推荐 - 物品相关推荐("看了还看") - 评分预测

练习2:Text-based推荐系统

使用Sentence-Transformers实现一个完整的文本推荐系统: - 支持MovieLens数据集 - 实现文本相似度召回 - 对比ID-based和Text-based推荐效果

练习3:LoRA微调推荐模型

在MovieLens-1M数据集上: - 构造Instruction格式的训练数据 - 用LoRA微调Qwen-2或LLaMA-3模型 - 评估推荐准确率(HR@10, NDCG@10)

练习4:推荐Agent开发

基于LangChain开发一个推荐Agent: - 集成至少3个工具(搜索、画像、评分) - 支持多轮对话 - 实现推荐解释功能


📚 延伸阅读

  1. 综述"A Survey on Large Language Models for Recommendation"(Wu et al., 2024)
  2. 教程:KDD 2024 Tutorial — "Large Language Models for Recommendation"
  3. 开源框架RecBole — 统一推荐算法库
  4. 博客:字节跳动技术博客 — "大模型在抖音推荐中的实践"
  5. 课程:Stanford CS224W + CS229 推荐系统章节

下一章17-现代推荐系统架构.md — 2024-2025推荐系统新趋势与前沿架构