X(推特) "为你推荐" 信息流推荐算法文档

源码地址:

概述

本推荐系统是驱动 X 平台 "为你推荐"(For You)信息流的核心算法。它结合了两种内容来源:

  1. 关注网络内容(In-Network):来自用户关注账户的帖子
  2. 关注网络外内容(Out-of-Network):通过机器学习召回的全平台内容

所有候选内容使用基于 Grok TransformerPhoenix 模型进行统一排序,该模型预测用户对每条帖子的多种互动概率,最终通过加权组合得出排序分数。

核心特点

  • 无人工特征工程:完全依赖 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 框架实现,包含以下阶段:

阶段组件功能描述
查询增强UserActionSeqQueryHydrator
UserFeaturesQueryHydrator
获取用户上下文(互动历史、关注列表)
候选召回ThunderSource
PhoenixSource
从 Thunder 和 Phoenix 获取候选帖子
候选增强CoreDataCandidateHydrator
GizmoduckCandidateHydrator
丰富候选帖子的额外数据
过滤多个 Filter 组件移除不符合条件的候选
评分PhoenixScorer
WeightedScorer
预测互动并计算最终分数
选择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  # 注意力输出缩放

关键技术

  1. RoPE 位置编码:使用旋转位置嵌入处理序列位置信息
  2. Grouped Query Attention (GQA):减少 KV 头数以提升推理效率
  3. RMSNorm:使用 RMS 归一化替代 LayerNorm
  4. 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-101.0100
A-210.6565
A-320.47547.5

这确保了即使某个作者内容质量很高,也不会霸占信息流。


关键设计决策

1. 无人工特征工程

系统完全依赖 Grok Transformer 从用户互动序列中学习内容相关性,不使用手工设计的内容相关性特征。

优势

  • 大幅简化数据管道和服务基础设施
  • 模型可以发现人类难以定义的复杂模式
  • 易于维护和迭代

2. 候选隔离机制

排序推理时,候选之间不能互相注意,只能关注用户上下文。

优势

  • 评分一致性:同一候选在不同批次中得分相同
  • 可缓存性:候选评分可以缓存复用
  • 可扩展性:支持增量评分新候选

3. 基于哈希的嵌入

使用多个哈希函数进行嵌入查找,而非直接的 ID 查找。

优势

  • 处理新实体(新用户、新帖子)无需更新嵌入表
  • 内存效率高
  • 天然支持冷启动

4. 多行为预测

模型预测多种用户行为概率,而非单一 "相关性" 分数。

优势

  • 可解释性:理解为什么推荐某内容
  • 灵活性:可以根据业务需求调整权重
  • 负向信号:可以利用负面行为(举报、屏蔽)降低低质内容排名

5. 可组合的管道架构

candidate-pipeline 框架提供了灵活的推荐管道构建能力:

  • 业务逻辑与管道执行/监控分离
  • 支持独立阶段并行执行
  • 优雅的错误处理
  • 易于添加新的数据源、过滤器、评分器

总结

核心是基于 Grok Transformer 的 Phoenix 模型。系统通过双塔模型进行高效召回,通过带候选隔离的 Transformer 进行精准排序,最后通过加权组合和多样性调整得出最终排名。

强调简洁性(无人工特征)、一致性(候选隔离)和可扩展性(可组合管道)。