X(原Twitter)推荐算法中文简介
文章目录
X(推特) "为你推荐" 信息流推荐算法文档
源码地址:
概述
本推荐系统是驱动 X 平台 "为你推荐"(For You)信息流的核心算法。它结合了两种内容来源:
- 关注网络内容(In-Network):来自用户关注账户的帖子
- 关注网络外内容(Out-of-Network):通过机器学习召回的全平台内容
所有候选内容使用基于 Grok Transformer 的 Phoenix 模型进行统一排序,该模型预测用户对每条帖子的多种互动概率,最终通过加权组合得出排序分数。
核心特点
- 无人工特征工程:完全依赖 Transformer 模型从用户互动历史中学习相关性
- 多行为预测:模型同时预测多种用户行为(点赞、回复、转发等),而非单一相关性分数
- 候选隔离机制:排序时各候选帖子互不影响,确保评分一致性和可缓存性
系统架构
┌─────────────────────────────────────────────────────────────────────────────┐
│ 用户请求 "为你推荐" 信息流 │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ HOME MIXER (编排层) │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ 查询增强 (Query Hydration) │ │
│ │ • 用户互动历史序列 (UserActionSeqQueryHydrator) │ │
│ │ • 用户特征 (UserFeaturesQueryHydrator): 关注列表、偏好等 │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ 候选召回 (Candidate Sources) │ │
│ │ ┌───────────────────────┐ ┌───────────────────────────┐ │ │
│ │ │ Thunder │ │ Phoenix Retrieval │ │ │
│ │ │ (关注网络内帖子) │ │ (关注网络外帖子召回) │ │ │
│ │ └───────────────────────┘ └───────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ 候选增强 (Hydration) │ │
│ │ 获取帖子元数据、作者信息、视频时长、订阅状态等 │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ 前置过滤 (Pre-Scoring Filters) │ │
│ │ 去重、年龄限制、自发帖子、屏蔽/静音用户、关键词过滤等 │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ 评分 (Scoring) │ │
│ │ ① Phoenix Scorer → ② Weighted Scorer → ③ Author Diversity → ④ OON │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ 选择 (Selection) │ │
│ │ 按最终分数排序,选取 Top K 候选 │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ 后置过滤 (Post-Selection Filters) │ │
│ │ VF过滤(垃圾/暴力/删除等)、会话去重 │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ 返回排序后的信息流 │
└─────────────────────────────────────────────────────────────────────────────┘
核心组件
Home Mixer(编排层)
位置: home-mixer/
Home Mixer 是整个推荐系统的协调中心,负责组装 "为你推荐" 信息流。它基于 CandidatePipeline 框架实现,包含以下阶段:
| 阶段 | 组件 | 功能描述 |
|---|---|---|
| 查询增强 | UserActionSeqQueryHydratorUserFeaturesQueryHydrator | 获取用户上下文(互动历史、关注列表) |
| 候选召回 | ThunderSourcePhoenixSource | 从 Thunder 和 Phoenix 获取候选帖子 |
| 候选增强 | CoreDataCandidateHydratorGizmoduckCandidateHydrator 等 | 丰富候选帖子的额外数据 |
| 过滤 | 多个 Filter 组件 | 移除不符合条件的候选 |
| 评分 | PhoenixScorerWeightedScorer 等 | 预测互动并计算最终分数 |
| 选择 | TopKScoreSelector | 按分数排序并选取 Top K |
| 副作用 | CacheRequestInfoSideEffect | 缓存请求信息供后续使用 |
服务通过 gRPC 端点 ScoredPostsService 对外提供服务。
Thunder(实时帖子存储)
位置: thunder/
Thunder 是一个内存帖子存储和实时数据摄取管道,负责追踪所有用户的近期帖子。
核心功能
- 实时消费:从 Kafka 消费帖子创建/删除事件
- 分类存储:为每个用户维护三类帖子索引:
- 原创帖子(非回复、非转发)
- 次级帖子(回复和转发)
- 视频帖子
- 快速查询:为请求用户的关注列表提供亚毫秒级查询
- 自动清理:自动删除超过保留期的旧帖子
数据结构
pub struct PostStore {
// 帖子全量数据,按 post_id 索引
posts: Arc<DashMap<i64, LightPost>>,
// 用户原创帖子时间线
original_posts_by_user: Arc<DashMap<i64, VecDeque<TinyPost>>>,
// 用户回复/转发时间线
secondary_posts_by_user: Arc<DashMap<i64, VecDeque<TinyPost>>>,
// 用户视频帖子时间线
video_posts_by_user: Arc<DashMap<i64, VecDeque<TinyPost>>>,
// 已删除帖子集合
deleted_posts: Arc<DashMap<i64, bool>>,
// 帖子保留时间(秒)
retention_seconds: u64,
}
Phoenix(ML模型)
位置: phoenix/
Phoenix 是核心机器学习组件,包含两个主要功能模块:
1. 召回模型(双塔模型)
用于发现关注网络外的相关帖子:
用户塔(User Tower):
- 编码用户特征和互动历史
- 使用 Transformer 处理用户历史序列
- 输出 L2 归一化的用户表示向量
候选塔(Candidate Tower):
- 将帖子和作者嵌入投影到共享空间
- 使用 MLP 进行特征转换
- 输出 L2 归一化的候选表示向量
相似度检索:
- 通过点积计算用户-候选相似度
- 使用近似最近邻(ANN)检索 Top-K 候选
# 用户表示构建
user_representation = transformer(user_embeddings + history_embeddings)
user_representation = L2_normalize(mean_pool(user_representation))
# 候选表示构建
candidate_representation = MLP(concat(post_embedding, author_embedding))
candidate_representation = L2_normalize(candidate_representation)
# 相似度计算
scores = user_representation @ corpus_embeddings.T
top_k_indices = top_k(scores, k)
2. 排序模型(Transformer with Candidate Isolation)
用于预测用户对每个候选帖子的互动概率:
输入构建:
序列 = [用户嵌入] + [历史帖子序列] + [候选帖子序列]
(1) (128) (32)
注意力掩码机制(关键创新):
- 用户+历史部分:标准因果注意力
- 候选部分:只能关注用户+历史和自身,不能关注其他候选
def make_recsys_attn_mask(seq_len, candidate_start_offset):
# 基础因果掩码
causal_mask = tril(ones((seq_len, seq_len)))
# 清零候选-候选注意力
attn_mask[candidate_start_offset:, candidate_start_offset:] = 0
# 恢复候选自注意力(对角线)
for i in range(candidate_start_offset, seq_len):
attn_mask[i, i] = 1
return attn_mask
输出:每个候选的多行为预测概率
Candidate Pipeline(候选管道框架)
位置: candidate-pipeline/
一个可复用的推荐管道框架,定义了以下 Trait:
| Trait | 功能 |
|---|---|
Source | 从数据源获取候选 |
QueryHydrator | 增强查询上下文 |
Hydrator | 为候选添加额外特征 |
Filter | 过滤不应展示的候选 |
Scorer | 计算排序分数 |
Selector | 排序并选择 Top 候选 |
SideEffect | 执行异步副作用(缓存、日志) |
该框架支持并行执行独立阶段,并提供可配置的错误处理和日志记录。
推荐流程
1. 查询增强(Query Hydration)
获取用户上下文信息:
| 增强器 | 获取数据 |
|---|---|
UserActionSeqQueryHydrator | 用户最近128条互动历史(点赞、回复、转发等) |
UserFeaturesQueryHydrator | 关注列表、用户偏好设置 |
2. 候选召回(Candidate Sourcing)
从两个来源获取候选帖子:
Thunder Source(关注网络内)
// 调用 Thunder 获取关注用户的帖子
let request = GetInNetworkPostsRequest {
user_id: query.user_id,
following_user_ids: query.user_features.followed_user_ids,
max_results: THUNDER_MAX_RESULTS,
...
};
Phoenix Source(关注网络外)
// 调用 Phoenix 召回服务
let response = phoenix_retrieval_client
.retrieve(user_id, user_action_sequence, max_results)
.await;
3. 候选增强(Candidate Hydration)
为每个候选帖子获取额外信息:
| 增强器 | 获取数据 |
|---|---|
InNetworkCandidateHydrator | 标记是否来自关注网络 |
CoreDataCandidateHydrator | 帖子核心元数据(文本、媒体等) |
VideoDurationCandidateHydrator | 视频时长 |
SubscriptionHydrator | 订阅状态 |
GizmoduckCandidateHydrator | 作者信息(用户名、认证状态) |
4. 过滤(Filtering)
前置过滤(评分前)
| 过滤器 | 功能 |
|---|---|
DropDuplicatesFilter | 去除重复帖子 ID |
CoreDataHydrationFilter | 移除元数据获取失败的帖子 |
AgeFilter | 移除超过最大年龄的帖子 |
SelfTweetFilter | 移除用户自己的帖子 |
RetweetDeduplicationFilter | 对相同内容的转发去重 |
IneligibleSubscriptionFilter | 移除用户无权访问的付费内容 |
PreviouslySeenPostsFilter | 移除用户已看过的帖子 |
PreviouslyServedPostsFilter | 移除本次会话已推送的帖子 |
MutedKeywordFilter | 移除包含用户静音关键词的帖子 |
AuthorSocialgraphFilter | 移除被屏蔽/静音作者的帖子 |
后置过滤(选择后)
| 过滤器 | 功能 |
|---|---|
VFFilter | 移除已删除/垃圾/暴力等违规内容 |
DedupConversationFilter | 对同一会话线程的多个分支去重 |
5. 评分(Scoring)
评分器按顺序执行:
① Phoenix Scorer - ML 预测
调用 Phoenix Transformer 模型,预测用户对每个候选的多种互动概率:
pub struct PhoenixScores {
favorite_score: Option<f64>, // P(点赞)
reply_score: Option<f64>, // P(回复)
retweet_score: Option<f64>, // P(转发)
quote_score: Option<f64>, // P(引用)
click_score: Option<f64>, // P(点击)
profile_click_score: Option<f64>, // P(查看作者主页)
vqv_score: Option<f64>, // P(高质量视频观看)
share_score: Option<f64>, // P(分享)
dwell_score: Option<f64>, // P(停留)
dwell_time: Option<f64>, // 预测停留时长
follow_author_score: Option<f64>, // P(关注作者)
not_interested_score: Option<f64>,// P(不感兴趣)
block_author_score: Option<f64>, // P(屏蔽作者)
mute_author_score: Option<f64>, // P(静音作者)
report_score: Option<f64>, // P(举报)
...
}
② Weighted Scorer - 加权组合
将多种预测概率加权组合成单一分数:
fn compute_weighted_score(candidate: &PostCandidate) -> f64 {
let s = &candidate.phoenix_scores;
// 正向行为(正权重)
let positive_score =
s.favorite_score * FAVORITE_WEIGHT
+ s.reply_score * REPLY_WEIGHT
+ s.retweet_score * RETWEET_WEIGHT
+ s.share_score * SHARE_WEIGHT
+ s.dwell_score * DWELL_WEIGHT
+ s.follow_author_score * FOLLOW_AUTHOR_WEIGHT
+ ...;
// 负向行为(负权重,惩罚)
let negative_score =
s.not_interested_score * NOT_INTERESTED_WEIGHT // 负值
+ s.block_author_score * BLOCK_AUTHOR_WEIGHT // 负值
+ s.mute_author_score * MUTE_AUTHOR_WEIGHT // 负值
+ s.report_score * REPORT_WEIGHT; // 负值
positive_score + negative_score
}
加权公式:

其中:
- 正向行为(点赞、转发、分享等)权重为正
- 负向行为(屏蔽、静音、举报等)权重为负
③ Author Diversity Scorer - 作者多样性
防止同一作者的帖子在信息流中过度集中:
impl AuthorDiversityScorer {
fn multiplier(&self, position: usize) -> f64 {
// position: 该作者当前帖子是本次推送中第几个
// decay_factor: 衰减因子(默认约0.5)
// floor: 最低衰减系数(默认约0.3)
(1.0 - self.floor) * self.decay_factor.powf(position as f64) + self.floor
}
}
多样性公式:

其中:
- d = 衰减因子(decay_factor)
- p = 该作者在本次结果中的帖子位置(0-indexed)
- f = 最低衰减系数(floor)
示例(假设 d=0.5, f=0.3):
- 第1篇帖子:1.0 x 原始分数
- 第2篇帖子:0.65 x 原始分数
- 第3篇帖子:0.475 x 原始分数
- 后续帖子逐渐趋近 0.3 x 原始分数
④ OON Scorer - 网络外内容调整
对关注网络外的内容应用权重因子:
let updated_score = match candidate.in_network {
Some(false) => base_score * OON_WEIGHT_FACTOR,
_ => base_score,
};
6. 选择(Selection)
pub struct TopKScoreSelector;
impl Selector<ScoredPostsQuery, PostCandidate> for TopKScoreSelector {
fn score(&self, candidate: &PostCandidate) -> f64 {
candidate.score.unwrap_or(f64::NEG_INFINITY)
}
fn size(&self) -> Option<usize> {
Some(TOP_K_CANDIDATES_TO_SELECT)
}
}
按最终分数排序,选取 Top K 个候选返回。
核心算法详解
Phoenix Transformer 排序模型
模型架构
基于 Grok-1 Transformer 架构,针对推荐系统场景进行适配:
@dataclass
class TransformerConfig:
emb_size: int # 嵌入维度
key_size: int # 注意力 key 维度
num_q_heads: int # Query 头数
num_kv_heads: int # Key/Value 头数(GQA)
num_layers: int # Transformer 层数
widening_factor: float # FFN 扩展因子
attn_output_multiplier: float # 注意力输出缩放
关键技术
- RoPE 位置编码:使用旋转位置嵌入处理序列位置信息
- Grouped Query Attention (GQA):减少 KV 头数以提升推理效率
- RMSNorm:使用 RMS 归一化替代 LayerNorm
- SiLU 激活:FFN 层使用 SiLU 激活函数
输入嵌入构建
# 用户嵌入:多哈希合并
user_embedding = projection(concat(hash_1_emb, hash_2_emb))
# 历史嵌入:帖子 + 作者 + 行为 + 产品表面
history_embedding = projection(concat(
post_embeddings,
author_embeddings,
action_embeddings, # 用户对该帖子的行为
product_surface_emb # 来自哪个产品(首页、搜索等)
))
# 候选嵌入:帖子 + 作者 + 产品表面
candidate_embedding = projection(concat(
post_embeddings,
author_embeddings,
product_surface_emb
))
候选隔离注意力掩码
User History[1:S] Cand[1] Cand[2] Cand[3]
User 1 0 0 0 0
Hist[1] 1 1 0 0 0
Hist[S] 1 1 0 0 0
Cand[1] 1 1 1 0 0 ← 只能看到 User+History+自己
Cand[2] 1 1 0 1 0 ← 只能看到 User+History+自己
Cand[3] 1 1 0 0 1 ← 只能看到 User+History+自己
这种设计确保每个候选的评分独立于批次中的其他候选,使得:
- 评分可缓存和复用
- 批次大小不影响单个候选的分数
- 支持增量评分新候选
双塔检索模型
用户塔
def build_user_representation(self, batch, embeddings):
# 1. 构建用户和历史嵌入序列
user_emb = block_user_reduce(user_hashes, user_embeddings)
history_emb = block_history_reduce(
history_post_hashes, history_post_embeddings,
history_author_embeddings, action_embeddings, ...
)
# 2. Transformer 编码
embeddings = concat([user_emb, history_emb], axis=1)
output = transformer(embeddings, padding_mask)
# 3. 均值池化 + L2 归一化
user_repr = mean_pool(output, padding_mask)
user_repr = L2_normalize(user_repr)
return user_repr
候选塔
def build_candidate_representation(self, batch, embeddings):
# 1. 拼接帖子和作者嵌入
post_author = concat([post_embeddings, author_embeddings])
# 2. 双层 MLP
hidden = SiLU(linear_1(post_author))
candidate_repr = linear_2(hidden)
# 3. L2 归一化
candidate_repr = L2_normalize(candidate_repr)
return candidate_repr
检索过程
def retrieve_top_k(user_repr, corpus_embeddings, top_k):
# 点积相似度
scores = user_repr @ corpus_embeddings.T
# 选取 Top-K
top_k_scores, top_k_indices = top_k(scores, k)
return top_k_indices, top_k_scores
加权评分公式
完整权重列表
| 行为类型 | 参数名 | 权重类型 |
|---|---|---|
| 点赞 | FAVORITE_WEIGHT | 正向 |
| 回复 | REPLY_WEIGHT | 正向 |
| 转发 | RETWEET_WEIGHT | 正向 |
| 引用 | QUOTE_WEIGHT | 正向 |
| 点击 | CLICK_WEIGHT | 正向 |
| 查看主页 | PROFILE_CLICK_WEIGHT | 正向 |
| 视频观看 | VQV_WEIGHT | 正向(需视频时长>阈值) |
| 分享 | SHARE_WEIGHT | 正向 |
| 私信分享 | SHARE_VIA_DM_WEIGHT | 正向 |
| 复制链接 | SHARE_VIA_COPY_LINK_WEIGHT | 正向 |
| 停留 | DWELL_WEIGHT | 正向 |
| 停留时长 | CONT_DWELL_TIME_WEIGHT | 正向 |
| 引用点击 | QUOTED_CLICK_WEIGHT | 正向 |
| 关注作者 | FOLLOW_AUTHOR_WEIGHT | 正向 |
| 不感兴趣 | NOT_INTERESTED_WEIGHT | 负向 |
| 屏蔽作者 | BLOCK_AUTHOR_WEIGHT | 负向 |
| 静音作者 | MUTE_AUTHOR_WEIGHT | 负向 |
| 举报 | REPORT_WEIGHT | 负向 |
分数偏移处理
fn offset_score(combined_score: f64) -> f64 {
if WEIGHTS_SUM == 0.0 {
combined_score.max(0.0)
} else if combined_score < 0.0 {
// 负分归一化处理
(combined_score + NEGATIVE_WEIGHTS_SUM) / WEIGHTS_SUM * NEGATIVE_SCORES_OFFSET
} else {
// 正分添加偏移确保正值
combined_score + NEGATIVE_SCORES_OFFSET
}
}
作者多样性算法
算法流程
1. 按 weighted_score 降序排列所有候选
2. 遍历排序后的候选:
for each candidate in sorted_candidates:
position = author_appearance_count[candidate.author_id]
author_appearance_count[candidate.author_id] += 1
multiplier = (1 - floor) * decay^position + floor
candidate.final_score = candidate.weighted_score * multiplier
3. 结果:同一作者的后续帖子分数被衰减
效果示例
假设用户 A 的 3 条帖子原始分数都是 100:
| 帖子 | 位置 | 衰减系数 | 最终分数 |
|---|---|---|---|
| A-1 | 0 | 1.0 | 100 |
| A-2 | 1 | 0.65 | 65 |
| A-3 | 2 | 0.475 | 47.5 |
这确保了即使某个作者内容质量很高,也不会霸占信息流。
关键设计决策
1. 无人工特征工程
系统完全依赖 Grok Transformer 从用户互动序列中学习内容相关性,不使用手工设计的内容相关性特征。
优势:
- 大幅简化数据管道和服务基础设施
- 模型可以发现人类难以定义的复杂模式
- 易于维护和迭代
2. 候选隔离机制
排序推理时,候选之间不能互相注意,只能关注用户上下文。
优势:
- 评分一致性:同一候选在不同批次中得分相同
- 可缓存性:候选评分可以缓存复用
- 可扩展性:支持增量评分新候选
3. 基于哈希的嵌入
使用多个哈希函数进行嵌入查找,而非直接的 ID 查找。
优势:
- 处理新实体(新用户、新帖子)无需更新嵌入表
- 内存效率高
- 天然支持冷启动
4. 多行为预测
模型预测多种用户行为概率,而非单一 "相关性" 分数。
优势:
- 可解释性:理解为什么推荐某内容
- 灵活性:可以根据业务需求调整权重
- 负向信号:可以利用负面行为(举报、屏蔽)降低低质内容排名
5. 可组合的管道架构
candidate-pipeline 框架提供了灵活的推荐管道构建能力:
- 业务逻辑与管道执行/监控分离
- 支持独立阶段并行执行
- 优雅的错误处理
- 易于添加新的数据源、过滤器、评分器
总结
核心是基于 Grok Transformer 的 Phoenix 模型。系统通过双塔模型进行高效召回,通过带候选隔离的 Transformer 进行精准排序,最后通过加权组合和多样性调整得出最终排名。
强调简洁性(无人工特征)、一致性(候选隔离)和可扩展性(可组合管道)。
文章作者 pengxiaochao
上次更新 2026-01-21
许可协议 不允许任何形式转载。