抖音的核心增长来自于其 Feed流的极致推荐体验,你刷的每一条短视频背后,都是一个复杂的排序系统在做“个性化判断”。本篇将从业务层拆解排序流程,再结合 Node.js 演示一个简化版 Feed 流排序系统。
🧭 一、Feed 流的推荐流程是什么?
Feed 流排序通常分为以下五个阶段:
- 召回(Recall) :根据兴趣/社交/热度快速筛出 10w+
- 初筛(Pre-filter) :剔除低质内容、黑名单、频繁内容
- 粗排(Rough Rank) :根据多个模型快速打分
- 精排(Fine Rank) :深度模型精确打分
- 重排/策略干预(Re-Rank) :保证新内容、多样性等
🔍 二、字节跳动如何设计 Feed 排序?
-
内容打分 = ctr × 质量 × 新鲜度 × 策略权重
-
策略干预(混排/强插) :
- 强插广告、热点内容、新创作者
-
Feed 多样性控制:
- 限制连刷相同风格内容(避免审美疲劳)
⚙️ 三、Node.js 实现一个简化版 Feed 排序原型
1. 内容源模拟(假设我们有100条短视频)
const contentPool = Array.from({ length: 100 }, (_, i) => ({
id: i,
ctr: Math.random(), // 点击率预估
quality: Math.random(), // 视频质量得分
freshness: Math.random(), // 新鲜度打分
isHot: Math.random() > 0.9, // 热门标记
}));
2. 排序打分函数设计
function calculateScore(item) {
let score = item.ctr * 0.4 + item.quality * 0.4 + item.freshness * 0.2;
if (item.isHot) score += 0.1; // 热点内容加权
return score;
}
3. 完整推荐流程模拟
function getFeed(userId, count = 10) {
const filtered = contentPool.filter(item => item.quality > 0.2); // 过滤低质
const scored = filtered.map(item => ({
...item,
score: calculateScore(item),
}));
const sorted = scored.sort((a, b) => b.score - a.score); // 排序
return sorted.slice(0, count);
}
console.log("推荐内容:", getFeed(123));
4. 输出示例:
推荐内容:
[
{ id: 28, ctr: 0.92, quality: 0.91, freshness: 0.68, score: 0.843 },
{ id: 15, ctr: 0.85, quality: 0.83, freshness: 0.71, score: 0.802 },
...
]
🧠 四、工程中的复杂度来自哪里?
| 模块 | 难点 |
|---|---|
| 精排模型 | Deep CTR/DSSM/DIN 等深度模型 |
| 多样性 | 类别隔离、兴趣切换判定 |
| 实时性 | 用户行为、内容入库实时更新 |
| 策略系统 | AB 实验、运营内容优先级干预 |
✍️ 五、总结与思考
- 抖音排序系统是“模型 + 策略 + 实时性”的综合体现
- 高点击率≠高排序得分,排序目标是长留存 +满意度最大化
- 简化版本帮助我们理解:Feed 本质上是多因子排序
🎁 拓展阅读
- 字节跳动《推荐系统实践总结》技术博客
- 《YouTube 推荐系统设计细节》
- DSSM & DIN 模型解读(知乎)