X 推荐算法分析

开源链接:https://github.com/xai-org/x-algorithm

一、系统架构概览

X 的"For You"推荐系统采用两阶段推荐架构 ,结合了关注内容发现内容,使用基于Grok的Transformer模型进行排序。

核心组件

  1. Home Mixer - 编排层,负责整个推荐流程的协调
  2. Thunder - 内网内容源,实时内存存储
  3. Phoenix - ML组件,包含检索和排序两个模型
  4. Candidate Pipeline - 可复用的推荐管道框架

二、完整推荐流程

阶段1:请求接收与查询增强

入口: home-mixer/server.rs - get_scored_posts()

rust 复制代码
// 1. 接收gRPC请求
async fn get_scored_posts(
    &self,
    request: Request<pb::ScoredPostsQuery>,
) -> Result<Response<ScoredPostsResponse>, Status>

查询增强器(Query Hydrators):

1.1 UserActionSeqQueryHydrator

位置: home-mixer/query_hydrators/user_action_seq_query_hydrator.rs

功能: 获取用户的交互历史序列

  • 从 User Action Sequence 服务获取用户最近的交互行为
  • 包括:点赞、转发、回复、点击、分享等行为
  • 对行为进行聚合和过滤
  • 截断到最大序列长度(UAS_MAX_SEQUENCE_LENGTH

关键代码:

rust 复制代码
// 获取用户交互序列
let uas_thrift = self.uas_fetcher.get_by_user_id(query.user_id).await;

// 聚合用户行为
let aggregated_actions = self.aggregator.run(&filtered_actions, 
    p::UAS_WINDOW_TIME_MS, 0);

// 截断序列
if aggregated_actions.len() > p::UAS_MAX_SEQUENCE_LENGTH {
    aggregated_actions.drain(0..drain_count);
}
1.2 UserFeaturesQueryHydrator

功能: 获取用户特征

  • 关注列表
  • 用户偏好设置
  • 其他用户元数据

输出: 增强后的查询对象包含:

  • user_action_sequence: 用户交互历史序列
  • user_features: 用户特征(关注列表等)

阶段2:候选内容获取

位置: candidate-pipeline/candidate_pipeline.rs - fetch_candidates()

两个候选源并行执行

2.1 Thunder Source(关注内容)

位置: home-mixer/sources/thunder_source.rs

原理:

  1. Thunder服务架构:

    • 实时数据流: 从Kafka消费推文创建/删除事件
    • 内存存储: 使用PostStore在内存中维护最近的推文
    • 数据结构:
      • posts: 所有推文的完整数据(按post_id索引)
      • original_posts_by_user: 每个用户的原创推文
      • secondary_posts_by_user: 每个用户的回复和转发
      • video_posts_by_user: 每个用户的视频推文
  2. Kafka消费流程:

    rust 复制代码
    // thunder/kafka/tweet_events_listener_v2.rs
    async fn process_tweet_events_v2() {
        loop {
            let messages = consumer.poll(batch_size).await;
            let (light_posts, delete_posts) = deserialize_batch(messages);
            post_store.insert_posts(light_posts);
            post_store.mark_as_deleted(delete_posts);
        }
    }
  3. 查询流程:

    rust 复制代码
    // home-mixer/sources/thunder_source.rs
    let request = GetInNetworkPostsRequest {
        user_id: query.user_id,
        following_user_ids: following_list,  // 关注列表
        max_results: THUNDER_MAX_RESULTS,
    };
    
    // Thunder服务根据关注列表从内存中查找推文
    let response = client.get_in_network_posts(request).await?;
  4. Thunder内部查询逻辑:

    rust 复制代码
    // thunder/thunder_service.rs
    // 从PostStore中获取关注用户的推文
    let all_posts = post_store.get_all_posts_by_users(
        &following_user_ids,
        &exclude_tweet_ids,
        start_time,
        request_user_id,
    );
    
    // 按时间排序(新推文优先)
    let scored_posts = score_recent(all_posts, max_results);

特点:

  • 亚毫秒级查询延迟
  • 自动清理过期推文
  • 支持实时更新
2.2 Phoenix Retrieval Source(发现内容)

位置: home-mixer/sources/phoenix_source.rs

原理:

  1. 两塔模型架构:

    • User Tower: 编码用户特征和交互历史为embedding
    • Candidate Tower: 编码所有推文为embedding
    • 相似度搜索: 使用点积相似度检索Top-K推文
  2. 检索流程:

    rust 复制代码
    // 使用用户交互序列进行检索
    let response = phoenix_retrieval_client.retrieve(
        user_id,
        sequence.clone(),  // 用户交互序列
        PHOENIX_MAX_RESULTS
    ).await?;
  3. Phoenix检索模型实现:

    python 复制代码
    # phoenix/recsys_retrieval_model.py
    class PhoenixRetrievalModel:
        def __call__(self, batch):
            # User Tower: 使用Transformer编码用户
            user_emb = self.model(user_features, history)
            user_emb = normalize(user_emb)  # L2归一化
            
            # Candidate Tower: 编码候选推文
            candidate_emb = self.candidate_tower(post_emb, author_emb)
            candidate_emb = normalize(candidate_emb)
            
            # 相似度计算(点积)
            scores = dot_product(user_emb, candidate_emb)
            
            # 返回Top-K
            return top_k_indices, top_k_scores

特点:

  • 从全局语料库中发现相关内容
  • 基于用户交互历史的个性化检索
  • 使用近似最近邻(ANN)搜索实现高效检索

阶段3:候选内容增强

位置: candidate-pipeline/candidate_pipeline.rs - hydrate()

多个增强器并行执行,为候选推文添加元数据:

3.1 InNetworkCandidateHydrator

标记推文是否来自关注用户

3.2 CoreDataCandidateHydrator

获取推文核心数据:

  • 推文文本
  • 媒体内容
  • 创建时间等
3.3 VideoDurationCandidateHydrator

获取视频推文的时长信息

3.4 SubscriptionHydrator

获取订阅状态信息

3.5 GizmoduckCandidateHydrator

获取作者信息:

  • 用户名
  • 认证状态
  • 作者元数据

阶段4:预评分过滤

位置: candidate-pipeline/candidate_pipeline.rs - filter()

过滤器顺序执行,每个过滤器移除不符合条件的候选:

4.1 DropDuplicatesFilter

移除重复的推文ID

4.2 CoreDataHydrationFilter

移除无法获取核心数据的推文

4.3 AgeFilter

移除过旧的推文(超过MAX_POST_AGE

4.4 SelfTweetFilter

移除用户自己发布的推文

4.5 RetweetDeduplicationFilter

去重转发内容(同一原始推文的多次转发只保留一个)

4.6 IneligibleSubscriptionFilter

移除用户无法访问的付费内容

4.7 PreviouslySeenPostsFilter

移除用户已经看过的推文

4.8 PreviouslyServedPostsFilter

移除本次会话中已经展示过的推文

4.9 MutedKeywordFilter

移除包含用户静音关键词的推文

4.10 AuthorSocialgraphFilter

移除来自被屏蔽/静音作者的推文


阶段5:评分

位置: candidate-pipeline/candidate_pipeline.rs - score()

评分器顺序执行,每个评分器更新候选的分数:

5.1 Phoenix Scorer(ML预测)

位置: home-mixer/scorers/phoenix_scorer.rs

功能: 使用Phoenix Transformer模型预测用户对各种行为的概率

模型架构:

python 复制代码
# phoenix/recsys_model.py
class RecsysModel:
    def __call__(self, batch, embeddings):
        # 输入:
        # - User embedding: [B, 1, D]
        # - History embeddings: [B, S, D]  (S=历史序列长度)
        # - Candidate embeddings: [B, C, D]  (C=候选数量)
        
        # Transformer处理(带候选隔离)
        # 关键:候选之间不能相互关注,只能关注用户和历史
        output = self.transformer(
            user_emb, history_emb, candidate_emb,
            attention_mask=create_candidate_isolation_mask()
        )
        
        # 输出:每个候选的多个行为概率
        logits = [B, C, num_actions]
        return logits

预测的行为类型:

  • 正面行为:favorite, reply, repost, quote, click, profile_click, video_view, photo_expand, share, dwell, follow_author
  • 负面行为:not_interested, block_author, mute_author, report
  • 连续值:dwell_time

关键代码:

rust 复制代码
// home-mixer/scorers/phoenix_scorer.rs
let result = phoenix_client.predict(
    user_id,
    sequence.clone(),  // 用户交互序列
    tweet_infos        // 候选推文信息
).await?;

// 提取预测概率
let phoenix_scores = PhoenixScores {
    favorite_score: p.get(ActionName::ServerTweetFav),
    reply_score: p.get(ActionName::ServerTweetReply),
    retweet_score: p.get(ActionName::ServerTweetRetweet),
    // ... 其他行为
};
5.2 Weighted Scorer

位置: home-mixer/scorers/weighted_scorer.rs

功能: 将多个行为预测组合成最终相关性分数

计算公式:

rust 复制代码
weighted_score = 
    favorite_score × FAVORITE_WEIGHT +
    reply_score × REPLY_WEIGHT +
    retweet_score × RETWEET_WEIGHT +
    click_score × CLICK_WEIGHT +
    // ... 其他正面行为
    - not_interested_score × NOT_INTERESTED_WEIGHT +
    - block_author_score × BLOCK_AUTHOR_WEIGHT +
    // ... 其他负面行为(负权重)

关键代码:

rust 复制代码
fn compute_weighted_score(candidate: &PostCandidate) -> f64 {
    let s = &candidate.phoenix_scores;
    
    let combined_score = 
        apply(s.favorite_score, FAVORITE_WEIGHT) +
        apply(s.reply_score, REPLY_WEIGHT) +
        apply(s.retweet_score, RETWEET_WEIGHT) +
        // ... 所有行为
        - apply(s.not_interested_score, NOT_INTERESTED_WEIGHT) +
        - apply(s.block_author_score, BLOCK_AUTHOR_WEIGHT);
    
    // 分数偏移和归一化
    offset_score(combined_score)
}
5.3 Author Diversity Scorer

位置: home-mixer/scorers/author_diversity_scorer.rs

功能: 降低同一作者多次出现的推文分数,确保信息流多样性

算法:

rust 复制代码
// 按分数排序
ordered.sort_by(|a, b| b.score.cmp(&a.score));

// 对每个作者,第一次出现保持原分数,后续出现按位置衰减
for (candidate, position) in ordered {
    let multiplier = (1.0 - floor) × decay_factor^position + floor;
    adjusted_score = original_score × multiplier;
    author_counts[author_id] += 1;
}

衰减公式:

复制代码
multiplier(position) = (1 - floor) × decay_factor^position + floor
5.4 OON Scorer(发现内容调整)

位置: home-mixer/scorers/oon_scorer.rs

功能: 对发现内容(Out-of-Network)的分数进行调整


阶段6:选择

位置: candidate-pipeline/candidate_pipeline.rs - select()

选择器: TopKScoreSelector
位置: home-mixer/selectors/top_k_score_selector.rs

功能: 按最终分数排序,选择Top-K候选

rust 复制代码
// 按分数降序排序
candidates.sort_by(|a, b| b.score.cmp(&a.score));

// 选择Top-K
candidates.truncate(TOP_K_CANDIDATES_TO_SELECT);

阶段7:选择后处理(

7.1 选择后增强

VFCandidateHydrator: 获取可见性过滤数据

7.2 选择后过滤

VFFilter: 移除被删除、垃圾、暴力、血腥等内容的推文

DedupConversationFilter: 去重同一对话线程的多个分支


三、关键技术设计

1. 无手工特征工程

  • 系统完全依赖Grok-based Transformer从用户交互序列中学习相关性
  • 无需手动设计内容相关性特征
  • 显著降低了数据管道和服务基础设施的复杂度

2. 候选隔离

  • Transformer推理时,候选之间不能相互关注
  • 确保推文分数不依赖于批次中的其他推文
  • 使分数一致且可缓存

3. 基于哈希的嵌入

  • 使用多个哈希函数进行嵌入查找
  • 减少嵌入表大小,提高效率

4. 多行为预测

  • 同时预测多种用户行为(点赞、转发、回复、举报等)
  • 正面和负面行为都有预测,提供更全面的用户偏好信号

5. 可组合的管道架构

  • candidate-pipeline框架提供灵活的推荐管道构建能力
  • 管道执行和监控与业务逻辑分离
  • 支持并行执行和优雅的错误处理
  • 易于添加新的源、增强器、过滤器和评分器

四、数据流图

复制代码
用户请求
    ↓
[Query Hydration]
    ├─ UserActionSeqQueryHydrator → 用户交互序列
    └─ UserFeaturesQueryHydrator → 用户特征(关注列表等)
    ↓
[Candidate Sourcing] (并行)
    ├─ Thunder Source → 关注推文(关注用户的推文)
    └─ Phoenix Retrieval Source → 全局推文(ML发现的推文)
    ↓
[Candidate Hydration] (并行)
    ├─ CoreDataCandidateHydrator → 推文核心数据
    ├─ GizmoduckCandidateHydrator → 作者信息
    ├─ VideoDurationCandidateHydrator → 视频时长
    └─ SubscriptionHydrator → 订阅状态
    ↓
[Pre-Scoring Filters] (顺序)
    ├─ DropDuplicatesFilter
    ├─ AgeFilter
    ├─ SelfTweetFilter
    ├─ MutedKeywordFilter
    └─ ... (10个过滤器)
    ↓
[Scoring] (顺序)
    ├─ Phoenix Scorer → ML预测(多个行为概率)
    ├─ Weighted Scorer → 加权组合分数
    ├─ Author Diversity Scorer → 多样性调整
    └─ OON Scorer → 外网内容调整
    ↓
[Selection]
    └─ TopKScoreSelector → 按分数排序,选择Top-K
    ↓
[Post-Selection Processing]
    ├─ VFCandidateHydrator → 可见性数据
    ├─ VFFilter → 可见性过滤
    └─ DedupConversationFilter → 对话去重
    ↓
[Side Effects]
    └─ CacheRequestInfoSideEffect → 缓存请求信息
    ↓
返回排序后的推文列表

五、性能优化

1. Thunder的内存存储

  • 所有内网推文存储在内存中
  • 亚毫秒级查询延迟
  • 自动清理过期推文

2. 并行执行

  • 候选源并行获取
  • 增强器并行执行
  • 副作用异步执行

3. 候选隔离

  • 使分数可缓存
  • 减少重复计算

4. 批处理

  • Phoenix模型批处理预测
  • Kafka消息批处理
相关推荐
UR的出不克3 小时前
基于Stacking集成学习的乙型肝炎预测模型:从数据到部署的完整实践
人工智能·机器学习·集成学习
罗湖老棍子3 小时前
强迫症冒险家的任务清单:字典序最小拓扑排序
数据结构·算法·图论·拓扑排序
不穿格子的程序员3 小时前
从零开始写算法——回溯篇4:分割回文串 + N皇后
算法·深度优先·dfs
ScilogyHunter3 小时前
qBI有什么用
算法·qbi
TonyLee0173 小时前
半监督学习介绍
人工智能·python·深度学习·机器学习
hjs_deeplearning3 小时前
文献阅读篇#11:自动驾驶中的基础模型:场景生成与场景分析综述(2)
人工智能·机器学习·自动驾驶
Ro Jace4 小时前
On Periodic Pulse Interval Analysis with Outliers and Missing Observations
人工智能·机器学习
龙山云仓4 小时前
No131:AI中国故事-对话荀子——性恶论与AI约束:礼法并用、化性起伪与算法治理
大数据·人工智能·深度学习·算法·机器学习
夏鹏今天学习了吗4 小时前
【LeetCode热题100(90/100)】编辑距离
算法·leetcode·职场和发展