X For You フィードアルゴリズム - アーキテクチャ仕様書
#概要
X For You フィードアルゴリズムは、ユーザーに最も関連性の高いコンテンツを提供する推薦システムです。 本システムは2つのソースからコンテンツを取得し、Grokベースのトランスフォーマーモデル (Phoenix) を使用してランキングを行います。
主要コンポーネント
| コンポーネント | 役割 | 実装言語 |
|---|---|---|
| Home Mixer | オーケストレーション層、パイプライン実行 | Rust |
| Thunder | インネットワーク投稿のリアルタイム配信 | Rust |
| Phoenix | ML予測(検索・ランキング) | Python/JAX |
| Candidate Pipeline | パイプラインフレームワーク | Rust |
設計原則
手作業による特徴量エンジニアリングの排除
Grokトランスフォーマーがユーザーのエンゲージメント履歴から関連性を学習
候補間の独立性
ランキング時、候補同士はアテンションしない(スコアの一貫性とキャッシャビリティを確保)
ハッシュベース埋め込み
複数のハッシュ関数による埋め込みルックアップ
マルチアクション予測
単一の関連性スコアではなく、複数のアクション確率を予測
#システムアーキテクチャ全体図
HOME MIXER (オーケストレーション層)
gRPC: ScoredPostsServiceInNetworkPostsService
RetrievalService
PredictionService
Gizmoduck, TES, Strato...
#8段階パイプライン詳細
Home Mixerが実行するパイプラインの各ステージ
Query Hydration
リクエストに必要なユーザーコンテキスト情報を取得
- -UserActionSeqQueryHydrator: エンゲージメント履歴取得
- -UserFeaturesQueryHydrator: フォローリスト、設定等取得
- -両Hydratorは並列実行 (join_all)
Candidate Sources
2つのソースから候補投稿を取得
- -Thunder: インネットワーク投稿 (メモリ内ストア)
- -Phoenix Retrieval: アウトオブネットワーク (Two-Tower Model)
- -両ソースは並列実行
Hydration
候補に追加データを付与
- -CoreDataCandidateHydrator: 投稿メタデータ
- -GizmoduckCandidateHydrator: 著者情報
- -VideoDurationCandidateHydrator: 動画長
- -SubscriptionHydrator: サブスクリプション状態
Pre-Scoring Filters
スコアリング前に不適格な候補を除外
- -DropDuplicatesFilter: 重複投稿IDを除外
- -AgeFilter: MAX_POST_AGE より古い投稿を除外
- -MutedKeywordFilter: ミュートキーワード含む投稿を除外
- -AuthorSocialgraphFilter: ブロック/ミュート済み著者を除外
Scoring
ML予測を実行し、最終スコアを計算
- -PhoenixScorer: Grok Transformerで19種類の確率予測
- -WeightedScorer: 重み付け合計スコア計算
- -AuthorDiversityScorer: 同一著者スコア減衰
- -OONScorer: Out-of-Networkスコア調整
Selection
スコア順にソートし、上位K件を選択
- -TopKScoreSelector: 降順ソート
- -K = params::RESULT_SIZE (設定可能)
- -スコアが高い順にカットオフ
Post-Selection Processing
選択後の最終検証とフィルタリング
- -VFCandidateHydrator: 可視性フィルタリングデータ取得
- -VFFilter: 削除/スパム/暴力コンテンツ除外
- -DedupConversationFilter: 会話スレッド重複排除
Side Effects
非同期の副作用処理(キャッシュ、ロギング等)
- -CacheRequestInfoSideEffect: リクエスト情報キャッシュ
- -レスポンスをブロックしない (fire-and-forget)
- -並列実行 (tokio::spawn)
#gRPCサービス構成
Home Mixer Service
Port: 50051メインのオーケストレーションサービス。クライアントからのリクエストを受け、パイプラインを実行
RPC: GetScoredPostsThunder Service
Port: 50052インネットワーク投稿を高速に取得。Zstd圧縮対応
RPC: GetInNetworkPostsPhoenix Prediction Service
Port: 50053ユーザーアクションシーケンスと候補からエンゲージメント確率を予測
RPC: PredictPhoenix Retrieval Service
Port: 50054ユーザー特徴からTop-Kアウトオブネットワーク候補を取得
RPC: Retrieve外部サービス依存関係
| サービス名 | 役割 | 使用コンポーネント |
|---|---|---|
| Gizmoduck | ユーザープロフィール情報 | GizmoduckCandidateHydrator |
| TES (Tweet Entity Service) | ツイートメタデータ | CoreDataCandidateHydrator等 |
| Strato | KVストア/設定 | UserFeaturesQueryHydrator, CacheSideEffect |
| SocialGraph | フォロー/ブロック関係 | AuthorSocialgraphFilter |
| VisibilityFiltering | コンテンツ可視性 | VFFilter |
| UAS | ユーザーアクション履歴 | UserActionSeqQueryHydrator |
#データモデルとスキーマ
Core Fields
user_id: i64- リクエストユーザーIDclient_app_id: i32- クライアントアプリ識別子country_code: String- 国コードlanguage_code: String- 言語コードseen_ids: Vec<i64>- 既読投稿IDserved_ids: Vec<i64>- 既配信投稿ID
Hydrated Fields
user_action_sequence- エンゲージメント履歴user_features- フォローリスト、ミュートキーワード等request_id: String- トレーシング用ID
Positive Engagement
favorite_scorereply_scoreretweet_scorequote_scoreclick_scoreprofile_click_scorephoto_expand_scorevqv_scoreshare_scoredwell_scorefollow_author_scoredwell_timeNegative Engagement
not_interested_scoreblock_author_scoremute_author_scorereport_scorepub struct PostStore {
posts: Arc<DashMap<i64, LightPost>>, // post_id -> 完全なポストデータ
original_posts_by_user: Arc<DashMap<i64, VecDeque<TinyPost>>>, // user_id -> オリジナル投稿
secondary_posts_by_user: Arc<DashMap<i64, VecDeque<TinyPost>>>, // user_id -> リプライ/RT
video_posts_by_user: Arc<DashMap<i64, VecDeque<TinyPost>>>, // user_id -> 動画投稿
deleted_posts: Arc<DashMap<i64, bool>>, // 削除済み投稿
retention_seconds: u64, // 保持期間
request_timeout: Duration, // リクエストタイムアウト
}#コンポーネント間の通信フロー
クライアントからのフィードリクエスト
UAS, Stratoからユーザー情報取得
候補ソースから投稿取得 (並列)
候補データ補完
内部処理 - 外部コール無し
ML予測実行
内部処理 - ソート + 切り詰め
可視性フィルタリング
キャッシュ更新 (非ブロック)
#MLモデルアーキテクチャ
[B, num_candidates, num_actions]
GROK TRANSFORMER (N layers)
- - num_q_heads: Queryヘッド数
- - num_kv_heads: Key/Valueヘッド数 (GQA対応)
- - Rotary Position Embedding (RoPE)
- - Candidate Isolation Attention Mask
- - Linear V: [D] → [ffn_size]
- - Linear W1 + GELU: [D] → [ffn_size]
- - Element-wise multiply
- - Linear: [ffn_size] → [D]
INPUT CONSTRUCTION
Multiple hash functions → embedding lookup → concat → project
候補同士が互いを参照できないようにする特殊なアテンションマスク:
双方向アテンション (互いに参照可能)
候補はユーザーコンテキストを参照可能
候補間は参照不可 (自己参照のみ)
- - スコアの一貫性: 候補のスコアがバッチ内の他の候補に依存しない
- - キャッシャビリティ: 同一 (user, candidate) ペアは常に同じスコア
- - 並列推論: バッチサイズを任意に変更可能
USER TOWER
- - Grok Transformer (候補分離なし)
- - Mean Pooling over valid positions
- - L2 Normalization
- - 出力: user_representation [B, D]
オンラインでリアルタイム計算
CANDIDATE TOWER
- - Hash Embeddings (post + author)
- - MLP Projection (2-layer + SiLU)
- - L2 Normalization
- - 出力: corpus_embeddings [N, D]
オフラインで事前計算、インデックス化
dot(user_emb, corpus_emb.T) → ANN search (FAISS, ScaNN)#運用考慮事項
スケーラビリティ
| コンポーネント | スケーリング戦略 |
|---|---|
| Home Mixer | 水平スケーリング(ステートレス) |
| Thunder | シャーディング(ユーザーID範囲) |
| Phoenix Prediction | GPU クラスタ、バッチ処理 |
| Phoenix Retrieval | ANN インデックス + レプリカ |
エラーハンドリング戦略
| ステージ | 失敗時の動作 |
|---|---|
| Query Hydration | エラーログ記録、デフォルト値で続行 |
| Thunder Source | スキップ、Phoenix のみで続行 |
| Phoenix Source | スキップ、Thunder のみで続行 |
| Hydration | 部分データで続行 |
| Phoenix Scoring | キャッシュスコア使用、または 0 スコア |
| VF Filter | 全候補通過(フェイルオープン) |
設定パラメータ
| パラメータ | デフォルト値 | 説明 |
|---|---|---|
| MAX_POST_AGE | 172800s (2日) | 投稿の最大経過時間 |
| RESULT_SIZE | 50 | 返却する投稿数 |
| MAX_POSTS_TO_RETURN | 1500 | Thunder から取得する最大投稿数 |
| MAX_INPUT_LIST_SIZE | 5000 | フォローリストの最大サイズ |
| RETENTION_SECONDS | 172800s | Thunder の投稿保持期間 |