Thunder vs Phoenix Retrieval Systems: How X Sources In-Network and Out-of-Network Candidates
Thunder is a low-latency in-memory lookup service for recent posts from followed accounts, while Phoenix is a learned two-tower neural retrieval system that discovers content from the global corpus using embedding similarity search.
The xai-org/x-algorithm repository implements these dual retrieval paths to balance immediate social relevance with content discovery. Understanding the difference between Thunder and Phoenix retrieval systems reveals how X’s Home-Mixer pipeline combines fresh in-network updates with out-of-network recommendations before final ranking.
Architectural Overview
Thunder (In-Network Retrieval)
Thunder supplies the most recent posts from accounts the viewer follows. It reads from an in-memory post cache populated by real-time activity streams, queried via the ThunderSource component in the Home-Mixer pipeline.
The implementation relies on a deterministic range query to the InNetworkPostsService defined in thunder/thunder_service.rs. For a given list of followed user IDs, the service returns the latest N posts as LightPost protobuf messages. No machine learning inference occurs at this stage; the system handles thousands of posts per request through simple memory-resident lookups.
Phoenix (Out-of-Network Retrieval)
Phoenix finds candidate posts from the entire corpus using a learned similarity model, specifically targeting accounts the viewer does not follow. It employs a two-tower neural architecture where the user tower encodes recent engagement history into a dense embedding, while the candidate tower pre-computes embeddings for all posts.
The retrieval logic lives in phoenix/xrex/data/parquet_recsys.py within the PhoenixDataset class. Using Approximate Nearest-Neighbour (ANN) search against a user embedding, Phoenix reduces millions of candidates to a few thousand before downstream ranking. These embeddings are materialized in checkpoint files loaded by the serving engine, enabling sub-second latency despite the computational intensity of dot-product similarity search.
Key Technical Differences
Source of candidates: Thunder pulls exclusively from followed user activity streams stored in a volatile PostStore, while Phoenix searches a global embedding index covering the entire corpus.
Computation model: Thunder operates as a deterministic lookup service with no ML inference, whereas Phoenix relies on a trained two-tower neural model to compute similarity scores between user and content embeddings.
Storage architecture: Thunder’s posts reside in volatile in-memory caches; Phoenix’s embeddings are persisted in checkpoint files that the serving engine loads for ANN queries.
Rate limiting: Thunder enforces per-second QPS limits using the governor crate via the RateLimiter in thunder_service.rs. Phoenix retrieval is gated by the size of the pre-computed index and does not require per-request throttling.
Implementation Examples
Fetching In-Network Posts with Thunder
The ThunderSource bridges the Home-Mixer pipeline to the Thunder service, converting protobuf posts into PostCandidate objects.
// Create a ThunderSource (usually done inside Home‑Mixer)
let thunder_source = ThunderSource {
thunder_client: Arc::new(ThunderClient::new().await),
thunder_capi_client: None, // optional CAPI client
};
// Build a request from a ScoredPostsQuery (simplified)
let query = ScoredPostsQuery {
user_id: 12345,
user_features: UserFeatures { followed_user_ids: vec![111, 222, 333] },
params: Params::default(),
// … other fields …
..Default::default()
};
let candidates = thunder_source.source(&query).await.unwrap();
println!("Fetched {} in‑network candidates", candidates.len());
This implementation appears in home-mixer/sources/thunder_source.rs and returns candidates processed by the InNetworkPostsService in thunder/thunder_service.rs.
Retrieving Global Candidates with Phoenix
The PhoenixDataset class handles checkpoint loading and ANN retrieval for out-of-network candidates.
from xrex.data.parquet_recsys import PhoenixDataset
from xrex.configs.xrecsys_two_tower import get_two_tower_config
# Load a synthetic checkpoint (or a real one)
dataset = PhoenixDataset(
checkpoint_path="checkpoints/two_tower_checkpoint/",
config=get_two_tower_config(),
)
# Obtain a user embedding (normally built from recent history)
user_embedding = dataset.user_encoder.encode_user_history(user_history)
# Retrieve top‑K similar candidates
top_k = dataset.retrieve_candidates(user_embedding, k=1000)
print(f"Phoenix retrieved {len(top_k)} candidates")
This code from phoenix/xrex/data/parquet_recsys.py is called by the PhoenixCandidatePipeline as shown in the repository README (lines 97-100).
Core Source Files
-
thunder/thunder_service.rs: Implements the gRPCInNetworkPostsService; handles rate limiting, statistics logging viaanalyze_and_report_post_statistics, and servesLightPostmessages. -
home-mixer/sources/thunder_source.rs: Bridges the Home-Mixer pipeline to the Thunder service, instantiatingThunderSourcealongside other candidate sources to run in parallel. -
phoenix/xrex/data/parquet_recsys.py: DefinesPhoenixDataset, the entry point for loading two-tower checkpoints and performing ANN retrieval. -
phoenix/xrex/train/trainer_recsys.py: Manages training of the two-tower model and produces the checkpoint containing the candidate embedding index. -
phoenix/README.md: Documents the two-tower architecture, embedding generation, and retrieval flow in the Retrieval: Two-Tower Model section. -
README.md(lines 60-64): Contains the high-level architecture diagram placing Thunder and Phoenix side-by-side in the Candidate Sources block.
Summary
- Thunder provides low-latency, deterministic lookups for recent posts from followed accounts using in-memory caches and simple range queries.
- Phoenix enables discovery-driven retrieval from the global corpus using a learned two-tower neural model and ANN search against pre-computed embeddings.
- Thunder handles thousands of posts per request with explicit rate limiting via the
governorcrate. - Phoenix scales to millions of candidates, reducing them to thousands through similarity search before ranking.
- Both systems feed the Home-Mixer pipeline: Thunder via
ThunderSourceand Phoenix viaPhoenixCandidatePipeline.
Frequently Asked Questions
What is the main architectural difference between Thunder and Phoenix?
Thunder operates as a lookup service for followed account activity using in-memory storage and deterministic queries, while Phoenix implements a learned retrieval system using a two-tower neural network to search the entire post corpus via embedding similarity. This distinction separates explicit social graph traversal from content-based discovery.
How does Phoenix handle retrieval at scale?
Phoenix pre-computes embeddings for all posts and stores them in checkpoint files. During serving, it performs Approximate Nearest-Neighbour (ANN) search using optimized vector indexes, reducing millions of candidates to a manageable top-K set for downstream ranking, all while maintaining sub-second latency.
Where is rate limiting implemented in the Thunder system?
Rate limiting is implemented in thunder/thunder_service.rs using the governor crate. The RateLimiter enforces per-second QPS limits on requests to the InNetworkPostsService, protecting the in-memory PostStore from overload.
Does Thunder use machine learning for candidate ranking?
No. Thunder applies no machine learning inference during retrieval; it returns the latest N posts for supplied user IDs using simple range queries. Machine learning ranking occurs later in the pipeline when Thunder’s results are blended with Phoenix candidates and scored by the final ranking model.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →