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