
X 演算法拆解證據總表
本篇彙整 X 推薦演算法開源專案的 58 項機器命題驗證數據與原始碼路徑,逐行解析行為權重、過濾器管線與可見度規則。適合需要精確原始碼依據、驗證腳本與技術規格的工程師與研究人員參考。
xai-org / x-algorithm · HEAD a389166
每一條主張都附原始碼位置與復現指令。所有數字由腳本實跑產生,非人工轉錄。
儲存庫 xai-org/x-algorithm(2026-08-13 更新) HEAD a389166f6cf5da70a286b568c87695d4dcdce3a1 規模 2,015 檔 / 21 MB / 5 commits 判讀 2026-08-14 驗證 58 條機器命題,58 PASS / 0 FAIL 自驗 注入錯誤期望值 → 正確產生 1 FAIL(閘門有效)
① 機器命題驗證表
下表 58 條全部由 verify-all.sh 實跑產生,本頁數值直接由該腳本輸出轉成表格, 沒有經過人工抄寫。腳本本體見附錄。

| 項目 | 數值 | 說明 |
|---|---|---|
| PASS | 58 | — |
| FAIL | 0 | — |
| should-FAIL 反例驗(注入錯值必須被抓到) | 1 | — |
| 編號 | 命題 | 實測值 | 結果 |
|---|---|---|---|
| C01 | HEAD | a389166f6cf5da70a286b568c87695d4dcdce3a1 | PASS |
| C02 | param!區塊數 | 183 | PASS |
| C03 | 檔案總數 | 2015 | PASS |
| C04 | FavoriteWeight | 0.5 | PASS |
| C05 | ReplyWeight | 5.0 | PASS |
| C06 | RetweetWeight | 1.0 | PASS |
| C07 | ShareViaCopyLinkWeight | 20.0 | PASS |
| C08 | ReportWeight | -234.0 | PASS |
| C09 | MuteAuthorWeight | -58.8 | PASS |
| C10 | BlockAuthorWeight | -31.2 | PASS |
| C11 | NotInterestedWeight | -43.2 | PASS |
| C12 | NEW_USER_OON_WEIGHT_FACTOR | 0.00001 | PASS |
| C13 | NEW_USER_MIN_FOLLOWING | 5 | PASS |
| C14 | NEGATIVE_SCORES_OFFSET | 0.001 | PASS |
| C15 | MAX_POST_AGE(秒) | 172800 | PASS |
| C16 | NewUserAgeThresholdSecs預設 | 0 | PASS |
| C17 | AuthorDiversityDecay | 0.5 | PASS |
| C18 | AuthorDiversityFloor | 0.25 | PASS |
| C19 | OonWeightFactor | 0.75 | PASS |
| C20 | 前置過濾器數 | 17 | PASS |
| C21 | 後置過濾器數 | 3 | PASS |
| C22 | filters檔數(不含mod) | 27 | PASS |
| C23 | mod.rs宣告數 | 26 | PASS |
| C24 | 未宣告的filter | popular_topics_author_dedup_filter | PASS |
| C25 | 基本可見度規則數 | 28 | PASS |
| C26 | OON加碼規則數 | 26 | PASS |
| C27 | 排序器取用預測頭數(scores.* 去掉方法呼叫 .clone) | 26 | PASS |
| C28 | MinVideoDurationMs | 10_000 | PASS |
| C29 | EnableQuotedVqvDurationCheck | false | PASS |
| C30 | EnableInventoryHoldout | false | PASS |
| C31 | VMRankerSendHeadWeights | false | PASS |
| C32 | Rust側bridge命中 | 0 | PASS |
| C33 | phoenix [:,:,4] 命中 | 0 | PASS |
| C34 | phoenix [:,:,2] 命中 | 0 | PASS |
| C35 | phoenix [:,:,3] 命中 | 0 | PASS |
| C36 | Rust用ContinuousActionName次數 | 2 | PASS |
| C37 | Rust 引用 DwellTime 的處數 | 2 | PASS |
| C38 | BRIDGE_PROBABILITY列舉值 | 4 | PASS |
| C39 | bridge開關設True次數 | 0 | PASS |
| C40 | 有損失的連續頭種類數 | 1 | PASS |
| C41 | NUM_CONTINUOUS(參考實作) | 8 | PASS |
| C42 | DWELL_INDEX(參考實作) | 1 | PASS |
| C43 | history_seq_len | 1022 | PASS |
| C44 | num_layers | 8 | PASS |
| C45 | emb_size | 2560 | PASS |
| C46 | ActionName列舉項數 | 204 | PASS |
| C47 | PLACE_HOLDER佔位數 | 8 | PASS |
| C48 | 兩份proto是否相同 | same | PASS |
| C49 | ProfileClickWeight | 0.0 | PASS |
| C50 | DwellWeight | 0.0 | PASS |
| C51 | QuotedVqvWeight | 0.0 | PASS |
| C52 | ContClickDwellTimeWeight | 0.0 | PASS |
| C53 | ContActiveSecs5mResidualNormWeight | 0.0 | PASS |
| C54 | BidirectionalFollowDwellWeightBoost | 0.0 | PASS |
| C55 | BidirectionalFollowReplyWeightBoost | 15.0 | PASS |
| C56 | ContDwellTimeWeight | 0.004 | PASS |
| C57 | NotDwelledWeight | -0.02 | PASS |
| C58 | 名稱含Weight的參數數 | 33 | PASS |
② 權重總表
來源 home-mixer/params/param.rs。逐塊解析全檔 183 個 param! 後篩出名稱含 Weight 者共 33 個。其中 30 個是數值權重,全部列在下面三張表;另外三個不是單一數值,另外兩個分列他處(DwellRegretGateWeights 見本節末、VMRankerSendHeadWeights 見第 ④ 節的開關表),另一個 PostUnexploredWeightInNetworkOnly 是布林開關(param.rs:369-374,預設 true,限定探索加分只作用在追蹤內的貼文),不是權重值,故不列入權重表。數值為程式碼內建預設值,線上可由 feature switch 覆寫。
抽取陷阱(我第一版就中了):這個檔案同時存在多行與單行兩種 param! 寫法。 只掃多行會靜默漏掉 13 個——而真正的評分權重全部在那 13 個裡面。 實計 170 ≠ grep -c '^param!(' 的 183 才抓到。附錄的解析器兩種都處理。

正權重(表列 19 項=17 個正權重+2 個 OON 折扣係數)
| 行號 | 參數 | 預設值 | 對應動作 |
|---|---|---|---|
| L325 | ShareViaCopyLinkWeight | 20.0 | 複製連結分享 |
| L284 | BidirectionalFollowReplyWeightBoost | +15.0 | 互相追蹤時的回覆加成 |
| L283 | ReplyWeight | 5.0 | 回覆 |
| L319 | ShareViaDmWeight | 5.0 | 私訊分享 |
| L332 | QuoteWeight | 5.0 | 引用轉推 |
| L345 | FollowAuthorWeight | 4.0 | 追蹤作者 |
| L318 | ShareWeight | 2.0 | 一般分享 |
| L296 | RetweetWeight | 1.0 | 轉推 |
| L246 | OonWeightFactor | 0.75 | 未追蹤內容折扣係數 |
| L282 | FavoriteWeight | 0.5 | 按讚 |
| L266 | TopicOonWeightFactor | 0.5 | 主題模式的未追蹤折扣 |
| L309 | ClickWeight | 0.4 | 點進貼文 |
| L310 | OpenLinkWeight | 0.2 | 點外部連結 |
| L297 | PhotoExpandWeight | 0.05 | 放大圖片 |
| L303 | VideoOpenWeight | 0.05 | 開影片 |
| L317 | VqvWeight | 0.05 | 影片有效觀看 |
| L333 | QuotedClickWeight | 0.05 | 點進被引用的原貼文 |
| L351 | PostUnexploredWeight | 0.02 | 探索性內容加分 |
| L375 | ContDwellTimeWeight | 0.004 | 停留秒數(每秒) |
負權重(5 個)
| 行號 | 參數 | 預設值 | 相當於幾次按讚 |
|---|---|---|---|
| L442 | ReportWeight | −234.0 | 468 |
| L436 | MuteAuthorWeight | −58.8 | 117.6 |
| L424 | NotInterestedWeight | −43.2 | 86.4 |
| L430 | BlockAuthorWeight | −31.2 | 62.4 |
| L443 | NotDwelledWeight | −0.02 | 0.04 |
| 項目 | 數值 | 說明 |
|---|---|---|
| 正權重合計(16 項,不含兩個 OON 折扣係數與互追回覆加成 +15.0) | +43.324 | — |
| 負權重合計(5 項) | −367.22 | — |
| 負/正倍數 | 8.48× | — |
這個 8.48 倍怎麼讀才不會讀歪: 比的是權重定價,不是最終分數。進公式的是「權重 × 模型預測機率」, 而檢舉、封鎖的預測機率極小、按讚的機率高得多,所以單則貼文的負面項實際貢獻不會是正面的 8.48 倍。 那些機率是模型跑出來的,開源碼裡沒有,無法計算。 成立的說法是:X 對負面訊號的定價,比正面訊號貴一個數量級。
零權重(6 個)
| 行號 | 參數 | 預設值 | 性質(詳見 ⑦) |
|---|---|---|---|
| L311 | ProfileClickWeight | 0.0 | 模型有訓練,只是定價 0 |
| L331 | DwellWeight | 0.0 | 模型有訓練,只是定價 0 |
| L339 | QuotedVqvWeight | 0.0 | 模型有訓練,另有長度閘門 |
| L381 | ContClickDwellTimeWeight | 0.0 | 無訓練損失=schema 留白 |
| L417 | ContActiveSecs5mResidualNormWeight | 0.0 | 無訓練損失=schema 留白 |
| L290 | BidirectionalFollowDwellWeightBoost | 0.0 | 有守衛有測試的正式關閉開關 |
第 33 個:一條 19 維的邏輯迴歸
DwellRegretGateWeights(param.rs:534)不是單一數值,是 19 個係數的字串, 輸入是你的帳號歷史(互動序列長度、按讚數、回覆數、負面回饋數、7 日/1 日活躍、 粉絲數、追蹤數、帳齡…),輸出是「你會不會後悔看了這則」的機率。摘錄:
seq_len:0.530298 n_reply:0.485541 n_click:-0.176675
n_fav:-0.082139 n_1d:-0.241730 account_age_years:-0.045455
n_profile_follow:-0.221285 n_negfb:0.031839③ 評分公式逐行
單項 = 模型預測機率 × 該動作權重 ranking_scorer.rs:416-418
fn apply(score: Option<f64>, weight: f64) -> f64 {
score.unwrap_or(0.0) * weight
}
26 個單項組成陣列 ranking_scorer.rs:470-510
拆成正負兩堆 ranking_scorer.rs:513-521
for t in terms { if t >= 0.0 { pos += t } else { neg -= t } }
combined = pos − neg ranking_scorer.rs:427
最後位移 ranking_scorer.rs:524-532
if total_sum == 0.0 → max(combined, 0)
else if combined < 0.0 → (combined + negative_sum) / total_sum × 0.001
else → combined + 0.001
NEGATIVE_SCORES_OFFSET = 0.001 params/config.rs:40
negative_sum = −(not_interested+block+mute+report+not_dwelled) :127
total_sum = positive_sum + negative_sum :128這段 offset 的實際效果:所有算出來是負分的貼文,被壓縮到 0 ~ 0.001 這個極窄區間。 負分貼文之間的排序差異幾乎歸零,全部沉到最底下擠成一團。 不是「排後面一點」,是「掉出可見範圍」。
兩個條件加成
| 機制 | 行為 | 位置 |
|---|---|---|
| 雙向追蹤回覆加成 | 互相追蹤時,回覆權重 5.0 → 20.0(5.0+15.0) | ranking_scorer.rs:186-193 |
| 雙向追蹤停留加成 | 同機制,預設 0.0(等於關閉) | ranking_scorer.rs:215-222 |

④ 三段調整
| 調整 | 算式與係數 | 位置 |
|---|---|---|
| 同作者衰減 | (1 − 0.25) × 0.5^k + 0.25,k=這位作者在同一批結果中前面已出現幾則(`author_counts` 取值,0 起算)。 第 1 則 ×1.0、第 2 則 ×0.625、第 3 則 ×0.4375…樓地板 0.25 | ranking_scorer.rs:614-616 param.rs:229-238 |
| 未追蹤折扣 | 沒追蹤的作者 ×0.75;帶主題時更重 ×0.5 | ranking_scorer.rs:681-698 |
| 新用戶模式 | 符合條件的新帳號,未追蹤內容 ×0.00001 條件:帳齡 < NewUserAgeThresholdSecs 且 追蹤數 ≥ 5 | ranking_scorer.rs:688-698 config.rs:38-39 |
不要把 0.00001 寫成聳動結論:NewUserAgeThresholdSecs 的預設值是 0 (param.rs:273)。帳齡不可能小於 0 秒,所以這個機制預設不生效。 正確說法是:開關存在、力道極端、目前關著。

三個「蓋好了但關著」的開關
| 開關 | 預設 | 打開會怎樣 |
|---|---|---|
| NewUserAgeThresholdSecs | 0 秒 | 新帳號的未追蹤內容 ×0.00001,等於只剩同溫層 |
| EnableInventoryHoldout | false | 依 (貼文 ID × 使用者 ID) 雜湊,穩定扣住指定百分比的原創/回覆/轉推。三個比例預設皆 0 |
| VMRankerSendHeadWeights | false | 把權重表送給 vm-ranker 重排服務;目前只送預測分數不送權重 |
⑤ 20 道過濾器
來源 home-mixer/candidate_pipeline/phoenix_candidate_pipeline.rs L344–362(前置 17 道)與 L417–421(後置 3 道)。全部無條件註冊,沒有任何條件式開關。

| # | 行號 | 過濾器 | 砍掉什麼 |
|---|---|---|---|
| 1 | L345 | DropDuplicatesFilter | 不同來源撈到的同一則 |
| 2 | L346 | CoreDataHydrationFilter | 內文與中繼資料載入失敗 |
| 3 | L347 | AgeFilter | 超過 48 小時(MAX_POST_AGE = 172800 秒) |
| 4 | L348 | SelfTweetFilter | 你自己發的 |
| 5 | L349 | OONRetweetReplyFilter | 未追蹤帳號的轉推與回覆 |
| 6 | L350 | OONNsfwSimclustersFilter | SimClusters 撈到、作者被標成人內容、且你沒追蹤 |
| 7 | L351 | RetweetDeduplicationFilter | 同一則被重複轉推 |
| 8 | L352 | IneligibleSubscriptionFilter | 沒訂閱所以看不到的付費內容 |
| 9 | L353 | PreviouslySeenPostsFilter | 已經看過的 |
| 10 | L354 | PreviouslySeenPostsBackupFilter | 同上,第二份曝光紀錄再擋一次 |
| 11 | L355 | PreviouslyServedPostsFilter | 本次工作階段已送出過的 |
| 12 | L356 | MutedKeywordFilter | 命中你的靜音關鍵字 |
| 13 | L357 | AuthorSocialgraphFilter | 你封鎖或靜音的帳號 |
| 14 | L358 | VideoFilter | 請求排除影片時擋影片 |
| 15 | L359 | TopicIdsFilter | 不在指定主題/在排除主題內 |
| 16 | L360 | NewUserMinEngagementFilter | 新帳號的未追蹤內容互動數不夠 |
| 17 | L361 | InventoryHoldoutFilter | 雜湊決定性地扣住一定比例(預設 0%) |
| 18 | L418 | VFFilter | 可見度系統回答 drop 的 |
| 19 | L419 | AncillaryVFFilter | 父/引用/轉推來源被 drop 的 |
| 20 | L420 | DedupConversationFilter | 同一串對話的其他分支 |
對帳結果:README 宣稱的 17+3 道與順序,與程式碼逐條完全吻合,零位移。這一項 X 沒有美化。
⑥ 54 條可見度規則
來源 visibility-filtering/rules/registry.rs(912 行)。第一條回答 drop 者為準,後面不再評估。

| 項目 | 數值 | 說明 |
|---|---|---|
| 人人適用 base_home_rules() L101–132 | 28 | — |
| 未追蹤內容加碼 oon_drops L138–170 | 26 | — |
| 未追蹤內容要通過的總數 | 54 | — |
基本 28 條依序:作者狀態 4 條(停權/停用/抹除/離站)→ 保護帳號 → 你封鎖 → 你靜音 → 靜音轉推 → 內容標籤 8 條(PDNA、退件、垃圾訊息、緊急、仇恨言論、暴力言論、濫用、公民誠信)→ 未廣播 → 過期 → 法律下架 2 條 → 敏感內容對登出/未成年/未填年齡 3 條 → 專屬內容 → 最後 4 條是插頁警示而非直接砍掉。
未追蹤多背的 26 條全部只能 drop:DMCA 媒體、地區限制媒體、成人內容 4 種判定、 高召回率的成人與垃圾訊息偵測(寧可錯殺)、惡意網址、「不要放大」標籤等。
⑦ 6 個歸零權重的三種性質
分辨方式:看模型有沒有被訓練去預測這個動作。有訓練、只是定價 0 =真槓桿; 連訓練損失都沒設 =只是留白。
共通機制:沒有任何「權重是 0 就跳過」的守衛(唯一例外是 BidirectionalFollowDwellWeightBoost,見下)。 算式一律 機率 × 權重,0 權重照樣計算、照樣進 26 項陣列,結果恆為 0。 模型仍花算力預測它、管線仍傳遞它,只是最後乘以零。
第 1 類:模型有訓練,只是定價 0 —— 真槓桿
| 參數 | 對應預測頭 | 打開的效果 |
|---|---|---|
| ProfileClickWeight | CLIENT_TWEET_CLICK_PROFILE = 30 | 「點作者頭像」開始計分。已進 positive_sum(:112),調高會同時放大分子與分母 |
| DwellWeight | CLIENT_TWEET_RECAP_DWELLED = 11 | 「有沒有停留」開始計分。現況是「秒數算錢、有沒有停留不算錢」 |
| QuotedVqvWeight | CLIENT_QUOTED_TWEET_VIDEO_QUALITY_VIEW = 48 | 被引用貼文的影片有效觀看開始計分,但另有長度閘門 |
QuotedVqv 的雙保險:util/candidates_util.rs:42-60 有一個同名函式quoted_vqv_weight(),它是把權重歸零的閘:若 EnableQuotedVqvDurationCheck 開啟(預設 false),被引用影片必須 > 10,000 毫秒,否則權重直接改寫成 0.0。
第 2 類:連訓練損失都沒設 —— 只是留白
整個 phoenix/ 訓練設定裡,只有 DWELL_TIME 一個連續頭配了損失函數 (recsys_model.py:473-479 與 xrecsys.py:566-585, 畫廊版面用 tweedie、其餘用 mae)。
| 參數 | 連續頭 | 實情 |
|---|---|---|
| ContClickDwellTimeWeight | CLICK_DWELL_TIME = 2 | 無訓練損失。但低按讚率懲罰機制已蓋好(baseline 0.01/alpha 0.5/floor 0.01/cap 1.0, ranking_scorer.rs:195-213)掛在一個權重 0 的項目上 |
| ContActiveSecs5mResidualNormWeight | ACTIVE_SECS_5M_RESIDUAL_NORM = 3 | 無訓練損失。衡量「你有沒有因為這則貼文而多留在 App 裡」 |
這兩個還有結構性問題:分子分母不對稱。positive_sum(:104-122)不包含這兩個連續項,但它們會進分子的 26 項加總。 而 total_sum 正是負分壓縮公式的分母(:524-532)。 一旦調上去,分子變大、分母不變,負分貼文的壓縮比例會失真。權重為 0 時看不出來,一調就浮現。
第 3 類:有守衛、有專屬測試的正式關閉開關
BidirectionalFollowDwellWeightBoost 是唯一有 != 0.0 短路守衛的 (ranking_scorer.rs:216-221)。測試碼裡有一個專門驗證「設 0 時必須毫無作用」的測試 bidirectional_weight_zero_boost_is_noop(L1288 起), 另一個測試把它設成 2.0 驗證加成生效(L1250-1253)。 它的雙胞胎兄弟(回覆版加成)是開著的,值 15.0。
從 204 到 21
| 層級 | 數量 |
|---|---|
| 動作列舉表登記的動作(含 8 個佔位符) | 204 |
| 模型輸出頭預算 ACTION_TYPE_MAP_LEN(補齊到 64) | 60 |
| 連續頭槽位(5 個真值補齊到 8) | 8 |
| 連續頭實際有訓練損失的 | 1 |
| For You 排序器實際取用的預測頭 | 26 |
| 權重非 0、真正左右排序的 | 21 |

⑧ BRIDGE_PROBABILITY 專卷
全 repo 不分大小寫 grep -rin bridg 共 25 命中。先剔除三類同名雜訊。
| 命中 | 位置 | 其實是什麼 |
|---|---|---|
| AdActionInfo.bridgeType AdActionInfo.isTwclidBridged | recsys.proto:1306-1307 | 廣告轉換歸因。twclid=Twitter Click ID。與推薦演算法的 bridging 無關 |
| _bridge_ads_s3_env() | retrieval_dataset.py:33,50 | 設定 S3 環境變數 |
| smyte_bridge | botmaker/scarecrow_features/ | Smyte(Twitter 2018 併購的反濫用公司)事件整合層 |
schema 裡有位置
enum ContinuousActionName { recsys.proto:437-443
INVALID_CONTINUOUS_ACTION_NAME = 0;
DWELL_TIME = 1; → Rust 權重 0.004(開著)
CLICK_DWELL_TIME = 2; → Rust 權重 0.0(關著)
ACTIVE_SECS_5M_RESIDUAL_NORM = 3; → Rust 權重 0.0(關著)
BRIDGE_PROBABILITY = 4; → Rust 連參數都沒有
}全 repo .rs 檔 grep bridge = 0 命中。排序公式裡沒有它的項次, 連一個乘以零的位置都沒留。
兩條接線,都是輸入、都關著
| 路徑 | 開關(預設) | 做什麼 |
|---|---|---|
| A:主模型 | concat_history_bridge_prob = False recsys_model.py:534 | 取 ca[:, :, 0] → clip 0~1 → 接在作者嵌入向量後(:976-978)→ 過投影矩陣 |
| B:特徵前處理 | enable_bridge_prob = False recsys_feature_prep.py:166 | 取 cont_actions[:, :, 0] → clip 0~1 → _embed_scalar_times_vector(bridge_p, "hist_bridge_prob_vec")(:756-761) =機率 × 一個 2,560 維可學習向量,加到歷史 token |
全 repo 沒有任何地方把這兩個開關設成 True——不在 configs、不在測試、不在 yaml/json/toml。 對照組 enable_dwell_time 用一模一樣的機制,預設 True, 且在多個設定檔明確帶上。同樣的水管,一條通水,一條封死。

索引矛盾:四條證據解開
兩條 bridge 路徑都讀索引 0,但列舉說 0 是 INVALID、bridge 是 4。
| 證據 | 內容 |
|---|---|
| 一 | 列舉值 2、3、4 從未被當成陣列索引使用。全 phoenix [:, :, 2]/[:, :, 3]/[:, :, 4] 各 0 命中; 只有 [:, :, 0] 與 [:, :, 1] 被讀 |
| 二 | 存在只有 2 格的連續陣列(parquet_recsys.py:845 預設 num_continuous_actions: int = 2;grpc_recsys.py:372 寫死 2)。 2 格裡能用的只有 0 和 1——正好是 bridge 與 dwell。若佈局全照列舉編號,2 格裝不下 bridge |
| 三 | 兩個 Rust 生產者 (crates/common/xai-recsys/src/util.rs:725-727、 crates/serving/xai-recsys-engine/src/util.rs:136-138) 寫入連續陣列時,唯一用到的列舉值是 ContinuousActionName::DwellTime。 全 repo Rust 檔裡 ContinuousActionName 只出現這 2 次。 即時服務路徑從不寫入 bridge,那格恆為 0.0 |
| 四 | 訓練資料路徑是逐格照抄: history_continuous_actions[base + j] = floats.value(j)(util.rs:1177-1187), 從 parquet 的 continuousActionValuesSeqSeq 欄位搬進來,程式碼完全不解讀語意。 誰定義第 0 格是 bridge?產生那份 parquet 的上游——而它不在這個 repo 裡 |
結論:陣列語意不完全由公開列舉決定。但在即時服務路徑上沒有歧義—— 只有 dwell 那格會被填,bridge 那格恆為 0.0。就算把開關打開,也是 0.0 × 學到的向量,加了等於沒加。
| 項目 | 數值 | 說明 |
|---|---|---|
| 為 bridge 寫好的完整接線 | 2 | — |
| 被打開的開關 | 0 | — |
| 訓練損失 | 0 | — |
| 排序權重參數 | 0 | — |
⑨ Phoenix 模型規格
來源 phoenix/xrex/configs/xrecsys.py。這是實際訓練設定,不是示範用的玩具模型。

| 項目 | 數值 | 意義 |
|---|---|---|
| history_seq_len | 1,022 | 一次看你最近 1,022 個行為 |
| candidate_seq_len | 64 | 一批評分 64 則候選 |
| num_layers | 8 | 8 層 Transformer |
| emb_size | 2,560 | 模型寬度 |
| query_heads / kv_heads | 20 / 4 | 分組查詢注意力(GQA) |
| total_samples | 1×10^11 | 1,000 億筆訓練樣本 |
| user_vocab_size | 100,000,000 | 1 億使用者雜湊桶 |
| item_vocab_size | 100,000,000 | 1 億貼文雜湊桶 |
| author_vocab_size | 30,000,000 | 3,000 萬作者 |
| ip_vocab_size | 10,000,000 | 1,000 萬 IP |
| emb_learning_rate | 0.2 | 嵌入層學習率 |
另有 nano 版(emb_size 512 / num_layers 4 / query_heads 4), 搭配倉庫附的合成資料產生器,外人可以真的把模型從頭訓練跑一遍。這是這次開源最實在的一塊。
技術選擇:JAX/Haiku(hk.Module)而非 PyTorch,自寫 CUDA kernel(6 個 .cu) 與 Pallas kernel 做注意力;損失支援 mse/mae/huber/tweedie (tweedie 專門處理「大量為零、偶爾很大」的分佈,正合互動資料的形狀)。
候選來源與周邊元件
| 元件 | 規模 | 負責什麼 |
|---|---|---|
| thunder/ | 24 檔 Rust | 記憶體裡存你追蹤對象的近期貼文(已追蹤來源) |
| phoenix/ | 303 檔 | 檢索+排序模型本體(未追蹤來源+打分) |
| simclusters/ | 232 檔 Scala | Twitter 時代的社群分群檢索(未追蹤來源) |
| vm-ranker/ | 10 檔 Rust | 最後重排;核心 dpp.rs(決定性點過程,做多樣化) |
| grox/ | 165 檔 Python | 用 LLM(Grok)做內容安全標註的離線流程 |
| botmaker/ | 492+73 檔 | 規則引擎與 73 條安全規則(Java/Scala 遺產) |
⑩ 開源留白與三個破綻
X 自己承認沒放的:Grox 的 LLM 提示詞(.j2 檔,即「AI 判定內容安全時到底問了什麼」)、 部分 botmaker 規則、部署與基礎設施程式碼。理由寫得很明白:怕被拿去鑽漏洞。

破綻一:一個過濾器檔案沒被宣告,等於死碼
home-mixer/filters/ 有 27 個 filter 檔,mod.rs 只宣告 26 個。 沒被宣告的是 popular_topics_author_dedup_filter.rs——在磁碟上,但編譯時不會被納入。
破綻二:mod.rs 第 8 行是空行,位置在字母序斷點上
宣告嚴格按字母排序,而 drop_duplicates_filter 與 following_retweet_deduplication_filter 之間空了一行。 這正是某個以 e 或 f 開頭的模組被刪掉會留下的痕跡。無法證明刪了什麼,但這是發布前有人動過手的痕跡。
破綻三:6 個過濾器存在但這條管線用不到
ad_adjacent_served、following_retweet_deduplication、 invalid_conversation_module、push_to_home_dedup、 result_size、self_reply_chain——有完整實作,但不在 Phoenix 主管線裡。 它們屬於其他 timeline 管線。這個 repo 給的是 For You 這一條線,不是 X 的全部。
⑪ 派工與交叉驗證紀錄
粗重但必須零誤差的工作派給低階模型;每一條交付都以原始碼親自復驗,未採信任何一方自報。
| 執行者 | 被派的工作 | 驗收 | 實跑對帳結果 |
|---|---|---|---|
| CX gpt-5.6-luna (最低推理檔) | ① 33 個權重交叉引用 1,679 行評分器 ② 6 個歸零權重全流向 ③ bridge 全流向 | 全數通過 | 抽驗 ranking_scorer.rs:63、:104-128、:216-221、 :470-510、:511-533、config.rs:38-40 —— 逐字相符。第三輪還主動找出我漏掉的 Rust 生產者 util.rs:725-727 |
| GM Gemini 3.7 Flash (High) | ① 過濾器順序對帳 ② 54 條可見度規則順序 ③ 測試碼鑑識 | 全數通過 | 獨立 sed -n '344,362p'、'101,133p' 重跑,名稱/順序/行號全部吻合。 第一輪我餵錯檔(給了只註冊 2 個 filter 的 for_you 管線), 它如實回報「只有 2 個」而沒有幫我圓場——是我的出題失誤 |
| MX MiniMax-Text-01 | 權重數值保真複核(獨立重讀原始碼) | 數值滿分 計數失準 | 30 個重疊項目的數值 100% 逐字正確,一個小數點都沒錯。 但多抓 5 個名稱不含 Weight 的參數、漏抓 1 個布林參數、自報 37 列實際 35 列、 多行參數行號偏移 1–2 行。數字可信,計數不可信 |
| HK Haiku ×3 | Phoenix 模型盤點、8 個元件目錄盤點、連續動作佈局全掃 | 通過 | 抽驗 xrecsys.py:241-251、:355-358 —— 逐字相符。 「只有 DWELL_TIME 有損失函數」這條關鍵線索就是從它的命中清單追下去的 |
| HK Haiku(第 4 次,盲測) | 不給答案,要求獨立推導 10 個關鍵數字 | 整份棄用 | 執行 0 次工具呼叫,10 題全部憑空捏造。詳見下方 |
一次造假事件(保留在案)
最後一輪盲測,代理回傳了格式完整、看起來很專業的 10 題答案,附「指令+輸出+答案」三段。 但它一次工具都沒跑(tool_uses: 0),所有「原始輸出」都是編的。實跑反駁:
| 它宣稱的東西 | 實際 grep 命中 |
|---|---|
| param!(FavoriteWeight, 0.0, 1000.0, 8.5); | 0 |
| filters.push(...) | 0 |
| FutureOutstanding / NumDrafts 等 filter 名 | 0 |
| CONTINUOUS_ACTION_UNKNOWN | 0 |
| 「param! 區塊共 37 個」 | 實際 183 |
| 「history_seq_len: 50」 | 實際 1,022 |
為什麼要把這件事寫進證據報告:這份捏造的交付格式完美、語氣自信、還附了「可重跑指令清單」。 如果沒有先建立機器真值,它會直接混進報告。 抓到它的不是懷疑,是對帳。——這正是「不信自報、必親跑驗收」這條紀律存在的理由。

我自己犯的三個錯(一併在案)
- 解析器靜默漏抓:第一版只掃多行 param!,漏掉 13 個單行寫法—— 而真正的評分權重全部在那 13 個裡。實計 170 ≠ grep -c 的 183 才抓到。
- 派工餵錯檔:把只註冊 2 個 filter 的 for_you_candidate_pipeline.rs 當成主過濾鏈餵給 GM,白跑一輪。真正的主鏈在 phoenix_candidate_pipeline.rs。
- 驗證腳本本身有 bug:第一版 verify-all.sh 用 grep -A4 抽多行參數的預設值,抓錯行,產生 6 個假 FAIL。 換成完整解析器後 58/58 全過。閘門自己會壞,所以閘門要自驗。
⑫ 證據界線:我不能證明什麼
- 不能證明線上實際值。param.rs 開頭註解寫明它是 "mirrored from config feature-switch defaults; last sync 2026-08-12", 而 feature switch 線上可調。程式碼能證明「公開版的預設值是什麼」, 證明不了「X 線上此刻用的是什麼」。
- 不能計算實際分數組成。公式是 權重 × 預測機率,而機率由模型產生,不在 repo 裡。 所有「某動作比某動作重要 N 倍」的說法,都只成立在定價層面。
- 不能還原 Grox 提示詞。X 明說沒放。內容安全判定的實際問法是黑的。
- 不能斷定連續動作陣列第 0 格的真正語意。訓練資料是逐格照抄上游 parquet, 而產生 parquet 的元件不在 repo 內。
- 不能涵蓋 For You 以外的線。6 個過濾器屬於其他管線,那些管線沒有公開。

⑬ 附錄:完整復現腳本
以下三步可從零復現本文全部 58 條命題。第 2 步的解析器同時處理多行與單行 param!, 這是避開第 ⑪ 節「錯誤一」的關鍵。

# 1. 取得同一份程式碼(HEAD 必須是 a389166)
git clone https://github.com/xai-org/x-algorithm.git
cd x-algorithm && git log -1 --format=%H
# 2. 抽出全部 183 個參數(多行+單行兩種寫法都處理)
python3 - <<'PY'
src=open('home-mixer/params/param.rs').read().split('\n')
rows={}; i=0
while i < len(src):
l=src[i]
if l.startswith('param!('):
if l.rstrip().endswith(');'):
parts=[x.strip() for x in l[7:].rstrip()[:-2].split(',')]
rows[parts[0]]=(i+1,parts[-1]); i+=1; continue
j=i+1; body=[]
while j<len(src) and not src[j].startswith(');'):
body.append(src[j].strip()); j+=1
parts=[b.rstrip(',').strip() for b in body if b.strip()]
rows[parts[0]]=(i+1,parts[-1]); i=j+1; continue
i+=1
print('param! 區塊 =', len(rows))
print('名稱含 Weight =', sum(1 for k in rows if 'Weight' in k))
for k in ['FavoriteWeight','ReportWeight','MuteAuthorWeight','ShareViaCopyLinkWeight',
'ProfileClickWeight','DwellWeight','QuotedVqvWeight','NewUserAgeThresholdSecs']:
print(f'{k:36s} L{rows[k][0]:<5d} = {rows[k][1]}')
PY
# 3. 其餘命題
sed -n '30,45p' home-mixer/params/config.rs # 五個關鍵常數
sed -n '511,533p' home-mixer/scorers/ranking_scorer.rs # 正負拆分與位移
sed -n '104,128p' home-mixer/scorers/ranking_scorer.rs # positive_sum / total_sum
sed -n '681,700p' home-mixer/scorers/ranking_scorer.rs # 未追蹤折扣與新用戶
sed -n '610,620p' home-mixer/scorers/ranking_scorer.rs # 多樣性衰減公式
sed -n '216,221p' home-mixer/scorers/ranking_scorer.rs # 唯一的 !=0.0 守衛
sed -n '42,60p' home-mixer/util/candidates_util.rs # quoted_vqv 長度閘門
sed -n '344,362p' home-mixer/candidate_pipeline/phoenix_candidate_pipeline.rs # 17 道前置
sed -n '417,421p' home-mixer/candidate_pipeline/phoenix_candidate_pipeline.rs # 3 道後置
sed -n '101,133p' visibility-filtering/rules/registry.rs # 28 條基本規則
sed -n '138,172p' visibility-filtering/rules/registry.rs # 26 條 OON 加碼
# 死碼證明:27 個檔案 vs 26 個宣告
ls home-mixer/filters/*.rs | grep -vc mod.rs
grep -c '^pub mod' home-mixer/filters/mod.rs
# bridge 專卷
grep -rin bridg . --exclude-dir=.git | wc -l # 25(含 3 類雜訊)
grep -ri bridge --include='*.rs' . | wc -l # 0 ← Rust 側完全沒有
sed -n '437,443p' phoenix/python/common/xai-proto/proto/recsys.proto
grep -rn '\[:, :, 4\]' phoenix --include='*.py' | wc -l # 0 ← 列舉值 4 從未當索引用
grep -rn 'ContinuousActionName' phoenix/crates --include='*.rs' # 2 行,都是 DwellTime
sed -n '725,730p' phoenix/crates/common/xai-recsys/src/util.rs # 生產者只寫 dwell
sed -n '1177,1187p' phoenix/crates/common/xai-recsys/src/util.rs # 訓練路徑逐格照抄
# Phoenix 真實超參數
sed -n '238,252p' phoenix/xrex/configs/xrecsys.py
sed -n '353,360p' phoenix/xrex/configs/xrecsys.py
grep -n '^NUM_CONTINUOUS\|^DWELL_INDEX' phoenix/reference/dump_gen.py本頁 58 條命題由 verify-all.sh 實跑輸出直接轉表,未經人工轉錄。 自驗:注入一個錯誤期望值 → 腳本正確產生 1 FAIL,證明比對邏輯有效。 原始交付檔(CX/GM/MX/HK 各方原文)與腳本留存備查。
來源與驗證
本文依據 xai-org 於 GitHub 公開的 X 推薦演算法原始碼撰寫,判讀日期 2026 年 8 月 14 日。
| 項目 | 內容 |
|---|---|
| 原始碼儲存庫 | xai-org/x-algorithm |
| 判讀版本 HEAD | a389166f6cf5da70a286b568c87695d4dcdce3a1 |
| 快照日期 | 2026-08-13 |
| 機器命題驗證 | 58 條,全數通過 |
| 本文引用的原始碼檔案 | x-algorithm README(官方說明)、權重參數定義 param.rs、評分器 ranking_scorer.rs、常數定義 config.rs、候選管線與過濾器註冊、可見度規則註冊表 |
本文所列每一條命題均由驗證腳本實跑產生,未經人工轉錄;驗證腳本本身另經 should-FAIL 反例檢查。
效力界線:原始碼中的參數註明為 feature switch 預設值的鏡像,線上可隨時調整。 本文能證明公開版本的預設值,不能證明平台線上當下實際使用的數值。 最終分數為「權重乘以模型預測機率」,而機率不在公開原始碼內,因此所有倍數比較僅成立於定價層。
FAQ
- 負權重與正權重相比,在演算法中定價相差多少?
- 根據程式碼內建預設值,正權重合計為 +43.324,負權重合計為 −367.22,負正倍數為 8.48 倍。這代表 X 對負面訊號的定價比正面訊號貴一個數量級,但單則貼文的實際得分仍需乘上模型預測機率。
- 貼文算出來若是負分,在推薦排序中會如何處理?
- 依據評分公式的位移機制,所有負分貼文會被壓縮到 0 至 0.001 的極窄區間內。這導致負分貼文之間的排序差異幾乎歸零,全部沉到最底端而掉出可見範圍。
- 推薦管線中一共設置了幾道候選貼文過濾器?
- 候選管線中無條件註冊了 20 道過濾器,包含 17 道前置過濾器與 3 道後置過濾器。過濾規則涵蓋重複內容、超過 48 小時貼文、未追蹤者的轉推與回覆,以及可見度系統判定剔除的內容。
- 推薦給非追蹤者的未追蹤內容(OON)需要通過幾條可見度規則?
- 所有人適用的基本可見度規則有 28 條,未追蹤內容則額外加碼 26 條規則。因此推薦給陌生人的內容總共必須通過 54 條過濾規則,且只要第一條回答 drop 即直接剔除。
- 演算法中的 BRIDGE_PROBABILITY 訊號目前的啟用狀態為何?
- 在公開的程式碼中,BRIDGE_PROBABILITY 雖然已定義列舉項與接線結構,但所有開關設為 True 的次數為 0,且無訓練損失與排序權重。這表示該功能處於未啟用且無即時資料來源輸入的狀態。
來源錨定
- xai-org/x-algorithm 原始碼儲存庫 · https://github.com/xai-org/x-algorithm · 在 IDAEO 的其他引用
- x-algorithm README(官方說明) · https://github.com/xai-org/x-algorithm/blob/a389166f6cf5da70a286b568c87695d4dcdce3a1/README.md · 在 IDAEO 的其他引用
- 權重參數定義 param.rs · https://github.com/xai-org/x-algorithm/blob/a389166f6cf5da70a286b568c87695d4dcdce3a1/home-mixer/params/param.rs · 在 IDAEO 的其他引用
- 評分器 ranking_scorer.rs · https://github.com/xai-org/x-algorithm/blob/a389166f6cf5da70a286b568c87695d4dcdce3a1/home-mixer/scorers/ranking_scorer.rs · 在 IDAEO 的其他引用
- 常數定義 config.rs · https://github.com/xai-org/x-algorithm/blob/a389166f6cf5da70a286b568c87695d4dcdce3a1/home-mixer/params/config.rs · 在 IDAEO 的其他引用
- 候選管線與過濾器註冊 · https://github.com/xai-org/x-algorithm/blob/a389166f6cf5da70a286b568c87695d4dcdce3a1/home-mixer/candidate_pipeline/phoenix_candidate_pipeline.rs · 在 IDAEO 的其他引用
- 可見度規則註冊表 · https://github.com/xai-org/x-algorithm/blob/a389166f6cf5da70a286b568c87695d4dcdce3a1/visibility-filtering/rules/registry.rs · 在 IDAEO 的其他引用
引用本文
TK Lin・《X 演算法拆解證據總表》・IDAEO 知識庫・2026-08-14・https://km.idaeo.ai/post/ai/x-algorithm-evidence更新於 2026-08-15