---
title: "处置与标签聚合"
description: "abuse-enforcement-service 读取模型分数后打标签、发挑战或封禁；申诉保护期；safety-label-source 供应标签；safety-label-user-agg 按帖子标签给账号打标签；下架原因的合并"
---

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

# 处置与标签聚合

## 这一页回答什么

- `abuse-enforcement-service/`（下称处置服务）读取什么输入，按什么规则决定打标签、发挑战还是封禁。
- `abuse-ledger-service/` 的“申诉保护期”是什么，怎样阻止重复处置。
- `safety-label-source/` 怎样把帖子标签提供给可见性过滤。
- `safety-label-user-agg/` 怎样根据一个账号最近帖子的标签，给该账号打标签。
- `takedowns/` 怎样合并帖子级和账号级的下架原因。

[打标签规则](https://x-algorithm.vergego.ai/concepts/labeling-rules/) 由事件驱动；本页的系统则基于模型分数或帖子标签的累计。

## 核心结论

1. **处置服务按规则表从上到下匹配，取第一条为真的规则**（`abuse-enforcement-service/service-lib/src/rules.rs:311-332`）。用户与帖子各有一张规则表，规则写在 YAML 中。文件注释写明“从 GrowthBook 动态配置镜像，最后同步 2026-10-20”（`abuse-enforcement-service/service-lib/rules/enforcement_user.yaml:1`）。
2. **动作只有六种：** 封禁账号（临时或永久）、加账号标签、加帖子标签、Arkose 挑战、验证码、活体检测（`abuse-enforcement-service/service-lib/src/decision.rs:1-24`）。
3. **最常见的处置是加 `SpamHighRecall` 账号标签，有效 7 天或 30 天。** 带这个标签的账号，其帖子在站外推荐中被丢弃（见 [可见性过滤](https://x-algorithm.vergego.ai/concepts/visibility-filtering/)）。
4. **用户表的最后一条是兜底封禁**：`act_suspend`，条件为 `true`，动作是临时封禁，策略为 `PlatformManipulation`（`enforcement_user.yaml:184-189`）。测试代码强制它必须在最后（`rules.rs:1227-1228`）。
5. **处置服务先跳过粉丝数高和可信度分高的账号。** 开源 YAML 中的阈值是占位值 12.34（`enforcement_user.yaml:19-33`）。代码中另有一道写死的粉丝上限检查（`abuse-enforcement-service/service-lib/src/safety_checks.rs:158-175`）。
6. **申诉推翻过的处置不会被自动重做。** 处置服务在封禁或加特定标签前，向 abuse-ledger-service 查询有效保护期；开源默认关闭这道检查（`abuse-enforcement-service/service-lib/src/overturn_hold.rs:150-162`）。
7. **帖子标签累计到一定数量，账号也会被打标签。** 默认规则：最近 5 条帖子中至少 3 条带 `NSFW_HIGH_PRECISION`（60 天内）时，账号获得 `NSFW_HIGH_PRECISION` 标签，有效 7 天（`safety-label-user-agg/postToUserLabelRules.strato:395-426`）。

## abuse-enforcement-service：读取分数，执行处置

### 输入

- 来自 Kafka 的评分事件 `ScoreResult`（`xai_abuse_proto::enforcement`，`abuse-enforcement-service/service-lib/src/facts.rs:5`、`:145-170`）。规则读取其中的 `score.labels`。BDSM 也定义了同名消息（`bdsm/proto/abuse_inference.proto:80`），二者是否为同一定义，源码未说明。BDSM 结果汇写出的 `enforcement_cusp_*`、`enforcement_threshold_reached` 与处置规则引用的标签名一致。
- 账号与帖子事实：是否存在、是否已封禁/停用、现有标签、粉丝数、可信度分（`cred.score`、`cred.is_high`）、是否在允许名单中（`facts.rs:215`、`abuse-enforcement-service/service-lib/src/allowlist.rs:10`）。
- `topic_labels` 配置决定哪些 Kafka 主题、带哪些标签的事件进入处置（`abuse-enforcement-service/service-lib/src/config.rs:50-55`）。该配置文件不在仓库中。

### 用户规则表（开源默认值）

| 顺序 | 规则 id | 条件 | 结果 |
|---|---|---|---|
| 1 | `user_in_allowlist` | 在允许名单 | 跳过 |
| 2 | `user_not_found` | 账号不存在 | 跳过 |
| 3 | `high_follower_count` | 粉丝数 ≥ 12.34（占位值） | 跳过 |
| 4 | `pagerank_skipped` | `cred.is_high` 或可信度分 ≥ 12.34（占位值） | 跳过 |
| 5 | `anchor_campaign_suspend` / `_cse` | 评分标签含对应值 | 临时封禁（平台操纵）/ 永久封禁（CSE） |
| 6 | `anchor_campaign_user` | `anchor_campaign_user` | 加 `SpamHighRecall`（无 TTL） |
| 7 | `panda_reports_embedding_v10_rough_spam`、`act_bb1_*_suspend` | 对应标签 | 临时封禁 |
| 8 | `act_bb1_*_bounce` | 对应标签 | `SpamHighRecall` 30 天 + 活体检测 |
| 9 | `act_liveness_check_and_spam_high_recall_7d` / `act_spam_high_recall_7d` | 对应标签 | `SpamHighRecall` 7 天（前者加活体检测） |
| 10 | `act_add_llm_slop_label` | `llm_slop_user`，且账号尚无 `SpamHighRecall` | `SpamHighRecall` 7 天 |
| 11 | `act_add_majority_poster_label` | `SpamEmbeddingMajorityPoster`，且尚无该标签 | `SpamHighRecall` 30 天 |
| 12 | `act_spam_liveness_check` | `spam_liveness_check_required` | 活体检测 |
| 13 | `already_suspended` / `already_deactivated` | 已封禁 / 已停用 | 跳过 |
| 14 | `act_cusp_arkose` / `_captcha` / `_liveness` | BDSM 临界挑战标签，且没有 `enforcement_threshold_reached` | 对应挑战 |
| 15 | `act_impersonation_scam_suspend` | `impersonation_scam_classifier_v1_suspend` | 临时封禁 |
| 16 | `act_suspend` | `true` | 临时封禁 |

依据：`abuse-enforcement-service/service-lib/rules/enforcement_user.yaml:5-189`。TTL 换算：604800000 ms = 7 天，2592000000 ms = 30 天。

BDSM 的 `enforcement_threshold_reached` 没有专门规则。带这个标签的事件跳过第 14 行，落到第 16 行，即临时封禁（依规则表推断）。

### 帖子规则表（开源默认值）

| 规则 id | 条件 | 结果 |
|---|---|---|
| `post_in_allowlist` / `user_in_allowlist` / `user_not_found` | 名单或不存在 | 跳过 |
| `high_follower_count` / `pagerank_skipped` | 作者粉丝或可信度高（占位值），且事件未要求跳过此检查 | 跳过 |
| `act_add_llm_slop_post_label` | `llm_slop_post` | 帖子标签 `RiskyHighVizReply`，30 天 |
| `act_add_gibberish_post_label` | `gibberish_post` | 帖子标签 `SpamHighRecall`，30 天 |
| `act_add_fast_reply_spam_post_label` | `fast_reply_spam_post` | 帖子标签 `SpamHighRecall`，30 天 |
| `anchor_campaign_post` / `act_add_spam_embedding_ptos_distilled_label` | 对应标签 | 帖子标签 `SpamHighRecall`（无 TTL） |
| `act_suspend_ncmec_reported_content_author` | `cse_reports_embedding_v2` | 作者永久封禁（CSE） |
| `post_no_actionable_label` | `true` | 跳过 |

依据：`abuse-enforcement-service/service-lib/rules/enforcement_post.yaml:3-82`。帖子表的兜底动作是跳过，不是封禁。

带 `SpamHighRecall` 标签的帖子在站外推荐中被丢弃（`visibility-filtering/rules/tweet_rules.rs:944-949`）。`RiskyHighVizReply` 只在通知级别中使用（`visibility-filtering/rules/levels.rs:217`）。

### 处置前的检查

```mermaid
flowchart TD
    E["评分事件 ScoreResult"] --> R["规则表: 第一条为真"]
    R -- "skip" --> X["不处置"]
    R -- "act" --> C["粉丝上限检查"]
    C -- "超上限" --> X
    C -- "未超" --> H{"需要查申诉保护期?"}
    H -- "否" --> A["执行动作"]
    H -- "是" --> L["abuse-ledger-service 查询"]
    L -- "有有效保护期" --> X
    L -- "无" --> A
```

- 粉丝上限：规则 `very_high_follower_count`，条件为 `cred.follower_count >= 12345.67`。超过上限时，处置服务把所有决定改成跳过，允许名单和账号不存在两种决定除外（`safety_checks.rs:158-175`、`rules.rs:291-309`）。该数值形似占位值，生产值未公开（推测）。
- 申诉保护期见下一节。

## abuse-ledger-service：申诉保护期

- 该服务只读一张表 `ledger.enforcement_holds`。查询条件：用户 id 匹配、未清除、未过期，且动作是封禁，或动作是加标签且标签在请求列表中（`abuse-ledger-service/src/sql.rs:3-7`）。
- 返回的保护记录包含 `action_kind`、`label`、`head`（模型头）、`expires_at`、`case_group_id`、`reason`（`abuse-ledger-service/src/repo.rs:15-25`）。
- 处置服务按以下方式调用它（`abuse-enforcement-service/service-lib/src/overturn_hold.rs`）：
  - 接口为 `/v1/holds/lookup`，默认超时 200 ms，正结果缓存 60 秒（`:24-33`）。
  - 模式有 `off` / `shadow` / `enforce` 三种，开源默认为 `off`。默认只检查封禁，不检查标签（`:150-162`、`:396-406`）。
  - `enforce` 模式下命中保护期时，处置服务跳过动作，并把状态记为 `hold_overturned`（`:1709-1710`）。
  - 永久封禁只受指定案件组的保护期或人工（`manual`）保护期约束（`:408-415`）。
- 保护期时长：上游 README 写明“按申诉队列设定的固定时长”（上游 README 组件表 `abuse-ledger-service/` 一行）。写入保护期的代码不在仓库中。

## safety-label-source：标签读取层

VF 通过 safety-label-source 读取帖子的 `SafetyLabelMap`（`visibility-filtering/server_deps.rs:39-40`、`:148`）。

| 层 | 参数（开源默认值） | 锚点 |
|---|---|---|
| 进程内缓存 | 每条 TTL 10 秒 | `safety-label-source/source.rs:13` |
| Dragonfly 缓存 | 键前缀 `sls:`；写入 TTL 24 小时；30 秒、90 秒两档刷新 | `safety-label-source/dragonfly.rs:25-38` |
| Manhattan 存储 | 超时 200 ms，重试 1 次，扫描上限 512 | `safety-label-source/mh_client.rs:11-13` |

- 标签可以带过期时间 `expires_at_msec`。读取时，safety-label-source 剔除过期标签（`safety-label-source/source.rs:35-54`、`:138-140`）。打标签规则中的 7 天、14 天 TTL 靠这一步生效。
- 远端不可用时，safety-label-source 走降级路径（`source.rs:130-134`）。

## safety-label-user-agg：按帖子给账号打标签

```mermaid
flowchart LR
    K["Kafka: vf_tweet_safety_labels_event_prod"] -- "延迟 10 分钟转发" --> P["Processor"]
    P --> T{"新加的标签是否触发规则?"}
    T -- "是" --> U["取作者状态: nsfw 标记 / 高 PageRank / 灰标 / 现有标签"]
    U --> S["扫描作者最近 N 条帖子的标签"]
    S --> M{"满足计数条件?"}
    M -- "是" --> W["写 Gizmoduck 账号标签, 带 TTL"]
```

- 输入：帖子标签事件流。Processor 只处理“新加”（Applied）事件；转发延迟 10 分钟，SLO 最大延迟 20 分钟（`safety-label-user-agg/safetyLabelToUserLevelAggregationV2Forwarder.strato:3-21`、`safetyLabelToUserLevelAggregationV2Processor.strato:14-19`）。
- 规则来自功能开关 `safety_understanding_post_to_user_label_rules`。开关缺省时，Processor 使用代码中的默认 JSON（`postToUserLabelRules.strato:360-432`）。
- 规则结构：触发标签 → 排除条件 → 若干条件，每个条件含 (窗口条数, 最少命中条数, 最大帖龄, 是否只看带媒体帖, 标签选择器) → 账号标签与 TTL（`postToUserLabelRules.strato:6-47`）。
- 可写的账号标签只有 `POSSIBLY_NSFW_ACCOUNT` 与 `NSFW_HIGH_PRECISION`（`postToUserLabelRules.strato:96-99`）。
- 配置上限：最多 10 条规则；窗口 ≤ 10；最少命中 ≤ 11；帖龄 ≤ 60 天；TTL ≤ 7 天（`postToUserLabelRules.strato:100-107`）。
- 帖子扫描：Processor 从作者主页时间线倒序取帖；遇到转发时，取原帖的标签（`safetyLabelToUserLevelAggregationV2Processor.strato:59-87`）。
- 写入时，`byUser` 与 `source` 都记为 `"Grox"`（`safetyLabelToUserLevelAggregationV2Processor.strato:91-106`）。

默认有两条规则：

| 规则 id | 触发标签 | 条件 | 账号标签 | 排除 | 锚点 |
|---|---|---|---|---|---|
| `possibly_nsfw_account` | NSFW_HIGH_PRECISION、SOFT_NSFW | 最近 10 条中至少 11 条带其一 | `POSSIBLY_NSFW_ACCOUNT`，7 天 | nsfw 用户、nsfw 管理员标记、高 PageRank 或灰标、已有同类标签 | `postToUserLabelRules.strato:363-394` |
| `nsfw_high_precision` | NSFW_HIGH_PRECISION | 最近 5 条中至少 3 条带该标签，帖龄 ≤ 60 天 | `NSFW_HIGH_PRECISION`，7 天 | nsfw 管理员标记、已有该标签 | `postToUserLabelRules.strato:395-426` |

`possibly_nsfw_account` 的默认条件“10 条中至少 11 条”永远无法满足，因此这条规则默认等于关闭（依代码推断）。VF 的账号标签枚举中也没有 `POSSIBLY_NSFW_ACCOUNT`（`visibility-filtering/models/author.rs:20-37`）。

`NSFW_HIGH_PRECISION` 账号标签会触发站外推荐丢弃（`visibility-filtering/rules/author_rules.rs:176-181`）。结果是：一个账号最近 5 条帖子中有 3 条被判为高精度成人内容时，接下来 7 天它的所有帖子都不会出现在非关注者的推荐中。

## takedowns：下架原因合并

- 帖子的 `takedownReasons` = 帖子自身原因 + 作者账号的原因。系统只在帖子的 `hasTakedown` 为真时查询（`takedowns/tweet-entity-service/TakedownReasonsTransform.scala:19-72`）。
- Gizmoduck 读取账号级原因时，先去掉“不执行”的部分：全部 DMCA，国家码为 `xy` 的法律请求和未注明原因，国家码为 `xx`/`xy` 的第三方举报（`takedowns/gizmoduck/RedactUnenforcedTakedownsFilter.scala:64-81`）。因此，账号级的版权下架不会波及该账号的所有帖子。
- VF 怎样按国家使用这些原因，见 [可见性过滤](https://x-algorithm.vergego.ai/concepts/visibility-filtering/) 的“国家下架与法律下架（takedown）”一节。

## 设计决策

| 决策 | 理由 |
|---|---|
| 规则放在 YAML 中，由动态配置下发 | 处置策略可以快速调整，不必发版 |
| 用户表以封禁兜底，帖子表以跳过兜底 | 推测：进入用户处置流的事件已经过上游模型和主题筛选；帖子事件只在标签明确时才处置 |
| 先检查名单、粉丝数、可信度分 | 减少对高影响力账号的自动误判 |
| 申诉保护期独立成服务，且只读 | 处置服务只需要“能不能做”的答案；写入走人工申诉流程 |
| 标签带 TTL，读取时过滤过期标签 | 自动化标签到期自然失效，不依赖清理任务 |
| 账号聚合规则有硬上限 | 防止配置错误导致大面积给账号打标签 |

## 源码锚点

- `abuse-enforcement-service/service-lib/src/rules.rs:287-332` —— 第一条为真的规则
- `abuse-enforcement-service/service-lib/src/decision.rs:1-24` —— 动作种类
- `abuse-enforcement-service/service-lib/rules/enforcement_user.yaml:5-189` —— 用户规则
- `abuse-enforcement-service/service-lib/rules/enforcement_post.yaml:3-82` —— 帖子规则
- `abuse-enforcement-service/service-lib/src/safety_checks.rs:158-175` —— 粉丝上限
- `abuse-enforcement-service/service-lib/src/overturn_hold.rs:150-162`、`:396-415` —— 申诉保护期门
- `abuse-ledger-service/src/sql.rs:3-7` —— 保护期查询
- `safety-label-source/source.rs:13-54` —— 本地缓存与过期过滤
- `safety-label-user-agg/postToUserLabelRules.strato:96-107`、`:360-428` —— 聚合规则上限与默认规则
- `takedowns/gizmoduck/RedactUnenforcedTakedownsFilter.scala:64-81` —— 不执行的账号级下架

## 相关页面

- [账号级信号](https://x-algorithm.vergego.ai/concepts/account-signals/) —— BDSM 评分与可信度分
- [打标签规则](https://x-algorithm.vergego.ai/concepts/labeling-rules/) —— 事件驱动的打标签
- [可见性过滤](https://x-algorithm.vergego.ai/concepts/visibility-filtering/) —— 标签的效果
- [Under the Hood 透明度报告](https://x-algorithm.vergego.ai/concepts/under-the-hood/) —— 用户能看到哪些标签和下架

Source: https://x-algorithm.vergego.ai/concepts/enforcement/index.mdx
