---
title: "打分与排序"
description: "PhoenixScorer 产出行为预测，VMRanker 调用 vm-ranker 服务执行加权求和、作者多样性衰减、站外降权、新作者扶持与 DPP 多样性筛选；权重乘以预测概率而非互动计数"
---

> 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.

# 打分与排序

## 这一页回答什么

本页说明推荐系统如何将 Phoenix 排序模型的预测概率转化为可排序的最终分。本页涵盖各行为预测的权重数值、加权求和的实现位置、三项后处理调整（作者多样性衰减、站外降权、新作者扶持）的公式与参数，以及 `docs/BIDIRECTIONAL_BOOST_CHANGE.md` 记录的双向关注加成规则。

## 核心结论

1. **内层流水线按顺序执行 5 个打分器**：`PhoenixScorer` → `ImmersiveVideoScorer` → `VMRanker` → `PageDecodeRerankScorer` → `PageRlExplorationScorer`（`home-mixer/candidate_pipeline/phoenix_candidate_pipeline.rs:475-481`）。系统在开源配置中默认关闭后两个打分器。旧版代码中的 `RankingScorer` 文件已移除。
2. **最终分由独立的 vm-ranker 服务计算**。`VMRanker` 打分器将候选帖子与 Phoenix 预测发送给 [VM Ranker 重排服务](https://x-algorithm.vergego.ai/concepts/vm-ranker/)。vm-ranker 完成加权求和、作者多样性衰减、站外降权和 DPP 多样性筛选。共享 crate `xai-value-model/scoring.rs` 定义了加权求和公式，home-mixer 与 vm-ranker 均调用该实现。
3. **加权公式为 `Σ weight_i × P(action_i)`，包含 30 个预测项**（`xai-value-model/scoring.rs:79-218`）。权重参数定义在 `home-mixer/params/param.rs:404-533`。负向行为（不感兴趣、拉黑、静音、举报、未停留）的权重为负数。
4. **权重乘以用户执行该行为的预测概率，不乘以历史互动计数。** 举报权重为 -234.0，绝对值是点赞权重的数百倍，但一次举报不会抵消数百个赞。源码注释指出，举报的基础概率比点赞低 1000 倍以上。因此模型必须赋予举报更大的权重，预测结果才能影响最终排序（`home-mixer/params/param.rs:375-403`）。
5. **系统依次执行三项后处理调整**：同一作者的第 k+1 条帖子乘以 `(1-0.25)·0.5^k + 0.25`；站外帖子以及关注者发送的回复与转发乘以 0.75（默认开启）；每次请求最多提升一条低曝光新作者原创帖子至第 16 名得分。前两项参数定义在 `vm-ranker/params.rs` 中，作为 vm-ranker 的代码默认值。
6. **双向关注回复加成已全量生效**：当帖子作者与当前用户互相关注且帖子为原创时，回复权重从 5.0 提升至 20.0（加成值为 `15.0`，`home-mixer/params/param.rs:411-416`）。停留加成默认值为 0.0，未上线。
7. **vm-ranker 远程调用失败时采用本地兜底策略**：home-mixer 使用本地计算的加权分和新作者扶持结果输出最终候选。此时系统不执行作者多样性衰减、站外降权和 DPP 筛选（`home-mixer/scorers/vm_ranker.rs:107-113`）。

## 打分阶段总览

```mermaid
flowchart TD
    C[过滤后的候选] --> PS["PhoenixScorer<br/>调 Phoenix 排序模型"]
    PS -->|"phoenix_scores<br/>每个行为一个预测"| IV["ImmersiveVideoScorer<br/>仅视频轮播请求"]
    IV --> VM["VMRanker 打分器<br/>本地加权分 + 新作者扶持"]
    VM -->|"RankRequest gRPC"| SVC["vm-ranker 服务<br/>加权求和 · 多样性 · 站外降权 · DPP"]
    SVC -->|"RankResponse score"| VM
    VM -. "RPC 失败" .-> LOCAL["保留本地分"]
    VM --> PD["PageDecodeRerankScorer<br/>默认关闭"]
    LOCAL --> PD
    PD --> RL["PageRlExplorationScorer<br/>默认关闭"]
    RL --> SEL["TopKScoreSelector 选择"]
```

流水线在 [candidate-pipeline 框架](https://x-algorithm.vergego.ai/concepts/candidate-pipeline-framework/) 中按顺序执行打分器。候选进入选择阶段的逻辑见 [候选选择与成型](https://x-algorithm.vergego.ai/concepts/candidate-selection/)。

## PhoenixScorer：取模型预测

`PhoenixScorer`（`home-mixer/scorers/phoenix_scorer.rs`）调用 [Phoenix 排序模型](https://x-algorithm.vergego.ai/concepts/phoenix-ranking/)，将各项行为的预测概率写入候选帖子的 `phoenix_scores` 字段。

- **启用条件**：命中文档缓存（`has_cached_posts`）时跳过打分；配置开关 `disable_home_mixer_phoenix_ranker` 开启时整体关闭打分器（`phoenix_scorer.rs:73-82`）。
- **集群路由**：`resolve_cluster()` 确定推理集群。默认集群由 `PhoenixInferenceClusterId` 指定。当 `PhoenixRankerNewUserHistoryThreshold` 大于 0 且用户历史行为序列长度低于该阈值时，路由至 `PhoenixRankerNewUserInferenceClusterId`。开源默认阈值为 0，即不对新用户分流（`home-mixer/params/param.rs:287-298`）。系统可通过配置开关 `override_qf_use_experiment2_fou` 与 `override_qf_use_experiment1_fou` 改写生产集群路由（`phoenix_scorer.rs:32-68`）。
- **空序列短路**：当 `scoring_sequence` 为空时，打分器返回空预测（`phoenix_scorer.rs:96-98`）。
- **请求发送**：打分器通过 `PredictionDispatch` 发出推理请求。该组件定义于 `xai_candidate_pipeline::component_library::egress`，开源仓库未包含其具体实现。
- **拓展打分头**：配置项 `EnableHomeExcursionScores`（默认值为 `true`，`param.rs:308-313`）开启时，预测结果额外包含离开首页类行为头（如 `home_video_continuation_secs` 与 `home_profile_visit_secs`）。

## 权重表

下表列出 `home-mixer/params/param.rs` 定义的权重参数。官方文档说明开发团队通过定时脚本将该文件的默认值同步为生产主值（`README.md:432`）。第三列表格提供 `vm-ranker/params.rs` 中同名参数的代码默认值。两处数值存在差异，具体说明见表格下方。

| 行为 | 参数 | param.rs 开源默认值 | param.rs 行号 | vm-ranker/params.rs 默认值 |
|------|------|------:|------|------:|
| 点赞 favorite | `FavoriteWeight` | 0.708 | `404-409` | 0.5 |
| 回复 reply | `ReplyWeight` | 5.0 | `410` | 5.0 |
| 双向关注回复加成 | `BidirectionalFollowReplyWeightBoost` | 15.0 | `411-416` | 15.0 |
| 双向关注停留加成 | `BidirectionalFollowDwellWeightBoost` | 0.0 | `417-422` | 0.0 |
| 转发 retweet | `RetweetWeight` | 1.0 | `423` | 1.0 |
| 展开图片 photo_expand | `PhotoExpandWeight` | 0.05 | `424-429` | 0.05 |
| 打开视频 video_open | `VideoOpenWeight` | 0.0 | `430-435` | 0.07 |
| 点击 click | `ClickWeight` | 0.274 | `436` | 0.3 |
| 打开链接 open_link | `OpenLinkWeight` | 0.2 | `437` | 0.2 |
| 点头像 profile_click | `ProfileClickWeight` | 0.0 | `438-443` | 0.0 |
| 视频质量观看 vqv | `VqvWeight` | 0.0 | `444` | 0.0 |
| 分享 share | `ShareWeight` | 2.118 | `445` | 2.0 |
| 私信分享 share_via_dm | `ShareViaDmWeight` | 5.0 | `446-451` | 5.0 |
| 复制链接分享 share_via_copy_link | `ShareViaCopyLinkWeight` | 20.0 | `452-457` | 20.0 |
| 停留 dwell | `DwellWeight` | 0.05 | `458` | 0.05 |
| 引用 quote | `QuoteWeight` | 5.0 | `459` | 5.0 |
| 点击被引用帖 quoted_click | `QuotedClickWeight` | 0.05 | `460-465` | 0.05 |
| 被引用帖视频观看 quoted_vqv | `QuotedVqvWeight` | 0.0 | `466-471` | 0.0 |
| 关注作者 follow_author | `FollowAuthorWeight` | 4.0 | `472-477` | 4.0 |
| post_unexplored | `PostUnexploredWeight` | 0.015 | `478-483` | 0.02 |
| post_video | `PostVideoWeight` | 0.0 | `484-489` | 0.0 |
| grok_analyze | `GrokAnalyzeWeight` | 0.0 | `490-495` | 0.0 |
| 停留时长（连续值）dwell_time | `ContDwellTimeWeight` | 0.0075 | `496-501` | 0.004 |
| 点击后停留时长 click_dwell_time | `ContClickDwellTimeWeight` | 0.385 | `502-507` | 0.4 |
| 不感兴趣 not_interested | `NotInterestedWeight` | -53.07 | `509-514` | -47.52 |
| 拉黑作者 block_author | `BlockAuthorWeight` | -31.2 | `515-520` | -31.2 |
| 静音作者 mute_author | `MuteAuthorWeight` | -58.8 | `521-526` | -58.8 |
| 举报 report | `ReportWeight` | -234.0 | `527` | -234.0 |
| 未停留 not_dwelled | `NotDwelledWeight` | -0.02 | `528-533` | -0.02 |

`vm-ranker` 单独提供三个可调权重参数：`VideoContinuationWeight`、`UserVideoContinuationWeight` 与 `ProfileVisitSecsWeight`，默认值均为 0.0（`vm-ranker/params.rs:66-83`）。home-mixer 在本地计算得分时将这三项固定设为 0.0（`home-mixer/scorers/value_model.rs:39-41`）。

**两套默认值的优先级关系**：两个服务读取同一组特性开关键（例如 `rust_home_mixer_favorite_weight`）。vm-ranker 在运行时从配置中心同步这些键的数值（`vm-ranker/main.rs:69-98`），代码中的默认值仅在配置缺失对应键时生效。官方文档仅声明 `home-mixer/params/param.rs` 与生产配置保持同步。因此本文档以 `param.rs` 的数值为基准，将 `vm-ranker` 的参数视为备用默认值。开源仓库未包含生产环境的真实配置值。

### 权重乘的是预测概率，不是互动计数

官方在 2026-08-14 发布的更新中澄清了权重的计算逻辑（`README.md:54`），并在 `home-mixer/params/param.rs:375-403` 与 `xai-value-model/scoring.rs:28-56` 中补充了说明注释：

- **乘数是预测概率**：每个权重乘以模型预测“当前用户对该候选帖子执行该动作”的概率值（或连续预测值，例如停留时长秒数）。权重不乘以帖子累计获得的点赞数或举报数。
- **权重比例不等于互动计数等价**：“举报权重是点赞权重的 468 倍，因此 1 次举报可以抵消 468 个赞”属于错误推论。数值 468 取自 vm-ranker 默认权重的比值 `234.0 / 0.5`；若按 param.rs 的默认值 0.708 计算，比值约为 330.5。无论使用哪一个比值，权重比均不代表计数等价关系。
- **基础概率差异**：全网用户举报帖子的先验概率比点赞概率低 1000 倍以上。系统增大举报权重，是为了让极小的预测概率依然能够对排序结果产生影响。
- **个性化预测机制**：模型计算个性化概率。少数用户的恶意举报行为主要降低该群体在相似用户推荐流中的权重，不会直接压低所有用户看到的帖子得分。
- **上下文限定**：推荐系统仅收集用户在首页时间线推荐内容中产生的交互行为。用户通过直接链接或群聊跳转打开帖子并进行举报，不会将负向信号计入推荐排序系统。

示例说明（以下数值仅用于原理解释，不属于源码数据）：假定某条帖子对当前用户的预测点赞概率为 P(点赞)=0.05，预测举报概率为 P(举报)=0.00002。点赞项贡献分为 `0.708 × 0.05 = 0.0354`，举报项贡献分为 `-234 × 0.00002 = -0.00468`，负向惩罚约为点赞正向得分的八分之一。只有当模型预测当前用户本人的举报概率显著上升时，负向得分才会成为主导因素。

## 加权求和：xai-value-model

### 30 个加权项

函数 `weighted_terms()`（`xai-value-model/scoring.rs:79-218`）为每个候选帖子计算 30 个 `(名称, 贡献)` 二元组。函数 `compute_weighted_score()` 将各项贡献相加得到综合得分（`scoring.rs:69-77`）。单项计算公式为 `score.unwrap_or(0.0) * weight`（`scoring.rs:57-59`），未输出预测值的打分头按 0.0 计算。

部分打分项包含附加生效条件：

- **reply 与 dwell**：系统通过 `reply_weight_for()` 与 `dwell_weight_for()` 读取权重。当满足双向关注条件时，系统叠加加成权重（`xai-value-model/weights.rs:86-102`）。
- **vqv 与 quoted_vqv**：视频满足合格条件时系统赋予相应权重，不合格时权重为 0.0（`scoring.rs:85-94`）。home-mixer 设定的合格条件包括：当前用户的粉丝数低于 `MAX_FOLLOWERS_THRESHOLD`，且视频时长大于 `MinVideoDurationMs`（10 000 毫秒，`param.rs:707-712`；`home-mixer/util/candidates_util.rs:19-34`）。开源版本中这两个权重的默认值均为 0.0。
- **post_unexplored**：该项仅对站内帖子生效；当配置项 `PostUnexploredIncludeOutOfNetwork` 为真时扩展至站外帖子（`scoring.rs:95-100`；默认值为 `false`，`vm-ranker/params.rs:96-101`）。开源源码未说明该项的业务语义。
- **video_continuation、user_video_continuation 与 profile_visit_secs**：这三项计算“打开概率 × 打开后时长”的乘积值（`scoring.rs:160-183`）。

### 偏移到非负区间

函数 `fuse_heads()` 将加权求和结果传递给 `offset_score()` 执行区间映射（`scoring.rs:65-67`、`239-248`）：

```rust
// xai-value-model/scoring.rs:239-248
pub fn offset_score(combined_score: f64, w: &ValueModelWeights) -> f64 {
    let total_sum = w.total_sum();
    if total_sum == 0.0 {
        combined_score.max(0.0)
    } else if combined_score < 0.0 {
        (combined_score + w.negative_sum()) / total_sum * NEGATIVE_SCORES_OFFSET
    } else {
        combined_score + NEGATIVE_SCORES_OFFSET
    }
}
```

常量 `NEGATIVE_SCORES_OFFSET = 0.001`（`xai-value-model/weights.rs:4`）。方法 `negative_sum()` 计算负向权重的绝对值之和，`total_sum()` 计算正向权重与负向权重绝对值的总量（`weights.rs:51-84`）。映射逻辑实现如下效果：正向得分整体向上平移 0.001；负向得分被压缩映射至 `[0, 0.001)` 区间，同时保持单调递增性。负分帖子排在所有正分帖子之后，但各负分帖子之间保留相对顺序。函数 `unoffset_score()` 执行逆向反变换（`scoring.rs:250-259`）。

## 三项后处理调整

函数 `compute_value_scores_with_adjustment()` 统一执行三项后处理，按以下顺序计算（`xai-value-model/scoring.rs:360-406`，默认路径为 `multiplier_pre_offset = false`）：

1. 获取每个候选帖子的加权得分 `weighted`。请求携带缓存加权分时，系统直接复用缓存值（`scoring.rs:369-375`）。
2. 叠加作者探索奖励 `author_exploration_bonus`（`scoring.rs:393-397`、`408-413`）。
3. 执行新作者扶持：调用 `apply_cold_start_decisions` 将入选帖子的得分提升至目标名次分数（`scoring.rs:341-358`）。
4. 按照第 3 步后的得分排序，分别计算作者多样性衰减系数与站外降权系数，并将两系数相乘作用于最终得分（`scoring.rs:399-404`）。

因此获得扶持的站外帖子在打分阶段依然会乘以站外降权系数。

### 作者多样性衰减

```rust
// xai-value-model/scoring.rs:261-263
pub fn diversity_multiplier(decay_factor: f64, floor: f64, exponent: f64) -> f64 {
    (1.0 - floor) * decay_factor.powf(exponent) + floor
}
```

函数 `author_pool_counts()` 按照候选得分降序遍历列表，记录各候选帖子在其作者名下的出现序号（从 0 开始计数），将其作为指数 k（`scoring.rs:265-282`）。相关参数定义于 vm-ranker：

| 参数 | 开源默认值 | 位置 |
|------|------:|------|
| `EnableAuthorDiversity` | `true` | `vm-ranker/params.rs:175-180` |
| `AuthorDiversityDecay` | 0.5 | `vm-ranker/params.rs:181-186` |
| `AuthorDiversityFloor` | 0.25 | `vm-ranker/params.rs:187-192` |

按照默认参数计算，同一作者的第 1、2、3、4 条帖子分别乘以系数 1.0、0.625、0.4375、0.34375，后续条目系数趋近于 0.25。home-mixer 在本地计算时关闭此项衰减（`home-mixer/scorers/value_model.rs:46-50`）。

### 站外降权

函数 `scoring_context()` 决定当前请求适用的站外降权系数（`vm-ranker/scoring/value_model.rs:123-147`）：

- **话题请求**：采用 `TopicOonWeightFactor`，默认值为 0.5（`vm-ranker/params.rs:211-216`）。
- **符合条件的新用户**：采用 `NewUserOonWeightFactor`，默认值为 0.00001（`params.rs:229-234`）。判定条件为账号注册时长小于 `NewUserAgeThresholdSecs` 且关注数不少于 `NEW_USER_MIN_FOLLOWING = 5`（`vm-ranker/scoring/value_model.rs:21`、`137-139`）。`NewUserAgeThresholdSecs` 默认值为 0（`params.rs:223-228`），因此开源版本默认不触发该分支。
- **其他请求**：采用 `OonWeightFactor`，默认值为 0.75（`params.rs:217-222`）。

函数 `oon_applies()` 判定哪些候选帖子适用该系数（`xai-value-model/scoring.rs:284-293`）：站外帖子统一执行降权；当开关 `EnableOonRescoreForInNetworkRepliesRetweets` 为真时，站内作者发布的回复与转发同样执行降权。该开关默认值为 `true`（`vm-ranker/params.rs:193-198`）。官方文档对该逻辑进行了相同描述（`README.md:375`）。

新用户分支将站外系数降至 0.00001。该逻辑生效时，新用户几乎只能接收到已关注作者的站内内容。

### 新作者扶持（cold start）

home-mixer 的 `AuthorColdStart` 模块负责生成扶持决策（`home-mixer/scorers/author_cold_start.rs:363-434`）。`VMRanker` 打分器在本地得分上执行该计算，并将决策随 RPC 请求传递至 vm-ranker 服务（`vm_ranker.rs:59-75`）。

扶持规则包含以下步骤：

1. 话题请求不执行新作者扶持（`author_cold_start.rs:384-386`）。
2. 系统在区间 `[ColdStartSlotMin, ColdStartSlotMax)` 内随机选取目标排位名次。默认配置区间为 `[15, 16)`，即固定指定为以 0 开始计数的第 15 位（第 16 名）。目标分数为该排位当前的候选得分（`author_cold_start.rs:216-226`）。
3. 候选帖子必须同时满足以下条件（`author_cold_start.rs:188-193`、`285-308`）：
   - 属于原创帖子，非回复或转发；
   - 作者粉丝数不超过 `ColdStartFollowerCap`；
   - 帖子发布时长不超过 `ColdStartMaxPostAgeSecs`；
   - 首页曝光次数 `view_count_on_home` 小于 `ColdStartImpressionThreshold`；
   - 当前在非零分候选列表中的排名处于前 `LowImpressionsMaxPositionRatio` 比例范围内；
   - 命中对应的实验分组（当当前用户处于对照组或实验组时，仅扶持匹配作者池的候选）。
4. 挑选候选：系统默认采用 Thompson 采样算法。每条候选根据参数分布 `Beta(α0 + 点赞数, β0 + 曝光数 − 点赞数)` 生成抽样值，选取抽样值最高的前 `ColdStartTsTopK` 条候选，再从中挑出当前得分最高的一条帖子（`author_cold_start.rs:243-283`）。
5. 选中的帖子得分更新为 `max(原分, 目标分)`。每次推荐请求最多扶持一条帖子（`author_cold_start.rs:331-332`）。

| 参数 | 开源默认值 | `home-mixer/params/param.rs` |
|------|------:|------|
| `EnableViewerColdStart` | `true` | `646-651` |
| `ColdStartImpressionThreshold` | 200 | `608-613` |
| `ColdStartSlotMin` / `ColdStartSlotMax` | 15 / 16 | `614-625` |
| `ColdStartFollowerCap` | 50000 | `626-631` |
| `ColdStartMaxPostAgeSecs` | 7200 | `632-637` |
| `LowImpressionsMaxPositionRatio` | 0.97 | `639-644` |
| `EnableColdStartThompsonSampling` | `true` | `652-657` |
| `ColdStartBetaAlpha0` / `ColdStartBetaBeta0` | 0.75 / 49.25 | `658-669` |
| `ColdStartTsTopK` | 2 | `670-675` |
| `ColdStartImpressionScale` | 1.0 | `676-681` |

先验分布 `Beta(0.75, 49.25)` 的均值为 1.5%，代表系统预设“新发帖子点赞率为 1.5%”。帖子曝光量增加后，抽样结果逐渐趋近真实互动率。

vm-ranker 服务接收到 `cold_start_lift_to_rank` 参数后，在重算得分的基础上再次执行名次分抬升（`xai-value-model/scoring.rs:341-358`），随后计算多样性与站外系数。

### 作者探索奖励与权重扰动

系统包含两项实验控制项，开源版本默认均不生效：

- `AuthorExplorationBonus`：根据作者所属实验分组为加权分增加常数偏移量（先执行逆偏移变换，加和后再执行偏移映射），默认值为 0.0（`vm-ranker/params.rs:205-210`；`vm-ranker/scoring/value_model.rs:243-262`）。
- `WeightPerturbationSigma`：根据用户标识对各项权重乘以扰动系数 `exp(±σ)`，符号取值由 `md5(salt:user_id:head)` 决定，默认值为 0.0（`vm-ranker/params.rs:163-174`；`xai-value-model/weights.rs:104-112`、`202-209`）。

## VMRanker 打分器与兜底

`VMRanker`（`home-mixer/scorers/vm_ranker.rs`）受特性开关 `EnableRanking` 控制，默认值为 `true`（`param.rs:300`）。该组件属于推荐主流程的核心路径，而非可选扩展层。单次执行流程分为三步：

1. **本地算分**：组件通过 `value_model::weights_for()` 获取权重并计算每个候选的 `weighted_score`，随后执行新作者扶持流程（`vm_ranker.rs:59-75`）。本地权重配置关闭了作者多样性衰减和站外降权（`home-mixer/scorers/value_model.rs:46-50`）。
2. **组装请求**：调用 `RequestShape::build()` 写入各候选帖子的 Phoenix 预测、站内属性、是否为回复或转发、是否为互关作者以及扶持名次等信息。请求设置 `value_model_id = "dpp"` 与 `compute_value_model = true`，并附带用户信息供 vm-ranker 解析特性开关（`home-mixer/scorers/vm_ranker_request.rs:27-76`）。针对 Under the Hood 调试请求，系统设置 `include_top_heads` 要求返回贡献最大的打分头。
3. **调用与回填**：客户端优先使用 xDS 寻址发起 gRPC 请求；当 xDS 调用失败时，仅在配置项 `VMRankerEnableFallback` 为真时回退至 DNS 客户端，该配置默认值为 `false`（`vm_ranker.rs:29-57`；`param.rs:554-559`）。当 RPC 整体失败时，打分器记录 `local_score_fallback` 指标并直接回退采用本地得分（`vm_ranker.rs:107-113`）。若服务返回结果中缺失某候选帖子，系统同样保留该帖子的本地得分（`vm_ranker.rs:122-139`）。客户端超时时间设为 400 毫秒（`home-mixer/clients/vm_ranker_client.rs:21`）。

vm-ranker 内部如何计算得分与执行行列式点过程（DPP）多样性筛选，见 [VM Ranker 重排服务](https://x-algorithm.vergego.ai/concepts/vm-ranker/)。

## 双向关注加成：BIDIRECTIONAL_BOOST_CHANGE.md

`docs/BIDIRECTIONAL_BOOST_CHANGE.md` 记录了官方在 2026 年 7 月上线的双向关注加成机制，作为算法调整的历史示例：

- **实现机制**：系统新增 `BidirectionalFollowHydrator` 水合器，查询帖子作者是否关注当前用户，并将结果写入 `is_mutual_follow_author` 标识。针对互关作者发布的**原创帖子**（非回复、非转发），系统在回复权重上叠加 `BidirectionalFollowReplyWeightBoost`。
- **发布周期**：官方于 7 月 10 日启动 A/B 测试，实验分组分别设置 5、10、15、20 四档增益。7 月 13 日将 20 推广至多数用户。7 月 24 日根据实验指标与用户反馈（世界杯期间站外讨论曝光量过低）将增益调整为 15。停留时长加成在测试后未推广上线。
- **当前状态**：机制已全量生效。`BidirectionalFollowReplyWeightBoost` 默认值为 15.0（`home-mixer/params/param.rs:411-416`），水合器开关 `EnableBidirectionalFollowHydration` 默认值为 `true`（`param.rs:839-844`），流水线已装配该水合组件（`phoenix_candidate_pipeline.rs:394-396`）。停留加成默认值保持 0.0（`param.rs:417-422`）。
- **代码重构演变**：原始文档中的代码变更作用于 `home-mixer/scorers/ranking_scorer.rs`。当前版本中该文件已被移除，对应逻辑迁移至 `xai-value-model`：资格判定见 `xai-value-model/inputs.rs:20-22`，权重加成见 `xai-value-model/weights.rs:86-102`。

按照开源默认参数，互关作者原创帖子的回复项权重为 `5.0 + 15.0 = 20.0`，达到普通帖子的 4 倍。该加成放大的是模型对“当前用户将进行回复”的预测概率。

## 其他打分器

| 打分器 | 启用条件 | 作用 |
|------|------|------|
| `ImmersiveVideoScorer` | 视频轮播开启、按沉浸式分排序、且有沉浸式行为序列 | 对轮播视频调用另一个 Phoenix 集群（默认 `Experiment3Fou`，`param.rs:1331-1336`），写入 `immersive_scores`（`home-mixer/scorers/immersive_video_scorer.rs:16-66`） |
| `PageDecodeRerankScorer` | `EnablePageDecodeRerank`，默认 `false`（`param.rs:326-331`） | Phoenix 在服务端按页解码出若干位置，入选候选排至最前，其余候选保持原分（`page_decode_rerank_scorer.rs:87-118`） |
| `PageRlExplorationScorer` | `EnablePageRlExploration`，默认 `false`（`param.rs:356-361`） | 对前 `PageRlExplorationTopK`（64）名候选按温度 0.2 执行 Plackett-Luce 采样重排，记录各位置采样概率（`page_rl_exploration_scorer.rs:81-104`） |
| `PhoenixScoresRankingScorer` | 仅在 `phoenix_scores_pipeline` 中生效 | 仅计算本地加权得分，不调用外部 vm-ranker 服务（`home-mixer/scorers/phoenix_scores_ranking_scorer.rs:10-32`） |

## 设计决策

| 决策 | 理由 |
|------|------|
| 预测多个行为概率，再显式加权 | 不同行为价值不同；改权重即可调整取向，不必重训模型 |
| 加权算式放进共享 crate `xai-value-model` | home-mixer 的兜底分和 vm-ranker 的正式分用同一份算式，避免两边漂移 |
| 最终分移到独立的 vm-ranker 服务 | 多样性和 DPP 需要看到整批候选，且依赖帖子 embedding 存储；独立服务可单独扩容、单独同步配置 |
| 负向权重很大 | 负向行为基础概率极低，权重不大则预测对排序几乎没有影响 |
| `offset_score` 把负分压进 `[0, 0.001)` | 下游的乘法调整要求非负分；压缩后负分帖仍彼此有序 |
| 新作者扶持只抬一条、只到第 16 位 | 给低曝光原创帖一次被看到的机会，同时限制对首屏的干扰 |
| vm-ranker 失败时用本地分 | 宁可少了多样性调整，也不让整条信息流失败 |

## FAQ

**Q：官方文档中提到的 `RankingScorer` 位于何处？**
A：该文件已被删除。官方链接指向的 `home-mixer/scorers/value_model.rs` 仅提供读取权重和计算本地加权分的辅助函数。加权求和、多样性衰减以及站外降权等逻辑已全部迁移至独立的 vm-ranker 服务中。

**Q：当一条帖子被大量用户举报时，是否会从所有推荐流中消失？**
A：在打分与排序阶段不会发生全网下架。排序阶段仅评估“当前观看者是否会举报”的个性化预测概率，不读取举报累计总数。帖子是否展示由 [可见性过滤](https://x-algorithm.vergego.ai/concepts/visibility-filtering/) 根据标签与安全策略统一决策。

**Q：已关注作者转发的帖子会被降权吗？**
A：在开源默认配置下会被降权。当开关 `EnableOonRescoreForInNetworkRepliesRetweets` 为 `true` 时，站内已关注作者发布的回复与转发帖子均会乘以 0.75 的站外降权系数。

## 源码锚点

- `home-mixer/candidate_pipeline/phoenix_candidate_pipeline.rs:455-481` —— 打分器装配顺序
- `home-mixer/params/param.rs:375-533` —— 权重注释与 29 个权重参数
- `home-mixer/params/param.rs:608-681` —— 新作者扶持参数
- `xai-value-model/scoring.rs:28-56` —— “权重乘的是预测概率”注释
- `xai-value-model/scoring.rs:79-218` —— 30 个加权项
- `xai-value-model/scoring.rs:239-263` —— `offset_score` 与多样性系数
- `xai-value-model/scoring.rs:284-406` —— 站外判定与调整顺序
- `xai-value-model/weights.rs:4`、`86-102` —— 偏移常量与双向关注加成
- `vm-ranker/params.rs:175-234` —— 多样性、站外降权参数
- `vm-ranker/scoring/value_model.rs:123-147` —— 站外系数选择
- `home-mixer/scorers/author_cold_start.rs:188-334` —— 新作者扶持
- `home-mixer/scorers/vm_ranker.rs:59-141` —— 本地分、调用与兜底
- `docs/BIDIRECTIONAL_BOOST_CHANGE.md` —— 双向关注加成的上线记录

## 相关页面

- [VM Ranker 重排服务](https://x-algorithm.vergego.ai/concepts/vm-ranker/) —— 最终分与 DPP 多样性筛选所在的服务
- [Phoenix 排序模型](https://x-algorithm.vergego.ai/concepts/phoenix-ranking/) —— `PhoenixScorer` 调用的模型，产出各行为预测
- [候选选择与成型](https://x-algorithm.vergego.ai/concepts/candidate-selection/) —— 打分之后的排序、截断与后处理
- [过滤流水线](https://x-algorithm.vergego.ai/concepts/filtering-pipeline/) —— 打分前的候选过滤
- [可见性过滤](https://x-algorithm.vergego.ai/concepts/visibility-filtering/) —— 帖子能否展示由它决定，与权重无关
- [运营迷思 vs 源码真相](https://x-algorithm.vergego.ai/guide/operating-myths/) —— “举报抵消点赞”等流行说法的对照
- [新号与冷启动：算法怎么区别对待新账号](https://x-algorithm.vergego.ai/guide/new-account-cold-start/) —— 新用户站外系数与新作者扶持
- [发帖指南 —— 从算法机制反推](https://x-algorithm.vergego.ai/guide/posting-guide/) —— 基于打分机制，创作者能怎么做
- [candidate-pipeline 框架与七个组件 trait](https://x-algorithm.vergego.ai/concepts/candidate-pipeline-framework/) —— `Scorer` trait 与顺序执行
- [home-mixer 编排层](https://x-algorithm.vergego.ai/concepts/home-mixer-orchestration/) —— 打分器在内层流水线中的位置

Source: https://x-algorithm.vergego.ai/concepts/scoring-and-ranking/index.mdx
