X的算法,是如何改变你的价值观的?

Posted by NoPanic on Wed, Jan 21, 2026

X For You Feed Algorithm

目录

章节 内容
一、项目概述 系统简介、核心特性、技术栈
二、系统架构 整体架构图、服务交互时序
三、核心组件 Home Mixer、Thunder(含三层分类、保留期、并发控制)、Phoenix
四、数据流程 请求处理流程、过滤器详解、用户行为序列(UAS)
五、ML模型架构 排序模型、Hash嵌入机制
六、候选管道框架 Trait定义、执行流程
七、评分算法 20个评分信号、视频评分机制、印象去重、双阶段安全审核
八、目录结构 项目文件组织
九、创作者指南 算法应用、内容策略

一、项目概述

X For You Feed Algorithm 是 X 平台 “For You” 推荐信息流的开源推荐系统。

该系统结合了网内内容(来自已关注账户的帖子)和网外内容(通过机器学习检索发现的内容),并使用基于 Grok 的 Transformer 模型进行排序。

代码仓库位置:https://github.com/xai-org/x-algorithm

1.1 核心特性

mindmap
  root((X推荐算法))
    网内内容
      Thunder服务
      实时帖子存储
      关注列表检索
    网外内容
      Phoenix检索
      两塔模型
      相似度搜索
    ML排序
      Grok Transformer
      多动作预测
      候选隔离
    管道框架
      可复用组件
      并行执行
      灵活扩展

1.2 技术栈

组件 技术 用途
Home Mixer Rust + gRPC 主编排服务
Thunder Rust + Kafka 实时帖子存储
Phoenix Python + JAX ML模型
Candidate Pipeline Rust 可复用管道框架

二、系统架构

2.1 整体架构图

flowchart TB
    subgraph Client["客户端"]
        APP[X App/Web]
    end

    subgraph HomeMixer["Home Mixer 编排服务"]
        direction TB
        GRPC[gRPC Server]
        QH[Query Hydrators]
        SOURCES[Candidate Sources]
        HYDRATORS[Candidate Hydrators]
        FILTERS[Filters]
        SCORERS[Scorers]
        SELECTORS[Selectors]
        SE[Side Effects]
    end

    subgraph Thunder["Thunder 实时存储"]
        direction TB
        TS[Thunder Service]
        PS[Post Store]
        KL[Kafka Listener]
    end

    subgraph Phoenix["Phoenix ML服务"]
        direction TB
        PR[Phoenix Retrieval]
        PP[Phoenix Prediction]
        GM[Grok Model]
    end

    subgraph ExternalServices["外部服务"]
        direction TB
        GD[Gizmoduck
用户元数据] SG[SocialGraph
社交关系] ST[Strato
用户特征] TES[TweetEntityService
推文实体] UAS[UserActionSequence
用户行为] VF[VisibilityFiltering
可见性过滤] end subgraph DataSources["数据源"] KAFKA[Kafka
推文事件流] DB[(用户数据库)] end APP -->|请求推荐| GRPC GRPC --> QH QH --> SOURCES SOURCES --> HYDRATORS HYDRATORS --> FILTERS FILTERS --> SCORERS SCORERS --> SELECTORS SELECTORS --> SE SE -->|返回结果| APP SOURCES -->|网内候选| TS SOURCES -->|网外候选| PR SCORERS -->|预测请求| PP PP --> GM TS --> PS KL --> PS KAFKA --> KL QH --> ST QH --> UAS HYDRATORS --> GD HYDRATORS --> TES FILTERS --> SG FILTERS --> VF ST --> DB GD --> DB SG --> DB

用餐厅比喻理解系统架构

把整个推荐系统想象成一家智能餐厅

系统组件 餐厅角色 职责
客户端 App 顾客 说"我饿了,给我推荐菜品"
Home Mixer 大堂经理 协调所有流程,最终把菜单给顾客
Thunder 常客档案柜 存着顾客朋友们最近做的菜(关注列表内容)
Phoenix 美食侦探 去全城搜罗可能合顾客口味的菜(网外内容)
外部服务 各种助手 查顾客口味偏好、过敏信息、消费记录等
flowchart LR
    subgraph Example["一次推荐请求的旅程"]
        direction TB

        C["用户小明打开App"] --> Q["大堂经理接待"]
        Q --> |"同时派出两路人马"| P1["去常客档案柜
找小明朋友的最新帖子"] Q --> P2["派美食侦探
搜索全平台好内容"] P1 --> MERGE["汇总所有候选"] P2 --> MERGE MERGE --> FILTER["筛掉不合适的
(已看过的、被屏蔽的)"] FILTER --> SCORE["给每道菜打分
预测小明喜欢的程度"] SCORE --> SELECT["选出最好的50道"] SELECT --> RETURN["呈现给小明"] end

实际案例:小明打开 X,系统同时从他关注的100个账号中找最新帖子(Thunder),又从全平台数十亿帖子中检索可能感兴趣的内容(Phoenix),合并后经过层层筛选和打分,最终在200毫秒内返回50条精选内容。

2.2 服务交互时序图

sequenceDiagram
    autonumber
    participant Client as 客户端
    participant HM as Home Mixer
    participant Thunder as Thunder
    participant Phoenix as Phoenix
    participant External as 外部服务

    Client->>+HM: GetScoredPosts(user_id, preferences)

    par 查询增强
        HM->>+External: 获取用户行为序列
        External-->>-HM: 用户历史动作
    and
        HM->>+External: 获取用户特征
        External-->>-HM: 用户元数据
    end

    par 候选获取
        HM->>+Thunder: 获取网内帖子
        Thunder-->>-HM: 关注者帖子列表
    and
        HM->>+Phoenix: ML检索候选
        Phoenix-->>-HM: 网外候选列表
    end

    par 候选增强
        HM->>+External: 获取帖子核心数据
        External-->>-HM: 帖子详情
    and
        HM->>+External: 获取作者信息
        External-->>-HM: 作者元数据
    and
        HM->>+External: 获取视频时长
        External-->>-HM: 视频信息
    end

    HM->>HM: 执行过滤器链

    HM->>+Phoenix: 预测用户参与度
    Phoenix-->>-HM: 多动作概率预测

    HM->>HM: 计算加权分数
    HM->>HM: 作者多样性调整
    HM->>HM: 网外分数调整
    HM->>HM: Top-K选择

    HM->>External: 异步缓存请求信息

    HM-->>-Client: 返回排序后的帖子列表

三、核心组件

3.1 Home Mixer(主编排服务)

Home Mixer 是整个推荐系统的核心编排层,负责协调各个组件完成推荐流程。

classDiagram
    class ScoredPostsService {
        +scored_posts(request) Response
    }

    class PhoenixCandidatePipeline {
        -query_hydrators: Vec~QueryHydrator~
        -sources: Vec~Source~
        -candidate_hydrators: Vec~Hydrator~
        -filters: Vec~Filter~
        -scorers: Vec~Scorer~
        -selector: Selector
        -side_effects: Vec~SideEffect~
        +execute(query) Result
    }

    class ScoredPostsQuery {
        +user_id: i64
        +language: String
        +device_context: DeviceContext
        +seen_post_ids: Vec~i64~
        +served_post_ids: Vec~i64~
        +user_action_features: UserActionFeatures
        +user_features: UserFeatures
    }

    class PostCandidate {
        +post_id: i64
        +author_id: i64
        +created_at: i64
        +is_retweet: bool
        +is_reply: bool
        +source: CandidateSource
        +phoenix_scores: PhoenixScores
        +weighted_score: f64
        +final_score: f64
    }

    class PhoenixScores {
        +p_favorite: f64
        +p_reply: f64
        +p_repost: f64
        +p_quote: f64
        +p_click: f64
        +p_profile_click: f64
        +p_video_view: f64
        +p_photo_expand: f64
        +p_share: f64
        +p_follow_author: f64
        +p_not_interested: f64
        +p_block_author: f64
        +p_mute_author: f64
        +p_report: f64
    }

    ScoredPostsService --> PhoenixCandidatePipeline
    PhoenixCandidatePipeline --> ScoredPostsQuery
    PhoenixCandidatePipeline --> PostCandidate
    PostCandidate --> PhoenixScores

用快递分拣中心比喻 Home Mixer

把 Home Mixer 想象成一个智能快递分拣中心,每个包裹就是一篇候选帖子:

flowchart TB
    subgraph HomeMixerAnalogy["Home Mixer = 快递分拣中心"]
        direction TB

        subgraph Step1["1. 收件登记 (Query Hydrators)"]
            Q1["了解收件人信息"]
            Q2["查询收件人偏好"]
            Q3["获取历史收件记录"]
        end

        subgraph Step2["2. 包裹来源 (Sources)"]
            S1["本地仓库
Thunder: 朋友寄的包裹"] S2["全国调货
Phoenix: 可能喜欢的商品"] end subgraph Step3["3. 包裹检查 (Hydrators)"] H1["核实发件人身份"] H2["检查包裹内容"] H3["标记包裹属性"] end subgraph Step4["4. 安检筛选 (Filters)"] F1["违禁品? 退回"] F2["已收过? 退回"] F3["发件人被拉黑? 退回"] end subgraph Step5["5. 优先级排序 (Scorers)"] SC1["预测收件人满意度"] SC2["计算综合优先级"] end subgraph Step6["6. 装车派送 (Selector)"] SEL["选出最重要的50个包裹派送"] end Step1 --> Step2 --> Step3 --> Step4 --> Step5 --> Step6 end

一个请求的完整生命周期

假设用户小红打开 App 请求推荐:

阶段 发生了什么 具体例子
Query Hydration 了解小红是谁 查到小红喜欢美妆、关注了50个账号、最近点赞了护肤内容
Sources 收集候选内容 Thunder返回300条关注者帖子,Phoenix返回500条网外帖子
Hydrators 补充帖子信息 给每篇帖子补上作者粉丝数、是否有视频、发布时间等
Filters 过滤不合适的 去掉小红已看过的、作者被小红屏蔽的、超过48小时的
Scorers 预测打分 预测小红对每篇帖子点赞/转发/停留的概率
Selector 选出最终结果 从剩余400条中选出分数最高的50条

关键洞察:整个过程约200毫秒完成,其中很多步骤是并行执行的(比如同时从Thunder和Phoenix获取候选)。

3.2 Thunder(实时帖子存储)

Thunder 是一个高性能的内存帖子存储服务,用于快速检索网内内容。

flowchart TB
    subgraph Thunder["Thunder 服务架构"]
        direction TB

        subgraph Input["数据输入"]
            KAFKA[Kafka 事件流]
            TEL1[TweetEventsListener V1]
            TEL2[TweetEventsListener V2]
        end

        subgraph Storage["存储层"]
            PS[PostStore]
            subgraph UserStores["用户帖子存储"]
                OP[原创帖子
Original Posts] SP[次级帖子
Replies/Retweets] VP[视频帖子
Video Posts] end end subgraph Service["服务层"] TS[Thunder Service] GRPC[gRPC Server] end subgraph Maintenance["维护任务"] TRIM[自动清理任务
Auto-Trim Task] end end KAFKA --> TEL1 KAFKA --> TEL2 TEL1 --> PS TEL2 --> PS PS --> OP PS --> SP PS --> VP TS --> PS GRPC --> TS TRIM --> PS Client[Home Mixer] -->|GetInNetworkPosts| GRPC

3.2.1 数据结构

erDiagram
    PostStore ||--o{ UserPostStore : contains
    UserPostStore ||--o{ TinyPost : has_original
    UserPostStore ||--o{ TinyPost : has_secondary
    UserPostStore ||--o{ TinyPost : has_video
    TinyPost ||--|| LightPost : references

    PostStore {
        DashMap users
        DashMap all_posts
        Duration retention_period
    }

    UserPostStore {
        i64 user_id
        VecDeque original_posts
        VecDeque secondary_posts
        VecDeque video_posts
    }

    TinyPost {
        i64 post_id
        i64 created_at
    }

    LightPost {
        i64 post_id
        i64 author_id
        i64 created_at
        bool is_retweet
        bool is_reply
        bool has_video
        String text
    }

3.2.2 三层帖子分类

Thunder 按内容类型将帖子分为三类,分别存储和检索:

flowchart TB
    subgraph PostClassification["帖子三层分类"]
        direction TB

        POST["新帖子入库"] --> CHECK1{"是回复或转发?"}

        CHECK1 -->|否| ORIGINAL["原创帖 original_posts"]
        CHECK1 -->|是| SECONDARY["次级帖 secondary_posts"]

        ORIGINAL --> CHECK2{"包含视频?"}
        SECONDARY --> CHECK3{"是转发且源帖有视频?"}

        CHECK2 -->|是| VIDEO1["同时存入 video_posts"]
        CHECK3 -->|是| VIDEO2["同时存入 video_posts"]
    end
分类 包含内容 检索上限 用途
original_posts 非回复、非转发的原创内容 MAX_ORIGINAL_POSTS_PER_AUTHOR 核心时间线内容
secondary_posts 回复和转发 MAX_REPLY_POSTS_PER_AUTHOR 补充互动内容
video_posts 带视频的原创或转发 MAX_VIDEO_POSTS_PER_AUTHOR 视频专属推荐

3.2.3 保留期与自动清理

flowchart LR
    subgraph Retention["内容保留机制"]
        NEW["新帖子"] --> STORE["存入 PostStore"]
        STORE --> TIMER["retention_period
默认 48 小时"] TIMER --> TRIM["Auto-Trim Task"] TRIM --> |"定期清理"| DELETE["移除过期帖子"] end

关键参数

  • retention_period: 默认 172,800 秒(48 小时)
  • 清理任务定期运行,移除超过保留期的帖子
  • 统计日志每 5 秒输出一次存储状态

创作者启示:内容在 Thunder 中最多保留约 48 小时,超过此时间将不再出现在关注者的网内推荐中。这解释了为什么"热度"有明确的时间窗口。

3.2.4 并发控制与性能保护

flowchart TB
    subgraph Concurrency["并发保护机制"]
        REQ["请求到达"] --> SEM{"信号量检查"}
        SEM -->|"有空位"| PROCESS["处理请求"]
        SEM -->|"已满"| REJECT["RESOURCE_EXHAUSTED"]

        PROCESS --> SPAWN["spawn_blocking"]
        SPAWN --> |"避免阻塞异步运行时"| QUERY["执行查询"]

        QUERY --> TIMEOUT{"超时检查"}
        TIMEOUT -->|"超时"| PARTIAL["返回部分结果"]
        TIMEOUT -->|"正常"| FULL["返回完整结果"]
    end
保护机制 作用 场景示例
请求信号量 限制并发请求数 防止突发流量压垮服务
spawn_blocking 隔离阻塞操作 保护异步运行时不被阻塞
请求超时 防止长时间等待 关注列表过大时快速降级

实际案例:如果用户关注了 10 万个账号,系统会设置超时,可能只返回部分内容而非完全失败。

3.2.5 次级帖子过滤规则

回复和转发有特殊的过滤逻辑:

flowchart TB
    subgraph SecondaryFiltering["次级帖子过滤"]
        SEC["次级帖子"] --> CHECK1{"是自己转发自己?"}
        CHECK1 -->|是| DROP1["排除"]
        CHECK1 -->|否| CHECK2{"是嵌套回复?"}

        CHECK2 -->|是| CHECK3{"回复对象是原帖
且作者在关注列表?"} CHECK3 -->|是| KEEP["保留"] CHECK3 -->|否| DROP2["排除"] CHECK2 -->|否| KEEP end

过滤原因

  • 自己转发自己:避免刷屏
  • 嵌套回复:只保留与关注者直接相关的对话

3.3 Phoenix(ML模型服务)

Phoenix 包含两个核心模型:检索模型和排序模型。

flowchart TB
    subgraph Phoenix["Phoenix ML服务"]
        direction TB

        subgraph Retrieval["检索阶段 - Two-Tower Model"]
            direction LR
            UT[用户塔
User Tower] CT[候选塔
Candidate Tower] SIM[相似度计算
Dot Product] UT -->|用户嵌入 B,D| SIM CT -->|帖子嵌入 N,D| SIM SIM -->|Top-K候选| OUT1[候选列表] end subgraph Ranking["排序阶段 - Grok Transformer"] direction TB subgraph Input["输入处理"] UI[用户输入] HI[历史输入] CI[候选输入] end subgraph Model["模型架构"] EMB[Hash嵌入层] TRANS[Transformer层] HEAD[预测头] end subgraph Output["输出"] PRED[多动作预测
14+动作概率] end UI --> EMB HI --> EMB CI --> EMB EMB --> TRANS TRANS --> HEAD HEAD --> PRED end end

用相亲网站比喻 Phoenix

这部分的逻辑跟抖音的推荐系统逻辑类似,感兴趣也可以看看:https://95152.douyin.com/article/15358

Phoenix 的工作就像一个智能相亲网站,分两步帮你找到合适的对象:

flowchart TB
    subgraph PhoenixAnalogy["Phoenix = 智能相亲网站"]
        direction TB

        subgraph Step1["第一步: 海选 (Two-Tower 检索)"]
            YOU["你的画像
喜欢技术、爱运动、25岁"] POOL["全平台候选池
数十亿用户"] MATCH["向量相似度匹配"] RESULT1["初筛500人
基础画像匹配"] YOU --> MATCH POOL --> MATCH MATCH --> RESULT1 end subgraph Step2["第二步: 精选 (Grok 排序)"] DETAIL["深入分析
性格、价值观、生活方式"] PREDICT["预测匹配度
会聊天? 会见面? 会交往?"] RESULT2["精选50人
最可能成功的"] RESULT1 --> DETAIL DETAIL --> PREDICT PREDICT --> RESULT2 end end

两阶段模型对比

阶段 模型 比喻 处理规模 精度
检索 Two-Tower 海选:看基础条件 数十亿→数百 较粗
排序 Grok Transformer 精选:深入了解 数百→数十 精细

具体例子:为技术博主小张找读者

第一步:Two-Tower 检索

flowchart LR
    subgraph UserTower["用户塔: 编码小张"]
        U1["关注了React、Vue"]
        U2["最近发了前端教程"]
        U3["粉丝多为程序员"]
        UV["→ 用户向量 [0.8, 0.2, ...]"]
    end

    subgraph CandidateTower["候选塔: 编码所有帖子"]
        C1["帖子A: React性能优化"]
        C2["帖子B: 美食探店"]
        C3["帖子C: Python入门"]
        CV["→ 帖子向量 [...], [...], [...]"]
    end

    UV --> |"计算相似度"| SIM["相似度排序"]
    CV --> SIM
    SIM --> TOP["Top-500: 主要是技术帖子"]

第二步:Grok Transformer 排序

对这500篇帖子,模型深入分析并预测:

帖子 预测点赞概率 预测回复概率 预测转发概率 最终排名
React性能优化 45% 12% 8% #1
Vue3新特性 38% 15% 10% #2
TypeScript技巧 35% 8% 5% #3
Python入门 5% 1% 0.5% #450

关键洞察:第一步只看"大方向是否匹配",第二步才精细预测具体互动行为。这就是为什么算法既能快速处理海量内容,又能精准预测用户偏好。

3.3.1 Grok Transformer 架构细节

十万张显卡,真的太明智了,现在看布局非常厉害了。

flowchart TB
    subgraph GrokModel["Grok Transformer 架构"]
        direction TB

        subgraph Embeddings["嵌入层"]
            direction LR
            UE[用户嵌入
UserEmbedding] PE[帖子嵌入
PostEmbedding] AE[作者嵌入
AuthorEmbedding] ACT[动作嵌入
ActionEmbedding] end subgraph Attention["注意力机制"] direction TB subgraph Mask["注意力掩码"] M1[用户+历史: 全双向注意力] M2[候选→用户/历史: 允许] M3[候选→候选: 仅自注意力] end MHA[多头注意力
Multi-Head Attention] end subgraph FFN["前馈网络"] GEGLU[GeGLU激活] DENSE[Dense层] end subgraph Prediction["预测层"] LOGITS[Logits] SIGMOID[Sigmoid] PROBS[概率输出] end end Embeddings --> MHA Mask --> MHA MHA --> FFN FFN --> LOGITS LOGITS --> SIGMOID SIGMOID --> PROBS

3.3.2 候选隔离机制

用通俗的话解释

想象你是一位老师,要给100篇作文打分。有两种打分方式:

方式A(传统方式):把100篇作文放在一起比较,互相参考着打分

  • 问题:如果换一批作文一起评,同一篇作文的分数可能会变

方式B(候选隔离):每篇作文独立打分,只参考学生的历史表现,不看其他作文

  • 优点:无论和哪些作文一起评,同一篇作文的分数始终一致

X 的算法采用方式B,这就是"候选隔离"。

flowchart TB
    subgraph Traditional["传统方式: 候选互相影响"]
        direction LR
        T1["帖子A"] <--> T2["帖子B"]
        T2 <--> T3["帖子C"]
        T1 <--> T3
        T_NOTE["A的分数受B、C影响"]
    end

    subgraph Isolated["候选隔离: 独立评分"]
        direction LR
        I1["帖子A"] --> USER["用户偏好"]
        I2["帖子B"] --> USER
        I3["帖子C"] --> USER
        I_NOTE["每个帖子只看用户,不看其他帖子"]
    end

具体例子

假设系统要为用户小明推荐内容,候选池有3篇帖子:

帖子 内容 作者
帖子A Python教程 技术博主张三
帖子B 美食探店 美食博主李四
帖子C 健身打卡 健身博主王五

小明的历史行为:最近点赞了5篇技术文章

flowchart TB
    subgraph Scoring["评分过程"]
        direction TB

        subgraph Context["共享上下文: 小明的信息"]
            U["小明的画像"]
            H["历史: 点赞5篇技术文章"]
        end

        subgraph Independent["独立评分: 每个帖子单独计算"]
            direction LR

            subgraph ScoreA["帖子A评分"]
                A["Python教程"]
                A --> |"参考"| U
                A --> |"参考"| H
                A --> |"不参考"| B
                A --> |"不参考"| C
                SA["预测: 80%会点赞"]
            end

            subgraph ScoreB["帖子B评分"]
                B["美食探店"]
                B --> |"参考"| U
                B --> |"参考"| H
                SB["预测: 15%会点赞"]
            end

            subgraph ScoreC["帖子C评分"]
                C["健身打卡"]
                C --> |"参考"| U
                C --> |"参考"| H
                SC["预测: 20%会点赞"]
            end
        end
    end

关键点

  • 帖子A的80%预测分,是基于"小明喜欢技术内容"得出的
  • 这个分数不会因为帖子B、C的存在而改变
  • 即使把帖子B、C换成其他内容,帖子A的分数仍然是80%

为什么这很重要?

flowchart LR
    subgraph Benefits["候选隔离的好处"]
        direction TB

        B1["公平性"]
        B1_DESC["你的帖子分数
不受同批次其他帖子影响"] B2["可缓存"] B2_DESC["同一用户+同一帖子
分数可以复用"] B3["可解释"] B3_DESC["分数只取决于
用户偏好×内容匹配度"] end

创作者启示

传统方式的问题 候选隔离的保障
如果同时有很多热门帖子,你的帖子可能被"比下去" 你的帖子分数独立计算,不受其他帖子影响
不同时间发布,面对不同竞争对手,分数不稳定 同一用户看你的帖子,预测分数始终一致
难以判断内容质量,因为分数受环境影响 分数直接反映"用户偏好×内容匹配",更有参考价值

实际案例:你发了一篇技术教程,在技术爱好者小明的信息流中预测分是85%。无论小明的候选池里还有什么其他内容(可能是热门娱乐新闻、大V的爆款帖子),你这篇帖子对小明的预测分始终是85%。最终排名取决于所有帖子各自的独立分数排序。

技术细节(可选阅读)

候选隔离通过特殊的注意力掩码实现:

1模型输入: [用户信息, 历史行为1, 历史行为2, ..., 候选1, 候选2, 候选3]
2
3注意力规则:
4- 用户和历史: 可以互相"看到"(双向注意力)
5- 候选帖子: 只能"看到"用户和历史,看不到其他候选
6- 结果: 每个候选的分数只由用户+历史决定

这种设计让系统可以:

  1. 一次性处理多个候选(高效)
  2. 保证每个候选分数独立(公平)
  3. 缓存已计算的分数(节省资源)

四、数据流程

4.1 完整请求处理流程

flowchart TB
    START([开始: 用户请求推荐]) --> QH

    subgraph QH["1.查询增强 (并行)"]
        direction LR
        QH1[UserActionSeqHydrator
获取用户行为历史] QH2[UserFeaturesHydrator
获取用户元数据] end QH --> SOURCES subgraph SOURCES["2.候选获取 (并行)"] direction LR S1[ThunderSource
网内帖子] S2[PhoenixSource
网外帖子] end SOURCES --> HYDRATORS subgraph HYDRATORS["3.候选增强 (并行)"] direction TB H1[CoreDataHydrator
帖子核心数据] H2[GizmoduckHydrator
作者信息] H3[InNetworkHydrator
网络关系] H4[SubscriptionHydrator
订阅状态] H5[VideoDurationHydrator
视频时长] H6[VFHydrator
可见性信息] end HYDRATORS --> FILTERS subgraph FILTERS["4.预评分过滤 (顺序)"] direction TB F1[DropDuplicatesFilter
去重] F2[CoreDataHydrationFilter
核心数据校验] F3[AgeFilter
时效性过滤] F4[SelfTweetFilter
过滤自己的帖子] F5[AuthorSocialgraphFilter
屏蔽/静音用户] F6[MutedKeywordFilter
静音关键词] F7[PreviouslySeenPostsFilter
已浏览帖子] F8[PreviouslyServedPostsFilter
已推送帖子] F9[IneligibleSubscriptionFilter
付费墙检查] F10[RetweetDeduplicationFilter
转发去重] F1 --> F2 --> F3 --> F4 --> F5 --> F6 --> F7 --> F8 --> F9 --> F10 end FILTERS --> SCORERS subgraph SCORERS["5.评分 (顺序)"] direction TB SC1[PhoenixScorer
ML预测] SC2[WeightedScorer
加权计算] SC3[AuthorDiversityScorer
作者多样性] SC4[OONScorer
网外调整] SC1 --> SC2 --> SC3 --> SC4 end SCORERS --> SELECTOR subgraph SELECTOR["6.选择"] SEL[TopKScoreSelector
选择Top-K] end SELECTOR --> POST subgraph POST["7.后处理"] direction TB PH[Post-Selection Hydration
后选增强] PF1[VFFilter
可见性检查] PF2[DedupConversationFilter
对话去重] PH --> PF1 --> PF2 end POST --> SIDE subgraph SIDE["8.副作用 (异步)"] SE[CacheRequestInfoSideEffect
缓存请求信息] end SIDE --> END([结束: 返回排序帖子列表])

用餐厅点餐比喻请求处理流程

把推荐请求想象成你走进一家智能自助餐厅

flowchart TB
    subgraph RequestAnalogy["一次推荐请求 = 一次智能点餐"]
        direction TB

        subgraph Phase1["1. 了解顾客 (Query Hydration)"]
            P1A["服务员查看你的会员卡"]
            P1B["调出你的口味档案"]
            P1C["查询你最近吃过什么"]
        end

        subgraph Phase2["2. 备选菜品 (Sources)"]
            P2A["厨房A: 你常点的菜
(Thunder 网内)"] P2B["厨房B: 今日主厨推荐
(Phoenix 网外)"] end subgraph Phase3["3. 菜品质检 (Hydrators)"] P3A["核实原材料新鲜度"] P3B["查看厨师评分"] P3C["确认是否含过敏原"] end subgraph Phase4["4. 剔除不合适的 (Filters)"] P4A["你过敏的? 移除"] P4B["你吃过的? 移除"] P4C["你拉黑的厨师? 移除"] end subgraph Phase5["5. 口味预测 (Scorers)"] P5A["预测你对每道菜的满意度"] P5B["综合评分排序"] end subgraph Phase6["6. 端上餐桌 (Selector)"] P6A["选出评分最高的50道菜"] end Phase1 --> Phase2 --> Phase3 --> Phase4 --> Phase5 --> Phase6 end

具体例子:小明的一次刷推

背景:用户小明打开 App,系统需要在 200 毫秒内返回推荐。

flowchart TB
    subgraph ConcreteExample["小明的这次刷新"]
        START["小明下拉刷新"] --> Q

        subgraph Q["1. 了解小明 (15ms)"]
            Q1["查到小明ID: 12345"]
            Q2["发现小明喜欢: 科技、游戏"]
            Q3["最近点赞了: 3篇AI文章"]
            Q4["屏蔽了: 2个营销号"]
        end

        Q --> S

        subgraph S["2. 收集候选 (50ms)"]
            S1["Thunder返回:
关注者的 350 条帖子"] S2["Phoenix返回:
可能喜欢的 650 条帖子"] S3["合计: 1000 条"] end S --> H subgraph H["3. 补充信息 (30ms)"] H1["补上每条帖子的:
作者粉丝数、发布时间
是否有视频、视频时长"] end H --> F subgraph F["4. 过滤 (20ms)"] F1["去掉重复: -50"] F2["去掉超过7天: -80"] F3["去掉自己发的: -5"] F4["去掉屏蔽作者: -30"] F5["去掉已看过: -200"] F6["剩余: 635 条"] end F --> SC subgraph SC["5. 打分 (60ms)"] SC1["Phoenix预测小明对每条的:
点赞概率、转发概率、停留时间..."] SC2["加权计算综合分数"] SC3["调整作者多样性"] end SC --> SEL subgraph SEL["6. 选择 (5ms)"] SEL1["选出分数最高的 50 条"] end SEL --> END["返回给小明
总耗时: ~180ms"] end

各阶段耗时分布

阶段 耗时 并行方式 做了什么
Query Hydration ~15ms 并行查询用户信息 获取小明的偏好、历史、社交关系
Sources ~50ms Thunder和Phoenix并行 收集1000条候选帖子
Hydrators ~30ms 6个Hydrator并行 补充帖子详细信息
Filters ~20ms 顺序执行10个过滤器 从1000条筛到635条
Scorers ~60ms Phoenix模型预测 给635条帖子打分
Selector ~5ms Top-K选择 选出最终50条

关键洞察:整个过程大量使用并行化,但过滤器必须顺序执行(因为后面的过滤器依赖前面的结果)。模型预测是最耗时的环节。

4.2 过滤器详细流程

flowchart TB
    subgraph FilterChain["过滤器链"]
        direction TB

        INPUT[输入候选
~1000条] --> F1 F1[DropDuplicatesFilter
移除重复ID] -->|去重后| F2 F2[CoreDataHydrationFilter
确保核心数据完整] -->|有效数据| F3 F3[AgeFilter
移除过期帖子
默认7天] -->|时效内| F4 F4[SelfTweetFilter
移除用户自己的帖子] -->|非自己| F5 F5[AuthorSocialgraphFilter
移除已屏蔽/静音作者] -->|未屏蔽| F6 F6[MutedKeywordFilter
移除含静音关键词的帖子] -->|无静音词| F7 F7[PreviouslySeenPostsFilter
移除最近浏览过的帖子] -->|未见过| F8 F8[PreviouslyServedPostsFilter
移除最近推送过的帖子] -->|未推送| F9 F9[IneligibleSubscriptionFilter
移除无权访问的付费内容] -->|可访问| F10 F10[RetweetDeduplicationFilter
同一原帖的转发只保留一条] -->|去重转发| OUTPUT OUTPUT[输出候选
~200-500条] end style INPUT fill:#e1f5fe style OUTPUT fill:#c8e6c9

用安检流程比喻过滤器链

把过滤器链想象成机场安检流程,每道关卡检查特定问题:

flowchart TB
    subgraph FilterAnalogy["过滤器链 = 机场安检"]
        direction TB

        PASSENGER["1000名乘客
(候选帖子)"] --> C1 subgraph C1["关卡1: 身份核验"] CHECK1["有人冒用别人身份证?
(重复ID)"] end C1 --> C2 subgraph C2["关卡2: 证件完整性"] CHECK2["证件信息不全?
(核心数据缺失)"] end C2 --> C3 subgraph C3["关卡3: 签证有效期"] CHECK3["签证过期?
(帖子超过7天)"] end C3 --> C4 subgraph C4["关卡4: 禁飞名单"] CHECK4["在黑名单上?
(被用户屏蔽的作者)"] end C4 --> C5 subgraph C5["关卡5: 违禁物品"] CHECK5["携带违禁词?
(含静音关键词)"] end C5 --> C6 subgraph C6["关卡6: 重复登机"] CHECK6["已经登过机?
(已看过/已推送)"] end C6 --> BOARD["约400名乘客通过
(进入评分阶段)"] end

具体例子:1000条帖子的过滤之旅

假设用户小红请求推荐,系统收集了 1000 条候选帖子,看它们如何通过过滤器链:

flowchart TB
    subgraph FilterExample["小红的1000条帖子过滤过程"]
        START["输入: 1000 条帖子"] --> F1

        F1["1. DropDuplicatesFilter
发现50条重复ID
剩余: 950"] --> F2 F2["2. CoreDataHydrationFilter
30条数据不完整
剩余: 920"] --> F3 F3["3. AgeFilter
80条超过7天
剩余: 840"] --> F4 F4["4. SelfTweetFilter
5条是小红自己发的
剩余: 835"] --> F5 F5["5. AuthorSocialgraphFilter
小红屏蔽了3个作者,共45条
剩余: 790"] --> F6 F6["6. MutedKeywordFilter
小红静音了'广告'关键词,命中20条
剩余: 770"] --> F7 F7["7. PreviouslySeenPostsFilter
小红最近看过180条
剩余: 590"] --> F8 F8["8. PreviouslyServedPostsFilter
已推送过120条
剩余: 470"] --> F9 F9["9. IneligibleSubscriptionFilter
15条付费内容小红无权看
剩余: 455"] --> F10 F10["10. RetweetDeduplicationFilter
同一原帖被转发多次,去重35条
剩余: 420"] --> END END["输出: 420 条进入评分"] end style START fill:#e1f5fe style END fill:#c8e6c9

过滤效果统计

过滤器 过滤掉 过滤原因 创作者启示
DropDuplicates 50 重复帖子ID 正常技术去重,无需关注
CoreDataHydration 30 数据异常 确保帖子发布成功
AgeFilter 80 超过7天 48小时内是黄金曝光期
SelfTweet 5 用户自己发的 正常逻辑,自己发的不推给自己
AuthorSocialgraph 45 被用户屏蔽 避免引战,减少被拉黑
MutedKeyword 20 含静音关键词 避免使用常见广告词
PreviouslySeen 180 用户看过 无法二次触达同一用户
PreviouslyServed 120 已经推送过 同上
IneligibleSubscription 15 付费墙 考虑免费内容引流
RetweetDedup 35 转发去重 被多人转发说明内容有传播性
总计 580 - 58%的候选被过滤

关键洞察:超过一半的候选在评分前就被过滤掉。“已看过"和"已推送"是最大的过滤器,这解释了为什么持续产出新内容很重要——旧内容无法重复触达同一用户。

创作者实战建议

基于过滤器机制,创作者可以:

  1. 保持发布频率:旧内容会被"已看过"过滤器拦截,新内容才有机会
  2. 避免引战:被用户屏蔽后,你的所有内容都会被该用户过滤
  3. 慎用敏感词:用户可能静音了某些关键词,避免不必要的词汇
  4. 内容要完整:确保帖子正常发布,数据完整才能通过检验

4.3 用户行为序列(UAS)处理

用户行为序列是 Phoenix 模型的关键输入,记录用户的历史互动行为。

flowchart TB
    subgraph UASPipeline["UAS 处理流程"]
        direction TB

        FETCH["从 UAS Fetcher 获取
Thrift 格式行为序列"] --> PRE["预聚合过滤"] PRE --> |"KeepOriginalUserActionFilter"| AGG["时间窗口聚合"] AGG --> |"UAS_WINDOW_TIME_MS"| POST["后聚合过滤"] POST --> |"DenseAggregatedActionFilter"| TRUNC["序列截断"] TRUNC --> |"保留最后 N 条"| OUTPUT["UserActionSequence
输出到 Phoenix"] end

处理步骤详解

步骤 操作 目的
获取 从 UAS 服务拉取原始行为流 获取完整历史
预过滤 保留原始动作,过滤衍生动作 减少噪音
时间聚合 在 UAS_WINDOW_TIME_MS 内聚合 合并短时间内重复行为
后过滤 密集聚合动作过滤 进一步精简
截断 保留最后 UAS_MAX_SEQUENCE_LENGTH 条 控制模型输入长度

行为类型

mindmap
  root((用户行为类型))
    正向互动
      Favorite 点赞
      Reply 回复
      Retweet 转发
      Quote 引用
    内容消费
      Click 点击
      VideoView 视频观看
      PhotoExpand 图片展开
    社交行为
      ProfileClick 主页点击
      Follow 关注
    负向反馈
      NotInterested 不感兴趣
      Block 屏蔽
      Mute 静音
      Report 举报

创作者启示

洞察 说明
历史影响预测 算法会参考用户过去与类似内容的互动来预测对你内容的反应
行为有窗口期 只有时间窗口内的行为被聚合,非常久远的行为权重降低
序列有长度限制 只保留最近的 N 条行为,更早的行为被丢弃
负向行为被记录 屏蔽、静音等负向行为同样影响后续推荐

实际案例:如果用户最近频繁点赞技术类内容,模型会预测该用户更可能点赞你的技术帖子。反之,如果用户近期对某类内容频繁标记"不感兴趣”,你的同类内容预测分会降低。


五、ML模型架构

5.1 Two-Tower 检索模型

flowchart TB
    subgraph TwoTower["Two-Tower 检索模型"]
        direction TB

        subgraph UserTower["用户塔 (User Tower)"]
            direction TB
            UF[用户特征]
            UH[用户行为历史]
            UE1[用户嵌入层]
            UE2[用户编码器]
            UV["用户向量 B x D"]

            UF --> UE1
            UH --> UE1
            UE1 --> UE2
            UE2 --> UV
        end

        subgraph CandidateTower["候选塔 (Candidate Tower)"]
            direction TB
            CF[帖子特征]
            AF[作者特征]
            CE1[候选嵌入层]
            CE2[候选编码器]
            CV["候选向量 N x D"]

            CF --> CE1
            AF --> CE1
            CE1 --> CE2
            CE2 --> CV
        end

        subgraph Matching["匹配层"]
            DOT[点积相似度
UV · CV^T] TOPK[Top-K选择] UV --> DOT CV --> DOT DOT --> TOPK end end TOPK --> OUT[检索候选列表]

用相亲配对比喻 Two-Tower 模型

把 Two-Tower 模型想象成一个智能相亲系统

flowchart TB
    subgraph TwoTowerAnalogy["Two-Tower = 相亲配对系统"]
        direction TB

        subgraph LeftTower["左塔: 了解你是谁"]
            L1["你的基本信息
(年龄、职业、城市)"] L2["你的兴趣爱好
(最近喜欢什么)"] L3["你的择偶标准
(历史互动偏好)"] L4["生成你的'画像向量'"] end subgraph RightTower["右塔: 了解候选对象"] R1["候选人基本信息"] R2["候选人特点"] R3["候选人背景"] R4["生成候选人'画像向量'"] end subgraph Matching["配对环节"] M1["计算你和每个候选人的
'契合度分数'"] M2["选出契合度最高的 1000 人
进入下一轮面试"] end LeftTower --> Matching RightTower --> Matching end

具体例子:为小明找兴趣帖子

场景:小明刷推荐,系统需要从数百万条帖子中快速筛选出可能感兴趣的 1000 条。

flowchart TB
    subgraph TwoTowerExample["Two-Tower 为小明检索帖子"]
        direction TB

        subgraph UserTowerEx["用户塔处理小明"]
            U1["输入小明的信息:
- 用户ID: 12345
- 最近点赞: AI、游戏、数码
- 关注的人: 100个科技博主"] U2["编码成128维向量:
[0.23, -0.15, 0.87, ...]"] end subgraph CandTowerEx["候选塔处理帖子"] C1["预计算所有帖子的向量
(离线处理,非实时)"] C2["帖子A: [0.21, -0.12, 0.85, ...]
帖子B: [-0.5, 0.3, 0.1, ...]
帖子C: [0.19, -0.18, 0.82, ...]
..."] end subgraph MatchEx["匹配计算"] M1["小明向量 · 帖子A向量 = 0.95 (很高!)"] M2["小明向量 · 帖子B向量 = 0.12 (很低)"] M3["小明向量 · 帖子C向量 = 0.91 (很高!)"] M4["选出分数最高的1000条"] end UserTowerEx --> MatchEx CandTowerEx --> MatchEx end

Two-Tower 的优势

特性 说明 实际意义
离线预计算 候选塔可以提前计算所有帖子的向量 不用每次请求都重新计算帖子特征
高效检索 向量点积可以用近似最近邻(ANN)加速 从百万帖子中毫秒级找到Top-K
独立更新 用户塔和候选塔可以分别训练更新 新帖子发布后快速入库

创作者启示:Two-Tower 决定了你的帖子能否进入"海选"。如果你的内容向量与大量用户的兴趣向量相似度低,就很难被检索出来。这就是为什么垂直领域持续输出很重要——让你的内容向量稳定在某个兴趣空间。

5.2 排序模型输入输出

flowchart LR
    subgraph Input["模型输入"]
        direction TB

        subgraph UserInput["用户输入"]
            UI1[用户ID哈希]
            UI2[用户特征嵌入]
        end

        subgraph HistoryInput["历史输入"]
            HI1[帖子嵌入序列]
            HI2[作者嵌入序列]
            HI3[动作类型序列]
        end

        subgraph CandidateInput["候选输入"]
            CI1[候选帖子嵌入]
            CI2[候选作者嵌入]
        end
    end

    subgraph Model["Grok Transformer"]
        TRANS[Transformer
with Candidate Isolation] end subgraph Output["模型输出"] direction TB subgraph PositiveActions["正向动作概率"] PA1["P_like"] PA2["P_reply"] PA3["P_repost"] PA4["P_quote"] PA5["P_click"] PA6["P_video_view"] PA7["P_share"] PA8["P_follow"] end subgraph NegativeActions["负向动作概率"] NA1["P_not_interested"] NA2["P_block"] NA3["P_mute"] NA4["P_report"] end end Input --> Model Model --> Output

用面试官打分比喻排序模型

把排序模型想象成一个经验丰富的面试官,需要给每个候选人打出多维度评分:

flowchart TB
    subgraph RankingAnalogy["排序模型 = 面试官评估"]
        direction TB

        subgraph InputInfo["面试官收到的信息"]
            I1["候选人简历
(帖子内容、作者)"] I2["你的偏好档案
(用户历史行为)"] I3["你最近面试过的人
(行为序列)"] end subgraph Evaluation["评估过程"] E1["Transformer 神经网络
综合分析所有信息"] end subgraph Scores["打分结果"] S1["你会喜欢这人吗? 85%"] S2["你会和他聊天吗? 45%"] S3["你会推荐给朋友吗? 30%"] S4["你会反感这人吗? 5%"] end InputInfo --> Evaluation --> Scores end

具体例子:小明看到一条 AI 帖子

假设候选池中有一条关于 ChatGPT 的帖子,看模型如何预测小明的反应:

flowchart TB
    subgraph RankingExample["模型预测小明对 AI 帖子的反应"]
        direction TB

        subgraph ModelInput["模型输入"]
            IN1["小明最近行为:
- 点赞了3篇AI文章
- 转发了1篇GPT教程
- 关注了2个AI博主"] IN2["这条帖子信息:
- 内容: ChatGPT新功能介绍
- 作者: 科技博主(10万粉)
- 有3张配图"] end subgraph Prediction["模型预测"] P1["分析小明对AI内容的历史反应"] P2["分析这个作者的内容质量"] P3["综合判断匹配度"] end subgraph Output["输出概率"] O1["P_like = 0.72
(72%可能点赞)"] O2["P_reply = 0.15
(15%可能评论)"] O3["P_retweet = 0.25
(25%可能转发)"] O4["P_click = 0.85
(85%可能点击看详情)"] O5["P_not_interested = 0.03
(3%可能标记不感兴趣)"] end ModelInput --> Prediction --> Output end

排序模型的关键特点

特点 说明 对创作者的意义
多任务预测 同时预测12+种用户行为 综合表现好的内容排名高
正负信号并存 既预测点赞也预测屏蔽 避免引发负向反馈很重要
依赖历史行为 参考用户最近与类似内容的互动 持续吸引特定人群能形成正循环
候选隔离 每条帖子独立评估 你的内容不会被其他帖子"带节奏"

关键洞察:排序模型不只看"用户会不会喜欢",还会预测"用户会不会反感"。一条帖子即使点赞概率高,如果举报概率也高,最终得分可能不理想。

5.3 Hash嵌入机制

flowchart TB
    subgraph HashEmbedding["Hash嵌入机制"]
        direction TB

        ID[实体ID
例如: user_id=12345] --> HASH subgraph HASH["多哈希函数"] H1[Hash函数1] H2[Hash函数2] H3[Hash函数N] end subgraph Buckets["嵌入桶"] B1[Bucket 1
size=vocab_size/n] B2[Bucket 2
size=vocab_size/n] B3[Bucket N
size=vocab_size/n] end subgraph Embeddings["嵌入向量"] E1[Embedding 1] E2[Embedding 2] E3[Embedding N] end H1 -->|"hash_id mod size"| B1 H2 -->|"hash_id mod size"| B2 H3 -->|"hash_id mod size"| B3 B1 --> E1 B2 --> E2 B3 --> E3 E1 --> SUM[Sum/Concat] E2 --> SUM E3 --> SUM SUM --> FINAL[最终嵌入向量] end subgraph Benefits["优势"] BEN1[减少嵌入表大小] BEN2[处理OOV问题] BEN3[提高泛化能力] end

用图书馆索引比喻 Hash 嵌入

传统方法需要为每个用户/帖子存储一个独立的"书架"(嵌入向量),但用户有数亿、帖子有数十亿,内存根本装不下。

Hash 嵌入的思路是:用多个共享书架,通过巧妙的索引方式让每个实体有独特的组合

flowchart TB
    subgraph HashAnalogy["Hash嵌入 = 共享书架系统"]
        direction TB

        subgraph Traditional["传统方式: 每人一个书架"]
            T1["用户1 → 书架1"]
            T2["用户2 → 书架2"]
            T3["..."]
            T4["用户10亿 → 书架10亿"]
            T5["问题: 需要10亿个书架!"]
        end

        subgraph HashWay["Hash方式: 共享书架"]
            H1["只有1000个共享书架"]
            H2["用户1 → 书架23 + 书架456 + 书架789"]
            H3["用户2 → 书架45 + 书架123 + 书架678"]
            H4["通过不同组合,每人都有独特的'混合书架'"]
        end
    end

具体例子:用户 ID 如何变成向量

假设要把用户 ID = 12345 转换成模型能理解的向量:

flowchart TB
    subgraph HashExample["把用户12345转成向量"]
        direction TB

        INPUT["用户ID: 12345"] --> HASH

        subgraph HASH["三个不同的哈希函数"]
            H1["哈希1: 12345 mod 1000 = 345"]
            H2["哈希2: (12345×7) mod 1000 = 415"]
            H3["哈希3: (12345×13) mod 1000 = 485"]
        end

        HASH --> LOOKUP

        subgraph LOOKUP["查找对应的嵌入桶"]
            L1["桶345的向量: [0.1, 0.2, ...]"]
            L2["桶415的向量: [0.3, 0.1, ...]"]
            L3["桶485的向量: [0.2, 0.4, ...]"]
        end

        LOOKUP --> COMBINE

        subgraph COMBINE["合并成最终向量"]
            C1["方式1: 相加求平均"]
            C2["方式2: 拼接在一起"]
            C3["结果: 用户12345的独特向量"]
        end
    end

Hash 嵌入的优势

问题 传统方案 Hash嵌入方案
内存占用 10亿用户 × 128维 = 512GB 100万桶 × 128维 = 512MB
新用户 没见过的用户没有向量 哈希总能得到一个组合
冷启动 新用户体验差 相似ID有相似向量,可泛化
更新成本 每个用户单独更新 批量更新共享桶

技术背景:这就是为什么 X 能在有限资源下处理数亿用户和数十亿帖子的推荐。Hash 嵌入是工程上的关键突破。


六、候选管道框架

6.1 核心Trait定义

flowchart TB
    subgraph Traits["核心 Trait"]
        direction TB
        SOURCE["Source
获取候选"] HYDRATOR["Hydrator
增强候选信息"] FILTER["Filter
过滤候选"] QH["QueryHydrator
增强查询信息"] SCORER["Scorer
评分"] SELECTOR["Selector
选择Top-K"] SIDEEFFECT["SideEffect
副作用处理"] end subgraph Pipeline["CandidatePipeline"] direction TB CP["候选管道
组合所有Trait"] end CP --> SOURCE CP --> HYDRATOR CP --> FILTER CP --> QH CP --> SCORER CP --> SELECTOR CP --> SIDEEFFECT

Trait 方法定义:

Trait 核心方法 作用
Source<Q,C> get_candidates(query) → Vec<C> 从数据源获取候选
Hydrator<Q,C> hydrate(query, candidates) → Vec<C> 补充候选的详细信息
Filter<Q,C> filter(query, candidates) → Vec<C> 过滤不符合条件的候选
QueryHydrator<Q> hydrate(query) → Q 补充查询的上下文信息
Scorer<Q,C> score(query, candidates) → Vec<C> 给候选打分
Selector<Q,C> select(query, candidates, limit) → Vec<C> 选出最终结果
SideEffect<Q,C> execute(query, candidates) 执行副作用(如缓存)

用工厂流水线比喻管道框架

把候选管道想象成一条汽车组装流水线,每个 Trait 就是一个工位:

flowchart TB
    subgraph PipelineAnalogy["候选管道 = 汽车组装流水线"]
        direction TB

        subgraph Station1["工位1: Source"]
            S1["从仓库取零件
(从各处获取候选帖子)"] end subgraph Station2["工位2: Hydrator"] S2["给零件贴标签、测尺寸
(补充帖子详细信息)"] end subgraph Station3["工位3: Filter"] S3["质检,不合格的扔掉
(过滤不适合的帖子)"] end subgraph Station4["工位4: Scorer"] S4["给每辆车打质量分
(给每条帖子评分)"] end subgraph Station5["工位5: Selector"] S5["选出最好的50辆出厂
(选出Top-K帖子)"] end subgraph Station6["工位6: SideEffect"] S6["记录生产日志
(缓存请求信息)"] end Station1 --> Station2 --> Station3 --> Station4 --> Station5 --> Station6 end

每个 Trait 的职责

Trait 类比 职责 实际例子
Source 仓库管理员 从各处获取候选 ThunderSource 从内存取关注者帖子
Hydrator 质检员 补充候选信息 VideoDurationHydrator 补充视频时长
Filter 安检员 剔除不合格候选 AgeFilter 剔除超过7天的帖子
QueryHydrator 档案员 了解"客户"信息 UserFeaturesHydrator 获取用户偏好
Scorer 评估师 给候选打分 WeightedScorer 计算综合分数
Selector 采购经理 选出最终结果 TopKScoreSelector 选前50名
SideEffect 文书 记录处理过程 CacheRequestInfoSideEffect 缓存请求

为什么这样设计?

flowchart TB
    subgraph DesignBenefits["管道设计的好处"]
        direction TB

        B1["模块化
每个组件职责单一,易于测试"] B2["可扩展
新增过滤器只需实现 Filter trait"] B3["可复用
同一个 Hydrator 可用于多个管道"] B4["可配置
通过组合不同组件构建不同管道"] end

创作者启示:理解管道设计有助于理解你的内容是如何被"处理"的。每一步都是独立的,不会因为某一步出问题而影响其他步骤。这也意味着你可以通过优化某一步(如提高内容质量通过更多 Filter)来提升整体表现。

6.2 管道执行流程

stateDiagram-v2
    [*] --> QueryHydration: 接收查询

    QueryHydration --> CandidateFetching: 查询增强完成
    note right of QueryHydration: 并行执行所有QueryHydrator

    CandidateFetching --> CandidateHydration: 候选获取完成
    note right of CandidateFetching: 并行执行所有Source

    CandidateHydration --> PreScoringFiltering: 候选增强完成
    note right of CandidateHydration: 并行执行所有Hydrator

    PreScoringFiltering --> Scoring: 过滤完成
    note right of PreScoringFiltering: 顺序执行Filter链

    Scoring --> Selection: 评分完成
    note right of Scoring: 顺序执行Scorer链

    Selection --> PostSelectionHydration: 选择完成
    note right of Selection: Top-K选择

    PostSelectionHydration --> PostSelectionFiltering: 后选增强完成

    PostSelectionFiltering --> SideEffects: 后选过滤完成

    SideEffects --> [*]: 返回结果
    note right of SideEffects: 异步执行副作用

具体例子:一条帖子如何走完管道

假设有一条科技博主发的 AI 帖子,看它如何在管道中被处理:

flowchart TB
    subgraph PipelineExample["这条AI帖子的管道之旅"]
        direction TB

        START["AI帖子诞生
作者: 科技博主, 内容: ChatGPT教程"] --> S1 S1["1. Source阶段
Phoenix检索时发现这条帖子
加入候选池"] --> S2 S2["2. Hydrator阶段
补充信息: 作者10万粉
有3张配图, 无视频"] --> S3 S3["3. Filter阶段
✓ 未过期(发布2小时)
✓ 用户未屏蔽作者
✓ 不含静音词
通过!"] --> S4 S4["4. Scorer阶段
Phoenix预测: P_like=0.72
加权计算: score=8.5"] --> S5 S5["5. Selector阶段
在1000条中排第15名
进入Top-50!"] --> S6 S6["6. SideEffect阶段
记录'已推送给用户小明'"] --> END END["成功! 出现在小明的时间线第15位"] end style START fill:#e1f5fe style END fill:#c8e6c9

管道各阶段的并行与顺序

gantt
    title 管道执行时序 (单位: 毫秒)
    dateFormat SSS
    axisFormat %L ms

    section 查询阶段
    QueryHydration (并行)      :q1, 000, 015

    section 获取阶段
    Thunder Source             :s1, 015, 055
    Phoenix Source             :s2, 015, 065

    section 增强阶段
    CoreDataHydrator           :h1, 065, 085
    AuthorHydrator             :h2, 065, 085
    VideoHydrator              :h3, 065, 080

    section 过滤阶段
    Filters (顺序)             :f1, 085, 105

    section 评分阶段
    PhoenixScorer              :crit, sc1, 105, 155
    WeightedScorer             :sc2, 155, 165

    section 选择阶段
    TopKSelector               :sel, 165, 170

性能洞察:Source 阶段和 Hydrator 阶段大量并行,Filter 和 Scorer 顺序执行。总耗时约 150-200ms,其中 Phoenix 模型预测占了最大头。


七、评分算法

7.1 完整评分信号体系

算法实际使用 19个离散信号 + 1个连续信号,分为五大类:

mindmap
  root((评分信号体系))
    互动类 正向
      favorite_score 点赞
      reply_score 回复
      retweet_score 转发
      quote_score 引用
    内容消费类 正向
      click_score 点击
      photo_expand_score 图片展开
      profile_click_score 主页点击
      quoted_click_score 引用点击
    视频类 正向
      vqv_score 视频观看
        条件:时长大于阈值
    分享类 正向
      share_score 通用分享
      share_via_dm_score 私信分享
      share_via_copy_link_score 复制链接
    停留类 正向
      dwell_score 离散停留
      dwell_time 连续停留时长
    转化类 正向
      follow_author_score 关注作者
    负向信号 惩罚
      not_interested_score 不感兴趣
      block_author_score 屏蔽作者
      mute_author_score 静音作者
      report_score 举报

信号完整列表

类别 信号名 权重方向 触发场景 创作者启示
互动 favorite_score 用户点赞 创作引发共鸣的内容
reply_score 用户回复 设计讨论话题,提出问题
retweet_score 用户转发 创造分享价值
quote_score 用户引用并评论 发布可延伸的观点
内容消费 click_score 用户点击查看详情 标题/首句吸引点击
photo_expand_score 用户展开查看大图 发布有细节的图片
profile_click_score 用户点击作者主页 展现独特人格特质
quoted_click_score 用户点击被引用的内容 引用高质量来源
视频 vqv_score 条件正 视频观看(需超过时长阈值) 制作超过最低时长的视频
分享 share_score 通用分享操作 创作值得分享的内容
share_via_dm_score 通过私信分享给朋友 垂直精准的实用内容
share_via_copy_link_score 复制链接分享 适合跨平台传播的内容
停留 dwell_score 用户在帖子上停留(离散) 提供有深度的内容
dwell_time 停留时长(连续值,秒) 长内容/Thread 保持信息密度
转化 follow_author_score 用户关注作者 建立系列感,预告后续
负向 not_interested_score 用户标记不感兴趣 避免与受众无关的内容
block_author_score 负(强) 用户屏蔽作者 避免引战和人身攻击
mute_author_score 用户静音作者 控制发布频率
report_score 负(最强) 用户举报 遵守社区规范

加权计算流程

flowchart LR
    subgraph Input["Phoenix 模型输出"]
        A["19个离散概率 P_i"]
        B["1个连续值 dwell_time"]
    end

    subgraph Process["加权计算"]
        C["Σ(w_i × P_i)"]
        D{"combined < 0?"}
        E["正分支: + offset"]
        F["负分支: 特殊归一化"]
    end

    A --> C
    B --> C
    C --> D
    D -->|是| F
    D -->|否| E
    E --> G["weighted_score"]
    F --> G

负分数处理:当加权总分为负时,采用特殊公式防止极端惩罚:

1negative_score = (combined + NEGATIVE_WEIGHTS_SUM) / WEIGHTS_SUM × NEGATIVE_SCORES_OFFSET

实际示例

假设某帖子的 Phoenix 预测结果:

场景 信号值 权重(假设) 贡献分
预测 10% 用户会点赞 0.10 +1.0 +0.10
预测 5% 用户会回复 0.05 +1.5 +0.075
预测 2% 用户会转发 0.02 +2.0 +0.04
预测 1% 用户会屏蔽 0.01 -10.0 -0.10
总分 +0.115

注意:一次屏蔽(-0.10)几乎抵消了点赞(+0.10)的全部收益,说明负向信号惩罚力度很大。

7.2 作者多样性评分

flowchart TB
    subgraph AuthorDiversity["作者多样性评分"]
        direction TB

        INPUT[输入: 按分数排序的候选列表]

        subgraph Algorithm["算法"]
            direction TB

            TRACK[跟踪每个作者出现次数]

            CALC["multiplier = (1 - floor) × decay^position + floor
            
position = 该作者之前出现次数 decay = 衰减因子 (例如: 0.7) floor = 最低保留比例 (例如: 0.1)"] APPLY["new_score = score × multiplier"] end subgraph Example["示例"] E1["作者A首次出现: multiplier = 1.0"] E2["作者A第2次出现: multiplier = 0.73"] E3["作者A第3次出现: multiplier = 0.51"] E4["作者A第4次出现: multiplier = 0.36"] E5["作者A第N次出现: multiplier → floor"] end INPUT --> TRACK TRACK --> CALC CALC --> APPLY APPLY --> OUTPUT[输出: 多样性调整后的候选列表] end

7.3 评分器链执行顺序

flowchart TB
    subgraph ScorerChain["评分器链"]
        direction TB

        C1[候选列表
无分数] --> S1 S1[PhoenixScorer
调用ML模型获取预测] -->|添加phoenix_scores| S2 S2[WeightedScorer
计算加权分数] -->|添加weighted_score| S3 S3[AuthorDiversityScorer
多样性调整] -->|更新final_score| S4 S4[OONScorer
网外内容调整] -->|更新final_score| C2 C2[候选列表
带最终分数] end style C1 fill:#ffecb3 style C2 fill:#c8e6c9

7.4 视频评分机制

视频内容有特殊的评分规则,vqv_score(Video Quality View)只在满足时长条件时才计入。

flowchart TB
    subgraph VideoScoring["视频评分判定"]
        V1[视频帖子] --> CHECK{"视频时长 > MIN_VIDEO_DURATION_MS?"}
        CHECK -->|是| APPLY["应用 VQV_WEIGHT 权重"]
        CHECK -->|否| SKIP["VQV 权重 = 0"]
        APPLY --> SCORE["计入 vqv_score × VQV_WEIGHT"]
        SKIP --> ZERO["vqv_score 贡献 = 0"]
    end

视频资格传播规则

flowchart LR
    subgraph VideoEligibility["视频资格判定"]
        direction TB

        O["原创视频帖"] -->|"has_video = true"| YES1["计入视频评分"]

        RT["转发帖"] --> CHECK2{"源帖有视频?"}
        CHECK2 -->|是| YES2["继承视频资格"]
        CHECK2 -->|否| NO2["无视频资格"]

        RP["回复帖"] --> NO3["始终无视频资格"]
    end

创作者启示

场景 是否计入 VQV 建议
原创视频 > 阈值时长 计入 确保视频超过最低时长
原创视频 < 阈值时长 不计入 考虑延长到阈值以上
转发他人视频 继承源帖 转发优质长视频仍有收益
回复中附带视频 不计入 视频内容应发为独立帖
GIF 动图 通常不计入 GIF 一般不满足时长要求

实际案例:发布一个 8 秒的短视频可能不会获得视频观看加分,但延长到 15 秒以上则可以。具体阈值为平台配置参数。

7.5 印象去重机制

算法使用多层去重防止用户重复看到相同内容。

flowchart TB
    subgraph Deduplication["三层去重机制"]
        direction TB

        subgraph Layer1["第一层: Bloom Filter"]
            BF["客户端 Bloom Filter"]
            BF --> |"概率性去重"| SEEN1["快速过滤已浏览"]
        end

        subgraph Layer2["第二层: 精确ID"]
            IDS["显式已见ID列表"]
            IDS --> |"精确匹配"| SEEN2["确定性过滤"]
        end

        subgraph Layer3["第三层: 对话去重"]
            CONV["对话ID追踪"]
            CONV --> |"同对话只留最高分"| SEEN3["Thread去重"]
        end

        INPUT["候选内容"] --> Layer1
        Layer1 --> Layer2
        Layer2 --> Layer3
        Layer3 --> OUTPUT["去重后候选"]
    end

Bloom Filter 工作原理

flowchart LR
    subgraph BloomFilter["Bloom Filter 原理"]
        POST["帖子ID"] --> HASH["多个哈希函数"]
        HASH --> BIT["位数组检查"]
        BIT --> |"所有位都为1"| MAYBE["可能已见"]
        BIT --> |"任意位为0"| NEW["一定未见"]
        MAYBE --> |"存在误判"| FP["假阳性:未见被判为已见"]
        NEW --> PASS["通过过滤"]
    end

优势

  • 空间效率:用少量内存追踪大量浏览历史
  • 无假阴性:已见内容一定会被过滤
  • 允许假阳性:少量未见内容可能被误过滤(可接受的代价)

对话级去重

flowchart TB
    subgraph ConversationDedup["对话去重示例"]
        direction TB

        subgraph Thread["用户A的Thread"]
            T1["帖子1: 主题介绍
得分: 0.8"] T2["帖子2: 详细分析
得分: 0.95"] T3["帖子3: 总结
得分: 0.7"] end T1 --> SAME["同一 conversation_id"] T2 --> SAME T3 --> SAME SAME --> SELECT["只保留得分最高的"] SELECT --> RESULT["帖子2 进入最终结果"] end

创作者启示

  • Thread 中最高质量的一条会代表整个 Thread
  • 不用担心 Thread 多条同时出现刷屏
  • 首条应该能独立吸引人(可能被单独展示)

7.6 双阶段安全审核

网内和网外内容适用不同的安全级别:

flowchart TB
    subgraph SafetyLevels["安全审核级别"]
        direction TB

        subgraph InNetwork["网内内容 In-Network"]
            IN_LEVEL["TimelineHome 级别"]
            IN_DESC["较宽松: 用户主动关注"]
        end

        subgraph OutOfNetwork["网外内容 Out-of-Network"]
            OON_LEVEL["TimelineHomeRecommendations 级别"]
            OON_DESC["较严格: 算法主动推荐"]
        end

        CONTENT["候选内容"] --> CHECK{"来源?"}
        CHECK -->|"关注列表"| InNetwork
        CHECK -->|"Phoenix检索"| OutOfNetwork
    end

两阶段审核流程

flowchart LR
    subgraph TwoStage["两阶段安全审核"]
        PRE["预选阶段"] --> |"VFHydrator"| DATA["获取安全数据"]
        DATA --> SCORE["评分选择"]
        SCORE --> POST["后选阶段"]
        POST --> |"VFFilter"| FINAL["最终过滤"]
    end
阶段 执行时机 作用
预选增强 评分前 获取安全元数据,为后续过滤做准备
后选过滤 Top-K 选择后 对入选内容做最终安全检查

为什么要两阶段?

  1. 预选阶段:快速获取大量候选的安全数据(批量处理效率高)
  2. 后选阶段:仅对最终入选的少量内容做精细检查(减少计算量)

创作者启示

内容类型 审核严格度 建议
粉丝可见内容 较宽松 仍需遵守基本规范
推荐给新用户 较严格 避免擦边内容,影响网外分发

实际案例:一条轻微争议的帖子可能在粉丝信息流正常显示,但不会被推荐给陌生用户。

7.7 网外内容调整

网外内容(来自 Phoenix 检索)会经过额外的分数调整:

flowchart LR
    subgraph OONScoring["网外分数调整"]
        IN["网内内容"] --> |"保持原分"| FINAL1["final_score"]
        OON["网外内容"] --> |"× OON_WEIGHT_FACTOR"| FINAL2["final_score × 系数"]
    end

设计意图

  • 优先展示用户主动关注的内容
  • 网外内容需要更高的预测分数才能与网内竞争
  • 平衡"信息茧房"与"用户偏好"

八、目录结构

flowchart TB
    subgraph ProjectStructure["项目目录结构"]
        direction TB

        ROOT[x-algorithm/]

        ROOT --> README[README.md
项目文档] ROOT --> LICENSE[LICENSE
Apache 2.0] ROOT --> COC[CODE_OF_CONDUCT.md] ROOT --> CP[candidate-pipeline/
可复用管道框架] ROOT --> HM[home-mixer/
主编排服务] ROOT --> TH[thunder/
实时帖子存储] ROOT --> PH[phoenix/
ML模型] subgraph CPFiles["candidate-pipeline/"] CP1[lib.rs] CP2[candidate_pipeline.rs
核心编排逻辑] CP3[source.rs
候选源Trait] CP4[hydrator.rs
增强器Trait] CP5[filter.rs
过滤器Trait] CP6[scorer.rs
评分器Trait] CP7[selector.rs
选择器Trait] CP8[query_hydrator.rs
查询增强Trait] CP9[side_effect.rs
副作用Trait] end subgraph HMFiles["home-mixer/"] HM1[main.rs
gRPC服务入口] HM2[server.rs
服务实现] HM3[candidate_pipeline/
管道实现] HM4[query_hydrators/
查询增强实现] HM5[sources/
候选源实现] HM6[candidate_hydrators/
候选增强实现] HM7[filters/
过滤器实现] HM8[scorers/
评分器实现] HM9[selectors/
选择器实现] HM10[side_effects/
副作用实现] HM11[clients/
外部服务客户端] end subgraph THFiles["thunder/"] TH1[main.rs
服务入口] TH2[thunder_service.rs
gRPC服务] TH3[posts/post_store.rs
帖子存储] TH4[kafka/
事件监听器] TH5[strato_client.rs
关注列表查询] end subgraph PHFiles["phoenix/"] PH1[grok.py
Transformer架构] PH2[recsys_model.py
排序模型] PH3[recsys_retrieval_model.py
检索模型] PH4[run_ranker.py
排序示例] PH5[run_retrieval.py
检索示例] end CP --> CPFiles HM --> HMFiles TH --> THFiles PH --> PHFiles end

8.1 设计决策总结

mindmap
  root((设计决策))
    无手工特征
      全部由Grok Transformer学习
      减少维护负担
      消除特征工程
    候选隔离
      候选间无注意力
      分数可缓存
      批处理灵活
    多动作预测
      14+动作类型
      权重可调
      无需重训练
    Hash嵌入
      多哈希函数
      减少内存占用
      提高泛化
    可组合架构
      通用Pipeline框架
      易于扩展
      并行执行
    关注点分离
      Thunder: 实时存储
      Phoenix: ML模型
      HomeMixer: 编排

8.2 性能指标

组件 目标延迟 说明
Thunder 查询 < 1ms 内存查找,亚毫秒级
Phoenix 检索 < 50ms 向量相似度搜索
Phoenix 排序 < 100ms Transformer推理
Home Mixer 端到端 < 200ms 完整推荐流程

8.3 监控与可观测性

flowchart TB
    subgraph Observability["可观测性架构"]
        direction TB

        subgraph Metrics["指标收集"]
            M1[请求计数]
            M2[响应延迟]
            M3[候选数量]
            M4[过滤率]
            M5[缓存命中率]
        end

        subgraph Thunder["Thunder指标"]
            T1[POST_STORE_REQUESTS]
            T2[POST_STORE_POSTS_RETURNED]
            T3[POST_STORE_POSTS_RETURNED_RATIO]
            T4[POST_STORE_TOTAL_POSTS]
            T5[POST_STORE_REQUEST_TIMEOUTS]
        end

        subgraph Logging["日志"]
            L1[INFO: 阶段完成]
            L2[WARN: 降级处理]
            L3[ERROR: 失败异常]
        end
    end

8.4 扩展指南

8.4.1 添加新的过滤器

sequenceDiagram
    participant Dev as 开发者
    participant Code as 代码库
    participant Pipeline as CandidatePipeline

    Dev->>Code: 1. 创建新Filter结构体
    Dev->>Code: 2. 实现Filter trait
    Dev->>Code: 3. 实现filter()方法
    Dev->>Pipeline: 4. 在pipeline配置中添加
    Pipeline->>Pipeline: 5. 自动集成到过滤链

8.4.2 添加新的评分器

sequenceDiagram
    participant Dev as 开发者
    participant Code as 代码库
    participant Pipeline as CandidatePipeline

    Dev->>Code: 1. 创建新Scorer结构体
    Dev->>Code: 2. 实现Scorer trait
    Dev->>Code: 3. 实现score()方法
    Dev->>Code: 4. 实现update()方法
    Dev->>Pipeline: 5. 在pipeline配置中添加
    Pipeline->>Pipeline: 6. 自动集成到评分链

九、创作者指南

基于对 X 推荐算法源代码的深入分析,本章节从技术原理出发,提炼出可落地的创作策略。

9.1 理解推荐系统的工作方式

X 的推荐系统由三个核心模块协同工作:

flowchart TB
    subgraph System["推荐系统架构"]
        direction TB

        subgraph Sources["内容来源"]
            S1["Thunder
关注列表内容"] S2["Phoenix Retrieval
全平台检索"] end subgraph Scoring["评分系统"] SC["Phoenix Model
Grok大模型打分"] end S1 --> POOL["候选内容池"] S2 --> POOL POOL --> SC SC --> RESULT["最终排序结果"] end
模块 技术实现 核心作用 创作者启示
关注流 Thunder 从用户关注列表中筛选近期内容 粉丝基数影响初始曝光量
发现流 Phoenix检索 基于向量相似度匹配全平台内容 内容质量决定能否触达新用户
排序模型 Phoenix Model 预测用户互动概率并排序 互动预期越高,排名越靠前

9.2 算法评分机制

算法同时预测14种正向行为和4种负向行为的发生概率,加权求和得出最终分数:

1最终分数 = Σ(权重_i × P_i) + 偏移量
2
3正向行为(权重 > 0):点赞、回复、转发、引用、点击、视频观看、分享、关注等
4负向行为(权重 < 0):不感兴趣、屏蔽、静音、举报

关键洞察:负向信号的惩罚力度通常远大于正向信号的奖励。一次被屏蔽可能需要多次点赞才能弥补。

9.3 内容必须通过的过滤关卡

在进入评分环节之前,内容需要通过一系列过滤器:

过滤器 过滤条件 应对策略
时效性过滤 发布超过48小时的内容不再推荐 把握发布时机,热点内容要快
重复检测 相同或高度相似的内容会被去重 确保每条内容有独特价值
社交关系过滤 被用户屏蔽或静音后完全不可见 避免引发用户反感的行为
关键词过滤 包含用户屏蔽词的内容不展示 注意敏感词汇的使用
安全审核 违规内容降权或移除 遵守平台社区规范

9.4 作者多样性机制

算法通过衰减系数防止单一作者霸占信息流:

1衰减公式:multiplier = (1 - floor) × decay^position + floor
2
3实际效果(假设 decay=0.7, floor=0.1):
4- 第1条内容: 得分保持100%
5- 第2条内容: 得分降至约73%
6- 第3条内容: 得分降至约51%
7- 第4条内容: 得分降至约36%

这意味着短时间内密集发帖会导致后续内容的竞争力大幅下降。

9.5 双渠道分发策略

渠道 流量特点 优化方向
网内分发 Thunder 稳定但有上限,取决于粉丝数量 维护粉丝关系,避免被取关
网外发现 Phoenix 不稳定但无上限,取决于内容质量 创作有广泛吸引力的内容

9.6 不同阶段的增长策略

阶段 粉丝规模 主要依赖 策略重点
冷启动期 < 1,000 发现流 创作能引起广泛共鸣的内容,借助热门话题获得初始曝光
成长期 1,000-10,000 双渠道并重 稳定服务现有粉丝的同时,持续尝试突破圈层
成熟期 > 10,000 关注流为主 深耕垂直领域,维护核心粉丝群体

新账号冷启动建议

新账号面临"鸡生蛋蛋生鸡"问题:没粉丝→没曝光→没粉丝。突破方法:

  1. 参与互助社区 - 但需要筛选高质量社区
  2. 积累第一批粉丝 - 先成为 KOC(关键意见消费者)
  3. 与大账号互动 - 一个大账号的回复/转发顶得上1000个散户
  4. 在热门帖子下留高质量评论 - 借势获得初始曝光

9.7 内容过滤机制详解

每条发布的内容在进入评分阶段之前,必须通过一系列过滤器的检查。这些过滤器基于代码中的 CandidateFilter 实现,主要分为以下几类:

flowchart LR
    POST["发布内容"] --> G1["时效性检查"]
    G1 --> G2["内容去重"]
    G2 --> G3["用户自身过滤"]
    G3 --> G4["转发归并"]
    G4 --> G5["付费内容权限"]
    G5 --> G6["已读标记"]
    G6 --> G7["屏蔽词匹配"]
    G7 --> G8["社交关系检查"]
    G8 --> G9["元数据完整性"]
    G9 --> G10["安全合规审核"]
    G10 --> SCORE["进入评分"]
过滤阶段 技术实现 对创作者的影响
时效性检查 基于发布时间戳,约48小时后从推荐池移除 内容有明确的生命周期,需把握发布节奏
内容去重 通过内容哈希识别重复发布 避免复制粘贴相同内容
用户自身过滤 不向用户推荐其自己的内容 系统正常行为
转发归并 同一原帖的多次转发只保留一条 原创内容在算法中更有优势
付费内容权限 订阅类内容需验证用户权限 付费墙内容仅对订阅者可见
已读标记 用户浏览过的内容不再重复推荐 需要持续产出新内容
屏蔽词匹配 检查用户设置的屏蔽关键词 避免使用可能被大量用户屏蔽的词汇
社交关系检查 被拉黑或静音的账号内容不展示 维护健康的社区互动关系
元数据完整性 验证帖子的必要字段是否完整 正常发布不会触发此问题
安全合规审核 检测违规或有害内容 遵守平台社区规范

9.8 创作者实践指南

基于算法评分机制,以下是提升内容表现的策略体系。


一、核心策略总览

mindmap
  root((创作者策略))
    互动类信号
      reply_score
        设计讨论话题
        提出开放问题
        经营评论区
      quote_score
        发布可延伸观点
        引用时添加见解
      retweet_score
        创造分享价值
        实用/认同/共鸣
    停留类信号
      dwell_time
        开头设悬念
        中间有密度
        结尾有价值
      photo_expand
        图片留悬念
        信息图优势
      video_view
        前3秒抓人
        添加字幕
        15-60秒最佳
    转化类信号
      profile_click
        展现人格特质
        优化Bio和固定帖
      follow_author
        建立系列感
        预告后续内容
      share_via_dm
        垂直专业内容
        精准实用信息
    规避负面
      not_interested
        避免刷屏
        控制发布间隔
      block/mute
        避免引战
        处理负面评论
      report
        遵守社区规范
        注意敏感边界

二、信号优化详解

2.1 互动类信号

目标:提升 reply_scorequote_scoreretweet_score

信号 低效写法 高效写法
reply “今天读完了一本好书,收获很大” “程序员转管理岗,技术能力会退化吗?我观察身边的案例,发现…”
quote “这篇文章写得很好” “这个观点我部分同意,但在实际项目中还需要考虑…”
retweet “分享一个工具” “找了三个月终于找到的免费设计资源,设计师朋友们收藏”

2.2 停留类信号

目标:提升 dwell_timephoto_expandvideo_view

信号 技巧 示例
dwell_time 悬念开头 “我用了一个反常识的方法,把转化率提升了3倍。一开始团队都反对…”
photo_expand 信息密集图 流程图、对比图、数据可视化(需要放大才能看清细节)
video_view 前3秒钩子 开头直接展示结果或冲突,而非缓慢铺垫

2.3 转化类信号

目标:提升 profile_clickfollow_authorshare_via_dm

信号 触发场景 示例
profile_click 展现独特视角 持续输出某垂直领域的深度见解,让人好奇"这人是谁"
follow_author 系列预告 “这是我总结的产品方法论第3篇,下周更新用户调研实战”
share_via_dm 精准实用 “给正在找工作的朋友:这5个简历细节90%的人都忽略了”

2.4 负面信号规避

目标:降低 not_interestedblockmutereport

信号 触发行为 规避方法
not_interested 内容与用户无关 明确目标受众,不追求所有人喜欢
block/mute 频繁刷屏或引战 控制发帖间隔,理性讨论不人身攻击
report 违规或争议内容 了解平台规则,敏感话题谨慎措辞

三、内容形式选择

flowchart LR
    subgraph 文字内容
        T1[长文/Thread] --> D1[dwell_time]
        T2[观点/问题] --> D2[reply_score]
        T3[干货总结] --> D3[retweet_score]
    end

    subgraph 图片内容
        P1[信息图] --> E1[photo_expand]
        P2[多图帖] --> E2[滑动查看]
        P3[高清细节图] --> E3[放大查看]
    end

    subgraph 视频内容
        V1[短视频15-60s] --> F1[vqv_score]
        V2[前3秒钩子] --> F2[完播率]
        V3[添加字幕] --> F3[静音友好]
    end

各形式适用场景

形式 适用场景 具体示例
Thread 复杂知识拆解 “我如何从0到1搭建数据中台,分7步讲清楚:1/7 首先要解决的是…”
观点帖 引发讨论 “为什么我不建议应届生去创业公司?说三个真实踩坑经历”
干货图 信息整合 一张图总结某框架的核心概念,需要放大查看细节
对比图 突出差异 Before/After 对比,优化前后的代码/设计/数据
短视频 操作演示 30秒演示一个实用技巧,开头直接展示效果
教程视频 完整流程 带字幕的步骤演示,关键节点有文字标注

四、分发渠道策略

flowchart TB
    subgraph 两大分发渠道
        IN[In-Network
关注流] OUT[Out-of-Network
发现流] end subgraph 新账号策略 N1[参与热门话题] --> OUT N2[在大V评论区互动] --> OUT N3[加入垂直社区] --> IN end subgraph 成熟账号策略 M1[维护粉丝互动] --> IN M2[偶尔破圈内容] --> OUT M3[建立内容系列] --> IN end

4.1 新账号冷启动

策略 具体做法 示例
热门话题参与 在趋势话题下发表有见地的观点 某技术发布新版本时,第一时间分享试用体验和踩坑记录
大V评论互动 在行业KOL帖子下留高质量评论 不是"说得好",而是补充一个具体案例或提出延伸问题
垂直社区 加入细分领域的互助群组 持续在某个技术话题下输出,成为该话题的活跃贡献者

4.2 成熟账号增长

策略 具体做法 示例
粉丝维护 定期回复评论、发起互动 每周固定一个"问答时间",回复粉丝提问
破圈内容 偶尔发布泛受众内容 平时发技术内容,偶尔发一篇职场成长感悟触达更广人群
内容系列 建立固定栏目 “每周工具推荐”、“踩坑日记"等让粉丝形成期待

五、内容规划

5.1 时效性矩阵

flowchart TB
    subgraph 高成本
        A1[教程系列
常青+高投入] A2[趋势解读
时效+深度] end subgraph 低成本 B1[工具推荐
常青+轻量] B2[个人感悟
日常互动] B3[话题讨论
中等时效] B4[热点评论
高时效+快速] end subgraph 时效性 direction LR LOW[常青内容] -.-> MID[趋势内容] -.-> HIGH[热点内容] end
类型 时效窗口 内容示例
常青教程 长期有效 “Git 工作流完全指南”、“系统设计面试必备知识”
工具推荐 较长有效 “提升开发效率的10个VS Code插件”
趋势解读 24-48小时 某大厂发布新技术后的深度分析和实践建议
话题讨论 12-24小时 行业热议话题的个人观点和经验分享
热点评论 2-4小时 突发新闻/事件的第一时间简短点评
日常互动 即时 工作日常分享、提问互动、粉丝答疑

5.2 发布节奏

flowchart LR
    subgraph 发布间隔
        I1[两帖间隔 2-4 小时]
        I2[避免 30 分钟内连发]
        I3[触发多样性衰减]
        I1 --> I2 --> I3
    end

    subgraph 账号规模建议
        S1[新账号: 1-2条/天
质量优先] S2[成长期: 2-3条/天
平衡曝光] S3[大账号: 可更频繁
衰减影响小] end

5.3 内容配比

pie title 内容类型配比
    "常青内容" : 40
    "趋势响应" : 30
    "互动内容" : 20
    "实验内容" : 10

示例:技术博主周计划

类型 比例 本周内容计划
常青内容 40% 周二:Docker入门教程 Thread;周四:代码审查最佳实践
趋势响应 30% 周一:回应最新发布的框架更新;周五:行业报告解读
互动内容 20% 周三:发起技术选型投票;周末:回复本周精选评论
实验内容 10% 周六:尝试一种新的内容形式(如短视频演示)

六、写作技巧

6.1 外链处理

flowchart TD
    LINK[需要放外链] --> Q1{内容能否独立?}
    Q1 -->|能| A1[主帖完整内容
链接放回复] Q1 -->|不能| Q2{是否长内容?} Q2 -->|是| A2[用Thread展开
链接放末条] Q2 -->|否| A3[截图关键信息
配合链接]
场景 处理方式 具体示例
推荐文章 主帖总结要点+链接放回复 主帖总结3个关键点,回复放原文链接
产品发布 截图关键信息+链接 截图产品核心功能界面,配文说明
长篇教程 Thread展开+末条放链接 用5条推文讲清核心步骤,最后一条放完整链接
自己的博客 提炼精华到推文 把博客最有价值的段落直接发出,链接作为"完整版”

6.2 Thread 写作结构

flowchart TB
    T1["首条: 独立成立 + 吸引继续"] --> T2["中间: 逻辑递进 + 信息密度"]
    T2 --> T3["末条: 总结 + 引导回首条"]

    NOTE["建议长度: 5-10条"]

示例模板

 11/6 [悬念开头 + 明确预期]
 2    三年前我从大厂裸辞去创业,烧光了50万积蓄。
 3    今天想聊聊这段经历教会我的6件事。
 4
 52/6 [核心观点1 + 具体案例]
 6    第一件事:现金流比梦想重要
 7    当时我们...
 8
 93/6 [核心观点2 + 具体案例]
10    第二件事:...
11
124/6 [核心观点3 + 具体案例]
13    第三件事:...
14
155/6 [核心观点4-5]
16    第四件事:...
17    第五件事:...
18
196/6 [总结 + 行动引导]
20    最后一件事:失败不可怕,可怕的是没有复盘
21    这6条是我用50万换来的教训,希望对你有帮助。
22    如果觉得有用,欢迎转发给需要的朋友。

七、速查表

目标 核心信号 策略要点
提升互动 reply_score 提问、讨论、争议性话题
促进转发 retweet_score 实用、认同、社交货币
增加引用 quote_score 可延伸观点、不完整信息
延长停留 dwell_time 悬念开头、Thread、长内容
图片优化 photo_expand 信息图、细节图、多图
视频优化 vqv_score 短时长、前3秒、加字幕
主页转化 profile_click 人格展现、系列内容
促进关注 follow_author 预告更新、持续价值
私信分享 share_via_dm 垂直实用、精准人群
规避惩罚 负面信号 控制频率、避免引战

内容检测清单

发布前使用此清单自检:

flowchart TB
    START["准备发布内容"] --> Q1{"是否有明确价值?
教育/娱乐/信息"} Q1 -->|是| Q2{"是否易于互动?
问题/讨论点"} Q1 -->|否| REVISE1["重新思考内容价值"] Q2 -->|是| Q3{"是否适合分享?
实用/有趣/独特"} Q2 -->|否| ADD["添加互动元素"] Q3 -->|是| Q4{"时机是否合适?
高峰时段/热点相关"} Q3 -->|否| ENHANCE["增强可分享性"] Q4 -->|是| Q5{"最近是否发过类似内容?"} Q4 -->|否| WAIT["等待更好时机"] Q5 -->|否| PUBLISH["发布"] Q5 -->|是| SPACE["间隔一段时间再发"]

数据驱动优化

关键指标追踪
指标 对应算法信号 优化方向
互动率 like + reply + repost 内容共鸣度
引用率 quote 话题延展性
个人主页点击 profile_click 个人品牌吸引力
粉丝增长 follow_author 长期价值
视频完播率 video_view 视频内容质量
平均停留时长 dwell_time 内容深度
A/B 测试建议
flowchart LR
    subgraph Testing["内容测试矩阵"]
        direction TB

        T1["测试不同开头钩子"]
        T2["测试发布时间"]
        T3["测试内容长度"]
        T4["测试媒体类型"]
        T5["测试话题标签"]
    end

    Testing --> ANALYZE["分析互动数据"]
    ANALYZE --> ITERATE["迭代优化"]
    ITERATE --> Testing

长期增长策略

flowchart TB
    subgraph GrowthFlywheel["增长飞轮"]
        direction TB

        CONTENT["优质内容"] --> ENGAGE["用户互动"]
        ENGAGE --> SIGNAL["正向信号"]
        SIGNAL --> RANK["算法推荐"]
        RANK --> REACH["更大曝光"]
        REACH --> FOLLOW["新粉丝"]
        FOLLOW --> NETWORK["网内流量增加"]
        NETWORK --> CONTENT
    end

核心原则

  1. 一致性 - 保持稳定的发布节奏和内容风格
  2. 互动性 - 积极回复评论,建立社区感
  3. 价值性 - 每条内容都要有明确的用户价值
  4. 真实性 - 避免刻意迎合算法而失去个人特色

八、算法认知纠偏

通过分析源代码,可以澄清一些广为流传但缺乏依据的说法:

关于发布频率

有观点认为"发得越多曝光越多"。但从代码来看,AuthorDiversityScorer 会对同一作者的连续内容施加递减系数。这意味着在短时间内密集发布,后续内容的得分会被压低。算法的设计意图是让用户信息流保持多样性,而非被单一创作者霸屏。

建议:控制发布频率,两条内容之间保持适当间隔,确保每条内容都有足够的曝光窗口。

关于粉丝数量

有说法称"粉丝越多推荐越多"。但在评分逻辑中,算法预测的是当前用户对当前内容的互动概率,这个计算过程中并没有作者粉丝数的加权因子。购买假粉丝不仅无法提升推荐,还可能因为这些账号不产生真实互动而稀释整体互动率。

建议:专注于内容质量和真实粉丝的培养,有机增长才是可持续的策略。

关于蓝标认证

有传言称"蓝标账号有流量加权"。通过代码分析,在 For You 推荐的评分逻辑中没有发现蓝标加权的实现。蓝标可能在其他产品功能中有影响(如回复排序),但在内容推荐算法中没有直接权重。

建议:是否订阅蓝标应基于其实际提供的功能来评估,而非假设的推荐加权。

关于发布时间

有观点宣称存在"普适的最佳发帖时间"。但算法是个性化的,每个用户看到内容的时间取决于他们自己的活跃模式。不存在对所有用户都有效的统一最佳时间。

建议:通过分析工具了解自己粉丝的活跃时间分布,测试不同时间段的效果,找到适合自己受众的发布节奏。

关于"限流"

当内容数据表现不佳时,常见的归因是"被限流了"。但从过滤器代码来看,只有明确违规的内容才会被过滤,不存在基于内容表现的"隐性限流"机制。数据下滑更可能的原因包括:

  • 内容与受众期待不匹配
  • 竞争环境变化
  • 发布时机问题
  • 受众兴趣迁移

建议:将注意力放在可控因素上——内容质量、发布策略、互动经营——而非外部归因。

关于历史数据

有说法认为"算法只看最近的表现"。但代码中存在 UserActionSequenceHydrator,用于获取用户的历史行为序列。这说明算法会参考较长时间范围内的用户行为来进行预测。

建议:保持长期稳定的内容质量,避免大起大落。历史表现会影响算法对你内容的预测。

关于评论区价值

有观点认为"在别人帖子下评论不如发自己的内容"。但评论本身也是内容展示的渠道,高质量的评论可以获得点赞、回复,从而被更多人看到。对于新账号来说,在热门帖子下留下有见地的评论是获得初始曝光的有效方式。

建议:将评论区视为内容输出的补充渠道,认真对待每一条评论。


认知纠偏速查

流传说法 代码实际表现 调整建议
发得多曝光多 多样性机制会压制连续内容 控制频率,保证每条内容的曝光窗口
买粉提升推荐 评分基于互动预测,非粉丝数 专注有机增长
蓝标有流量加权 推荐算法中无此逻辑 基于实际功能评估价值
存在最佳发帖时间 算法个性化,因人而异 分析自己粉丝的活跃时间
数据差是被限流 过滤器只针对违规内容 反思内容和策略本身
只看近期表现 会参考历史行为序列 保持长期稳定质量
评论区没价值 评论是曝光的有效渠道 认真参与有质量的讨论

文档生成时间: 2026-01-21 基于 X For You Feed Algorithm 开源代码库分析