📝 Niyazi'nin Blogu

📑 İçindekiler

X'in 'For You' Algoritması Artık Açık Kaynak: Derin Teknik İnceleme

📅 2026-08-14  ·  ⏱ 14 dk okuma  ·  👁 9 kez okundu  ·  xtwitteralgoritmaopen-sourcemachine-learningrecommendation-systemai

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:

  1. User tokens: hash + profil özellikleri (ülke, dil, lokasyon, cinsiyet, yaş, yüklü uygulamalar)
  2. History embeddings: post + author + action + SID + context (timezone, saat, surface, post yaşı) + dwell time
  3. 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.

  1. Feed'deki post'lar skorlanıp sıralanır
  2. 15-16. pozisyondaki skor belirlenir (hedef slot)
  3. Eligible post aranır: orijinal post, ≤1000 takipçi, <1000 view
  4. 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

  1. Reply en değerli sinyal: 5.0 weight, karşılıklı takipte 20.0. Like sadece 0.5.
  2. Copy link share altın: 20.0 weight — en yüksek pozitif sinyal.
  3. Günde 10 post = 7'si floor'a düşer: Author diversity 0.25 floor'da sabit.
  4. Mute, like'lardan daha güçlü: Bir mute (-58.8), 117 like'ı sıfırlar.
  5. 48 saat penceresi: "Recency boost" yok — sadece Thunder'da olup olmadığı önemli.
  6. OON post'lar %25 cezalı: Takipçi kazanmak (follow_author = 4.0) çok değerli.
  7. Yeni yazarlara otomatik boost: <1000 impression'da 15-16. sıraya yerleşir.
  8. Karşılıklı takip 4x reply boost: Sadece orijinal post'larda.
  9. Dwell time weight = 0: Continuous dwell time (0.004) değerlidir, raw dwell değil.
  10. 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.

← Önceki"TrendHawk Taraması — 14 Ağustos 2026"Sonraki →TrendHawk Geniş Tarama — 17 Ağustos 2026 (Teknoloji Dışı)
M
3x
j/ sonraki k/ önceki s kaydır f mod +/ font Esc çık