X 推荐算法开源了,一次点赞值 0.5 分,一次举报值 -234 分
- 设置点赞 0.5 分、举报-234 分的评分权重,体现平台对主动分发行为的重视
- 公开完整架构但涂改安全参数,如 BDSM 阈值设为 9.99 占位符
- 实施排序与可见性分离,排序模型不负责安全过滤,独立审计调整
- 包含 Phoenix 排序模型、多路候选检索、VMRanker 多样性重排等组件
- 强调排序-过滤分权设计模式,适用于需平衡业务与安全的推荐系统
大家好,我是若风。
你有没有想过,你在 X(原来的 Twitter)上每点一个赞,在推荐算法眼里值多少钱?
答案写在 home-mixer/params/param.rs 第几百行的位置,FavoriteWeight 的默认值是 0.5。
你转发一条帖子,值 1.0 分。你回复一条帖子,值 5.0 分。你把链接复制出去分享,值 20.0 分。
而如果你点了举报,扣 234.0 分。
这些数字不是猜的,是 xAI 在 2026 年 8 月 13 日开源的推荐算法仓库里白纸黑字写着的。整个 xai-org/x-algorithm 仓库目前 27981 Star,4735 Fork,核心代码用 Rust 写的,Apache 2.0 协议。这是人类历史上第一次,一个拥有数亿用户的社交媒体平台,把信息流推荐算法的核心代码和训练参数全盘公开。
但说真的,看完整个仓库之后,我发现「开源」这个词在这里的含义,比你想的要复杂得多。
一条请求的完整旅程
先别急着看权重,你得先搞清楚 For You 信息流到底是怎么拼出来的。
整个系统由一个叫 home-mixer 的服务驱动,它内部跑两条流水线。第一条是 Post Pipeline,负责找到帖子、排序、过滤。第二条是 Blending Pipeline,把排好序的帖子和广告、推荐关注、提示信息混在一起。
Post Pipeline 有 7 个阶段,你刷新一次首页,这 7 步在几百毫秒内全部跑完。
第一步是 Query Hydration,把你的近期行为序列拉出来。你最近点赞了什么、回复了什么、看了多久、屏蔽了谁、屏蔽了哪些关键词,全部组装成模型的输入。这个「用户行为序列」是整个排序模型最重要的特征。
第二步是 Candidate Sources,并行查询三个来源。Thunder 负责站内内容,它把你关注账号的近期帖子缓存在内存里。Phoenix retrieval 负责站外发现,它把你和每条帖子都编码成向量,然后做近邻检索。SimClusters 是第三个来源,它按「谁和谁互动模式相似」把账号和帖子聚成簇,再用簇来发现你可能感兴趣的内容。
坦白讲,三路并行这个设计不稀奇,大部分推荐系统都这么干。稀奇的是接下来第三步的 Hydration,它要给每条候选帖子补充几十个字段,帖子文本、媒体信息、作者详情、账号标签、引用帖、语言、互动计数、订阅状态,一口气全灌进去。这些字段后续会喂给排序模型和过滤规则。
第四步是 Pre-Scoring Filters,在打分之前先砍掉一批。重复帖、超过 48 小时的老帖、你自己的帖、被你屏蔽的账号的帖、你已经看过的帖、你无权访问的订阅帖,通通在这一步移除。
第五步是核心,Scoring。
在进入打分细节之前,先用一张图把整个系统的分层架构看清楚。自上而下是请求实时走的 Request Path,底部虚线框是离线持续运行的内容理解系统,它产出的标签供过滤层读取。
注意图中高亮的核心层「模型打分」,三个组件 PhoenixScorer、RankingScorer、VMRanker 各管一段。PhoenixScorer 预测概率,RankingScorer 算最终分数,VMRanker 做多样性重排。而底部的评分权重一览,就是接下来要逐个拆解的东西。
每个动作的标价
这里就是整个仓库最透明的部分。
Phoenix 是一个 transformer 模型,用 JAX 训练,Rust 服务。它不预测一个笼统的「相关度」分数,而是对每条帖子预测你可能会采取的每一种行为的概率。你可能点赞、回复、转发、引用、分享、复制链接分享、私信分享、点开链接、点开头像、看完视频、停留多久、关注作者,也可能点「不感兴趣」、屏蔽作者、举报。
一共 20 多种行为,每种都有一个预测概率。
然后 RankingScorer 把这些概率加权求和,算出一个最终分数。公式很简单,Final Score = Σ (weight_i × P(action_i))。正面行为正权重,负面行为负权重。
我在 ranking_scorer.rs 里找到了 ScoringWeights 结构体,39 个字段,每一个都从 param.rs 读默认值。这里面的数字才是真正有意思的东西。
正面权重从高到低排,最值钱的几个动作是,复制链接分享 ShareViaCopyLinkWeight = 20.0,私信分享 ShareViaDmWeight = 5.0,回复 ReplyWeight = 5.0,引用 QuoteWeight = 5.0,关注作者 FollowAuthorWeight = 4.0,转发 RetweetWeight = 1.0,分享 ShareWeight = 2.0。
然后是点赞 FavoriteWeight = 0.5。
你可能觉得不对劲。点赞不是社交媒体最重要的互动吗?在 X 的算法里,一个点赞只值 0.5 分,而你复制一条链接分享出去值 20 分,差了 40 倍。
其实吧,这个权重分布透露了一个很清晰的信号。X 最看重的不是你在平台内的被动消费,而是你把内容带到平台外的主动分发行为。复制链接意味着你要去别的地方推荐这条帖子,私信分享意味着你在做一对一的真实推荐。这些行为的信号强度远高于随手一点。
更让人意外的是,DwellWeight = 0.0,停留时间权重为零。ProfileClickWeight = 0.0,点击作者头像权重也为零。
你没看错,X 的排序模型在直接评分阶段完全不考虑你在一篇帖子上停留了多久,也不考虑你有没有点进作者主页。这跟大多数人的直觉相反,大家总觉得社交媒体在拼命优化「让你多停留」。在 X 这里,至少在 Phoenix 的直接评分环节,停留时长没有权重。
当然,停留时间并没有完全被忽略。它出现在两个地方。一个是 ContDwellTimeWeight = 0.004,这是连续停留时间的残差权重,值很小。另一个是一个叫「Dwell Regret」的机制,后面会讲到,那个机制里停留时间的权重能到天文数字。
再说负面权重。这是整个评分体系里最暴力的部分。
举报 ReportWeight = -234.0。你点一次举报,直接扣 234 分。考虑到点赞才加 0.5 分,你需要 468 个点赞才能抵消一个举报。
屏蔽作者 BlockAuthorWeight = -31.2,不感兴趣 NotInterestedWeight = -43.2,静音作者 MuteAuthorWeight = -58.8。
还有一个我前面提到的 Dwell Regret 机制。在 param.rs 里有一个 DwellRegretNegReport 参数,默认值 -60000.0。这是一个完全不同量级的惩罚。它的工作方式是,如果你举报了一条帖子,但你在举报之前在这条帖子上停留了较长时间,系统会认为你被「钓鱼」了,停留体验很差,于是给你一个极其夸张的负分。这个机制在 ranking_scorer.rs 里通过 sigmoid 函数控制,有专门的温度参数和均值参数来调节灵敏度。
这个设计很聪明。它区分了「快速划过的举报」和「认真看了之后觉得恶心然后举报」,后者得到的惩罚信号要强得多。
打分之后还有三道加工程序
分数算出来还不算完。RankingScorer 在加权求和之后,还有三个调整步骤。
第一个是 Author Diversity,作者多样性衰减。同一个作者的第二条帖子,分数乘以 AuthorDiversityDecay = 0.5,第三条再乘 0.5,以此类推,但不会低于 AuthorDiversityFloor = 0.25。这保证了你不会在信息流里看到同一个人连刷七八条。
第二个是 Out-of-Network Discount,站外内容折扣。来自你没关注的账号的帖子,分数乘以 OonWeightFactor = 0.75。你关注的人的回复和转发也会被乘以这个折扣系数。这是一个保守的设计,X 宁可让你多看到你关注的人的内容,也不愿用陌生人的内容冒险。
第三个是 New-Author Boost,新作者提升。如果作者的曝光量低于某个阈值,系统会把他的帖子往目标位置提一提。这个机制在 home-mixer/scorers/author_cold_start.rs 里实现,目的是给新人一口流量。
三步调整之后,还有一个 VMRanker 要过。这是一个独立的服务,代码在 vm-ranker/ 目录下。它用的技术叫 Determinantal Point Process,行列式点过程。说人话就是,它会通过帖子向量之间的相似度来调整排序,牺牲一点点分数来换取相邻帖子之间的多样性。你在信息流里很少看到连续好几条话题高度重复的帖子,功劳有一部分在这里。
排序和可见性,彻底分开
这是我看完整个仓库之后觉得最值得聊的一个设计决策。
README 里有一节叫 Key Design Decisions,第四条写得很明确,「Ranking and Visibility Are Separate」。排序决定顺序,可见性过滤决定一条帖子到底能不能出现。两个独立的服务,不同的输入,不同的规则。
你想一想这意味着什么。
Phoenix 模型可以拼了命地优化互动率,它不需要操心安全、合规、法律这些事。因为就算它把一条帖子排到了第一名,如果可见性过滤说「这条帖子不能展示」,那它在 VFFilter 这一步就会被无声地移除掉。
可见性过滤的代码在 visibility-filtering/ 目录下,核心是 rules/registry.rs 里的规则注册表。它定义了三个安全等级,FilterAll、TimelineHome、TimelineHomeRecommendations。不同等级跑不同的规则集。
最有意思的是 TimelineHomeRecommendations 这个等级。它专门管那些「推荐给你的、来自你没关注的账号」的帖子。在这个等级下,有一批规则只能执行 DROP(移除)操作,不能 ALLOW。比如 NsfwNearPerfectAuthorRule,如果一个账号被标记为 NSFW Near Perfect(高精度 NSFW 判定),它出现在推荐流里时会被直接移除。但同样的帖子,如果你关注了这个账号,它在你关注流的 TimelineHome 等级下是可以正常显示的。
这个设计在代码里有对应的单元测试来保证行为正确。同一条 NSFW 帖子,推荐流里 DROP,关注流里 ALLOW。规则是上下文敏感的。
可见性过滤的判定结果有三种。ALLOW 正常展示,INTERSTITIAL 在一个可点击的遮罩后面展示(比如成人或暴力内容),DROP 直接不展示。而真正执行 DROP 的是 Post Pipeline 第七步的 VFFilter 和 AncillaryVFFilter,后者负责级联移除,如果一条帖子的父帖被移除了,它的回复也会跟着消失。
为什么要把排序和过滤分开?我在代码里读到的答案是,如果让排序模型自己学会过滤不安全内容,模型会在互动率和安全性之间做隐式权衡,这种权衡不可审计、不可解释。拆开之后,安全策略可以独立审计、独立调整,不需要重新训练模型。
这个思路我给起了个名字,叫 「排序-过滤分权」。立法、司法、行政三权分立的政治学原理,套在推荐系统上居然成立。排序模型是立法机构,它提出「这条帖子应该排第几」。可见性过滤是司法机构,它裁决「这条帖子能不能出现」。两者互不干涉,各自独立运行。
这个模式不只适用于社交媒体。任何需要同时优化业务指标和安全合规的推荐系统,都可以借鉴。不要让你的排序模型背负安全责任,给它一个独立的裁判。
被涂掉的那部分
到这里你可能觉得,X 这次开源够彻底的了。连每个行为的评分权重都写出来了。
但问题是,仓库里有些东西被刻意涂掉了。
README 里有一节叫「What's not in this repo?」,明确列了两类缺失的内容。一是 Grox 的 LLM 提示词,那些 .j2 文件里的具体提示词没有公开。二是一部分 botmaker 规则。
botmaker 是 X 的规则引擎语言,scarecrow 是运行它的框架。在 botmaker-rules/scarecrow/bot/ 目录下确实有不少 .bot 文件,比如 GroxTweetProcessor.bot、NSFW_Card_Image_Media_To_URL_Verdict.bot、Tweet_Spam_High_Recall_RTF_All_Bad_URL_Sources.bot。但 README 说,为了降低被人利用来绕过安全系统的风险,部分规则没有放进仓库。
这还算能理解。真正让我觉得有问题的是另一个地方。
仓库里有一个叫 bdsm 的模块,全称 Behavioral Inauthentic-Account Detection Model,行为不真实账号检测模型。它通过读取一个账号随时间的行为序列来判断是不是机器人或滥用账号。这个模块的安全阈值文件 bdsm/runtime/sink_policy.yaml 里,所有阈值都被设成了 9.99。
FollowBot 是 9.99,EngagementAmplifier 是 9.99,RTBot 也是 9.99。
概率的有效范围是 [0, 1],9.99 是一个明显的占位符。这意味着这个文件虽然放在了开源仓库里,但它实际上什么都检测不了。你把它原样部署,没有一个账号会被判定为机器人。
GitHub Issue #25 专门提了这个问题。发帖的人说,这种做法「undermines the repository's transparency mission」,直接削弱了仓库的透明度使命。你想跑通 BDSM 模块,要么自己反编译猜测阈值结构,要么填一堆永远不会触发的 9.99,要么凭空猜合理的阈值。仓库连一个示例模板都没给。
我在 abuse-enforcement-service/service-lib/rules/enforcement_user.yaml 里也发现了类似的手法。有一条规则写的是 cred.follower_count >= 12.34,旁边注释写着「Prod uses a different follower count floor; this is a mock value to reduce gaming」。生产环境用的是另一个粉丝数门槛,这里放了个假值 12.34 来防止被人钻空子。
所以「开源」在这里的含义是,架构全公开,权重全公开,但安全系统的实际操作参数被替换成了假值或占位符。你能看到这座房子怎么盖的,但不知道门锁的密码。
这是不是一个问题?我觉得要分两面看。
一方面,X 确实公开了比任何同类平台都多得多的信息。你能看到完整的流水线架构,看到每一个评分权重的默认值,看到可见性过滤的规则注册表,甚至看到 Phoenix 模型的训练代码和合成数据生成脚本。这个透明度在社交媒体行业是前所未有的。
另一方面,安全系统的参数被涂掉,意味着你无法独立验证这套系统在实际运行中到底怎么处理机器人、垃圾信息和滥用行为。你看到的是框架,不是运行时。
这两面之间的张力,大概是所有想开源安全系统的平台都会面临的困境。全公开,会被钻空子。全保密,就失去了开源的意义。X 选择了中间路线,但中间路线永远是最难自圆其说的。
几个值得单独拎出来说的细节
Hash-Based Embeddings。Phoenix 不管是检索还是排序,都不维护词表。它用多个哈希函数做 embedding lookup。phoenix/crates/common/xai-recsys/src/model_config.rs 里的 HashTableConfig 结构体为 user、item、author、IP 各自维护了一套哈希参数,包括 hash_scales、biases 和 modulus。好处是新帖子发出来立刻可表示,不需要等词表更新。坏处是哈希碰撞会引入噪声,但多哈希函数的设计就是为了分摊碰撞概率。
Candidate Isolation。transformer 推理时,候选帖子之间不能互相 attend,只能 attend 到用户上下文。这个设计在 README 的 Key Design Decisions 第二条里明确写了。它保证了同一条帖子不管跟哪些其他帖子一起出现在一个 batch 里,得分都是一样的。这听起来是个小细节,但它让打分结果可缓存、可复现。如果帖子之间可以互相影响,同一个 batch 的组合方式就会改变每条帖子的得分,缓存就失效了。
llm_slop_user 标签。在 enforcement_user.yaml 里有一条规则,如果账号被打上了 llm_slop_user 标签,就自动加上 SpamHighRecall 标签,TTL 是 30 天。X 已经在用模型检测 AI 生成的垃圾内容账号,并在执法规则里自动降权。如果你在 X 上大量发 AI 生成的低质内容,系统会给你打标签、限流,甚至移出推荐池。
只有 5 次提交。整个仓库从 2026 年 1 月创建到现在,只有 5 次 commit,而且全部是同一条消息「Open-source X Recommendation Algorithm」。这意味着 X 不是在 GitHub 上实时开发的,而是定期把内部代码导出到公开仓库。你看不到真实的开发历史、提交记录和贡献者信息。这是一个单向的代码发布渠道,不是一个开源协作项目。
最后聊两句
X 的推荐算法仓库值不值得看?如果你做推荐系统、信息流排序或者内容安全,非常值得。它是一个工业级推荐系统的完整解剖标本,从候选检索到模型打分到可见性过滤,每一个环节都有真实代码可读。
如果你想拿它来搭建自己的推荐系统,那你需要意识到,这个仓库的大部分代码是设计来在 X 的内部基础设施上运行的。很多依赖(比如 xai_service_runner、xai_kafka)没有包含在仓库里,你拿不到。真正能端到端跑起来的只有 Phoenix 模型的训练和推理部分,它带了 Cargo workspace、pyproject.toml、quickstart 文档和合成数据生成脚本。
但作为学习材料,它已经是市面上能找到的最好的推荐系统开源参考之一。
那个「排序-过滤分权」的设计模式,我觉得是整个仓库最值得带走的东西。不管你做什么样的推荐系统,只要你需要同时追求业务指标和安全合规,把它拆成两个独立系统,永远比让一个模型什么都管要干净。

评论互动