X'in 'For You' Algoritması Artık Açık Kaynak: Derin Teknik İnceleme
X'in "For You" Algoritması Artık Açık Kaynak: Derin Teknik İnceleme
13 Ağustos 2026'da X, "For You" feed algoritmasını GitHub'da Apache v2 lisansıyla açık kaynak yaptı. Bu yazıda her bileşeni kod seviyesinde, örneklerle inceledik.
Giriş: Neler Açıldı?
X (eski Twitter), 13 Ağustos 2026'da algoritma şeffaflığı konusunda şimdiye kadarki en büyük adımı attı. "For You" feed'ini dolduran çekirdek sıralama algoritmasını github.com/xai-org/x-algorithm adresinde açık kaynak olarak yayınladı.
Önceki açık kaynak çabalarından farkı şudur: bu sefer sadece "işte model mimarisi" denmiyor — scoring ağırlıkları, filtreleme kuralları, visibility filtering sistemi, bot tespit modelleri ve training kodu da dahil. Codebase önceki versiyondan 10-15 kat daha büyük.
Üstelik bir "Under the Hood" şeffaflık aracı da lanse edildi: kullanıcılar hesaplarına uygulanan visibility etiketlerini JSON olarak indirebilir ve herhangi bir LLM'e vererek "hesabım neden fewer kişiye ulaşıyor?" sorusunun cevabını alabilir.
Bu yazıda, repo'daki kodu dosya dosya inceledik ve her bileşeni örneklerle açıklıyoruz.
Bölüm 1: Sistem Mimarisi — Feed Nasıl Kuruluyor?
Kullanıcı X'i açtığında, "For You" feed'i şu pipeline'dan geçer:
Kullanıcı feed açar
↓
HOME MIXER (Rust)
├── 1. Query Hydration: kullanıcı son aksiyonları, takip listesi, block/mute
├── 2. Candidate Sources (paralel):
│ ├── Thunder (in-network, son 48 saat)
│ ├── Phoenix retrieval (out-of-network, embedding similarity)
│ └── SimClusters (cluster-based discovery)
├── 3. Hydration: post metni, media, author detayları, engagement counts
├── 4. Pre-Scoring Filters: duplicate, 48h age, self-post, already-seen, muted
├── 5. Scoring:
│ ├── PhoenixScorer: 24 aksiyon olasılığı
│ ├── RankingScorer: weighted sum + author diversity + OON discount
│ └── VMRanker: DPP reranking (çeşitlilik)
├── 6. Selection: Top K post
├── 7. Post-Selection Filters: visibility filtering, conversation dedup
└── Blending: ads, who-to-follow, prompts aralara eklenir
Her aşamayı ayrı ayrı inceleyelim.
Bölüm 2: Phoenix — Öneri Sisteminin Beyni
Phoenix, X'in feed'ini dolduran ana ML motorudur. İki aşamalı çalışır: Retrieval (milyonlarca post → ~1500 aday) ve Ranking (~1500 aday → sıralı feed).
2.1 Retrieval — Two-Tower Model
Retrieval aşaması, kullanıcının geçmiş etkileşimlerine bakarak milyonlarca post arasından ~1000-1500 aday seçer. Bunun için "iki kule" (two-tower) mimarisi kullanılır.
User Tower (Kullanıcı Kulesi) kullanıcının son 1022 etkileşimini (like, reply, retweet, share, mute, block vb.) bir transformer'a verir ve 2560 boyutlu bir embedding üretir.
Önemli bir tasarım kararı: production'da per-user ID embedding yok. Yani "kullanıcı #12345" diye öğrenilmiş bir vektör yok. Kullanıcı tamamen neyle etkileşime girdiğiyle + profil özellikleriyle (ülke, dil, cinsiyet, yaş aralığı, yüklü uygulamalar) temsil edilir. Bu demektir ki yeni bir kullanıcı bile geçmiş etkileşimleri olduğu kadar iyi temsil edilebilir.
Candidate Tower (Aday Kulesi) her post için bir embedding üretir. Post'lar artık hash-based ID yerine Semantic ID (SID) ile temsil edilir: her post'un multimodal embedding'inden (metin + görsel) residual quantization ile 6 seviye × 256 kod türetilir. Aynı konudaki post'lar benzer SID prefix'leri paylaşır, bu sayede model daha önce hiç görmediği post'ları bile tanıyabilir.
Örnek senaryo:
Diyelim ki kullanıcı geçmişte şu etkileşimlerde bulundu:
- Bir AI haber post'unu like'ladı
- Bir coding thread'ine reply yaptı
- Bir teknoloji tartışmasını retweet etti
User Tower bunları alır ve şuna benzer bir embedding üretir:
[0.12, -0.34, 0.56, ...] (2560 boyut)
Post corpus'undan iki post karşılaştıralım:
- Post A (AI haberleri): embedding
[0.11, -0.30, 0.54, ...]→ dot product = 0.87 (yüksek) → aday seçildi - Post B (yemek tarifi): embedding
[-0.45, 0.22, 0.08, ...]→ dot product = 0.03 (düşük) → elendi
Index nasıl tutulur? Her checkpoint kaydedildiğinde, candidate tower tüm corpus'u embed'ler ve sonuç checkpoint'in içine kaydeder. Serving açılırken corpus'u sıfırdan embed'leme yok — direkt checkpoint'ten yüklenir. Production corpus boyutu: 10.24M post.
Training: Contrastive learning — in-batch negatives + 64 sampled global negatives. Positive signal: favorite (like). log-Q correction uygulanır.
2.2 Ranking — Transformer with Candidate Isolation
Retrieval'den gelen ~1500 aday, daha güçlü bir transformer modeliyle puanlanır.
Model boyutları (production):
| Parametre | Production | Nano (tek GPU) |
|---|---|---|
| Embedding boyutu | 2560 | 512 |
| Transformer katmanı | 8 | 4 |
| Attention head (GQA) | 20 query / 4 KV | 4 / 2 |
| History sequence | 1022 | 1022 |
| Candidate sequence | 64 | 64 |
Input üç parça:
- User tokens: hash + profil özellikleri (ülke, dil, lokasyon, cinsiyet, yaş, yüklü uygulamalar)
- History embeddings: post + author + action + SID + context (timezone, saat, surface, post yaşı) + dwell time
- Candidate embeddings: post + author + SID + context
Candidate Isolation — Kritik Tasarım Kararı:
Attention mask'te aday post'lar birbirini göremez. Sadece user ve history'ye attend edebilir, kendi kendilerine attend edebilir, ama diğer aday post'lara bakamazlar.
Keys →
User | History (1022) | Candidates (64)
Queries ↓ ──────┼─────────────────┼─────────────────
User ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✗ ✗ ✗ ✗ ✗ ✗ ✗
History ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✗ ✗ ✗ ✗ ✗ ✗ ✗
Candidate 1 ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✗ ✗ ✗ ✗ ✗ ✗ ← sadece kendini
Candidate 2 ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✗ ✓ ✗ ✗ ✗ ✗ ✗ ← sadece kendini
Neden? Bir post'un skoru hangi diğer post'ların batch'te olduğuna bağlı olmamalı. Bu sayede skorlar deterministic ve cache'lenebilir. Aynı post farklı kullanıcılarda farklı batch'lerde olsa da aynı skoru alır.
Output: 64 discrete action olasılığı (like, reply, retweet, quote, share, click, profile click, video open, follow author, not interested, mute, block, report vb.) + 8 continuous-action head (dwell time regression).
2.3 Kendi Makinenizde Çalıştırın
X, synthetic data ile tüm pipeline'ı tek GPU'da çalıştırmanız için kod ve talimatlar sağlıyor:
# Synthetic veri üret
uv run python reference/world_snapshots.py --out ./synth_index --seed 20260721
uv run python reference/dump_gen.py --out ./synth_dump --seed 20260721 \
--num-rows 12288 --partitions 4 --rows-per-file 1024
# Ranking modelini train et
uv run python reference/train_synth.py --data ./synth_dump --steps 6 --out checkpoints
# Retrieve → Rank döngüsü
uv run python reference/retrieve_then_rank.py \
--data ./synth_dump --sessions 3 --topk 16 \
--retrieval-port 9990 --ranking-port 9988
Gereksinimler: Linux + NVIDIA GPU + CUDA 12 + Python 3.11+ + Rust toolchain.
Bölüm 3: Scoring — Olasılıklar Skora Dönüşüyor
Phoenix'in ürettiği 24 olasılık, ranking_scorer.rs içinde ağırlıklarla çarpılıp toplanarak tek bir skora dönüşür.
3.1 Production Ağırlıkları
home-mixer/params/param.rs dosyasından, production'da kullanılan gerçek ağırlıklar:
Pozitif Sinyaller
| Aksiyon | Ağırlık | Yorum |
|---|---|---|
| Favorite (like) | 0.5 | Orta değer |
| Reply | 5.0 | Yüksek — tartışma çok değerli |
| Retweet | 1.0 | Orta-yüksek |
| Share (bookmark) | 2.0 | Yüksek |
| Share via DM | 5.0 | Çok yüksek — direkt paylaşım |
| Share via Copy Link | 20.0 | En yüksek — off-platform yayılım |
| Quote | 5.0 | Çok yüksek |
| Follow Author | 4.0 | Yüksek — yeni takipçi kazandırır |
| Click | 0.4 | Düşük |
| Open Link | 0.2 | Düşük |
| Photo Expand | 0.05 | Çok düşük |
| Video Open | 0.05 | Çok düşük |
| Dwell | 0.0 | Sıfır — sadece continuous dwell time kullanılır |
| Cont. Dwell Time | 0.004 | Çok düşük ama sürekli |
| Post Unexplored | 0.02 | Keşfedilmemiş içerik için küçük boost |
Negatif Sinyaller (Cezalar)
| Aksiyon | Ağırlık | Yorum |
|---|---|---|
| Not Interested | -43.2 | Çok ağır |
| Block Author | -31.2 | Çok ağır |
| Mute Author | -58.8 | En ağır negatif (report hariç) |
| Report | -234.0 | Nükleer — tek report post'u öldürür |
| Not Dwelled | -0.02 | Çok hafif |
Bu tablodan çıkan en çarpıcı sonuç: like'ın ağırlığı sadece 0.5 ama mute'un cezası -58.8. Yani bir kullanıcının post'unuzu mute etmesi, 117 like'lık katkıyı sıfırlar. Report ise 468 like'a bedel.
3.2 Skor Hesaplama Örneği
Diyelim ki Post X için Phoenix şu skorları verdi:
favorite: 0.12 reply: 0.03
retweet: 0.05 share: 0.02
share_dm: 0.01 copy_link: 0.005
quote: 0.01 click: 0.08
follow_author: 0.008 dwell_time: 15.3
not_interested: 0.02 mute: 0.001
report: 0.0001
Pozitif katkılar:
0.5 × 0.12 = 0.060 (favorite)
5.0 × 0.03 = 0.150 (reply)
1.0 × 0.05 = 0.050 (retweet)
2.0 × 0.02 = 0.040 (share)
5.0 × 0.01 = 0.050 (share via DM)
20.0 × 0.005 = 0.100 (share via copy link)
5.0 × 0.01 = 0.050 (quote)
0.4 × 0.08 = 0.032 (click)
4.0 × 0.008 = 0.032 (follow author)
0.004 × 15.3 = 0.061 (cont dwell time)
─────────────────────
Pozitif toplam: 0.631
Negatif katkılar:
-43.2 × 0.02 = -0.864 (not interested)
-58.8 × 0.001 = -0.029 (mute author)
-234.0 × 0.0001 = -0.023 (report)
-0.02 × 0.3 = -0.006 (not dwelled)
─────────────────────────
Negatif toplam: -0.953
Net skor: 0.631 - 0.953 = -0.322
Negatif olduğu için offset_score fonksiyonu devreye girer ve skor normalize edilir. Bu örnekte post, tek bir "not interested" sinyali yüzünden negatif bölgeye düşmüş — bu da like'ların tek başına post'u taşıyamadığını gösteriyor.
Bölüm 4: Post-Scoring Ayarlamaları
4.1 Author Diversity — Aynı Yazardan Çok Post Görme
Aynı yazardan gelen üst üste post'lar için eksponansiyel decay uygulanır.
Parametreler: decay = 0.5, floor = 0.25
Yazar A'nın 1. post'u: skor × 1.0 (tam skor)
Yazar A'nın 2. post'u: skor × 0.5 (%50)
Yazar A'nın 3. post'u: skor × 0.25 (floor — daha fazla düşmez)
Yazar A'nın 4. post'u: skor × 0.25 (floor)
Örnek: Bir yazar günde 10 post atıyor.
Diversity öncesi:
Post 1: 5.0, Post 2: 4.8, Post 3: 4.5, ...
Diversity sonrası:
Post 1: 5.00 (×1.0)
Post 2: 2.40 (×0.5)
Post 3: 1.13 (×0.25 — floor)
Post 4-10: hepsi floor'da → 0.70-1.05 arası
Sonuç: Yazar A'dan 2-3 post görünür, 7-8'i görünmez.
Bu, "günde 10 post at, daha fazla görün" stratejisinin artık çalışmadığı anlamına geliyor. Az ama güçlü post, çok ama floor'a düşmüş post'tan daha iyi.
4.2 OON Discount — Takip Etmediğin Yazarlar
Takip etmediğin yazardan gelen post'lar (out-of-network), in-network post'lara göre %25 daha düşük skor alır.
OON Weight Factor = 0.75
Topic-filtered feed'de: 0.50 (daha agresif)
Post X (takip ettiğin yazardan): skor = 5.0 → 5.0
Post Y (takip ETMEDİĞİN yazardan): skor = 5.0 → 5.0 × 0.75 = 3.75
4.3 Bidirectional Follow Boost — Karşılıklı Takip
Temmuz 2026'da eklenen ve çok tartışılan özellik. Karşılıklı takipte olan yazarların orijinal post'ları için reply weight'i 5.0'dan 20.0'a çıkıyor.
Sen → @Alice (takip) ve @Alice → Sen (takip) = KARŞILIKLI
@Alice orijinal post atar:
Reply weight: 5.0 + 15.0 = 20.0 ← 4 kat boost!
@Alice bir post'a reply yapar:
Reply weight: 5.0 ← boost YOK (sadece orijinal post'larda)
Tarihçe:
- 10 Temmuz 2026: A/B test başladı (0, 5, 10, 15, 20 değerleri)
- 13 Temmuz 2026: 20.0 geniş çapta yayınlandı
- 24 Temmuz 2026: 15.0'a düşürüldü (World Cup feedback — takip etmedikleri hesaplardan da tartışma görmek istiyorlardı)
4.4 Cold Start Boost — Yeni Yazarlar İçin
Az impression almış (<1000 view) yeni yazarların post'larını feed'de yukarı taşır.
- Feed'deki post'lar skorlanıp sıralanır
- 15-16. pozisyondaki skor belirlenir (hedef slot)
- Eligible post aranır: orijinal post, ≤1000 takipçi, <1000 view
- En yüksek skorlu eligible post, hedef slot skoruyla değiştirilir
Örnek:
Feed sıralaması:
#15: 2.10 ← ColdStartSlotMin
#16: 2.05 ← ColdStartSlotMax → hedef = 2.05
...
#23: 0.50 (Yeni yazar @newbie, 80 follower, 12 view) ← eligible!
Sonuç: @newbie'nin post skoru 0.50 → 2.05'e boost'lanır
→ Feed'de ~16. sıraya yerleşir
Bölüm 5: VMRanker — Çeşitlilik İçin DPP
Determinantal Point Process (DPP) ile benzer post'ları ayırır, çeşitliliği artırır.
Parametreler: theta = 0.65, max_selected_rank = 150
Skor sıralaması:
#1: Post A (5.0, tech)
#2: Post B (4.9, tech — A'ya benzer)
#3: Post C (4.5, spor — farklı)
#4: Post D (4.3, müzik — farklı)
DPP theta=0.65 ile:
#1: Post A (5.0) → seçildi
#2: Post B (4.9) → A'ya benzer, penalty → 3.2'ye düşer
#3: Post C (4.5) → farklı → 4.5 (B'yi geçti!)
#4: Post D (4.3) → farklı → 4.3
Etkisi: feed'de aynı konudan 3-4 tane üst üste post görmezsin.
Bölüm 6: Thunder — In-Network Post Store
Takip ettiğin hesapların son post'larını memory'de tutar.
- Her post publish edildiğinde Thunder'a yazılır
- Post'lar memory'de 48 saat tutulur, sonra düşer
- 48 saatten eski post'lar sadece Phoenix retrieval ile bulunabilir
"Recency boost" diye bir şey yok. Recency bir pencerdır, bir çarpan değil. Post ya 48 saat içinde Thunder'dadır (aday olur) ya da değildir.
Bölüm 7: SimClusters — Topluluk Bazlı Keşif
Kullanıcıları ve post'ları cluster'lara ayırarak takip etmediğin hesaplardan aday post getirir.
Senin cluster'ların: {tech: 0.8, AI: 0.6, music: 0.3}
@strangerA cluster'ları: {tech: 0.9, AI: 0.7} → yüksek örtüşme → aday
@strangerB cluster'ları: {cooking: 0.9} → düşük → aday değil
Bölüm 8: Visibility Filtering — Görünürlük Filtreleme
Ranking post'ların sırasını belirler. Visibility filtering ise gösterilip gösterilmeyeceğine karar verir.
Üç karar: ALLOW (göster), INTERSTITIAL (tıkla gör), DROP (gizle)
Base Home Rules (tüm feed'ler):
- Suspended/Deactivated/Erased author → Drop
- Block/Mute → Drop
- Spam, FOSNR (hateful conduct, violent speech, abuse) → Drop
- Stale tweet, Legal takedown → Drop
- NSFW → Interstitial
Sadece OON için ekstra: DMCA, Geo-restricted, NSFW high recall, Malicious URL, Compromised user, Impersonation → Drop
Kritik kural: İlk DROP kararı veren kural kazanır. Author kendisi her zaman muaf.
Bölüm 9: BDSM — Bot/Spam Tespiti
Kullanıcı davranış sequence'ını analiz ederek bot/spam tespit eden transformer modeli.
- Time-aware RoPE: aksiyonlar arası zaman farkları önemli
- 8 task head: FollowBot, LikeBot, EngagementAmplifier, ReplySpamBot, TweetSpamBot, RTBot, MultiActionBot, LegitimateUser
- 256 action type, 512 sequence length
Bot pattern:
[like @14:00:01, like @14:00:03, like @14:00:05, ...]
Zaman farkları: [2s, 2s, 2s, ...] → mekanik cadence → bot!
Normal kullanıcı:
[like @09:15, reply @09:23, like @10:02, ...]
Zaman farkları: [8m, 39m, ...] → doğal → meşru
Threshold değerleri gizli (adversary'lerin evasion boundary'yi öğrenmesini önlemek için).
Bölüm 10: Agatha ve User-Cred-v2
Agatha: Hesabın diğer kullanıcılar tarafından nasıl algılandığını ölçer (block/fav oranı, report/fav oranı).
User-Cred-v2: Follow graph üzerinde PageRank çalıştırarak güvenilirlik skoru üretir.
Bölüm 11: Botmaker + Scarecrow
Event-based rule engine. Belirli olaylar olduğunda kurallar çalışır ve etiket uygulanır.
ON post_publish
IF account_age < 7 days AND follower_count < 50 AND post_count > 100
APPLY SPAM_HIGH_RECALL
Bölüm 12: Under the Hood — Şeffaflık Aracı
Kullanıcılar hesaplarına uygulanan visibility etiketlerini JSON olarak indirebilir. JSON'ı LLM'e verip + GitHub repo'ya yönlendirip "hesabım ne durumda?" sorusunun cevabını alabilirler.
Pilot: en az 1 yıllık hesaplarda başladı.
Bölüm 13: End-to-End Örnek
Saat 14:00'da X'i açtığınızda olanlar:
1. QUERY HYDRATION
- Son 1022 etkileşim, 450 takip, 12 block, 5 mute
2. CANDIDATE SOURCES (paralel)
Thunder: 320 post (48h içinde, takip edilenler)
Phoenix: 1000 post (10.24M index'ten)
SimClusters: 200 post (cluster match)
Toplam: ~1520 aday
3. PRE-SCORING FILTERS
Duplicate, 48h, self, block/mute, seen: -350
Kalan: ~1170 post
4. SCORING
Phoenix 24 olasılık × ağırlıklar → skor
Post A (karşılıklı takip): 8.5 (reply boost 20.0)
Post B (OON): 3.2 (× 0.75)
Post C (yeni yazar): 0.8 → cold start → 2.05
5. DIVERSITY + DPP + SELECTION → Top 150
6. VISIBILITY FILTERING
3 drop (spam OON), 2 interstitial (NSFW), 1 drop (abuse)
Kalan: 144 post
7. BLENDING
144 organic + 3 ad + 2 who-to-follow + 1 prompt = ~150 item
→ Ekrana gönderildi
Pratik Çıkarımlar
- Reply en değerli sinyal: 5.0 weight, karşılıklı takipte 20.0. Like sadece 0.5.
- Copy link share altın: 20.0 weight — en yüksek pozitif sinyal.
- Günde 10 post = 7'si floor'a düşer: Author diversity 0.25 floor'da sabit.
- Mute, like'lardan daha güçlü: Bir mute (-58.8), 117 like'ı sıfırlar.
- 48 saat penceresi: "Recency boost" yok — sadece Thunder'da olup olmadığı önemli.
- OON post'lar %25 cezalı: Takipçi kazanmak (follow_author = 4.0) çok değerli.
- Yeni yazarlara otomatik boost: <1000 impression'da 15-16. sıraya yerleşir.
- Karşılıklı takip 4x reply boost: Sadece orijinal post'larda.
- Dwell time weight = 0: Continuous dwell time (0.004) değerlidir, raw dwell değil.
- Bidirectional boost tarihi: 20.0'dan 15.0'a düşürüldü — çok agresif boost keşfetmeyi öldürüyordu.
Sonuç
X'in bu açık kaynak çıkışı, sosyal medya algoritmaları alanında bir ilki temsil ediyor. Daha önce hiçbir major platform, recommendation algoritmasının bu kadarını — scoring ağırlıkları, filtreleme kuralları, bot tespit modelleri, hatta training kodu — açık source yapmamıştı.
Kodun çalıştırılabilir olması (synthetic data + nano config + tek GPU) da önemli: araştırmacılar sadece okumakla kalmayıp, modeli gerçekten train edip serve edebilirler. Pull request gönderebilirler.
Elbette her şey açık değil. Grok prompt'ları, bazı botmaker kuralları, BDSM threshold değerleri gizli tutulmuş. Ama "Under the Hood" aracı, bu gizli sistemlerin çıktılarını kullanıcıya gösteriyor.
X'in çağrısı net: "Kodu denetleyin, eleştirin, geliştirin." Bakalım topluluk bu çağrıya nasıl cevap verecek.
İncelemenin tamamı github.com/xai-org/x-algorithm reposundaki kod bazında hazırlanmıştır. Son senkronizasyon: 12 Ağustos 2026.