Laravel 2026.01.20

Xのタイムラインアルゴリズム完全解説:候補分離とGrok Transformerの技術

約18分で読めます

xAI社が公開したX(旧Twitter)の推薦アルゴリズムを技術的に深掘り。候補分離アーキテクチャ、Grok Transformerの活用、19種類のエンゲージメント予測、重み設計の哲学まで紹介します。

xAI社が公開したX(旧Twitter)の「For You」タイムラインアルゴリズムのコードを詳細に解析しました。この記事では、推薦システムとして革新的な「候補分離アーキテクチャ」、Grok Transformerの活用方法、そして19種類のエンゲージメント予測を組み合わせたスコアリングロジックについて、技術者向けに深く解説します。

はじめに:なぜXのアルゴリズムは特別なのか

2025年、xAI社はXの推薦アルゴリズムをGitHubで公開しました(https://github.com/xai-org/x-algorithm)。このリポジトリには、数億ユーザーの「For You」タイムラインを支えるコア実装が含まれています。

一般的な推薦システムと大きく異なるのは、候補が互いに影響しない設計です。通常、推薦システムは「候補A、B、Cを並べて比較してランク付け」しますが、Xは各候補を独立してスコアリングします。これにより、スコアのキャッシュが可能になり、バッチ構成に依存しない一貫性が保たれます。

リポジトリの基本情報

  • 言語構成: Rust 62.9% + Python 37.1%
  • ライセンス: Apache 2.0
  • 主要モジュール: home-mixer(オーケストレーション)、thunder(In-network投稿ストア)、phoenix(ML検索・ランキング)、candidate-pipeline(汎用フレームワーク)

アーキテクチャ概要:ThunderとPhoenixの2系統統合

Xのタイムラインは、2つの異なる情報源を統合しています。

graph TB
    User[ユーザーリクエスト] --> HomeMixer[Home Mixer<br/>統合レイヤー]
    
    HomeMixer --> Thunder[Thunder<br/>In-Network]
    HomeMixer --> Phoenix[Phoenix<br/>Out-of-Network]
    
    Thunder --> ThunderStore[(インメモリストア<br/>2日分の投稿)]
    Phoenix --> TwoTower[Two-Tower Retrieval<br/>ML検索]
    
    ThunderStore --> Candidates1[約1000件の候補]
    TwoTower --> Candidates2[約1000件の候補]
    
    Candidates1 --> Merge[候補統合<br/>約2000件]
    Candidates2 --> Merge
    
    Merge --> Filters[13種類のフィルター]
    Filters --> Scorers[4段階のスコアリング]
    Scorers --> TopK[Top-K選択<br/>約50件]
    
    TopK --> Timeline[For Youタイムライン]

Thunder(In-Network)

役割: フォロー中のユーザーの投稿を高速に提供

pub struct PostStore {
    // 完全な投稿データ
    posts: DashMap<PostId, LightPost>,
    
    // ユーザーごとのタイムライン(軽量参照)
    original_posts_by_user: DashMap<UserId, VecDeque<TinyPost>>,
    secondary_posts_by_user: DashMap<UserId, VecDeque<TinyPost>>,
    video_posts_by_user: DashMap<UserId, VecDeque<TinyPost>>,
}

// 軽量参照(16バイト)
struct TinyPost {
    post_id: u64,
    created_at: i64,  // Snowflake timestamp
}

特徴:

  • 完全インメモリ: DBアクセスなしでサブミリ秒応答
  • 2日分保持: 古い投稿は自動削除
  • DashMap使用: 並行読み書き可能なハッシュマップ

Phoenix(Out-of-Network)

役割: 未フォローのユーザーの投稿をML検索で発見

Two-Tower Retrievalを使用して、数百万の候補から約1000件に絞り込みます。

class PhoenixRetrievalModel:
    def encode_user(self, batch, embeddings):
        # User Tower: Transformerでユーザー履歴をエンコード
        user_emb = self.user_embedding(batch)
        history_embs = self.history_embedding(batch)
        
        # Grok Transformer適用
        transformer_out = self.grok_transformer(
            concat([user_emb, history_embs]),
            mask=None
        )
        
        # User表現取得(L2正規化)
        user_repr = normalize(transformer_out[:, 0, :])
        return user_repr
    
    def retrieve(self, user_repr, corpus_embeddings, top_k=1000):
        # ドット積類似度でTop-K取得
        scores = user_repr @ corpus_embeddings.T
        top_k_indices = jax.lax.top_k(scores, k=top_k)[1]
        return top_k_indices

候補分離アーキテクチャ:推薦システムの常識を覆す設計

通常の推薦システムとの違い

従来の推薦システム:

候補A、B、Cを一緒にTransformerに入力
→ A、B、Cが互いに影響し合う
→ バッチ構成が変わるとスコアも変わる
→ キャッシュ不可

Xの候補分離アーキテクチャ:

候補Aは「ユーザー、履歴」のみ見る
候補Bは「ユーザー、履歴」のみ見る
候補Cは「ユーザー、履歴」のみ見る
→ お互いに影響しない
→ バッチ構成に依存しない
→ スコアキャッシュ可能

アテンションマスクによる実装

候補分離は、Transformerのアテンションマスクで実現されます。

def make_recsys_attn_mask(
    user_size: int,      # 1 (user embedding)
    history_size: int,   # S (履歴投稿数)
    candidate_size: int, # C (候補投稿数)
) -> Array:
    """
    マスク構造:
    
            User  History(1..S)  Candidates(1..C)
    User      ○      ○             ○
    Hist(1)   ○      ○             ×
    Hist(S)   ○      ○             ×
    Cand(1)   ○      ○             ○ (自分のみ)
    Cand(C)   ○      ○             ○ (自分のみ)
    
    候補は:
    - User embeddingに注意できる
    - 履歴投稿に注意できる
    - 自分自身に注意できる
    - 他の候補に注意できない ← 候補分離の核心
    """
    
    total_size = user_size + history_size + candidate_size
    mask = jnp.ones((total_size, total_size))
    
    # 候補同士のアテンションをブロック
    cand_start = user_size + history_size
    for i in range(candidate_size):
        for j in range(candidate_size):
            if i != j:
                mask[cand_start + i, cand_start + j] = 0
    
    return mask

候補分離のメリット

  1. スコアの一貫性: 同じユーザー・候補なら、他の候補の有無に関わらず同じスコア
  2. キャッシュ可能: 候補ごとのスコアを事前計算して保存できる
  3. A/Bテスト公平性: アルゴリズム変更の影響を正確に測定できる
  4. スケーラビリティ: 候補を個別に評価できるため、並列化しやすい

Grok Transformerの技術詳細

XのアルゴリズムはGrok-1からTransformer技術を移植しています。

アーキテクチャ

class Transformer(hk.Module):
    def __init__(self, config):
        self.num_layers = config.num_layers  # 2
        self.emb_size = config.emb_size      # 128
        self.layers = [DecoderLayer(config) for _ in range(num_layers)]
    
    def __call__(self, embeddings, mask):
        x = embeddings  # [B, T, D]
        
        for layer in self.layers:
            x = layer(x, mask)
        
        return x

class DecoderLayer(hk.Module):
    def __call__(self, x, mask):
        # 1. Pre-norm + Multi-Head Attention + Residual
        normed = RMSNorm(x)
        attn_out = MHABlock(normed, mask)
        x = x + attn_out
        
        # 2. Pre-norm + FFN + Residual
        normed = RMSNorm(x)
        ffn_out = DenseBlock(normed)
        x = x + ffn_out
        
        return x

Grok-1からの移植要素

技術 説明
RoPE Rotary Position Embedding(位置エンコーディング)
GQA Grouped Query Attention(KVヘッド数 < Qヘッド数)
SwiGLU Activation関数(Swish × GLU)
RMSNorm Root Mean Square Layer Normalization
Pre-normalization アテンション/FFNの前に正規化

スコアリングロジック:19種類のエンゲージメント予測

マルチアクション予測

Xのモデルは、1つの候補に対して19種類のエンゲージメント確率を同時に予測します。

actions = [
    "favorite",              # いいね
    "reply",                 # リプライ
    "retweet",              # リツイート
    "quote",                # 引用RT
    "photo_expand",         # 画像拡大
    "click",                # クリック
    "profile_click",        # プロフィールクリック
    "video_quality_view",   # 動画再生
    "share",                # シェア
    "share_via_dm",         # DM共有
    "share_via_copy_link",  # リンクコピー
    "dwell",                # 滞在
    "quoted_click",         # 引用先クリック
    "follow_author",        # フォロー
    "not_interested",       # 興味なし
    "block_author",         # ブロック
    "mute_author",          # ミュート
    "report",               # 報告
    "dwell_time",           # 滞在時間(連続値)
]

重み設計の哲学

アクション 重み 理由
フォロー +12 新しいフォローは最強のポジティブシグナル
DM共有 +10 個人的な共有は高価値
リプライ +9 会話が生まれるのは重要
いいね +2 片手間でできるため軽い
リツイート +1 ボタン1つなので軽い
通報 -500 最悪のシグナル
ブロック -200 強い拒絶
ミュート -100 中程度の拒絶
興味なし -50 軽い拒絶

ネガティブシグナルの重みが桁違いに大きい理由

ポジティブシグナルの合計が+30程度なのに対し、ネガティブシグナルは-500まであります。これは「嫌われたら終わり」という設計思想を表しています。

Xが最適化しているのは単なるエンゲージメント最大化ではなく、「ユーザーが嫌がらないレベルで、有意義な会話を生む投稿を優先」することです。

ランキング調整:多様性とIn/Out-of-Network

著者多様性スコア

同じ著者の投稿が連続すると、スコアが減衰します。

// AuthorDiversityScorer
DIVERSITY_DECAY = 0.5;    // 50%減衰
DIVERSITY_FLOOR = 0.2;    // 最低20%維持

// 減衰の推移:
// 1回目: 100% (初出)
// 2回目:  60%
// 3回目:  40%
// 4回目:  30%
// 5回目以降: 20%

Out-of-Network候補のペナルティ

未フォローの投稿には、最終的に0.75倍のペナルティが適用されます。

// OONScorer
In-network候補 (score=100) → 100 (変更なし)
Out-of-network候補 (score=100) → 75 (25%減少)

これにより、「知らない人のバズツイート」より「フォロー中の普通の投稿」が優先される仕組みになっています。

実装技術の詳細

Rust + Pythonのハイブリッド構成

言語 担当領域 理由
Rust (62.9%) パイプライン、サーバー、ストア 高速、並行性、メモリ安全性
Python (37.1%) ML推論、モデル定義 JAX、NumPy、ML生態系

Bloomフィルターによる既読管理

// PreviouslySeenPostsFilter
BloomFilter {
    size: 10000,
    hash_count: 3,
    false_positive_rate: ~1%
}

特性:

  • 偽陽性あり: 見てないのに「見た」と判定される可能性が約1%
  • 偽陰性なし: 見たものを「見てない」と判定することはない
  • 超軽量: 10000エントリでも数KBのメモリ

なぜBloom Filterを使うのか

完璧な既読管理(ハッシュセット)だと、数万の投稿IDを保持する必要があります。Bloom Filterなら偽陽性1%を許容して、メモリを大幅に削減できます。

設計思想の考察

なぜ候補分離なのか

  1. スコアの一貫性: 同じ候補なら、他の候補の有無に関わらず同じスコア
  2. キャッシュ戦略: 候補ごとにスコアを事前計算できる
  3. A/Bテスト: アルゴリズム変更の影響を正確に測定
  4. スケーラビリティ: 候補を個別評価→並列化しやすい

Xが最適化している価値

Xは単なる「エンゲージメント最大化」ではなく、**「ユーザーが嫌がらないレベルで、有意義な会話を生む投稿を優先」**しています。

証拠:

  • リプライの重み(+9)が、いいね(+2)より大幅に高い → 会話重視
  • ブロック(-200)、通報(-500)の重みが巨大 → 嫌われたら即死
  • Out-of-Network候補のペナルティ(0.75倍) → 安心感重視

CMS比較ガイド

WordPress vs Laravel vs Shopify 徹底比較表

詳しく見る

まとめ

X Algorithmの核心は、以下の3つの革新にあります:

  1. 候補分離アーキテクチャ - 他の推薦システムと一線を画す設計
  2. Grok Transformerの活用 - Two-TowerとRankingでの使い分け
  3. 重み設計の哲学 - ネガティブシグナルを極端に重視

これらの技術により、Xは高速(サブ100ms)かつ高品質なタイムライン生成を実現しています。

技術者として特に参考になるのは:

  • アテンションマスクによる候補分離の実装方法
  • マルチアクション予測(19種類同時)の学習戦略
  • Rust + Pythonのハイブリッド構成
  • インメモリストアとBloom Filterの組み合わせ

このアルゴリズムは、推薦システムの設計において「キャッシュ可能性」「一貫性」「スケーラビリティ」を重視する場合の良いお手本となるでしょう。

この記事をシェア

この記事の内容でお困りですか?

無料でご相談いただけます

Webサイトの改善、システム開発、AI導入など、 お気軽にご相談ください。初回相談は無料です。

無料相談してみる
AIに無料相談