课程七:推荐系统
课程七:推荐系统架构演进案例
目标:推荐系统是许多互联网产品的核心引擎,其架构演进深刻体现了算法与工程的紧密结合。本课程将通过一个典型推荐系统的逐步优化,带你掌握召回策略、排序模型、实时个性化、冷启动应对、以及工程与算法协同设计等核心架构能力。
阶段 0:蛮荒时代(千人一面的静态推荐)
系统描述
- 场景:一个初创电商网站,需要在首页给用户展示一些商品。
- 功能:非常简单,首页固定展示"销量最高"的 Top 10 商品。所有用户看到的完全一样。
- 技术栈:
- 后端:Python/Java (在业务逻辑中直接查询数据库)
- 数据:MySQL (一张
products
表,包含sales_count
字段)
当前架构图
graph LR
Client --> API;
API -- "SELECT * FROM products ORDER BY sales_count DESC LIMIT 10" --> DB["(MySQL)"];
此刻的痛点:
- 转化率低:用户兴趣千差万别,"一刀切"的推荐效果很差。
- 体验单调:用户每次来看到的都差不多,缺乏新鲜感。
- 资源浪费:热门商品过度曝光,大量长尾商品(可能符合部分用户需求)被埋没。
阶段 1:初识个性化 → 基于协同过滤 (CF) 的尝试
挑战浮现
- 业务要求提升用户转化率和体验,需要根据用户的历史行为(如浏览记录、购买记录)进行个性化推荐。
❓ 架构师的思考时刻:如何迈出个性化第一步?最经典的方法是什么?
(直接关联用户行为?基于用户相似度还是物品相似度?计算量如何?实时性要求?)
✅ 演进方向:引入基于物品的协同过滤 (Item-CF)
- 核心思路 (Item-CF):核心思想是"喜欢物品 A 的用户,通常也喜欢物品 B"。
- 离线计算相似度:通过 MapReduce 或 Spark 任务,分析用户行为日志(如用户-物品交互矩阵),计算物品之间的相似度(如余弦相似度、Jaccard 相似度等)。
- 存储相似度:将计算出的物品相似度矩阵存储到高速缓存(如 Redis)中,便于在线快速查询。例如,存储为
item_A -> {item_B: 0.8, item_C: 0.6, ...}
。
- 在线推荐逻辑:
- 当用户访问时,获取该用户最近交互过的物品列表。
- 从 Redis 中查询这些物品的相似物品列表。
- 对相似物品进行聚合、排序(如按相似度加权),去除用户已交互过的物品,得到最终推荐列表。
- 架构调整:引入离线计算和在线缓存查询。
graph TD
subgraph "离线计算 (Batch Processing)"
Logs("用户行为日志") --> Hadoop("Hadoop/Spark Item-CF计算");
Hadoop --> Redis("Redis 存储物品相似度");
end
subgraph "在线推荐 (Real-time Serving)"
Client --> API("推荐接口");
API -- 获取用户近期行为 --> UserDB["(用户行为库)"];
API -- 查询相似物品 --> Redis;
API -- 聚合排序 --> Result("推荐结果");
Result --> Client;
end
带来新问题:Item-CF 依赖用户历史行为,对于新用户或行为稀疏的用户(冷启动问题)效果不佳;推荐结果可能局限于用户已知的领域,缺乏多样性。
阶段 2:单一策略不够 → 多路召回与融合
新的挑战:覆盖率与多样性不足
- 单一的 Item-CF 策略无法覆盖所有用户(特别是新用户)。
- 推荐结果容易聚焦在少数热门或用户熟悉的领域,缺乏惊喜感和多样性。
- 需要结合更多信息源和策略来丰富推荐结果。
❓ 架构师的思考时刻:如何扩大推荐范围,引入更多可能性?
(除了 Item-CF,还有哪些信息可以用?比如全局热点?用户画像?如何组合不同的推荐来源?)
✅ 演进方向:构建多路召回引擎 + 结果融合
- 扩展召回通道 (Recall Channels):并行运行多个召回策略,每个策略负责从不同角度筛选候选物品。
- 通道 1:Item-CF (基于用户历史行为的相似物品,保证个性化深度)
- 通道 2:全局热门 (基于全局统计的热销/热门物品,保证基础覆盖率,应对冷启动)
- 通道 3:用户画像匹配 (User Profile) (基于用户标签如年龄、性别、地域、兴趣标签等,匹配对应人群偏好的物品)
- 通道 4:(可选) LBS 召回 (基于用户地理位置推荐附近相关的物品或服务)
- 通道 5:(可选) 新品召回 (推荐近期上架的新品,增加多样性)
- 召回结果融合与截断:
- 每个召回通道各自独立获取一批候选物品(例如,每个通道召回 Top N,N 可以根据通道特性调整)。
- 将所有通道召回的物品进行合并去重。
- 可以采用简单的合并,或者根据通道的置信度、业务目标进行加权融合。
- 最后截断,保留一定数量(如 500-1000 个)的候选物品,送入后续的排序阶段。
架构调整(增加召回层):
graph TD
subgraph "召回层 (Recall Engine)"
RecallService("召回服务") --> ItemCF("Item-CF 通道");
RecallService --> Hot("热门商品通道");
RecallService --> Profile("用户画像通道");
RecallService --> LBS("LBS 通道");
RecallService --> New("新品通道");
ItemCF & Hot & Profile & LBS & New --> Fusion("融合层 去重/截断");
end
Fusion --> Rank("排序层");
效果:显著提升了推荐的覆盖率和多样性,但召回阶段只负责粗选,物品的排序还比较粗糙,用户点击率可能不高。
阶段 3:粗排不够精 → 引入机器学习排序模型
挑战再升级:点击率 (CTR) 亟待提升
- 多路召回虽然扩大了候选集,但物品展示的顺序对用户点击意愿影响巨大。简单的按召回分数或热度排序,效果不佳。
- 需要更精准地预测用户对每个召回物品的点击概率 (CTR),将最可能被点击的物品排在前面。
❓ 架构师的思考时刻:如何从几百个候选物中挑出用户最可能点击的 Top N?
(需要更精细的排序。用什么特征?什么模型?在线预测性能要求高吗?)
✅ 演进方向:构建精排模型 (Rank Model) 进行 CTR 预估
- 特征工程 (Feature Engineering):构建丰富的特征是模型效果的基础。
- 用户特征 (User Features):年龄、性别、地域、历史行为统计(如历史点击率、购买偏好)、用户实时行为特征(如当前浏览的商品)。
- 物品特征 (Item Features):类别、价格、品牌、历史 CTR、销量、好评率。
- 上下文特征 (Context Features):时间(小时、工作日/周末)、设备类型、网络环境、请求来源页面。
- 模型选型与训练:
- 初期可选:逻辑回归 (LR) 或 GBDT+LR (Facebook 经典方案),训练快,可解释性好。
- 进阶可选:深度学习模型,如 Wide&Deep (Google), DeepFM, DIN (Alibaba) 等,能更好地捕捉特征间的非线性交互关系,通常效果更优,但训练和部署更复杂。
- 模型使用历史的曝光和点击日志进行离线训练。
- 在线预测 (Online Inference):
- 将训练好的模型部署为一个模型服务(如使用 TensorFlow Serving, Triton Inference Server, ONNX Runtime 或自建 gRPC/HTTP 服务)。
- 在线推荐流程中,召回层拿到候选物品后,实时查询相关特征(可能需要 Feature Store 支持),调用模型服务对每个候选物品进行 CTR 预估打分。
- 根据模型预测的 CTR 分数进行降序排序,得到最终展示给用户的推荐列表。
架构调整(增加排序层与模型服务):
graph TD
Recall("召回层 输出候选集") --> FeatureEng("特征工程 实时查询特征");
FeatureEng --> ModelServing("模型服务 TF Serving/Triton");
ModelServing -- CTR预估分 --> RankSort("排序模块");
RankSort --> API("API 返回排序后结果");
API --> Client;
subgraph "离线训练"
Logs --> TrainData("样本拼接/特征加工");
TrainData --> ModelTrain("模型训练 GBDT/DeepFM");
ModelTrain -- 部署 --> ModelServing;
end
subgraph "在线依赖"
FeatureEng -- 查询 --> FeatureStore("特征存储 Redis/HBase");
end
效果:显著提升推荐的精准度和用户点击率,但模型是离线训练的,无法快速响应用户兴趣的实时变化。
阶段 4:用户兴趣变化快 → 探索实时反馈与在线学习
新挑战:抓住用户的"即时兴趣"
- 用户兴趣可能在短时间内发生变化(比如突然想买某个东西),依赖离线训练(通常是 T+1 更新)的模型无法捕捉这种实时变化,导致推荐滞后。
- 如何让推荐系统更快地适应用户的实时行为反馈?
❓ 架构师的思考时刻:如何让模型更快地学习用户的新偏好?
(离线训练周期太长。能否在线更新模型?实时特征怎么构建?如何平衡"探索"新内容和"利用"已知偏好?)
✅ 演进方向:引入实时特征 + 在线学习 / EE 策略
- 构建实时特征流 (Real-time Feature Pipeline):
- 用户的实时行为(点击、浏览、加购、搜索等)通过埋点发送到 Kafka。
- 使用流处理引擎(如 Flink 或 Spark Streaming)实时消费 Kafka 数据。
- 计算用户的短期行为统计特征(如"过去 5 分钟点击的商品类别"、"当前 Session 搜索的关键词"),更新到在线特征存储中,供排序模型实时使用。
- 模型在线更新 (Online Learning):
- 采用支持在线更新的模型训练范式,根据实时的用户反馈(点击/未点击)流式地更新模型参数。
- 常用算法包括:FTRL (Follow The Regularized Leader),适用于大规模稀疏特征的在线 LR 模型。
- 这通常需要更复杂的架构支持。
- 探索与利用 (Explore & Exploit - EE) 策略:
- 在排序阶段或排序后,引入 EE 算法(如 Thompson Sampling, LinUCB 等 Multi-Armed Bandit 算法)来动态调整物品展示顺序。
- 目标是在"利用"已知用户偏好(推荐模型预测的高 CTR 物品)和"探索"用户可能感兴趣的新内容(给新物品或低 CTR 物品一些展示机会)之间取得平衡,从而更快地发现用户的新兴趣点,并优化长期收益。
架构调整(强化实时链路):
graph TD
subgraph "实时特征链路"
Behavior("用户实时行为") --> Kafka;
Kafka --> Flink("Flink/Spark Streaming");
Flink -- 更新 --> FeatureStore("实时特征库 Redis/HBase");
end
subgraph "在线排序链路"
Recall --> FeatureEng("特征工程");
FeatureEng -- 查询实时/离线特征 --> FeatureStore;
FeatureEng --> ModelServing("在线模型");
ModelServing --> RankSort;
RankSort --> EE("EE策略调整");
EE --> API;
end
subgraph "在线学习链路(可选)"
Feedback("用户反馈 点击/未点击") --> Kafka;
Kafka --> OnlineUpdate("在线模型更新模块 FTRL");
OnlineUpdate -- 更新参数 --> ModelServing;
end
效果:提升了推荐的实时性和对用户短期兴趣变化的响应速度,但冷启动和多样性问题仍然需要专门解决。
阶段 5:新用户新商品怎么办? → 攻克冷启动与多样性
老大难问题:冷启动与信息茧房
- 新用户冷启动:用户刚注册,没有任何行为数据,协同过滤和基于行为的排序模型都无法工作。
- 新物品冷启动:新商品刚上架,没有用户交互数据,很难被推荐出去。
- 多样性与拓展性:推荐系统容易陷入"越推越窄"的境地(信息茧房),用户只看到自己熟悉领域的东西,如何提升推荐的多样性和惊喜感?
❓ 架构师的思考时刻:如何让新用户、新物品也能获得推荐机会?如何打破信息茧房?
(没有行为数据,还有什么信息可用?比如物品本身的内容?用户注册信息?如何在排序时兼顾准确性和多样性?)
✅ 演进方向:利用内容特征 + 多目标优化 + 混合策略
- 引入内容特征与内容相似度:
- 利用 NLP 技术(如 Word2Vec, BERT)或 CV 技术(如 CNN)提取物品的内容嵌入向量 (Content Embedding),例如从商品标题、描述、图片中提取特征。
- 新物品冷启动:可以通过计算新物品与老物品的内容相似度,将其推荐给喜欢相似物品的用户。
- 新用户冷启动:可以基于用户注册时提供的信息(如选择的兴趣标签),推荐内容上匹配的物品。
- 内容特征也可以作为排序模型的输入特征。
- 排序阶段多目标优化 (Multi-Objective Optimization):
- 排序模型不再只优化 CTR,而是同时优化多个目标,如:CTR、CVR (转化率)、GMV (成交总额)、推荐多样性、用户停留时长等。
- 通过调整不同目标的权重或使用更复杂的模型结构来实现多目标平衡。
- 可以在排序后进行重排序 (Re-ranking),例如使用 MMR (Maximal Marginal Relevance) 算法,在保证相关性的前提下,提升结果的多样性。
- 制定专门的冷启动与探索策略:
- 新用户策略:基于用户注册信息、人口属性、地理位置等推荐全局热门或该类人群偏好的物品。
- 新物品策略:给予一定的强制曝光机会(流量倾斜),快速积累交互数据;或利用内容相似度进行推荐。
- 探索机制:结合 EE 算法,主动给用户推荐一些跨领域的、用户可能感兴趣的新物品。
架构调整(完善策略与目标):
graph TD
subgraph "内容处理 (离线)"
ItemContent("商品内容 文本/图片") --> NLP_CV("NLP/CV 模型");
NLP_CV -- 生成向量 --> ContentEmbeddingDB("内容向量库 FAISS/Milvus");
end
subgraph "在线推荐链路"
Recall -- "(增加内容召回通道)" --> Fusion;
Fusion --> FeatureEng;
FeatureEng -- "(增加内容特征)" --> ModelServing("多目标排序模型");
ModelServing --> ReRank("重排序模块 MMR/多样性调整");
ReRank --> API;
%% 冷启动策略融合
ColdStartStrategy("冷启动/探索策略") --> Fusion;
ColdStartStrategy --> ReRank;
end
总结:推荐系统架构的进化之路
阶段 | 核心挑战 | 关键解决方案 | 代表技术/模式 |
---|---|---|---|
0. 静态 | 无个性化 | 按热度静态排序 | SQL ORDER BY |
1. CF 初试 | 用户兴趣差异 | 基于物品的协同过滤 (Item-CF) | MapReduce/Spark (离线), Redis (在线缓存) |
2. 多路召回 | 覆盖率/多样性不足 | 多策略召回通道 + 融合 | 用户画像, LBS, 全局热门, 加权融合 |
3. 精排模型 | 点击率 (CTR) 低 | 机器学习排序模型 (CTR 预估) | LR, GBDT, DeepFM, Wide&Deep, TF Serving, Feature Store |
4. 实时反馈 | 兴趣变化快/滞后 | 实时特征 + 在线学习 / EE | Kafka, Flink/Spark Streaming, FTRL, Bandit 算法 |
5. 冷启动等 | 新用户/物品/多样性 | 内容特征 + 多目标优化 + 探索策略 | NLP/CV Embedding, MMR, 冷启动规则 |
课程设计亮点与思考
- 算法与工程深度融合:清晰地展示了推荐算法的演进(CF -> LR/GBDT -> Deep Learning -> Bandit/Online Learning)如何驱动工程架构的变革(批处理 -> 实时计算 -> 模型服务 -> 在线学习架构)。
- 核心问题驱动:围绕推荐系统最核心的挑战(个性化、实时性、冷启动、多样性、准确性)展开,逻辑清晰。
- 关键技术全覆盖:系统性地介绍了推荐领域常用的技术栈,包括离线计算、实时计算、缓存、数据库、模型服务、特征工程、向量检索等。
- 权衡与取舍:隐式或显式地体现了在不同阶段,架构师需要在成本、复杂度、效果、实时性等多个维度进行权衡。
- 实践导向:贴近工业界实际做法,例如多路召回、精排、EE 探索等都是大型推荐系统的标配。
掌握推荐系统的架构演进,不仅能理解其技术实现,更能洞察互联网产品如何通过数据和算法驱动增长的核心逻辑。