---
title: "打标签规则（scarecrow 与 botmaker）"
description: "scarecrow 在事件发生时用 botmaker 规则给帖子和账号打标签；本页列出已公开规则的阈值与豁免条件"
---

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

# 打标签规则（scarecrow 与 botmaker）

## 这一页回答什么

- `scarecrow/`、`botmaker/`、`botmaker-rules/` 三个目录各自负责什么，怎样配合。
- botmaker 规则语言的结构：事件、条件、动作、过期时间。
- 编译器和运行时怎样执行一条规则，出错时怎样处理。
- 已公开的规则文件给哪些帖子和账号打了什么标签，阈值和豁免条件是什么。
- 哪些规则没有公开。

标签的读取方和效果见 [可见性过滤](https://x-algorithm.vergego.ai/concepts/visibility-filtering/)。

## 核心结论

1. **scarecrow 是事件驱动的打标签服务。** 它把 botmaker 作为规则引擎嵌入，并从 `botmaker-rules/scarecrow/` 加载规则（上游 README Labeling Path 第 2 段；`scarecrow/ScarecrowRuntime.scala:37-46`）。
2. **一条规则的含义是：某事件发生时，如果条件成立，就执行动作。** 规则文件含 `id`、`event`、`condition`、`action`、`expiry`、`isActive` 字段（示例：`botmaker-rules/scarecrow/bot/GroxTweetProcessor.bot:1-39`）。
3. **条件为真时，运行时记为 VIOLATED 并执行动作；条件抛出异常时，运行时记为 ABORTED，不执行动作**（`botmaker/src/scala/com/twitter/botmaker/rule/RuleEvaluator.scala:120-171`）。
4. **公开的规则普遍豁免三类账号：** 高 PageRank 账号、政府认证（灰标）账号、临时跳过名单（`AutoExpiringTempSkipList`）中的账号。高 PageRank 账号指 user-cred-v2 分数 ≥ 54 或带 `PREDICTED_HIGH_PAGE_RANK` 标签的账号；没有分数时，规则改用粉丝数 > 25000 判断（`botmaker-rules/scarecrow/derived-feature/IsHighPageRankUser.df:3-18`、`HighPageRankThreshold.df:1-2`）。
5. **很多标签带过期时间。** 常见值是 7 天（`OneWeekInSecs`）和 14 天。
6. **部分规则没有公开。** 上游 README 写明 “Some botmaker rules” 不在仓库中，理由是降低被规避的风险（上游 README “What's not in this repo?” 一节）。`botmaker-rules/scarecrow/bot/` 中只有 20 个规则文件。

## 三个目录的分工

| 目录 | 内容 | 关键文件 |
|---|---|---|
| `botmaker/` | 规则语言的语法、编译器、运行时 | `src/antlr/com/twitter/botmaker/antlr/BotMaker.g`、`src/java/com/twitter/botmaker/compiler/Compiler.java`、`src/scala/com/twitter/botmaker/rule/RuleEvaluator.scala` |
| `scarecrow/` | 嵌入 botmaker 的服务，提供数据源和动作函数注册表 | `ScarecrowBotMaker.scala`、`ScarecrowRuntime.scala`、`legacy/*Registry.scala` |
| `botmaker-rules/scarecrow/` | 规则（`.bot`）与派生特征（`.df`，可复用的表达式） | `bot/`（20 个）、`derived-feature/`（53 个） |

```mermaid
flowchart LR
    EV["事件: tweet / url_event / follow / media_update / health_side_effect 等"] --> SC["scarecrow"]
    SC --> BM["botmaker 运行时"]
    RULES["botmaker-rules/scarecrow/*.bot"] --> BM
    DF["derived-feature/*.df"] --> BM
    BM -- "条件为真" --> ACT["动作: TweetRtfApplyLabel / SetUserLabel / 创建人工审核报告"]
    ACT --> STORE["标签存储"]
    STORE --> VF["visibility-filtering"]
```

## 规则语言

ANTLR 文法定义了规则语言的语法（`botmaker/src/antlr/com/twitter/botmaker/antlr/BotMaker.g:83-153`）：

- 布尔：`TRUE`、`FALSE`、`&&`、`||`、`!`。小写的 `true`/`false`/`null` 是保留的禁用词（`BotMaker.g:84-86`）。
- 变量以冒号开头，如 `:scores`（`BotMaker.g:96`）。
- 符号用反引号，如 `` `AutoExpiringTempSkipList` ``（`BotMaker.g:92`）。
- 正则匹配用 `MATCHES`（`BotMaker.g:137-138`）。
- 字段访问用 `.`，例如 `GetUser(:userId).safety.verified_type`（`BotMaker.g:97`、`152-153`）。

规则文件示例（Grox 回复垃圾分规则）：

```yaml
# botmaker-rules/scarecrow/bot/GroxTweetProcessor.bot:1-30
id: '25026'
event: health_side_effect
condition: |
  Exists(userId) && Exists(spamScore) && Exists(postId) &&
  healthSideEffectSubEvent == "groxScore" &&
  spamScore >= 0.97 &&
  !IsTestUser(userId)
action: |
  ...
  if (!:replyFromConvAuthor && !:highPageRankOrAutoExpiringTempSkipListOrGrayVerified) {
    SetTweetRtfApplyLabelWithExpirationMs(
      "RISKY_HIGH_VIZ_REPLY", postId, CurrentTimeMs() + (OneDayInMillis * 14))
  }
```

（示例为节选，省略了日志语句。）

## 编译与执行

- 编译器把规则编译成两棵 AST（抽象语法树）：条件树 `booleanAstRoot` 与动作树 `actionAstRoot`（`botmaker/src/scala/com/twitter/botmaker/rule/RuleEvaluator.scala:45-49`）。
- 编译失败的规则被换成 `FakeEvaluator`。它的结果固定为 ABORTED，不执行动作（`RuleEvaluator.scala:74-104`）。
- 条件求值的结果如下（`RuleEvaluator.scala:120-158`）：
  - `TRUE` → `VIOLATED`，执行动作；
  - `FALSE` → `UNVIOLATED`；
  - 异常 → `ABORTED` 或 `ABORTED_IGNORED`；普通异常按“条件为假”处理。
- 动作阶段抛出的异常记为 `FAILED`（`RuleEvaluator.scala:172-199`）。
- 每条规则都有超时；超时后，运行时取消该规则的上下文（`RuleEvaluator.scala:51-67`）。
- 规则可以配置动作限速（`botmaker/src/scala/com/twitter/botmaker/rule/ActionRateLimiter.scala:8-18`）。开源的默认实现不限速（`ActionRateLimiter.scala:20-31`）。

## 已公开规则一览

下表只列出与标签直接相关的规则。阈值均为开源默认值。

| 规则 id / 文件 | 事件 | 条件要点 | 动作 | 过期 | 锚点 |
|---|---|---|---|---|---|
| 3226 `Tweet_Spam_High_Recall_RTF_All_Bad_URL_Sources` | url_event | 链接跳转链判定为 `*BAD` | verdict 匹配 `BAD` 打帖子标签 `SPAM`，否则 `SPAM_HIGH_RECALL`（`MATCHES` 是否全匹配，源码未说明） | 无 | `bot/Tweet_Spam_High_Recall_RTF_All_Bad_URL_Sources.bot:1-46` |
| 6754 `LQ_Tweets_With_LQ_URL_Verdict_At_Mention_To_NonFollower_v2` | url_event | 跳转链中任一环节为 `LOW_QUALITY`，终点不是 GOOD/WHITELIST | 帖子标签 `SPAM_HIGH_RECALL` | 无 | `bot/LQ_Tweets_With_LQ_URL_Verdict_At_Mention_To_NonFollower_v2.bot:1-19` |
| 20790 `rtf_tweets_on_unsafe_verdict` | url_reputation_change | 链接信誉变为 UNSAFE（PUT）或撤销（DELETE） | 回溯含该链接的帖子，加/去 `SEARCH_BLACKLIST`、`DO_NOT_AMPLIFY`、`UNSAFE_URL`、`MALICIOUS_URL` | 无 | `bot/rtf_tweets_on_unsafe_verdict.bot:1-35` |
| 20719 `PinnedLowQualityOrBadUrl` | user_modification | 新置顶帖含 BAD 或 LOW_QUALITY 链接 | 账号标签 `SPAM_HIGH_RECALL` | 7 天 | `bot/PinnedLowQualityOrBadUrl.bot:1-42` |
| 20732 `FollowFromActorWithPinnedLowQualityOrBadUrl` | follow | 关注他人的账号，其置顶帖含 BAD 或 LOW_QUALITY 链接 | 账号标签 `SPAM_HIGH_RECALL` | 7 天 | `bot/FollowFromActorWithPinnedLowQualityOrBadUrl.bot:1-47` |
| 21711 `BBQDuplicateTextProd` | bqbm_scheduled_queries | BigQuery 重复文本聚类任务命中 | 帖子标签 `COPYPASTA_SPAM`；每分钟上限 100000 次 | 无 | `bot/BBQDuplicateTextProd.bot:1-74` |
| 25026 `GroxTweetProcessor` | health_side_effect | Grox `spamScore >= 0.97`，且回复者不是会话发起人 | 帖子标签 `RISKY_HIGH_VIZ_REPLY` | 14 天 | `bot/GroxTweetProcessor.bot:1-37` |
| 20998 `AgathaSpamProduction__ApplySearchTopTweetLabel` | tweet | Agatha `AllSpamReportsPerFav > 0.9975` 或 `SpamSuspended > 0.98` | 帖子标签 `AGATHA_SPAM` | 7 天 | `bot/AgathaSpamProduction__ApplySearchTopTweetLabel.bot:1-31` |
| 21278 `ProductionAgatha__FilterOutOrganicNotifications` | new_send_notification_write | Agatha `SpamSuspended > 0.99`，或两种举报比分数 > 0.999 | 账号标签 `AGATHA_SPAM_TOP_USER`；6 天内不重复处理 | 7 天 | `bot/ProductionAgatha__FilterOutOrganicNotifications.bot:1-36` |
| 22418 `NsfwTweetMediaProcessor` | health_side_effect | 帖子媒体被判成人内容（类别 `3`；`3` 且分数 > 0.99；或 `4`） | 尝试给作者打账号标签 `NSFW_HIGH_PRECISION` / `NSFW_NEAR_PERFECT` / `NSFW_HIGH_RECALL` | 见下文 | `bot/NsfwTweetMediaProcessor.bot:1-40` |
| 22358 `nsfw_user_write_user_label` | health_side_effect | 子事件 `nsfw_user` | 账号标签 `NSFW_HIGH_PRECISION` 与 `NSFW_HIGH_RECALL` | 7 天 | `bot/nsfw_user_write_user_label.bot:1-11` |
| 20616 `ViolenceAndGore_ImageModel_MTT` | media_update | 暴力血腥模型：帖子图片精度 > 0.6；视频原始分 ≥ 0.95；头像/横幅 ≥ 0.85 | 帖子标签 `GORE_AND_VIOLENCE_HIGH_PRECISION`；头像/横幅只送人工审核 | 无 | `bot/ViolenceAndGore_ImageModel_MTT.bot:9-102` |

`bot/` 下还有 NSFW 卡片图片、Grok 生成图片、Grok 分享等规则（如 `NSFW_Card_Image_URL_to_Tweet_Verdict.bot`、`NSFW_Grok_Share.bot`）。它们的模式相同：模型或 URL 裁定 → 帖子标签。媒体模型见 [媒体模型](https://x-algorithm.vergego.ai/concepts/media-models/)。

## 成人内容账号标签的门槛

`NsfwTweetMediaProcessor` 不直接给账号打标签。它调用派生特征 `ApplyNsfwUserLabel`，按以下步骤执行：

1. 把这条帖子记入按用户分桶的 HyperLogLog 计数（一种近似去重计数结构），窗口为 1 天（`derived-feature/ApplyNsfwUserLabel.df:15-38`）。
2. 检查一天内的同类帖子数。数量 > 2（即至少 3 条）时才继续（`ApplyNsfwUserLabel.df:38`）。
3. 对同一用户的同一标签，1 天内只处理一次（`ApplyNsfwUserLabel.df:41-44`）。
4. 调用 `ApplyNsfwUserLabelOrCreateReport`（`derived-feature/ApplyNsfwUserLabelOrCreateReport.df:1-93`），按三种情况分支：
   - 不打标签的情况：过去 90 天内人工移除过该用户的 NSFW 标签；或用户是高 PageRank 账号且成人内容粉丝分 < 0.1；或用户是灰标、金标、跳过名单账号。其中高 PageRank、灰标、金标、跳过名单账号每周最多送一次人工审核（`:5-51`）。
   - 普通账号：打标签，默认 7 天（`:2`、`:52-64`）。
   - 其余情况（例如高 PageRank 账号但不满足送审条件），且不是 `nsfw_admin`：打标签 3 天（`:65-72`）。

## 设计决策

| 决策 | 理由 |
|---|---|
| 规则与服务分离，规则可单独上线并带过期时间 | 应对新型滥用时不必发版；过期字段防止临时规则长期残留 |
| 条件异常按“未命中”处理 | 数据源故障时宁可漏标，也不误标 |
| 大号、政府号、跳过名单普遍豁免 | 减少对高影响力账号的误判；高风险情况改为送人工审核 |
| 标签多带 TTL（存活时间） | 自动化判断有误差；标签到期自动消失，不需要人工清理 |
| 部分规则不公开 | 公开阈值等于告诉对手规避边界 |

## 源码锚点

- `botmaker/src/antlr/com/twitter/botmaker/antlr/BotMaker.g:83-153` —— 词法与语法
- `botmaker/src/scala/com/twitter/botmaker/rule/RuleEvaluator.scala:120-199` —— VIOLATED / ABORTED / FAILED
- `scarecrow/ScarecrowRuntime.scala:37-46` —— 运行时组装
- `botmaker-rules/scarecrow/derived-feature/IsHighPageRankUser.df:3-27` —— 高 PageRank 豁免
- `botmaker-rules/scarecrow/derived-feature/IsUserGrayVerified.df:1-11` —— 政府认证判断
- `botmaker-rules/scarecrow/bot/GroxTweetProcessor.bot:1-37` —— `RISKY_HIGH_VIZ_REPLY`
- `botmaker-rules/scarecrow/bot/PinnedLowQualityOrBadUrl.bot:1-42` —— 置顶坏链接 → 账号标签

## 相关页面

- [可见性过滤](https://x-algorithm.vergego.ai/concepts/visibility-filtering/) —— 标签在请求路径上的效果
- [账号级信号](https://x-algorithm.vergego.ai/concepts/account-signals/) —— Agatha 分数与 user-cred-v2 分数的来源
- [处置与标签聚合](https://x-algorithm.vergego.ai/concepts/enforcement/) —— 基于模型分数的另一条打标签路径
- [Grox 分类器](https://x-algorithm.vergego.ai/concepts/grox-classifiers/) —— `spamScore` 的来源
- [媒体模型](https://x-algorithm.vergego.ai/concepts/media-models/) —— 成人与暴力媒体判定
- [Under the Hood 透明度报告](https://x-algorithm.vergego.ai/concepts/under-the-hood/) —— 用户能看到哪些标签

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