这一页回答什么
scarecrow/、botmaker/、botmaker-rules/三个目录各自负责什么,怎样配合。- botmaker 规则语言的结构:事件、条件、动作、过期时间。
- 编译器和运行时怎样执行一条规则,出错时怎样处理。
- 已公开的规则文件给哪些帖子和账号打了什么标签,阈值和豁免条件是什么。
- 哪些规则没有公开。
标签的读取方和效果见 可见性过滤。
核心结论
- scarecrow 是事件驱动的打标签服务。 它把 botmaker 作为规则引擎嵌入,并从
botmaker-rules/scarecrow/加载规则(上游 README Labeling Path 第 2 段;scarecrow/ScarecrowRuntime.scala:37-46)。 - 一条规则的含义是:某事件发生时,如果条件成立,就执行动作。 规则文件含
id、event、condition、action、expiry、isActive字段(示例:botmaker-rules/scarecrow/bot/GroxTweetProcessor.bot:1-39)。 - 条件为真时,运行时记为 VIOLATED 并执行动作;条件抛出异常时,运行时记为 ABORTED,不执行动作(
botmaker/src/scala/com/twitter/botmaker/rule/RuleEvaluator.scala:120-171)。 - 公开的规则普遍豁免三类账号: 高 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)。 - 很多标签带过期时间。 常见值是 7 天(
OneWeekInSecs)和 14 天。 - 部分规则没有公开。 上游 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 个) |
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 回复垃圾分规则):
# 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 裁定 → 帖子标签。媒体模型见 媒体模型。
成人内容账号标签的门槛
NsfwTweetMediaProcessor 不直接给账号打标签。它调用派生特征 ApplyNsfwUserLabel,按以下步骤执行:
- 把这条帖子记入按用户分桶的 HyperLogLog 计数(一种近似去重计数结构),窗口为 1 天(
derived-feature/ApplyNsfwUserLabel.df:15-38)。 - 检查一天内的同类帖子数。数量 > 2(即至少 3 条)时才继续(
ApplyNsfwUserLabel.df:38)。 - 对同一用户的同一标签,1 天内只处理一次(
ApplyNsfwUserLabel.df:41-44)。 - 调用
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)。
- 不打标签的情况:过去 90 天内人工移除过该用户的 NSFW 标签;或用户是高 PageRank 账号且成人内容粉丝分 < 0.1;或用户是灰标、金标、跳过名单账号。其中高 PageRank、灰标、金标、跳过名单账号每周最多送一次人工审核(
设计决策
| 决策 | 理由 |
|---|---|
| 规则与服务分离,规则可单独上线并带过期时间 | 应对新型滥用时不必发版;过期字段防止临时规则长期残留 |
| 条件异常按“未命中”处理 | 数据源故障时宁可漏标,也不误标 |
| 大号、政府号、跳过名单普遍豁免 | 减少对高影响力账号的误判;高风险情况改为送人工审核 |
| 标签多带 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 / FAILEDscarecrow/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_REPLYbotmaker-rules/scarecrow/bot/PinnedLowQualityOrBadUrl.bot:1-42—— 置顶坏链接 → 账号标签