---
title: "端到端数据流：一条帖子从发布到被推荐"
description: "一条帖子从发布到出现在用户的 For You 信息流：后台写入侧（摄入、标签、索引、热门列表）与实时请求路径的分工，以及两者经存储系统交接的机制"
---

> Documentation Index
> Fetch the complete documentation index at: https://x-algorithm.vergego.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# 端到端数据流：一条帖子从发布到被推荐

## 这一页回答什么

本页将各个子系统串联为主线，解析一条帖子在发布之后经历的完整推荐链路。内容重点区分后台异步写入环节与实时请求读取环节，并说明两类环节在存储层交接的具体机制。

## 核心结论

1. **推荐数据流分为读写两侧**。写入侧由“帖子发布”事件驱动，在后台异步执行，不依赖特定用户的请求；读取侧由“用户打开 For You”动作触发，受制于严格的接口延迟预算。
2. **读写两侧仅通过存储系统交接**。写入侧将计算产物写入 Thunder 内存库、标签存储、召回索引与热门帖子列表；读取侧在处理推荐请求时查询上述存储系统。帖子发布流程与推荐展示流程之间不存在同步远程调用。
3. **写入侧包含四条后台异步管线**：Thunder 实时摄入、内容理解与打标签（标签路径）、Phoenix 召回索引更新以及热门帖子离线任务。每条管线具有独立的运行周期与延迟特征。
4. **Thunder 仅在内存中保留最近 2 天内的帖子**。参数 `post_retention_seconds` 默认配置为 172800 秒（`thunder/args.rs:48-49`）；预打分过滤器同步剔除发布时间超过 48 小时的候选帖子（`home-mixer/params/config.rs:39`）。
5. **读取侧将推荐结果异步写回系统**。接口返回推荐结果后，side effect 异步记录已展示帖子历史、缓存候选帖子并上报事件日志；后续请求读取已展示历史以执行去重与翻页加载（`home-mixer/candidate_pipeline/for_you_candidate_pipeline.rs:241-260`）。

## 全景图

```mermaid
flowchart TB
    POST([某人发布一条帖子]) --> KAFKA[(Kafka 帖子事件)]

    subgraph WRITE["写入侧 · 后台异步"]
        KAFKA --> THI["Thunder 摄入"]
        THI --> THS[(Thunder 内存库<br/>近 2 天)]
        KAFKA --> GROX["grox 等内容理解"]
        GROX --> RULES["打标签规则<br/>scarecrow / 处置服务"]
        RULES --> LBL[(标签存储)]
        POST -. "帖子事件" .-> RA["phoenix-rankall 索引更新"]
        RA --> IDX[(Phoenix 召回索引)]
        THS --> PPJ["热门帖子任务<br/>每 300 秒"]
        PPJ --> POP[(热门帖子列表)]
    end

    subgraph READ["读取侧 · 实时请求"]
        REQ([有人打开 For You]) --> QH[Query 水合]
        QH --> SRC[候选源]
        SRC --> HYD[候选水合]
        HYD --> FIL[预打分过滤]
        FIL --> SCO[打分]
        SCO --> SEL[选择]
        SEL --> VF["选后水合与过滤<br/>可见性 / 品牌安全"]
        VF --> MIX[混排]
        MIX --> FEED([For You 信息流])
        MIX --> SE["side effect"]
    end

    THS -. ThunderSource .-> SRC
    IDX -. PhoenixSource .-> SRC
    POP -. PopularPostsSource .-> SRC
    LBL -. "可见性过滤读取" .-> VF
    SE -. "served history / 缓存" .-> QH
```

phoenix-rankall 的事件来源与 Kafka 的关联关系以官方文档说明为准（“随事件更新索引”，`README.md:289-290`）；具体消费的 topic 清单详见 [Phoenix RankAll 召回索引](https://x-algorithm.vergego.ai/concepts/phoenix-rankall/)。

## 写入侧：帖子发布后在后台发生什么

### ① Thunder 摄入

Thunder 从 Kafka 消费帖子创建与删除事件，在内存中维护按作者组织的索引数据。系统支持两种运行角色，通过 `is_serving` 参数切换（`thunder/kafka_utils.rs:71-125`）：

- **feeder**：消费原始帖子事件，将其转码为精简的 `InNetworkEvent` 并重新发布；
- **serving**：消费 `InNetworkEvent`，将帖子写入 `PostStore` 内存库。

数据写入阶段直接丢弃超出保留期的历史帖子（`thunder/posts/post_store.rs:127-135`），后台任务每隔 2 分钟执行一次内存数据裁剪（`thunder/main.rs:109`）。实现细节详见 [Thunder Kafka 摄入](https://x-algorithm.vergego.ai/concepts/thunder-kafka-ingestion/) 与 [Thunder 站内帖子内存库](https://x-algorithm.vergego.ai/concepts/thunder-in-network-store/)。

### ② 内容理解与打标签（标签路径）

grox 是独立的流式服务，同样从 Kafka 消费帖子数据。例如 `KafkaPostLoader` 根据不同 topic 生成计算任务（`grox/flows/upa/generators.py:1-51`）。grox 执行分类器推理并生成文本特征嵌入向量；media-model-proxy 与 clip 计算图像和视频特征；agatha、bdsm 与 user-cred-v2 分析账号行为特征并计算账号信用分。上述特征经 scarecrow 规则引擎评估、abuse-enforcement-service 处置判定以及 safety-label-user-agg 汇总计算，最终转化为帖子和账号的安全标签写入存储（`README.md:186-218`）。

在安全标签就绪前，请求侧读取到的标签数据为空。空标签的判定逻辑因业务方而异：品牌安全判定在缺失 Grok 标签时默认返回中风险（`home-mixer/models/brand_safety.rs:116-120`），导致帖子无法紧邻商业广告展示。详见 [Grox 服务架构](https://x-algorithm.vergego.ai/concepts/grox-architecture/)、[媒体模型](https://x-algorithm.vergego.ai/concepts/media-models/)、[账号信号](https://x-algorithm.vergego.ai/concepts/account-signals/)、[标签规则](https://x-algorithm.vergego.ai/concepts/labeling-rules/) 与 [处置服务](https://x-algorithm.vergego.ai/concepts/enforcement/)。

### ③ Phoenix 召回索引

phoenix-rankall 维护供 Phoenix 召回检索的帖子索引；phoenix-rankall-strato 在帖子进入索引前预先查询可见性过滤服务，决定其写入的目标索引（`README.md:289-290`）。因此，站外召回阶段检索出的候选帖子已预先完成一轮可见性筛选。详见 [Phoenix RankAll 召回索引](https://x-algorithm.vergego.ai/concepts/phoenix-rankall/)。

### ④ 热门帖子任务

`popular_posts_job` 默认每隔 300 秒运行一次：任务读取高活跃作者名单，从 Thunder 检索上述作者的原创帖子，读取帖子浏览量，结合浏览量与发布时长计算综合得分，最终筛选出 500 条热门候选写入存储（`home-mixer/main.rs:52-53`、`home-mixer/popular_posts_job.rs:134-179`）。仅高粉丝量的活跃作者帖子能够入选该列表。详见 [home-mixer 编排层](https://x-algorithm.vergego.ai/concepts/home-mixer-orchestration/)。

## 读取侧：一次 For You 请求

请求入口为 `ForYouFeedServer::get_for_you_feed`，该方法调用外层流水线的 `execute_traced`（`home-mixer/for_you_server.rs:30-50`）。外层流水线通过 `ScoredPostsSource` 调度内层 `PhoenixCandidatePipeline`（详见 [home-mixer 编排层](https://x-algorithm.vergego.ai/concepts/home-mixer-orchestration/)）。推荐请求的处理流程按阶段划分为六个步骤：

### 1. 查询准备

`QueryBuilder` 拉取用户画像数据并评估实验开关状态（`home-mixer/server.rs:79-184`）。外层 Query 水合阶段读取 served history，获取近期已展示帖子标识符与模块疲劳度状态（`query_hydrators/served_history_query_hydrator.rs:29-57`）。内层 21 个 Query 水合器并发补全用户互动序列、关注列表、屏蔽列表、曝光 Bloom 过滤器与互动特征（`phoenix_candidate_pipeline.rs:285-348`）。

### 2. 候选召回

内层 9 个候选源并发执行拉取任务（`phoenix_candidate_pipeline.rs:380-390`）。其中 4 个主力候选源直接读取写入侧生成的存储数据：

| 源 | 读取目标 |
|----|----------|
| `ThunderSource` | 写入侧 ① 维护的 Thunder 内存库 |
| `PhoenixSource` | 写入侧 ③ 维护的召回索引（经由 Phoenix 召回服务检索） |
| `PopularPostsSource` | 写入侧 ④ 维护的热门帖子列表 |
| `SimclustersSource` | SimClusters ANN 向量检索服务（以用户近期互动帖子为种子） |

当用户关闭“为你推荐”开关时，系统仅保留 `ThunderSource` 拉取关注流内容；当上一轮请求缓存的候选帖子数量充足时，系统优先命中本地缓存源。详见 [home-mixer 编排层](https://x-algorithm.vergego.ai/concepts/home-mixer-orchestration/)。

### 3. 水合与预打分过滤

15 个候选水合器并发补全候选帖子的正文文本、作者信息、引用帖、多媒体元数据、语言属性与互动计数（`phoenix_candidate_pipeline.rs:392-423`）。21 个预打分过滤器按序剔除重复帖子、过期帖子、作者本人的帖子、站外转发帖子、已读已展示帖子、屏蔽与静音账号帖子及命中静音词的帖子（`phoenix_candidate_pipeline.rs:429-453`），最后根据召回源配额将候选总量截断至不超过 2800 条。详见 [过滤流水线](https://x-algorithm.vergego.ai/concepts/filtering-pipeline/)。

### 4. 候选打分

`PhoenixScorer` 调用 [Phoenix 排序模型](https://x-algorithm.vergego.ai/concepts/phoenix-ranking/) 计算各项互动行为的发生概率；`VMRanker` 对各项概率执行加权计算与冷启动分数调整，随后调用 [vm-ranker](https://x-algorithm.vergego.ai/concepts/vm-ranker/) 服务完成多样性重排（`phoenix_candidate_pipeline.rs:475-481`）。详见 [打分与排序](https://x-algorithm.vergego.ai/concepts/scoring-and-ranking/)。

### 5. 选择与选后检查

`TopKScoreSelector` 截取排序得分最高的前 50 条候选。`VFCandidateHydrator` 仅针对这 50 条候选帖子查询可见性过滤服务（`candidate_hydrators/vf_candidate_hydrator.rs:53-130`），该环节是**标签路径产物接入请求路径的主要汇合点**；`AdsBrandSafetyVfHydrator` 同步读取安全标签以计算品牌安全判定。`VFFilter` 等 5 个选后过滤器按序剔除不可见帖子与同一会话的重复帖子，最终将候选结果截断至 35 条。详见 [候选选择与成型](https://x-algorithm.vergego.ai/concepts/candidate-selection/) 与 [可见性过滤](https://x-algorithm.vergego.ai/concepts/visibility-filtering/)。

### 6. 广告混排与结果写回

外层 `BlenderSelector` 执行广告混排并插入推荐模块，生成最终不超过 48 项的信息流内容（`home-mixer/params/config.rs:21-22`）。推荐结果返回客户端后，13 个 side effect 任务在后台异步执行：

- `UpdateServedHistorySideEffect` 记录本次推荐展示的帖子与模块标识符，供后续请求更新 `served_ids` 与疲劳度状态；
- `PublishSeenIdsToKafkaSideEffect`、`ServedCandidatesKafkaSideEffect` 与 `ClientEventsKafkaSideEffect` 将展示记录与客户端事件投递至 Kafka；
- 内层 `RedisPostCandidateCacheSideEffect` 将本轮入选与未入选的候选帖子（上限 750 条）写入 Redis，供后续翻页请求快速复用（`side_effects/redis_post_candidate_cache_side_effect.rs:45-60`、`params/param.rs:701-706`）。

## 离线异步与实时：对照表

| 环节 | 所在侧 | 触发方式 | 时效特征 |
|------|--------|----------|----------|
| Thunder 摄入 | 写入 | 帖子事件流驱动 | 准实时处理，存在消费延迟 |
| 内容理解与打标签 | 写入 | 帖子事件、账号行为及定时批任务驱动 | 流式或批处理执行，存在分钟级延迟 |
| 召回索引更新 | 写入 | 索引事件流驱动 | 官方文档未公开具体延迟数值 |
| 热门帖子任务 | 写入 | 定时触发，每 300 秒执行一次 | 配合每 60 秒一次的本地缓存刷新 |
| 查询准备、召回、水合、过滤、打分、选择、混排 | 读取 | 用户主动请求驱动 | 在单次请求的延迟预算内同步完成 |
| side effect | 读取侧尾部 | 推荐响应返回后触发 | 后台异步执行，不计入用户端延迟 |

## 时效性：帖子发布后多久能被推荐

- **进入站内候选集**：取决于 Thunder 消费 Kafka 的摄入延迟。在帖子写入内存库前，关注者的 `ThunderSource` 无法检索到该帖子。
- **进入站外候选集**：取决于召回索引的更新周期；若要进入热门帖子列表，还需等待下一轮热门任务执行以及 60 秒的本地缓存刷新（`home-mixer/util/popular_posts.rs:7`）。
- **安全标签就绪前**：可见性过滤服务仅能读取到未完成的空标签，品牌安全判定默认标记为中风险。
- **可被推荐的生命周期有限**：发布时长超过 48 小时的帖子由 `AgeFilter` 自动剔除，Thunder 内存库同样仅保留 2 天内的内容。

线上各处理环节的实际延迟数值，开源代码库未作公开说明。

## 设计决策

| 决策 | 理由 |
|------|------|
| 读写两侧经存储系统解耦 | 帖子发布的高吞吐写入与推荐请求的低延迟读取属于不同约束，解耦后可独立优化 |
| 内容理解计算置于后台异步执行 | 分类推理与向量嵌入计算开销大，在请求路径中仅读取预存标签以保护响应延迟 |
| 仅对精选入围候选执行可见性查询 | 跨服务远程查询开销较高，对精选出的 50 条候选发起查询远比全量查询数千条经济 |
| 召回索引写入前预先执行可见性过滤 | 避免站外召回阶段将宝贵配额消耗在无法展示的违规内容上 |
| 读取侧将展示历史异步写回存储 | 支持跨请求去重控制，并管理推广模块的曝光疲劳度 |

## 常见问题

**Q：系统为何不在用户请求到达时实时执行候选帖子的安全分类？**  
A：模型分类与特征嵌入属于重计算密集型任务。若将其置于在线请求路径，接口响应延迟将无法满足实时交互要求。系统通过 grox 等服务在后台预先计算并持久化标签，推荐引擎在线仅读取计算结果。

**Q：写入侧与读取侧在工程架构上如何实现关联？**  
A：两者不直接建立进程间连接。`ThunderSource` 查询 Thunder 内存库，`PhoenixSource` 查询召回索引，`PopularPostsSource` 查询热门列表缓存，`VFCandidateHydrator` 通过可见性过滤服务读取标签存储。

**Q：新发布的帖子是否会立即出现在关注者的 For You 信息流中？**  
A：无法绝对保证立即展现。展示前需要等待 Thunder 消费 Kafka 事件并完成内存写入；若可见性规则依赖的安全标签尚未落库，推荐判定结果也可能与标签就绪后存在差异。

## 源码锚点

- `thunder/kafka_utils.rs:71-125` —— Thunder 两种 Kafka 角色
- `thunder/posts/post_store.rs:127-135` —— 写入时按保留期过滤
- `thunder/args.rs:48-49` —— 保留期默认 172800 秒
- `grox/flows/upa/generators.py:1-51` —— grox 以 Kafka 为输入
- `home-mixer/popular_posts_job.rs:134-179` —— 热门帖子任务
- `home-mixer/for_you_server.rs:30-50` —— For You 请求入口
- `home-mixer/candidate_pipeline/phoenix_candidate_pipeline.rs:285-543` —— 内层各阶段装配
- `home-mixer/candidate_hydrators/vf_candidate_hydrator.rs:53-130` —— 标签进入请求路径
- `home-mixer/candidate_pipeline/for_you_candidate_pipeline.rs:241-260` —— 外层 side effect

## 相关页面

- [系统架构总览](https://x-algorithm.vergego.ai/concepts/system-architecture/) —— 请求路径与标签路径的静态总览
- [home-mixer 编排层](https://x-algorithm.vergego.ai/concepts/home-mixer-orchestration/) —— 服务、流水线、候选源
- [candidate-pipeline 框架](https://x-algorithm.vergego.ai/concepts/candidate-pipeline-framework/) —— 读取侧的阶段框架
- [Thunder Kafka 摄入](https://x-algorithm.vergego.ai/concepts/thunder-kafka-ingestion/) —— 写入侧 ①
- [Grox 服务架构](https://x-algorithm.vergego.ai/concepts/grox-architecture/) —— 写入侧 ② 的内容理解
- [标签规则](https://x-algorithm.vergego.ai/concepts/labeling-rules/) —— 写入侧 ② 的规则层
- [Phoenix RankAll 召回索引](https://x-algorithm.vergego.ai/concepts/phoenix-rankall/) —— 写入侧 ③
- [可见性过滤](https://x-algorithm.vergego.ai/concepts/visibility-filtering/) —— 标签在请求中的使用方
- [For You 是怎么工作的](https://x-algorithm.vergego.ai/guide/how-it-works/) —— 白话入口
- [帖子是怎么被选中的](https://x-algorithm.vergego.ai/guide/how-posts-are-picked/) —— 白话版

Source: https://x-algorithm.vergego.ai/concepts/end-to-end-dataflow/index.mdx
