系统设计:推荐系统

推荐系统设计面试全攻略:协同过滤、内容推荐、深度学习推荐架构,涵盖召回、粗排、精排、重排四阶段漏斗,以及冷启动、实时性、多样性与 EE 问题的解决方案。

系统设计:推荐系统

从召回到精排,构建千万级用户的个性化推荐架构。

推荐系统是互联网公司最核心的系统之一,直接影响用户留存和商业化收入。面试中常要求设计一个完整的推荐架构,考查候选人对算法、工程、数据三者的综合能力。


场景分析(Scenario)

需求

  • 功能需求:为用户推荐个性化内容(新闻、视频、商品等)
  • 用户规模:DAU 1000 万,日均请求 10 亿次
  • 延迟要求:首页推荐 < 200ms,非首页 < 500ms
  • 内容规模:物品池 1 亿+,日新增 100 万

核心挑战

  1. 海量物品如何快速召回:从 1 亿候选中选出数百个
  2. 实时兴趣捕捉:用户刚刚点了赞,下次刷新要体现
  3. 冷启动:新用户、新物品无历史数据
  4. 多样性与新颖性:避免信息茧房
  5. Exploration vs Exploitation:已知兴趣 vs 新领域探索

服务架构(Service)

┌─────────────┐    ┌─────────────────────────────────────────────┐
│   Client    │───▶│         Recommendation Service                │
└─────────────┘    │  ┌────────┐  ┌────────┐  ┌──────┐  ┌──────┐ │
                   │  │ Recall │─▶│  Pre-Rank  │─▶│ Rank │─▶│ ReRank│ │
                   │  └────────┘  └────────┘  └──────┘  └──────┘ │
                   └─────────────────────────────────────────────┘
                            │              │              │
                   ┌────────▼──────┐  ┌─────▼──────┐  ┌──▼─────┐
                   │ Feature Store │  │ Model Service │  │ Rule Engine│
                   └───────────────┘  └──────────────┘  └─────────┘

四阶段漏斗

阶段输入输出目标
召回(Recall)1亿 → 500粗筛候选快、广、轻
粗排/预排序(Pre-Rank)500 → 100初筛排序平衡速度与精度
精排(Ranking)100 → 20精准预估 CTR/CVR高精度
重排(Re-Rank)20 → 10最终展示体验优化

召回层(Recall)

召回层必须在 < 20ms 内从 1 亿候选中选出数百个。核心思想:多路召回 + 倒排索引。

多路召回策略

召回路原理适用场景
协同过滤(CF)相似用户/物品有历史行为的用户
内容召回(CB)标签匹配解决冷启动
向量召回(Embedding)DNN 计算相似度泛化能力强
热门召回全局/分群热门兜底策略
运营规则运营配置新品推广、活动

协同过滤(Collaborative Filtering)

用户协同过滤(User-CF)

找到与目标用户兴趣相似的用户,推荐他们喜欢的物品。

import numpy as np
from scipy.spatial.distance import cosine

def user_cf(ratings, target_user, k=5):
    """
    ratings: user-item matrix (users x items)
    target_user: index of the user
    """
    user_sim = 1 - np.array([
        cosine(ratings[target_user], ratings[u])
        if np.sum(ratings[u]) > 0 else 0
        for u in range(len(ratings))
    ])

    # Exclude self, get top-k similar users
    user_sim[target_user] = -1
    top_k_users = np.argsort(user_sim)[-k:]

    # Aggregate ratings from similar users
    scores = np.zeros(ratings.shape[1])
    for u in top_k_users:
        scores += user_sim[u] * ratings[u]

    # Recommend items target user hasn't seen
    seen = ratings[target_user] > 0
    scores[seen] = 0
    return np.argsort(scores)[::-1][:10]

问题:用户矩阵往往非常稀疏,计算复杂度高 (O(U^2))。

物品协同过滤(Item-CF)

更适合用户量级远大于物品量级的场景(如电商)。

计算物品之间的共现相似度:

$$sim(i, j) = \frac{|N(i) \cap N(j)|}{\sqrt{|N(i)| \cdot |N(j)|}}$$

优势:物品相似矩阵更稳定(物品变化慢),推荐更有可解释性。

向量召回:双塔模型(Two-Tower Model)

User Tower                    Item Tower
┌──────────┐                 ┌──────────┐
│ User ID  │                 │ Item ID  │
│ Profile  │                 │ Category │
│ History  │─▶ Embedding ──▶ │ Tags     │
│ Context  │                 │ Stats    │
└──────────┘                 └──────────┘
     │                            │
     └───────── Sim(Q, I) ────────┘
  • 用户塔和物品塔分别输出固定维度的 embedding
  • 通过内积/余弦相似度计算匹配分数
  • 物品 embedding 预先计算并写入 ANN 索引库

近似最近邻(ANN)索引

向量召回需要快速搜索最相似的 K 个物品:

算法原理召回率内存占用
Faiss(IVF-FLAT)聚类 + 倒排高中等
Faiss(IVF-PQ)聚类 + 乘积量化中等低
HNSW分层可 navigable 小世界图很高高
Milvus企业级向量数据库高高

精排层(Ranking)

精排层提供精确的 CTR(点击率)或 CVR(转化率)预估。

###特征体系

特征类别示例
用户画像年龄、性别、兴趣标签、活跃度
物品特征类目、标签、热度、质量分
交叉特征用户偏好类目 × 物品类目
上下文时间、地理位置、设备
统计特征历史 CTR、曝光数、点击数
序列特征最近 50 次点击序列

###排序模型演进

阶段模型特点
1.0LR轻量、可解释,无法学习交叉
2.0FM / FFM自动学习二阶特征交叉
3.0Wide & Deep记忆 + 泛化双路
3.5DeepFMFM + DNN,无需人工特征工程
4.0DIN / DIEN引入 Attention,序列建模
5.0MMoE多目标联合优化

DeepFM 简化结构

import torch
import torch.nn as nn

class DeepFM(nn.Module):
    """简化版 DeepFM 用于理解核心结构"""
    def __init__(self, field_dims, embed_dim=8, mlp_dims=[64, 32]):
        super().__init__()
        self.num_fields = len(field_dims)

        # Embedding layer (shared by FM and Deep)
        self.embedding = nn.ModuleList([
            nn.Embedding(dim, embed_dim) for dim in field_dims
        ])

        # FM 一阶线性部分
        self.fm_first = nn.ModuleList([
            nn.Embedding(dim, 1) for dim in field_dims
        ])

        # Deep MLP
        input_dim = self.num_fields * embed_dim
        layers = []
        for dim in mlp_dims:
            layers.extend([nn.Linear(input_dim, dim), nn.ReLU(), nn.Dropout(0.2)])
            input_dim = dim
        layers.append(nn.Linear(input_dim, 1))
        self.mlp = nn.Sequential(*layers)

    def fm_layer(self, embeddings):
        """
        FM 二阶交叉: sum(sum(vi * vj)) = 0.5 * [ (sum vi)^2 - sum(vi^2) ]
        embeddings: [batch, num_fields, embed_dim]
        """
        square_of_sum = torch.sum(embeddings, dim=1) ** 2
        sum_of_square = torch.sum(embeddings ** 2, dim=1)
        fm_out = 0.5 * torch.sum(square_of_sum - sum_of_square, dim=1, keepdim=True)
        return fm_out

    def forward(self, x):
        # x: [batch, num_fields] 每个 field 的离散 ID
        # Embedding lookup
        embeddings = torch.stack([
            self.embedding[i](x[:, i]) for i in range(self.num_fields)
        ], dim=1)  # [batch, num_fields, embed_dim]

        # FM first-order
        fm_first = torch.sum(
            torch.stack([self.fm_first[i](x[:, i]) for i in range(self.num_fields)], dim=1),
            dim=1
        )  # [batch, 1]

        # FM second-order
        fm_second = self.fm_layer(embeddings)

        # Deep part
        deep_input = embeddings.view(x.size(0), -1)
        deep_out = self.mlp(deep_input)

        # Final prediction (sigmoid in loss)
        return fm_first + fm_second + deep_out

多目标优化(MMoE)

推荐系统往往同时优化多个目标:

  • 点击(CTR):用户是否点击
  • 点赞/收藏( Engagement) :浅层互动
  • 停留时长(Dwell Time) :深度消费
  • 分享/评论(Conversion) :深层转化

使用 MMoE(Multi-gate Mixture-of-Experts)共享底层表示,同时优化多个目标。


重排层(Re-Rank)

重排层关注用户体验,目标是:多样性 + 新颖性 + 业务规则。

多样性算法:MMR(Maximal Marginal Relevance)

$$MMR = \lambda \cdot Relevance(S_i) - (1 - \lambda) \cdot \max_{S_j \in R} Similarity(S_i, S_j)$$

  • 平衡相关性与多样性
  • 高相关性且与已选物品差异大的物品得分高

业务规则插入

  • 必出规则:运营活动、新品扶持
  • 打散规则:同类目不超过连续 3 个
  • 频率控制:同一作者/品牌间隔不低于 N 个
  • 负反馈过滤:用户点过"不喜欢"的物品过滤

存储设计(Storage)

数据流架构

User Behavior ──▶ Kafka ──▶ Flink ──▶ Feature Store
                                    │         │
                                    ▼         ▼
                              Training      Online Serving
                                    │         │
                                    └─▶ Model Store ◀── Train Pipeline

存储选型

数据存储原因
用户画像Redis Cluster低延迟、高 QPS
物品特征Redis / Feature Store批量预加载
实时行为Kafka + Flink流式处理
离线特征Hive / ClickHouse批量计算
向量索引Milvus / FaissANN 搜索
模型文件S3 / 对象存储大模型文件
A/B TestMySQL / Config Center实验配置

冷启动策略

场景策略
新用户基于注册信息的CB召回、热门兜底、探索导向推荐
新物品内容标签匹配、新品流量扶持、相似物品扩展
新系统专家规则 → 简单模型 → 深度学习逐步迭代

Bandit 算法:解决 Exploration

  • Epsilon-Greedy:以 ε 概率随机探索
  • UCB(Upper Confidence Bound) :兼顾均值和方差
  • Thompson Sampling:贝叶斯采样,平衡探索和利用

实时推荐

近实时特征更新

点击 ──▶ Kafka ──▶ Flink 窗口聚合 ──▶ Redis Feature Store
                                         │
用户刷新 ──────────────────────────────▶ 推荐服务读取最新特征
  • Flink 滑动窗口实时计算用户最近行为特征
  • 写入 Redis TTL 7 天
  • 推荐服务读取时合并实时 + 离线特征

面试答题框架

推荐系统面试回答结构

阶段一:需求澄清(2 分钟)

  • 推荐什么内容?新闻/视频/商品?
  • 用户规模、物品规模、QPS 预期
  • 实时性要求?能否接受 T+1 离线计算?

阶段二:召回层设计(5 分钟)

  • 多路召回策略(CF + CB + Vector + Hot)
  • 每路召回的数量和分数归一化
  • ANN 索引选型(Faiss / Milvus)
  • 如何评估召回质量(Recall@K)

阶段三:排序层设计(5 分钟)

  • 特征工程:用户/物品/交叉/上下文/序列
  • 模型选型:从 LR → DeepFM → DIN 的演进
  • 在线 serving:TensorFlow Serving / Triton
  • 多目标优化是否必要?

阶段四:重排与体验(3 分钟)

  • 多样性:MMR、类目打散
  • 新颖性:EE 问题、Bandit 算法
  • 业务规则:频率控制、负反馈

阶段五:系统与工程(3 分钟)

  • 数据流:Kafka + Flink + Feature Store
  • A/B Test 框架
  • 冷启动处理
  • 监控:CTR、多样性、覆盖率

常见追问

追问回答要点
“如何解决信息茧房?”多样性算法 + 探索机制 + 人工运营干预
“新用户怎么推荐?”基于画像的 CB + 热门 + 快速收集反馈
“推荐结果怎么离线评估?”AUC、GAUC、NDCG、HR@K;线上 A/B Test 为准
“如何实时更新用户兴趣?”Flink 实时特征 + 在线学习 / 近实时模型更新
“推荐去重怎么做?”用户曝光/点击写入 Bloom Filter + Redis Set

关键知识点总结

模块核心技术
召回Item-CF、双塔模型、ANN(HNSW/Faiss)、多路融合
排序DeepFM、DIN、MMoE、特征工程
重排MMR、规则引擎、Bandit、频率控制
工程Kafka + Flink、Feature Store、Model Serving、A/B Test
冷启动CB 兜底、探索机制、新物品扶持、多臂老虎机

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页