AI个性化推荐在视频平台的应用:从召回、排序到重排的全链路优化
一、背景与问题定义
推荐系统是视频平台的核心引擎。一个千万 DAU 的平台,每天产生数十亿次推荐请求,每次请求需要在 200ms 内从数百万候选视频中筛选出 20~40 个结果。这背后的核心挑战不是"算得准",而是"算得快且准"——延迟约束下,模型的复杂度有硬上限。
推荐系统的标准架构分为三层:召回(从百万到千)、排序(从千到百)、重排(从百到几十)。每一层都有独特的约束条件和优化目标,不可混为一谈。本文从工程实现的角度复盘三层架构的设计细节,并重点讨论冷启动的解决策略。
二、全链路推荐架构
召回层的多路设计
3.1 协同过滤召回
经典的 ItemCF:基于用户的历史观看行为,构建视频与视频的共现矩阵。两个视频被同一用户观看的时间间隔越短,共现权重越高。
工程实现上,共现矩阵离线计算(Spark 每日更新),在线服务通过 Hologres(阿里云实时数仓)的向量检索接口查询:
@Service
public class CollaborativeRecallChannel {
@Autowired
private HologresClient hologresClient;
public List<RecallItem> recall(long userId, int recallSize) {
// 1. 查询用户最近观看的 Top N 视频
List<UserHistoryItem> recentHistory =
historyService.getRecentViews(userId, 20);
if (recentHistory.isEmpty()) {
return Collections.emptyList();
}
// 2. 对每个历史视频查询其 Top K 相似视频
Set<Long> recallSet = new LinkedHashSet<>();
for (UserHistoryItem item : recentHistory) {
List<Long> similarVideos = hologresClient.querySimilarVideos(
item.getVideoId(), 30);
recallSet.addAll(similarVideos);
}
// 3. 去重并截断
return recallSet.stream()
.limit(recallSize)
.map(vid -> new RecallItem(vid, RecallChannelType.COLLABORATIVE, 0.0))
.collect(Collectors.toList());
}
}
3.2 内容标签召回
利用视频的 AI 标签(参见第 4 篇文章),将用户历史观看视频的标签构建为兴趣向量,然后检索标签相似度最高的视频。这里的关键是"标签衰减"——用户 30 天前看过的美食视频,其兴趣权重应该衰减到 10%。
public class ContentTagRecallChannel {
public List<RecallItem> recall(long userId, int recallSize) {
// 构建用户的兴趣标签向量(时间衰减加权)
Map<String, Double> interestVector = buildInterestVector(userId);
// 对每个高权重标签,检索 Top K 视频
List<RecallItem> results = new ArrayList<>();
for (Map.Entry<String, Double> entry : interestVector.entrySet()) {
if (entry.getValue() < 0.1) continue; // 低权重标签跳过
List<Long> videos = esSearchClient.searchByTag(
entry.getKey(), 20);
for (Long vid : videos) {
results.add(new RecallItem(vid,
RecallChannelType.CONTENT_TAG, entry.getValue()));
}
}
return results.stream()
.distinct()
.sorted(Comparator.comparingDouble(RecallItem::getScore).reversed())
.limit(recallSize)
.collect(Collectors.toList());
}
private Map<String, Double> buildInterestVector(long userId) {
List<UserHistoryItem> history =
historyService.getRecentViews(userId, 200);
Map<String, Double> vector = new HashMap<>();
long now = System.currentTimeMillis();
for (UserHistoryItem item : history) {
double daysAgo = (now – item.getTimestamp()) / (1000.0 * 86400);
double decay = Math.exp(-0.05 * daysAgo); // 指数衰减
for (String tag : item.getTags()) {
vector.merge(tag, decay, Double::sum);
}
}
return vector;
}
}
3.3 实时行为召回
用户在当前会话中刚看完了一个视频,下一步推荐什么?实时行为召回关注的是会话级别的即时兴趣信号——用户刚看完一个足球视频,短时间内推荐更多足球相关内容。
3.4 多路合并与去重
四路召回的结果在内存中合并、去重、并统一赋予初始分(按通道权重加权)。协同过滤得分 ×0.4 + 内容标签得分 ×0.3 + 实时行为得分 ×0.2 + 热度兜底得分 ×0.1。去重后的候选集约 1500~2000 条,送入精排层。
三、精排模型与特征工程
精排模型采用 DeepFM 架构,核心优势是同时建模低阶特征交互(FM 部分)和高阶特征交互(DNN 部分)。特征分为四组:
| 用户侧特征 | 年龄、性别、注册天数、活跃等级、兴趣标签向量 | ~256 维 |
| 视频侧特征 | 时长、品类、标签、CTR、完播率、发布时间 | ~128 维 |
| 上下文特征 | 时刻(早/中/晚)、设备、网络类型、请求位置 | ~32 维 |
| 交叉特征 | 用户-品类交互、用户-时长偏好 | ~64 维 |
所有特征通过统一的 Feature Store 获取,推理延迟约束在 50ms 以内。模型使用 TensorFlow Serving 部署,每个请求走一次前向推理,产出 200 个视频的预估 CTR。
四、重排层的多样性控制
精排的 Top 200 结果可能存在"信息茧房"——全是同一品类、同一作者的视频。重排层通过 MMR(Maximal Marginal Relevance)算法做多样性打散:
public class RerankService {
public List<VideoItem> rerank(List<VideoItem> candidates,
UserProfile user, int resultSize) {
List<VideoItem> selected = new ArrayList<>();
List<VideoItem> remaining = new ArrayList<>(candidates);
double lambda = 0.6; // 相关性 vs 多样性权衡
for (int i = 0; i < resultSize && !remaining.isEmpty(); i++) {
VideoItem best = null;
double bestScore = Double.NEGATIVE_INFINITY;
for (VideoItem item : remaining) {
double relevance = item.getCtrScore();
double diversity = 1.0 – maxSimilarity(item, selected);
double mmrScore = lambda * relevance + (1 – lambda) * diversity;
// 新鲜度奖金:24小时内发布的视频 +0.05
if (isRecent(item, 24)) {
mmrScore += 0.05;
}
if (mmrScore > bestScore) {
bestScore = mmrScore;
best = item;
}
}
selected.add(best);
remaining.remove(best);
}
return selected;
}
private double maxSimilarity(VideoItem item, List<VideoItem> selected) {
if (selected.isEmpty()) return 0.0;
return selected.stream()
.mapToDouble(s -> cosineSimilarity(item.getEmbedding(), s.getEmbedding()))
.max()
.orElse(0.0);
}
}
冷启动用户的处理:新用户无历史数据,采用"试探→反馈→调整"的策略。初次推荐时,20% 的位置给热门视频(探针),60% 给所在地区/年龄段的热门视频(人群统计),20% 给随机品类视频(发现新兴趣)。后续根据用户对三类内容的完播率和互动率,逐步调整比例。
五、总结
推荐系统的全链路优化是"木桶效应"的典型场景:召回覆盖不够,精排再准也没用;重排缺乏多样性,用户刷几条就审美疲劳。三层架构的设计让每层聚焦各自的约束条件——召回追求覆盖率,精排追求准确性,重排追求体验多样性。
后续方向:引入多目标优化(同时优化 CTR、完播率、关注转化率);利用强化学习建模长期用户满意度(而非单次点击);以及构建实时特征更新通道(将特征从 T+1 更新提升到分钟级),缩小离线训练与在线服务的 gap。



