芥末
发布于 2026-01-20 / 0 阅读
0
0

X 推荐算法开源解读:Thunder、Phoenix 与多行为打分机制

X 的「为你推荐」信息流,本质上是一个大规模推荐系统:它要在海量帖子里,快速找出当前用户可能感兴趣、又不违反可见性和安全约束的内容,并按顺序展示出来。

这套系统的核心变化可以概括成一句话:排序层不再主要依赖人工设计的特征和固定规则,而是把用户历史行为、帖子内容和上下文交给基于 Transformer(基于注意力机制的深度学习架构)的模型学习,再预测用户对每条候选帖子的多种行为概率。

推荐流程可以拆成四层:

flowchart TD
    A[用户刷新为你推荐] --> B[候选召回]
    B --> B1[Thunder: 关注圈内容]
    B --> B2[Phoenix: 非关注圈发现]
    B1 --> C[打分前过滤]
    B2 --> C
    C --> D[Transformer 排序模型]
    D --> E[多行为概率预测]
    E --> F[加权求和得到最终分]
    F --> G[多样性/OON/去重等调整]
    G --> H[打分后过滤]
    H --> I[生成信息流]

推荐系统到底在解决什么问题

社交平台的信息流推荐不是简单按时间排序,也不是单纯按照点赞数排序。它要同时处理几个目标:

目标含义
相关性用户看到后是否可能感兴趣
新鲜度是否能及时看到新发内容
发现性是否能接触到未关注账号的优质内容
多样性信息流里不要被同一个账号、同一类内容刷屏
安全与可见性屏蔽、静音、删除、举报、不可见内容不能乱推
负反馈控制用户可能拉黑、举报、点「不感兴趣」的内容要降权

以前很多推荐系统会把这些目标写成大量人工规则,例如:

如果帖子包含某类特征,加多少分
如果账号粉丝很多,加多少分
如果帖子发布时间很近,加多少分
如果用户关注过类似账号,加多少分

这种方式的问题是规则会越来越多,规则之间互相影响,维护成本很高。更麻烦的是,用户行为本身很复杂,很难靠几条人工规则表达。

X 新推荐系统的思路是:让模型从历史互动序列里学习用户偏好,把点赞、回复、停留、视频观看、负反馈等行为统一建模,然后用概率来决定排序。

需要注意一点:所谓「AI(人工智能)驱动」主要指排序和相关性建模层。工程系统里仍然需要过滤、去重、可见性检查和安全策略,否则被删除的帖子、被拉黑账号、重复内容都可能进入信息流。

候选内容来自两条路径:Thunder 和 Phoenix

信息流排序前,系统必须先拿到一批候选帖子。X 的候选来源分成两类:关注圈内容和非关注圈发现内容。

Thunder:关注圈实时内容库

Thunder 负责处理用户已经关注账号的内容。它更像一个实时内容存储和查询系统,重点不是「发现陌生内容」,而是让用户及时看到关注对象的新动态。

它的典型工作方式是:

flowchart LR
    A[帖子发布/删除事件] --> B[Kafka 消息队列]
    B --> C[Thunder 消费事件]
    C --> D[维护用户关注圈内容索引]
    D --> E[快速返回原创帖/回复/转发/视频]

Kafka(分布式消息队列)在这里承担事件流转角色。帖子发布、删除、转发等事件进入 Kafka 后,Thunder 消费这些事件,并更新每个用户关注圈内的候选内容库。

Thunder 解决的是「我关注的人刚发了什么」这个问题。

Phoenix:全球发现引擎

Phoenix 负责从用户没有关注的账号里找内容。它是推荐系统里更接近「发现」的部分,也是小账号内容可能获得陌生流量的关键。

Phoenix 采用双塔结构:

模块作用
用户塔 User Tower把用户画像、历史互动、兴趣上下文编码成向量
候选塔 Candidate Tower把帖子内容、发布账号、互动信号等编码成向量
相似性搜索通过向量点积或近似最近邻检索,找出匹配候选
flowchart LR
    U[用户历史行为] --> UT[用户塔]
    UT --> UV[用户向量]

    P[海量帖子] --> CT[候选塔]
    CT --> PV[帖子向量]

    UV --> S[向量相似性搜索]
    PV --> S
    S --> C[非关注圈候选帖子]

这种结构的优势是可以把「用户是否可能喜欢某条帖子」转成向量匹配问题。只要帖子向量和用户向量足够接近,它就有机会进入候选集,即使发布账号没有大量粉丝。

这也是推荐系统削弱粉丝数量优势的关键机制:粉丝多仍然有利于早期曝光,但非关注圈召回让内容本身的匹配度变得更重要。

排序模型:不预测一个分数,而是预测多种行为

很多人会把推荐算法理解成「给帖子算一个热度分」。X 的新排序方式更细:模型并不是直接输出一个抽象的热度,而是预测用户看到这条帖子后可能发生的多种行为。

可以把模型输出理解成一组概率:

P(like)
P(reply)
P(repost)
P(dwell)
P(video_view)
P(not_interested)
P(report)
P(mute_account)
P(block_account)
...

其中:

  • P(like):用户点赞的概率
  • P(reply):用户回复的概率
  • P(repost):用户转发的概率
  • P(dwell):用户停留阅读的概率
  • P(video_view):用户点开视频观看的概率
  • P(not_interested):用户点「不感兴趣」的概率
  • P(report):用户举报的概率
  • P(mute_account):用户静音账号的概率
  • P(block_account):用户拉黑账号的概率

最终排序分数可以抽象成:

Final Score = Σ(weight_i × P(action_i))

正向行为的权重为正,负向行为的权重为负。

用表格看更直观:

行为类型示例预测项权重方向对排序的影响
正向互动点赞、回复、转发概率越高,分数越高
深度消费停留阅读、点开视频说明用户可能真正消费内容
关系行为关注、进入主页等可能表示账号和用户兴趣匹配
轻度负反馈不感兴趣、跳过降低相似内容继续出现的概率
强负反馈举报、静音、拉黑对推荐分数伤害很大

这种多目标建模比单一热度分更合理。因为一条帖子可能点赞很多,但也可能引发大量举报;一条长帖点赞不高,但用户停留时间很长。多行为预测能把这些信号拆开处理。

为什么负反馈杀伤力很大

负反馈不是普通的「没兴趣」,而是用户在告诉系统:这类内容、这个账号,甚至这种话题不应该继续出现。

公开机制里明确涉及几个负向预测项:

P(block_account)
P(mute_account)
P(report)
P(not_interested)

这些预测项的权重是负数。也就是说,如果模型认为某个用户看到一条帖子后很可能拉黑、静音、举报或点「不感兴趣」,这条帖子在该用户面前的排序分数会明显下降。

更重要的是,强负反馈可能不只影响单次曝光。如果某类内容持续带来举报、静音、拉黑,模型会学到这类模式与负体验相关,后续进入更大推荐池的机会也会降低。

停留时间为什么会成为关键指标

P(dwell) 是独立预测项,表示用户是否可能停留阅读。

这对内容形态有直接影响。短句、段子、图片可能容易获得点赞,但长帖、故事线、系列讨论如果能让用户停下来阅读,也会给模型提供强信号。

推荐系统关心的不是「帖子有多长」,而是:

用户看到它后,是否停止滑动并实际消费?

因此,能让用户读完、思考、回复的内容,比单纯骗点击的标题更稳定。标题党可能带来短期点击,但如果后续伴随跳出、举报、不感兴趣,最终分数会被负向项抵消。

视频预测看的是点开概率,不等于完播率

公开信息里涉及的视频预测项是:

P(video_view)

它关注用户是否可能点开视频,而不是直接把完播率作为核心排序项。

这意味着 X 的视频推荐逻辑和短视频平台不完全一样。短视频平台通常极度依赖播放完成率、重复播放、滑走时间等细粒度观看指标;X 这里更强调信息流场景下用户是否愿意打开视频。

对视频内容来说,封面、首屏信息、配文和开头几秒会影响 P(video_view)。但不能把它简单理解成「只要骗点开就行」,因为后续负反馈仍然会进入整体评分。

多样性机制:连续刷屏会被衰减

推荐系统不能只按分数排序,否则信息流可能被同一个账号连续占满。X 使用发布者多样性评分器来衰减重复发布者的分数,保证信息流里出现不同来源。

简化后可以这样理解:

flowchart TD
    A[候选列表按模型分排序] --> B{同一发布者是否频繁出现}
    B -- 否 --> C[保留原排序]
    B -- 是 --> D[后续帖子分数衰减]
    D --> E[混入其他发布者内容]

这对高频发帖账号影响很直接:连续发很多条,不代表每条都能拿到同等曝光。系统会倾向于让用户看到更多来源,而不是被一个账号占据屏幕。

候选隔离:每条帖子独立打分

候选隔离机制的重点是:排序模型给一条候选帖子打分时,不让它感知同一批次里的其他候选帖子,只让它与用户上下文交互。

flowchart LR
    U[用户上下文] --> A[候选帖子 A 打分]
    U --> B[候选帖子 B 打分]
    U --> C[候选帖子 C 打分]

    A -.不能感知.-> B
    B -.不能感知.-> C
    C -.不能感知.-> A

这样做有两个好处:

好处解释
分数稳定同一条帖子不会因为同批次出现了什么其他帖子而分数变化
便于缓存分数只依赖用户上下文和候选本身,更容易复用计算结果

这也意味着别人的爆款不会直接「抢走」某条帖子的模型分。真正影响排序的是用户与帖子之间的匹配、行为预测概率、过滤和后处理调整。

当然,最终展示位置仍然是有限的。爆款不会改变你的帖子分数,但信息流页面空间有限,所有候选仍然会在后续排序和混排中竞争展示位置。

OON 调分:非关注圈内容要单独平衡

OON(Out-of-Network,非关注网络)指用户没有关注的账号发布的内容。Phoenix 找到的内容通常属于 OON 候选。

OON 内容需要特殊调分,因为信息流不能全部是关注圈内容,也不能全部是陌生内容。系统要在两者之间做平衡:

内容来源优点风险
关注圈内容关系明确,用户预期强发现性不足,容易信息茧房
OON 内容能发现新账号、新话题相关性更不确定,负反馈风险更高

OON Scorer 的作用就是调整非关注圈候选的分数,使「关注」和「发现」保持合适比例。具体调分公式没有完整公开,但可以确定的是,非关注圈内容不会简单和关注圈内容混在一起按同一个裸分排序。

过滤分两阶段:打分前过滤和打分后过滤

推荐系统里的过滤非常关键。模型排序前后都需要过滤,只是目的不同。

打分前过滤

打分前过滤发生在模型计算之前,目标是减少无效候选,避免浪费推理资源。

常见过滤包括:

过滤项作用
删除内容过滤已删除帖子不进入排序
可见性过滤受权限、地区、账号状态限制的内容不进入排序
屏蔽/静音过滤用户已经屏蔽或静音的账号不进入候选
重复内容过滤明显重复或已曝光内容减少进入排序
安全过滤明显违规内容提前剔除

流程如下:

flowchart LR
    A[原始候选] --> B[删除/不可见检查]
    B --> C[屏蔽/静音关系检查]
    C --> D[安全策略检查]
    D --> E[去重与已曝光检查]
    E --> F[进入排序模型]

打分后过滤

打分后过滤发生在模型已经算完分数之后,目标是保证最终信息流质量。

典型处理包括:

后处理作用
已看内容去重用户看过的帖子不反复出现
多样性调整避免同一账号或同一主题密集出现
混排控制平衡关注圈、OON、视频等不同内容类型
安全复查排序后仍可能做额外策略检查
展示约束控制回复、转发、广告、推荐卡片等展示比例
flowchart LR
    A[模型打分候选] --> B[按分数排序]
    B --> C[发布者多样性]
    C --> D[OON 比例调整]
    D --> E[已曝光去重]
    E --> F[安全与可见性复查]
    F --> G[最终信息流]

这解释了一个常见现象:一条帖子即使模型分较高,也不一定会直接展示在最前面,因为后处理还会考虑多样性、比例、去重和安全约束。

去手工特征后,Transformer 学的是什么

去掉手工特征工程并不表示系统没有特征,而是特征不再主要由工程师手写成规则。Transformer 会从用户历史行为序列里学习表示。

例如,一个用户的互动序列可能是:

点赞 AI 话题
停留阅读长帖
回复机器学习讨论
跳过娱乐视频
举报低质量营销内容
关注开源项目账号

模型会把这些行为编码成上下文表示,再和候选帖子交互,预测用户对候选的各种行为概率。

sequenceDiagram
    participant U as 用户历史行为
    participant T as Transformer
    participant C as 候选帖子
    participant H as 多个预测头
    participant S as 最终分数

    U->>T: 编码互动序列
    C->>T: 输入候选表示
    T->>H: 输出行为概率
    H->>S: 权重加权求和

这种做法的核心收益是:模型可以学习复杂模式,而不是依赖人工枚举。

例如,人工规则可能只能写出:

用户喜欢机器学习,所以推荐机器学习内容

模型可以学到更细的模式:

用户喜欢深度技术长帖
用户对短平快资讯停留较少
用户更愿意回复开源工具实践
用户对夸张营销标题有负反馈

这类偏好很难靠人工规则完整表达。

哈希嵌入:用更低成本处理海量稀疏特征

推荐系统会遇到大量稀疏 ID:

  • 用户 ID
  • 帖子 ID
  • 账号 ID
  • 话题 ID
  • 媒体 ID
  • 行为类型
  • 上下文特征

如果每个 ID 都维护独立向量表,存储和查询成本会很高。哈希嵌入的做法是用多个哈希函数把大量 ID 映射到有限的嵌入表中,再组合得到表示。

简化示例:

def hash_embedding(feature_id, embedding_tables, hash_functions):
    vectors = []
    for table, h in zip(embedding_tables, hash_functions):
        index = h(feature_id) % len(table)
        vectors.append(table[index])
    return sum(vectors)

这样可以控制嵌入表规模,同时覆盖大量稀疏特征。代价是哈希冲突不可避免,需要靠多哈希和训练过程降低影响。

对内容发布者意味着什么

推荐系统优化的是用户行为概率,不是单纯奖励某种形式。想获得更稳定的曝光,需要围绕正向行为和低负反馈设计内容。

建议对应机制
开头直接给出明确价值或冲突点提高停留和继续阅读概率
内容结构清楚,减少阅读阻力提高 P(dwell)
鼓励真实讨论,而不是只求点赞回复、对话类行为权重更高
有评论时及时回应对话链能增强互动信号
避免连续刷屏发布者多样性机制会衰减重复来源
少做夸张标题和误导内容负反馈会抵消短期点击收益
谨慎在正文堆外链外跳可能降低站内消费信号
视频重视封面、配文和开头影响 P(video_view)

需要强调的是,小账号并不会自动获得流量。Phoenix 只是让小账号有机会进入非关注圈候选,真正能否扩大曝光,还要看早期用户的停留、互动、负反馈和后续排序表现。

开发者怎么阅读这套系统

如果要研究代码,可以从候选召回、排序、过滤、后处理四条线入手,而不是一上来就通读所有文件。

git clone https://github.com/xai-org/x-algorithm
cd x-algorithm

# 查找核心模块名
grep -R "Thunder" .
grep -R "Phoenix" .
grep -R "OON" .
grep -R "Diversity" .
grep -R "Filter" .

阅读顺序建议按推荐链路来:

顺序关注点
候选召回Thunder 和 Phoenix 如何产生候选
打分前过滤哪些内容在模型前被剔除
排序模型Transformer 输入、输出和预测头
分数融合多行为概率如何加权
后处理多样性、OON、去重、可见性如何影响最终展示

如果只关心业务策略,重点看过滤、权重、负反馈和多样性;如果关心机器学习实现,重点看用户塔、候选塔、Transformer 推理和多行为预测头;如果关心后端架构,重点看 Kafka、实时索引、缓存和服务编排。

核心要点

X 推荐系统可以抽象成一条完整链路:

flowchart TD
    A[用户上下文] --> B[Thunder 召回关注圈内容]
    A --> C[Phoenix 召回非关注圈内容]
    B --> D[打分前过滤]
    C --> D
    D --> E[Transformer 多行为预测]
    E --> F[加权分数]
    F --> G[多样性与 OON 调整]
    G --> H[打分后过滤]
    H --> I[信息流展示]

几个关键结论:

  1. 排序核心从人工特征转向 Transformer 学习用户行为序列。
  2. Thunder 负责关注圈实时内容,Phoenix 负责非关注圈发现。
  3. 排名不是看单一热度,而是预测多种行为概率后加权求和。
  4. 拉黑、静音、举报、不感兴趣等负反馈会显著降低推荐分。
  5. 停留阅读和真实对话是重要正向信号。
  6. 发布者多样性机制会抑制连续刷屏。
  7. 候选隔离让每条帖子独立打分,便于缓存和保持分数稳定。
  8. OON 调分用于平衡关注圈内容和陌生内容发现。

参考资料:


评论