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 | 排序器取用預測頭數 | 27 | 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用的唯一連續動作 | 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 個。數值為程式碼內建預設值,線上可由 feature switch 覆寫。
抽取陷阱(我第一版就中了):這個檔案同時存在多行與單行兩種 param! 寫法。 只掃多行會靜默漏掉 13 個——而真正的評分權重全部在那 13 個裡面。 實計 170 ≠ grep -c '^param!(' 的 183 才抓到。附錄的解析器兩種都處理。

正權重(17 個)
| 行號 | 參數 | 預設值 | 對應動作 |
|---|---|---|---|
| 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 |
| 項目 | 數值 | 說明 |
|---|---|---|
| 正權重合計(19 項,不含兩個 OON 折扣係數) | +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=該作者第幾則。 第 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 就跳過」的守衛(唯一例外是 F)。 算式一律 機率 × 權重,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 各方原文)與腳本保留在 ~/work/xalgo-research/。
來源與驗證
本文依據 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 對負面訊號的定價比正面訊號貴一個數量級,但單則貼文的實際得分仍需乘上模型預測機率。
- 負の重みは正の重みと比べ、アルゴリズム上でどれほど値付けが異なる? — コードに組み込まれた既定値によれば、正の重みの合計は +43.324、負の重みの合計は −367.22、負正比は 8.48 倍である。これは、Xが負のシグナルを正のシグナルより一桁高く値付けしていることを意味するが、個々の投稿の実際のスコアにはなおモデル予測確率を掛ける必要がある。
- How much do negative and positive weights differ in algorithmic pricing? — Under the code's built-in defaults, positive weights total +43.324 and negative weights total −367.22, a negative-to-positive multiple of 8.48. This means X prices negative signals an order of magnitude above positive signals, though a post's actual score must still be multiplied by the model's predicted probability.
- 貼文算出來若是負分,在推薦排序中會如何處理?
- 依據評分公式的位移機制,所有負分貼文會被壓縮到 0 至 0.001 的極窄區間內。這導致負分貼文之間的排序差異幾乎歸零,全部沉到最底端而掉出可見範圍。
- 投稿の計算結果が負のスコアの場合、推薦順位ではどのように扱われる? — スコア式のシフト機構により、すべての負スコア投稿は 0 から 0.001 のきわめて狭い区間に圧縮される。その結果、負スコア投稿間の順位差はほぼゼロになり、すべて最下位に沈んで表示範囲から外れる。
- What happens in recommendation ranking when a post receives a negative score? — Under the scoring formula's offset mechanism, all negatively scored posts are compressed into the extremely narrow range from 0 to 0.001. Ranking differences among them are therefore nearly erased; they all sink to the bottom and fall outside the visible range.
- 推薦管線中一共設置了幾道候選貼文過濾器?
- 候選管線中無條件註冊了 20 道過濾器,包含 17 道前置過濾器與 3 道後置過濾器。過濾規則涵蓋重複內容、超過 48 小時貼文、未追蹤者的轉推與回覆,以及可見度系統判定剔除的內容。
- 推薦パイプラインには候補投稿フィルターが合計何段設定されている? — 候補パイプラインには20段のフィルターが無条件に登録され、17段の前置フィルターと3段の後置フィルターを含む。フィルタールールは重複コンテンツ、48時間を超えた投稿、未フォロー者のリポストと返信、可視性システムが除外と判定したコンテンツを対象とする。
- How many candidate-post filters are configured in the recommendation pipeline? — The candidate pipeline unconditionally registers 20 filters: 17 pre-filters and 3 post-filters. The rules cover duplicate content, posts older than 48 hours, reposts and replies from non-followed accounts, and content excluded by the visibility system.
- 推薦給非追蹤者的未追蹤內容(OON)需要通過幾條可見度規則?
- 所有人適用的基本可見度規則有 28 條,未追蹤內容則額外加碼 26 條規則。因此推薦給陌生人的內容總共必須通過 54 條過濾規則,且只要第一條回答 drop 即直接剔除。
- 非フォロワーに推薦する未フォローコンテンツ(OON)は、何件の可視性ルールを通過する必要がある? — 全員に適用される基本可視性ルールは28件で、未フォローコンテンツにはさらに26件が追加される。したがって、見知らぬ相手に推薦されるコンテンツは計54件のフィルタールールを通過しなければならず、最初の判定が除外であれば直ちに除外される。
- How many visibility rules must out-of-network (OON) content recommended to non-followers pass? — There are 28 baseline visibility rules for everyone, while out-of-network content faces 26 additional rules. Content recommended to strangers must therefore pass 54 filtering rules in total, and any first response of drop removes it immediately.
- 演算法中的 BRIDGE_PROBABILITY 訊號目前的啟用狀態為何?
- 在公開的程式碼中,BRIDGE_PROBABILITY 雖然已定義列舉項與接線結構,但所有開關設為 True 的次數為 0,且無訓練損失與排序權重。這表示該功能處於未啟用且無即時資料來源輸入的狀態。
- アルゴリズム内の BRIDGE_PROBABILITY シグナルは現在どのような有効化状態か? — 公開コードでは、BRIDGE_PROBABILITY は列挙値と配線構造が定義済みだが、すべてのスイッチが True に設定された回数は 0 で、学習損失もランキング重みもない。これは、この機能が有効化されておらず、リアルタイムのデータソース入力もない状態であることを示す。
- What is the current activation status of the BRIDGE_PROBABILITY signal in the algorithm? — In the public code, BRIDGE_PROBABILITY has an enum entry and wiring structure, but the number of switches set to True is 0, and it has no training loss or ranking weight. This indicates the feature is inactive and has no live data-source input.
來源錨定
- 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