最新 X.com 推荐算法代码解读和测试:「第二篇只剩 62.5%」是被读错的
先交代一句篇幅:这篇正文比较长,全文约 25 万字,是把代码逐项核对完的完整研究版。觉得太长,可以先看导读版(我在 X 上发的 13 条实操版:https://x.com/alexlee20122022/status/2116710008553447863);或者直接用我已经做好的 skill:https://github.com/alexliyu7352/for-you-skills ——手册里的结论已经做成了能直接调用的技能,不用自己逐条对照。
先问一个大家每天都在踩的坑:一条帖子放四张图,第一张是你精心设计的封面(比如写着“这次测试的三个发现”),第四张图才是真正的测试结果表格。你觉得推荐系统的 AI 会先读到哪张图?
翻开 X 公开算法库(xai-org/x-algorithm)里 V8.2 的内容理解代码(renderer_v82.py),负责挑图的 _collect_post_media 函数给出了一个非常干脆的答案:从第一张图开始挨个检查,只要遇到第一张有可用内容的图片,立刻 return(直接返回收工,根本不往下读了)。也就是说,当四张图都能正常打开时,这个分支拿走的只有你的第一张封面图。如果封面图上只写了一句空洞的标题“这次测试的三个发现”,那第四张图里真正核心的测试数据,在这一次图片选取里压根不会跟着送进去。1
顺着代码继续往下查发文频率,又会撞见另一句流传极广的运营口诀:“一天发第二篇只剩 62.5% 权重,每天最多发两三篇,隔四小时才能恢复权重。”在代码里确实能算出 0.625 这个数字,但程序根本没有数“你今天一共发了几篇”。它真正数的是:在给某位读者单次刷新抓出来的同一批候选帖子里,同一个作者的帖子排到了第几篇。一旦把“单次候选池里的排序位置”错当成“每日发文额度”,后面推出来的“每天最多发两三篇长文”、“两篇之间必须隔四小时恢复权重”,就统统失去了代码依据。2 3 4
看懂这两件事,你手头的发文动作马上就不一样了:第一件事提醒我们发多图帖时必须盯紧首图的信息量;第二件事帮我们卸下包袱,不用再被一个读错的数字绑架发帖排程。再顺着源码往下翻,你还会看到一连串直接影响日常运营的真相:读者的“收藏(Bookmark)”是怎么在暗中帮你在后续推荐里捞人的?为什么在旧帖底下直接补一条重要更正,老读者在首页反而刷不到?自己直接点“转发(Repost)”老帖子会撞上哪几道拦截墙?以及当账号曝光突然腰斩时,官方在代码里留了哪个后台记录可以让我们自己查清原因?
本文完整核对了 X 的 For You(为你推荐)公开推荐代码,原始基准固定在提交 5ed7963,并回溯核对了十月份的 20 个历史参数快照,一直追到最新公开提交 606b254(修订于 2026 年 10 月 29 日)。源码能够证明系统的处理条件与边界;而文中的写作和运营实操建议,则是我根据这些代码事实作出的推导判断。文中的局部算术例子用来帮你直观算清公式逻辑,不代表真实账号的线上增长实验;凡是公开代码还没披露、需要线上日志或实验数据才能确认的边界条件,我都毫无保留地集中列在了文末的 49 个待确认问题清单里。5
1 网上流传的说法,哪些有依据
在逐条核对传言之前,我们先用大白话把 X 上的三种常见发文格式分清楚,免得后面张冠李戴:
- 长 Post(Longer Post):本质上还是一条普通帖子,只是开通会员后字数上限放宽到了 25,000 个字符;
- Article(专栏文章):是用专门的独立文章编辑器发布的专栏,支持多级标题、内嵌图片视频和引用帖子,发完会收进你个人主页专属的 Articles 栏目;
- 串文(Thread):是一条接一条自己回复自己、串联起来的帖子组合(本文统一叫“串文”,后面说“三条串文”,指的就是同一条 Thread 里首尾相连的三条帖子)。
这三种格式的底层数据结构、内容读取方式和前端展示逻辑完全不同,千万不能拿同一套“发几篇”的规矩去硬套。6 如果你正纠结手头写好的一篇深度长文到底该发成“长 Post”还是“Article”,可以先跳去看后面的“同一篇长文,该发长 Post 还是 Article”章节——我在那里把正文截断、阅读计时、64 赞拉取图片门槛(is_high_fav:Article 的正文图片要达到这个热度才会被完整拉取,后文细说)、V5 与 V8.2 阅读器差异以及可见性规则全部拆开核对了一遍,并给出了可以直接照着做的发布组合。
网上关于 X 算法的爆款攻略,大多源自 Hootsuite、X Algorithm Playbook、Gridlok、SocialPilot 和 Bangerkit 等第三方分析文章。我们先用两张总表把这些流传最广的说法和源码核对结论摆在一起对个账,随后再把支撑它们的公式、代码和边界条件一层层剥开讲透。7 8 9 3 4
| 公开文章中的说法 | 对照代码后的判断 |
|---|---|
| 每天发 2–3 则。 Hootsuite | 原文只是针对一般社交帖子的日常运营建议,根本没有写“最多”和“长文”这两个限制词。公开推荐路径也证实不了“每天最多发两三篇长文”的算法上限。 |
| 一天第二篇只剩 62.5%,最多三篇,间隔四小时。 X Algorithm Playbook | 把“同一次刷新候选池里的同作者排序位置”,错当成了“全天发文篇数”。源码公式只管同池竞争,推不出每天三篇或隔四小时恢复的排程。 |
| 长文之间搭配短帖。 常见运营建议 | 官方确实支持用短预告、文章摘录来帮长文导流分发;但公开的同作者衰减计数器只认作者 ID,不会因为中间插了短帖就清零重置。这两种理由必须分清。 |
| 长文拆成三条 thread。 常见运营建议 | 有前端展示依据:官方说明与对话组装代码(convo_marshaller.rs)都涉及“三条”这个结构。但打分代码里没有任何给三条串文额外加分、或给第四条扣分的公式。 |
关于互动权重、外链惩罚和小账号冷启动,网上同样流传着好几条让人真假难辨的口诀:7 9 10
| 公开文章中的说法 | 对照代码后的判断 |
|---|---|
| 模型预测读者会不会互动,再加权排序。 Bangerkit | 完全成立。 预测概率是针对“此时此刻正在刷首页的这位具体读者”实时算出来的,根本不是一张全站通用的“互动计件积分表”。 |
| 读者回复后,作者再回复,一次来回值 150 个赞。 Gridlok | 算错了世代,也搞错了概念。 不仅错拿了 2023 年 4 月早就淘汰的旧版权重(75 ÷ 0.5 = 150),还把“乘以预测概率”误当成了“乘以实际互动次数”。 |
| 外链固定减少 30–50% 曝光,放首条回复就能避开。 Gridlok | 假的。 查遍公开计分路径都没有“带外链扣 30–50%”的公式;而且最新 v2 外链审查机器人已经删掉了“排除回复”的豁免,塞首条评论照查不误。 |
| 小作者的新帖子有探索机会,涉及两小时、五万粉和 200 次 Home 曝光。 Bangerkit | 主要条件确有代码依据(author_cold_start.rs),但必须同时满足多项资格与抽样挑选步骤;且 200 次是内部 Home 曝光上限门槛,不是系统保底白送 200 个观众。 |
| Premium 在圈内/圈外推荐有 4 倍/2 倍算法加成。 Gridlok | 目前核查的 For You 公开路径证实不了这组固定倍数加成。官方帮助页确实写明订阅会员享有“回复排序优先”,但那不是主时间线 4 倍/2 倍乘数的证据。 |
1.1 十月更新里,还有哪些话被说过了头
2026 年 10 月的一系列代码更新,确实重点改造了“停留阅读时间预测(CREAD)”和“把好文章读到底的召回训练(ld 分支,ld=Long Dwell,深度阅读停留)”。但网上的二传手总结贴,习惯把模型训练目标、入库索引条件、排序权重系数和最终拿到的曝光量混为一谈。我们把这 12 条十月热门传言逐一拆回各自对应的代码模块,真相是这样的:
| 流传说法 | 核对结果与需要保留的条件 |
|---|---|
| 十月八日改善停留预测 十三日增加阅读召回 | 有官方 README 更新说明与 Git 提交历史支撑;但 README 公告是后来补记的,且“预测改善了多少百分比”没有公开可复现的线上评测数据。 |
| 点赞系数为 0.66 停留系数增加 50% | 同一个参数文件(home-mixer/params/param.rs)的历史快照完全支持;但这指的是乘在预测值上的公开权重系数(0.004 升至 0.006),不是读者每看一次的记账入账分,更不等于曝光同比暴涨 50%。 |
| 读完的文章现在能赢两次 | 阅读停留信号确实同时参与了“第一步召回捞候选(ld 分支)”和“第二步打分排序(停留权重)”;但“完整读到末尾(100% 完读)”的前端事件定义并未公开,也没有曝光翻倍的承诺。 |
| 两小时 两百次观看 五万粉以下的新帖有加推 | 确有小账号冷启动机制(冷启动=新帖刚发出、系统还不认识它,先给一小批曝光试试水温的阶段);但“发布 ≤ 2 小时”与“Home 曝光 < 200 次”必须同时满足,外加原创、非垫底 3%、Thompson 抽样(一种边试边学的随机抽样挑选法,第 21 章会用“摇号”讲透)等条件,且看的是内部 view_count_on_home 而非前台总观看数。 |
| 新帖不再先被截掉 | 10 月 22 日启用的 FairShareRankingFilter 确实改为按候选来源比例分配 2,800 个打分名额;但它保护的是“冷启动等来源渠道按比例进场”,不是给所有新帖发免死金牌,渠道内部排在后面的帖子仍会被截掉。 |
| 只有原创能触及陌生人 | 普通首页的圈外过滤器(OONRetweetReplyFilter)确实会拦截未关注作者的普通转发;但如果同行大 V 转发了你的帖,对大 V 的粉丝来说这属于“圈内候选”,依然能帮你触达不认识你的陌生读者。 |
| 第一个与第三十二个赞开启新流量池 | 1fav 和 32fav 索引及二次幂更新门槛确实存在;但写入索引、更新、召回与最终曝光是四码事,且普通帖 32fav_1day 在公开 For You 代码树里还没找到消费端在读它。 |
| 收藏零分 视频观看零分 | 主打分表里某一项直接系数为 0,绝不代表整套系统无视它:收藏(Bookmark)会作为 SimClusters 相似召回种子和沉浸式(点开全屏看视频、看图的那种浏览方式)召回训练正例;视频也有打开权重、停留预测及专属视频索引流程。 |
| 互追回复值 20 第二篇只剩 62% | 两个数字都有确切公式来源:前者(5 + 15 = 20)只作用于非回复、非转发原创帖在互关读者面前的回复预测;后者(0.625)按单次候选池内的同作者排序位置计算,绝不是每日发文配额。 |
| 视频超过十秒才进名单 | 三个核心沉浸式视频索引(1fav_video、video、nsfw_video)确实要求时长严格大于 10,000 毫秒(> 10 秒);但 5 秒短视频依然能进普通帖的 1fav 索引,不能说短视频全站没资格。 |
| 任一账号标签都会结束陌生人触及 | 指定的账号级安全标签(如 SPAM_HIGH_RECALL、NSFW_HIGH_PRECISION)确实会在 HomeRecommendations 拦截陌生人推荐;但必须看清标签种类、受众范围、检查入口和 7 天有效期,不能一概而论。 |
| 两天后 For You 永远不再显示 | 普通候选流程的 AgeFilter 确实只保留 ≤ 48 小时的候选;但它是按当前候选自己的 tweet_id 算年龄的,近期转发拥有全新的 tweet_id,不能只拿原帖年龄断定全站彻底失效。 |
2 “今天更新了算法”,究竟是哪一天、哪一项更新
平时刷 X 看到海外博主惊呼“X 今天(today)又改算法了!”,这句话可能对应三种完全不同的情况:可能是官方刚刚在 README 补写了一段更新说明,可能是公开代码库刚刚合并了一次新的 Git 提交(commit),也可能是线上某个灰度实验(灰度=先放给一小部分用户试用的实验)改了开关。要想不被带节奏,第一步就是把“today”对应到具体的提交时间和代码行上。本文核对用到的两份核心代码快照,精确时间如下:11
| 公开提交 | UTC 时间 | 洛杉矶时间(PDT,UTC−7) | 阅读时的用途 |
|---|---|---|---|
| 5ed796374ea48ee26058aab66ab10c266bea2bef | 2026-10-28 02:49:03 | 2026-10-27 19:49:03 | 本文主报告固定的主要代码核对基准 |
| 606b254b45be798bfaecfa8c23f5a9c51bc8000c | 2026-10-29 02:57:55 | 2026-10-28 19:57:55 | 核对最新一份公开快照新增或修改了哪些参数与开关 |
来源 11
你看,606b254 这笔提交在 UTC 世界标准时间已经是 10 月 29 日凌晨,但在美国加州洛杉矶当地时间还是 10 月 28 日晚上 7 点 57 分。所以判断别人帖子里的“today”准不准,得先看发帖人所在的时区和他指的具体改动。更重要的是:Git 提交时间只能证明这份代码快照是什么时候对外公开的,不能单独证明某项线上实验在那一秒钟就已经覆盖了全站所有用户。11 12
把整个 10 月份官方公告与公开快照里的关键变动按时间顺序排开,哪些是实打实改了代码参数的,哪些是过度引申的,一张表就能看清:
| 文件日期或公开快照 | 变更所在层级 | 能核对到的内容 | 不能直接推成的结论 |
|---|---|---|---|
| 官方更新说明:2026-10-08 | 排序模型对停留时间的预测 | README 指出停留时间估计改善;从代码里有正式名字的配置(具名配置)与损失函数,可看到 CREAD 30 门槛对数切分方法 | 每篇长文都获得固定加分,或全站长文曝光增加某个固定百分比 |
| 官方更新说明及公开快照:2026-10-13 | 召回训练与部分 Home Mixer 系数 | 双塔召回新增 ld 分支(拿停留事件作正例);同一路径连续停留系数由 0.004 升到 0.006 | 所有“看完”事件都等于 100% 读到全文末尾,或 0.006 是每次实际阅读的记账入账分 |
| 公开快照:2026-10-14 | Home Mixer 默认系数 | 点赞 Favorite 由 0.6 升到 0.66;不感兴趣 Not interested 由 -47.52 变成 -52.272 | 点赞已经成为所有互动里权重最大的系数(其实远小于复制链接的 20 和回复的 5) |
| 公开快照:2026-10-21/22 | 模型打分前的候选初筛 | FairShare 过滤器在 10/21 先写进代码但默认关闭;10/22 快照将启用开关改为 true | 所有新帖都绝对不会被删,或每篇新帖都有保底流量池 |
| 公开快照:2026-10-28 UTC | 页面记录与可选排序路径 | 5ed7963 增加 page logging、page decode 与 page RL exploration 三个公开参数,默认启用开关全是 false | 只要代码文件里出现了新函数,全站所有读者当天就已经用上了它 |
| 公开快照:2026-10-29 UTC | 记录、视频 Carousel 与具名训练配置 | 606b254 将 page logging 改为 true;新增 open × immersive dwell 乘项及 immersive_page_rl_cread 配置 | 开启日志记录等于排序结果已改变,或新增视频项已经给所有视频发了流量红利 |
对比 10 月 28 日的 5ed7963 和 10 月 29 日的 606b254 两份快照可以确认:我们最关心的点赞(Favorite)、回复(Reply)、复制链接(Copy link)、连续停留(ContDwellTime)和各项负向惩罚的 Home Mixer 默认权重系数,在这两天之间完全没有变化。同一时期变动的是模型配置、日志开关和部分规则重构。因此,说“这组核心打分系数没变”是准确的;但如果说“整套算法一字没改”就不对了。15 17
2.1 新的视频公式已经写进代码,默认开关却还没打开
举个最典型的例子:在 10 月 29 日(606b254)的视频轮播栏(Carousel)计分代码 video_carousel.rs 里,程序员确实新加了一项乘法公式——用“视频被打开的预测概率(video_open_score)”乘以“沉浸式路径预测的停留时间(immersive_dwell_time)”,再乘以一个新系数 VideoCarouselOpenTimesImmersiveDwellWeight。
听起来像是视频迎来了史诗级加强对吧?但只要你去翻一下配套的参数文件 param.rs,就会发现:在公开默认值里,这个新系数的数值是 0.0,而且整个视频轮播栏的总开关 EnableVideoCarousel 依然是 false(关闭)! 这说明代码只是提前把公式框架搭好了,绝不能看到代码更新就宣称“10 月 29 日起所有视频都按观看时长拿到了新优待”。17
# 公式重述,并非逐字源码
carousel_score =
video_open_weight * video_open_score
+ immersive_vqv_weight * immersive_vqv_score
+ open_times_immersive_dwell_weight
* video_open_score * immersive_dwell_time
# 606b254 公开默认:
# EnableVideoCarousel = false
# VideoCarouselOpenTimesImmersiveDwellWeight = 0.0
来源:17
同一次提交还新增了一份叫 immersive_page_rl_cread 的强化学习训练配置。我们能从源码里查清楚它用了哪些训练目标,但不能光凭配置文件写进了仓库,就断定线上所有用户都已经切换到了这个新模型权重(checkpoint)——那还需要线上部署记录、流量分桶配置和实验数据的支持。17
3 一条帖子要经过哪些步骤,才会出现在首页
很多创作者之所以被各种算法传言绕晕,是因为脑子里把推荐算法想象成了“通关打怪”:以为自己发一条帖子,系统就给帖子建个积分卡,有人点个赞加 1 分、转推加 2 分,攒够多少分就升入下一个流量池。真代码完全不是这么跑的!
真实的推荐发生在某位读者下拉刷新 For You 首页的那一次请求里。为了让你彻底看懂后面的每一条代码规则,我们先把这一次请求里发生的事拆成四个核心步骤:5 18 19 20
- 第一步:抓候选(进临时篮子 / 召回 Retrieval)
当读者张三下拉刷新首页时,系统会同时派出好几个“采购员(候选来源 Sources)”去不同的仓库里帮张三抓可能感兴趣的帖子——比如派
Thunder采购员去抓“张三关注的人刚发的帖子(圈内 In-Network)”,派Phoenix采购员去抓“虽然张三没关注、但根据张三近期阅读历史 AI 觉得他会感兴趣的陌生人帖子(圈外 Out-Of-Network)”,派SimClusters去抓“同好社区热议或与张三收藏相似的帖子”。这几个采购员总共会抓出几千篇帖子,统统倒进一个**专门为张三这一次刷新准备的“临时候选池(临时篮子)”**里。 - 第二步:初筛与资格过滤(Pre-scoring Filters)
几千篇帖子里有很多不能直接端上桌的:比如张三以前已经刷到过的帖子(
previously_seen_posts_filter.rs)、超过 48 小时的旧候选(age_filter.rs)、张三已经拉黑或静音的作者(author_socialgraph_filter.rs),都会在这里被挑出去扔掉;如果剩下的帖子还是太多(超过 2,800 篇),检票员FairShareRankingFilter还会按各个采购员送来的数量比例分配 2,800 张入场券。 - 第三步:算预测分排座次(打分排序 Scoring & Ranking)
进到打分房间的帖子,会由 AI 模型(Phoenix 与 Value Model;Value Model 是价值模型,负责给候选帖估分排序,后文简称 VM Ranker)挨个端详,提前预测(押注):“如果现在把这篇帖子展示给张三看,张三有多大概率会点赞、回复、复制链接、点开细读、或者点不感兴趣?” 把这些预测概率乘上对应的权重系数加总,再套上同作者
0.625多样性衰减、小账号冷启动提拔等调整,算出来的总分就叫排序分数(Ranking Score)。 - 第四步:后置去重、可见性检查与卡片组装(Post-selection & Marshalling)
按分数高低挑出前排胜出者后,系统还会做同一串对话去重(
DedupConversationFilter)、检查安全与可见性标签(Visibility Filtering),最后由界面组装器(如convo_marshaller.rs)把被选中的帖子和它的被引用原文、最多 1 条中间对话祖先、以及穿插的广告组装成你在屏幕上看到的首页信息流。5 18 19 20
你看:同作者 0.625 乘数发生在第三步“打分排序”,三条串文截断发生在第四步“界面卡片组装”,而旧帖底下补新回复被过滤则发生在第二步“已读检查”。脑子里有了这张“临时篮子 → 过滤 → 算预测分 → 组装卡片”的地图,接下来看篇数、串文和补充更新时,你就再也不会搞混它们各自管哪一段了。
4 同作者第二篇乘 0.625,程序到底在数什么
我们先看流传最广的“每天最多发 2–3 篇,第二篇打 6.25 折”。Hootsuite 在 2025 年发布的社交媒体指南里,确实建议商业账号每天发 2 到 3 条帖子。但去查它的英文原稿就会发现,人家说的是一般日常帖子的运营节奏建议,既没有限定为“长文”,更没有说“超过三条会被算法惩罚降权”。把别人的日常运营建议传成“平台的算法硬上限”,纯属传话传歪了。3
另一份常被援引的《X Algorithm Playbook》,在文章前半部分其实解释得很准确:同一个作者的多条内容,如果在**同一次推荐响应(同一个临时篮子)**里碰面,会按分数高低排序、依次打折衰减。可到了文章后半部分的总结表格里,作者却突然把适用范围偷换成了“一天之内发第二篇只剩 62.5% 权重”,并由此推导出了“每天最多发三篇、两篇之间至少隔四小时”。SocialPilot 指南里关于“每日作者发文额度”的说法,也犯了一模一样的错误。4 8
打开 xai-value-model/scoring.rs 源码,里面负责计算“作者多样性乘数(Author Diversity Multiplier)”的核心代码其实只有这一行:2
(1.0 - floor) * decay_factor.powf(exponent) + floor
把 VM Ranker 的公开默认参数 decay_factor = 0.5(衰减率)、floor = 0.25(保底值)代进去,数学公式就是:21
$$ m(k)=0.75\times 0.5^{k}+0.25 $$
这里的指数 $k$ 从 0 开始起算,代表的是:在当前这位读者刚刚刷新出来的那一个临时候选池(临时篮子)里,属于同一个作者(相同 author_id)的帖子按分数从高到低排在第几位!
- 你在这个篮子里分数最高的第 1 篇($k=0$):乘数是 $0.75\times 0.5^0 + 0.25 = \mathbf{1.0}$(完全不打折);
- 你在这个篮子里排在第 2 篇($k=1$):乘数是 $0.75\times 0.5^1 + 0.25 = \mathbf{0.625}$(打 6.25 折);
- 你在这个篮子里排在第 3 篇($k=2$):乘数是 $0.75\times 0.5^2 + 0.25 = \mathbf{0.4375}$(打 4.375 折);
- 再往后排,乘数会一步步逼近最低保底线
0.25。而且因为是按当前篮子里的初步分数从高到低排座次,哪怕你下午刚发的那篇比上午发的那篇更晚,只要下午那篇预测分最高,它照样排在同作者第一位拿1.0满分!2
很多朋友会问:“为什么我的两篇帖子 A1、A2 会同时掉进同一个读者的临时篮子里?这 0.625 又是怎么影响排名的?”
我们不妨拿粉丝张三刷首页的例子算一笔账:假设你上午 10 点发了帖子 A1,中午 12 点又发了帖子 A2。张三今天上午忙工作没看手机,下午 1 点才第一次打开 X 下拉刷新。因为 A1 和 A2 他都没看过,采购员就把你的 A1(假设预测得分为 1.0)和 A2(预测得分为 0.9),连同另一位作者写的 B1(预测得分为 0.8)一起抓进了张三的临时篮子里。只看作者多样性乘数这一步(固定其他处理不变),算分结果如下:
| 候选内容 | 套乘数前的分数 | 作者乘数 | 调整后 |
|---|---|---|---|
| 你的 A1 | 1.0 | 1 | 1.0 |
| 你的 A2 | 0.9 | 0.625 | 0.5625 |
| 别人的 B1 | 0.8 | 1 | 0.8 |
你看:原本你的 A2(0.9 分)比别人的 B1(0.8 分)分更高,但因为在张三的这个临时篮子里,A2 是你的第二篇作品,吃了一记 0.625 的同作者衰减,调整后变成了 0.5625 分,结果被别人的 B1(0.8 分)反超了!这个算例直观地说明了:在同一次推荐请求里,如果你有多篇未读帖子同时进池,它们确实会互相竞争位置(至于 A2 最终在全站少了多少曝光,还要看其他候选帖的分数和后续步骤,不能简单拿 0.625 当作全站总曝光掉了 37.5%)。
但是,最关键的转折来了——换一位读者李四,情况就完全变了!
假设读者李四上午 11 点刷手机时,就已经看过了你的 A1。等李四下午 1 点再次打开 X 刷新首页时,A1 因为已经在李四的“已读名单(seen_ids)”里,在前面第二步就被过滤掉了,压根不会进李四下午 1 点的临时篮子!此时,李四的临时篮子里只有你中午 12 点发的 A2 这一篇——那么在李四这里,A2 就是同作者第 1 篇($k=0$),照样按 1.0 计算(同作者第 1 篇,不打折)!
这段函数每次处理读者的刷新请求时,都会从零新建一张临时的作者计数表(HashMap),输入参数只有候选帖的 author_id 和当前排序分数,代码里根本没有“你今天已经发了几篇”这个全局计数器。2
当然,短时间内密集连发好几篇,确实更容易让还没上线的同一批读者在刷新时把你的多篇帖子同时抓进一个篮子里。另外,如果你去翻代码库,确实能在一个叫 PopularPosts(热门帖召回源,popular_posts.rs)的文件里看到一句限制:“默认从近 24 小时内,每位作者最多选 5 篇”。但请注意:那仅仅是 PopularPosts 这一个单一进货渠道自己的局部挑选上限,而真正挑大梁的关注流(Thunder)和 AI 推荐流(Phoenix)根本没有这个 5 篇限制,绝不能把它当成全站每天只能发 5 篇的规定。22
所以,两篇帖子之间隔几个小时再发,可以作为照顾读者阅读消化节奏的运营安排;但谁要是跟你说“算法规定隔满四小时就能重置冷却计时、恢复权重”,你就让他把计时器的代码交出来——因为 scoring.rs 这段函数既不看表计时,也不会在半夜 12 点归零。我自己的实操原则很简单:如果手头两篇草稿翻来覆去讲的还是同一个观点,那就直接合并成一篇写透;如果下一篇有了全新的测试数据、新问题或新进展,随时写完随时发!光换个标题炒冷饭,也改不了你头顶上的同一个 author_id。2
4.1 两篇长文之间插短帖,能恢复权重吗
运营圈里还有一种常见说法:“连发两篇长文权重会掉,但只要在两篇长文中间穿插发一条短帖,就能把长文的权重洗回来。”
我们得把两件事彻底分开:第一,用短帖给长文做预告或摘录导流,好不好用?好用!第二,中间发一条短帖,能不能在算法里重置同作者 0.625 计数器?完全不能,甚至可能帮倒忙!
先看第一件事:X 官方的 Articles 创作者指南确实推荐“长短搭配”的分发打法——比如长文发布前,先发一条简短的提问或预告预热;长文发布后,把里面的核心结论或精彩片段拆成短帖或串文,挂上链接把读者引回全文。但官方指南里从来没有要求你必须“一长一短交替发”来伺候算法,也没规定每天最多两三篇长文或必须固定写三条串文。6
再看第二件事:代码里的同作者衰减函数只认 author_id,根本不管你发的是两万字长文、还是十个字的短帖!我们还是拿刚才那个临时篮子算一笔明白账——固定其他条件不变,假设你的长文 A1 得分为 1.0,长文 A2 得分为 0.9。现在你在它俩中间插发了一条短帖,而且这条短帖也同时掉进了这位读者的临时篮子里。我们分别算一下“短帖得分高于 A2(比如拿了 0.95 分)”和“短帖得分低于 A2(比如拿了 0.5 分)”两种情况:
| 固定其他条件后 | A2 的 k | A2 乘数 | A2 调整后分数 |
|---|---|---|---|
| 不加短帖 | 1 | 0.625 | 0.5625 |
| 加入短帖,分数 0.95 | 2 | 0.4375 | 0.39375 |
| 加入短帖,分数 0.5 | 1 | 0.625 | 0.5625 |
结果一目了然:
- 如果插进去的短帖表现神勇(
0.95分),排在了长文 A2(0.9分)的前面,那长文 A2 在你名下的排序位置就从第 2 名($k=1$)被挤到了第 3 名($k=2$),乘数直接从0.625暴跌到0.4375,调整后分数只剩0.39375! - 如果短帖分低(
0.5分)排在 A2 后面,或者短帖压根没进这个篮子,那 A2 还是排第 2 名($k=1$),乘数依然是0.625。 不管哪种情况,代码里都绝对没有“遇到一条短帖就把作者计数器清零”的逻辑(当然,表里的分数变化只代表这一步的乘数计算,不直接等同于最终曝光的增减比例)。
拿“怎么跟客户谈报价”这个选题来说:你的长文章里可以放完整的各档方案对照表、标准回复话术和不接单的红线情况;而配套发的短帖,就专门挑出读者最头疼的一个具体场景,比如**“客户开口就说预算不够,报价单里的哪些项目可以先砍掉延后?”**——在短帖里直接把判断标准和一个真实案例写出来,最后再附上长文入口。
等过两天,评论区又有人问出另一个新痛点:“客户痛快接受了报价,但在交付过程中没完没了地追加小修改怎么办?” 这时候就非常值得单独再写一条新帖来回答,因为这是一个全新的具体问题。相反,如果只是为了迷信“长短交替洗权重”,硬凑一条毫无信息量的水贴(比如光喊一句“今天刚发的这篇干货大家一定要看!”),不仅算法里洗不掉半点衰减,读者看了也只会觉得你在刷屏。
4.2 同作者之外,相似内容还可能在另一轮选择中竞争
很多懂一点技术的朋友还会追问一个更深的问题:“听说除了同作者衰减,X 还有一套专门过滤相似内容的 DPP 算法。那我每次发帖前,能不能自己在电脑上用开源大模型把草稿转成向量(Embedding)查个重,或者换几个近义词来躲过查重?”
在 vm-ranker/scoring/dpp_model.rs 和 dpp.rs 里,确实有一套 DPP(Determinantal Point Process,行列式点过程)多样性选择机制。它的作用是在适用的请求里(取决于 DPP 上下文、开关和产品条件),同时结合帖子的预测分数和多模态内容向量表示,从候选池里挑出一组既高分、又题材不撞车的内容组合。85
我根据源码逻辑做过一个简化的数学算例:假设候选池里有三条帖子,初步得分依次是第 1 条 1.0 分、第 2 条 0.99 分、第 3 条 0.8 分。其中第 1 条和第 2 条的内容向量完全重合(讲的是同一件事),而第 3 条的内容向量跟它俩完全正交(讲的是另一个新话题)。当 DPP 要从中挑出两条时,最终胜出的是第 1 条(1.0 分)和第 3 条(0.8 分)!代码会保留被选中帖子的分数,而把没被选中的第 2 条(哪怕它原本有 0.99 的高分)的分数直接置为 0 分。补一句边界:这里说的「置零」,是把它的分数压到 0、排到队尾,不是把帖子从系统里删掉;如果整个池子里正分候选不够填满名额,后面的 top_k_score_selector.rs 还可能把零分候选兜底捞回来。。85
那为什么你没法自己在本地电脑上提前把文章转成向量来查重,也没法靠“换几个近义词”蒙混过关?
因为 X 用来生成帖子语义表示的,并不是你在网上随便下载的某个通用开源文本模型,而是它内部不公开模型权重的 Grox 多模态模型(grox/flows/mm_emb),并且还会把多模态语义 ID 和经过哈希处理(哈希=把 ID 搅成一串固定长度的数字指纹,模型只认指纹不认原名)的作者 ID 组合在一起。更重要的是,多模态大模型提取的是整段文字和图片的深层语义,防的就是“换汤不换药”。连续写同一个领域的话题时,与其费尽心机把同一句结论换十种说法、改几个近义词,不如每一篇都实打实补上不同的测试证据、失败案例或新使用场景——内容真正有了新东西,向量自然就拉开了距离。
5 三条串文的依据,主要在展示方式
为什么国内外那么多运营教程都在异口同声地建议:“写串文(Thread)最好写成 3 条”?
先看官方自己的说法:X 官方帮助中心的《如何创建串文(Create a thread)》页面明确写到,当你刷到已经关注的作者发布的串文时,如果是 2 到 3 条,通常会在时间线上连成一组直接展示出来;一旦达到 4 条及以上,时间线上就会把中间截断折叠,只提供一个“展开整串(Show this thread)”的点击入口。注意,官方这里描述的是“已关注作者在时间线上的常规展示方式”,并不是对所有推荐流结果的绝对承诺。23
再去翻公开算法库,我们在界面组装模块 home-mixer/util/urt/convo_marshaller.rs 里找到了与这个“3 条”严丝合缝对应的硬核代码!代码里定义了一个常量 NUM_INTERMEDIATE_ANCESTORS = 1(最多只保留 1 条中间祖先帖),然后按下面这几行逻辑把帖子拼成首页上的对话卡片:18
const NUM_INTERMEDIATE_ANCESTORS: usize = 1;
let item_ids: Vec<u64> = root
.into_iter()
.chain(intermediates.iter().copied())
.chain(std::iter::once(focal_id))
.collect();
很多不写代码的朋友第一次看到“根帖(root)+ 1 条中间祖先帖(intermediates)+ 当前被选中的候选帖(focal_id)”会一头雾水:“这到底是干什么用的?跟写 3 条串文有什么关系?”
我们把它还原成读者刷手机时的真实画面,你一下就全明白了:
首先,这段代码是在打分排序和筛选全部结束之后才出来干活的,所以打分公式里没有任何给 3 条串文加分、或给第 4 条扣分的规则。18
但是,更容易被所有创作者漏掉的残酷真相是:当你的串文有好几条时,系统最后选出来展示在读者首页上的那条“中奖帖(focal_id)”,不一定是前三条,更可能是最后一两条!
上游的 Thunder 关注流和 Phoenix 回复祖先补齐流程(phoenix_reply_ancestors_hydrator.rs),会给选中的回复帖带上它的“第一条根帖(root)”和“直接回复的上一条父帖(parent)”。假设你发了一条一气呵成的直线串文(1 → 2 → 3 → …),并且最后一条分帖在打分中胜出、被选中要展示到读者首页上。我在本地照着 convo_marshaller.rs 的代码重算了一遍,不同长度的串文在读者屏幕上组装出来的卡片序号是这样的:18
| 串文与本次选中的候选 | 这个模块组出的帖子序号 |
|---|---|
| 共三条,选中第 3 则 | 1、2、3 |
| 共四条,选中第 4 则 | 1、3、4 |
| 共十条,选中第 10 则 | 1、9、10 |
你看懂上面这张表有多吓人了吗?!
- 如果你的串文一共只有 3 条,当第 3 条被选中时,系统拿出“根帖(第 1 条)+ 1 条直接上一条(第 2 条)+ 当前选中帖(第 3 条)”拼成卡片端给读者——读者在首页上一眼看到的就是完整的
1、2、3,起承转合一条都不漏! - 可如果你的串文写了 10 条,当第 10 条被选中时,系统同样只拿“根帖(第 1 条)+ 1 条直接上一条(第 9 条)+ 当前选中帖(第 10 条)”——结果读者在首页刷到的对话卡片,直接变成了诡异的
1、9、10!你辛辛苦苦在第 2 条到第 8 条里写的全部推导过程和铺垫,在首页卡片上被直接跳过隐身了!(当然,这是假设直线串文且末条入选的示例;实际选中哪一条、祖先数据是否齐全、中间有没有删帖都会影响结果,十条串文未必每次都显示1、9、10,但核心风险在于:中间的分帖随时可能不在首页首屏的组合卡片里!)
设想一下:如果你在第 9 条的开头只写了一句“所以根据上面的分析,答案就很清楚了”,那一个在首页只刷到 1、9、10 卡片的读者,根本不知道你说的“上面的分析”是啥!反过来,如果你把第 9 条改成:“当网站设计报价超过客户预算时,第一步是先缩小这次交付的页面范围,比如先做首页、把 3 个内页留到二期”——这样哪怕读者只看到 1、9、10,每一条分帖本身也把问题和结论交代得明明白白。所以发串文前,一定要把重要的分帖单独拎出来读一遍,看看去掉上下文别人还能不能看懂。
5.1 整条 thread 只占一个作者名额吗
《X Algorithm Playbook》里还教过一招:“把多篇内容合成一条 Thread 发,整条 Thread 在算法里只占 1 个作者名额,能躲开同作者 0.625 衰减。”
去查源码,系统里确实有一个叫 DedupConversationFilter(dedup_conversation_filter.rs,对话去重过滤器)的东西,它的作用是在同一段对话(同一个 conversation_id)的多条候选中,只保留得分最高的那一条,把同串里其余分低的分帖删掉,最后再把胜出者组装成一个首页对话卡片。4 19
但是!魔鬼全在“先后顺序”里!
打开 candidate_pipeline.rs 和 phoenix_candidate_pipeline.rs 查一下执行顺序就会发现:整条推荐流水线是先送进打分器(Scorers,包含 VM Ranker)算完分、做完候选挑选(Selection),最后才跑后置过滤器(Post-selection filters,也就是 DedupConversationFilter)!而在送进 VM Ranker 打分的那一刻(vm_ranker_request.rs),程序传过去的依然是一条条独立的帖子 ID(tweet_id)和它们背后一模一样的作者 ID(author_id),根本没有先把整条串文打包合并成一个候选再去算作者数!19
翻成大白话就是:当你发了一条 5 段式的串文,只要里面有两三条分帖同时闯过了前面的初筛、掉进同一个读者的临时篮子里,它们在打分环节就会先自己跟自己抢名额、实打实地触发 0.625、0.4375 的同作者衰减!等它们互相砍完分数、挑出胜者之后,DedupConversationFilter 才出来把同串里落败的分帖清理掉。 所以,串文虽然方便你把连贯的话题穿成一串,但千万别指望靠它绕开同作者衰减,更不建议把一篇本来能写进单篇长 Post 的内容硬拆成十几条碎串文去互相抢权重。
5.2 用一个具体问题,试写三条串文
真正动手写串文时,除了上面说的“分帖自相残杀”和“中间楼层被折叠”,还有一个更现实的门槛:没关注你的陌生读者(圈外 Out-Of-Network),到底能刷到你串文里的哪一条?
在我们核查的 Phoenix 推荐候选流程中,有一个专门处理圈外转发和回复的过滤器叫 oon_retweet_reply_filter.rs。它里面控制“是否放行未关注作者的回复帖进入推荐流”的开关 EnablePhoenixOonReplies,在公开配置里的默认值是 false(关闭)!
要知道,一条串文除了第 1 条(根帖 Root)是原创帖之外,从第 2 条开始往后的所有分帖,在数据结构上统统都是“回复贴(in_reply_to_tweet_id 有值)”!也就是说,在 EnablePhoenixOonReplies = false 的默认设置下,后续的第 2、3、4 条分帖在这条普通推荐管线里会被直接拦截,没关注你的陌生人往往只有机会刷到你的第 1 条(根帖)。就算线上某些实验把这个开关打开了,也还有召回来源、根节点等额外条件,不是开了就全放行。另外这只管首页这条推荐路径:读者点进对话详情页、或者已经关注你的粉丝,照样能看到后续分帖。。24
正因为陌生人极大概率只能先刷到你的第 1 条,如果你在第 1 条里只写一句吊胃口的废话——比如“关于怎么跟客户谈报价,我用下面十条给大家讲清楚,最后一条最关键,往下看👇”——那你就等于把真正有价值的干货全都藏在了陌生人根本刷不到的后半截里,只看到第 1 条的陌生人一头雾水,直接就划走了!
如果一个具体问题刚好适合用 3 条串文 讲清楚,怎么写才能既让陌生人看第 1 条就拿走干货,又让点开看全串的读者获得完整方案?我们拿“自由职业者怎么应对客户嫌报价贵”来写一组可以直接套用的 3 条串文模板:
第一条(根帖:直接亮出核心判断与原则,绝不空喊口号):
1/3 客户说“太贵了”,先别急着打折。
把报价包含的成品、修改次数和交期列出来。预算确实不够,再谈删掉哪些项目。
只降价却照单全做,后面很难谈追加费用。
第二条(中间帖:直接给出一眼看懂的方案对比,教读者具体怎么操作):
2/3 拿网站设计举例:
原方案:首页+3 个内页,修改 2 轮。 缩减方案:这次先做首页,内页留到下一阶段。
把两个方案的费用分开列,让客户知道少付的钱对应少做哪些事。避免“便宜一点,其他照旧”。
第三条(末尾帖:补上边界底线、给一句能直接复制发送的话术,最后再自然提问互动):
3/3 如果客户要求“全部照做,只是降价”,问题就不是方案太大。
可以这样回:“这个预算我能提供的是 A 方案。如果内容和交期都不调整,我无法按原规格承接。”
你遇到的“太贵”,通常是在谈预算,还是在要求全做又降价?
你看这三条:哪怕陌生读者只刷到第 1 条,他已经拿到了“降价必减交付范围”的核心方法;如果粉丝在时间线上刷到 1、2、3 组合卡片,第 2 条展示了怎么拆页面,第 3 条连现成的回绝话术都喂到了嘴边。像这种单一痛点的小闭环,用 3 条串文刚刚好。但如果你的内容是一份包含五张测试对比图和三个反例的硬核测评报告,那就老老实实用一篇完整的长 Post 或 Article 把所有证据一次性铺开,最多另外发一条 3 段式的摘要串文去导流,千万别为了硬凑“3 条串文”而把关键测试证据给删了。
顺便提一句,网上常有人争论“发串文和发单篇长 Post 到底哪个流量更好”。Hootsuite 团队曾在 2024 年 1 月做过一次真人对照实验:让同一个账号先后发了 3 组串文和 3 条单篇长帖。结果是两种格式里各跑出了一篇爆款,打了个平手。但仔细看实验条件就会发现:作者是在发长帖阶段才刚开通的 Premium 会员,两边写的选题不完全一样,而且统计串文数据时只算了首条帖子的曝光。这 6 篇样本可以作为一个有趣的参考案例,但既不能证明 2026 年的今天哪种格式包赢,也不能证明“3 条就是全宇宙最优解”。25
这套“单条信息独立完整”的原则,同样适用于你去别人帖子底下留言回复,以及怎么放外部链接:
- 去别人帖子下回复时:如果原帖作者问了一个你刚好懂的具体问题,那就直接把干货答案留在他的评论区里。如果聊着聊着碰撞出了另一个值得展开的新话题,那就把前因后果补齐,单独发成一条你自己的原创帖——千万别直接把评论区里那句没头没尾的“正如我刚才说的……”复制出来发帖,因为刷到你主页的陌生人根本不知道你刚才跟谁聊了什么。
- 需要在帖子里放外部链接时:核心是看读者点开链接到底要干嘛。比如你要送读者一份能直接复制使用的报价单模板,那就在正文里先把“这份模板包含哪几个核心字段、怎么用”讲明白。如果你出于版面整洁考虑,选择把链接放到第一条评论(首条回复)里,别忘了那本质上是另一条回复帖,读者得多点一步才能找到;至于“把外链挪到首条评论就能逃避处罚、多拿曝光”的说法,从公开代码里完全找不到依据(后面外链章节我们会专门拆解 v2 规则)。
6 “作者回一句,等于 150 个赞”的数字来自 2023 年(彻底搞懂“事前算命押注”与“事后记账”的区别)
平时看网上的 X 运营攻略,最容易让人热血沸腾的就是各种“加分倍率表”:什么“读者评论后作者再回一句,一次来回等于 150 个赞”、“读者从时间线点进你主页并点关注,直接加 4 分”、“有人点一次复制链接就加 20 分”、“被举报一次抵消 468 个赞”。
有趣的是,X 的 xai-value-model/scoring.rs 源码注释里,还真原封不动出现过“一次举报抵消 468 个赞”这句话——但程序员写这句话,是为了把它当成典型的错误理解靶子来批评!紧挨着这句话旁边,源码注释清清楚楚地写着一句警告:2
// watch time -- the weights do not multiply raw engagement counts.
翻译成大白话就是:“注意!这些权重系数乘的根本不是实际发生的互动次数!” 谁要是拿“你的帖子实际收到了几个赞、几次转发、几次复制链接”直接去乘权重表里的数字,那他算的根本就不是这套推荐系统的代码!
那句流传甚广的“作者去评论区回一句顶 150 个赞”又是从哪来的呢?去翻 2023 年 4 月 5 日 Twitter 第一次开源时的旧版 Heavy Ranker 文档,里面确实有下面这三行参数(省略其余行):26
scored_tweets_model_weight_fav: 0.5
scored_tweets_model_weight_reply: 13.5
scored_tweets_model_weight_reply_engaged_by_author: 75.0
你看:75.0 ÷ 0.5 = 150,除法算术本身没算错。但错在了两个致命地方:
第一,这是 2023 年 4 月早就淘汰的旧架构参数,现在的 xai-org/x-algorithm 早就不是这套系数了;
第二,哪怕在 2023 年,75.0 乘的也是“AI 预测当前这位读者会留言回复、并且作者会和这条回复互动”的预测概率,从来没有规定“作者去评论区每敲一行字回复,系统就给原帖记账兑现 150 个赞的曝光”。26
到了如今的 2026 年新版融合计分代码(scoring.rs)里,依然是严格的“权重 × 预测值”写法,比如点赞项和回复项的代码是这样的:2
apply(scores.favorite_score, weights.favorite),
apply(scores.reply_score, weights.reply_weight_for(candidate)),
把互动概率这一部分的计分逻辑写成数学公式,就是:
$$ S_{\mathrm{engagement}}(u,p)=\sum_i w_i,P(a_i\mid u,p) $$
你看懂这个公式里的字母代表什么,就彻底顿悟了:$u$ 是此时此刻正在下拉刷新首页的那位具体读者(User),$p$ 是临时篮子里待打分的那篇候选帖子(Post),$a_i$ 是某种互动动作(比如点赞、回复、关注、复制链接),而 $P(a_i\mid u,p)$ 就是 AI 模型在帖子展示给这位读者之前,提前算命押注算出来的“这位读者看到这篇帖子后做这个动作的概率”!
换一位读者刷首页,因为他的阅读习惯和历史偏好不同,AI 对同一篇帖子算出来的预测概率 $P(a_i\mid u,p)$ 就会完全不同(完整的排序分数还会加上后面讲的停留时间预测值以及同作者衰减等调整,上面这个式子专门用来看清互动权重到底在乘什么)。2 5
这时候很多创作者会问:“既然排序分数是在读者看到帖子之前‘事前算命’算出来的,那读者看完帖子之后,真正去点了赞、点了关注、或者复制了链接,岂不是一点用都没有了?”
当然有用!而且大有用处——只不过它不是给你做“事后记账加分”,而是作用在“下一波刷首页的读者”身上!
在公开的 Home 模型配置(phoenix/xrex/configs/xrecsys.py)里,明确开启了真实互动计数(engagement counts)作为上游 AI 大模型的输入特征(特征=喂给模型看的一项项数据,比如这篇帖子已经攒了多少赞、读者过去点过什么);而且后面要讲的小账号冷启动抽样(Thompson sampling)也会直接读取真实的点赞数 fav_count。
也就是说:当第一批刷到你帖子的读者,真的纷纷点开细读、复制了链接、或者顺着帖子点进你主页点了关注,这些真实发生的互动计数会立刻变成这篇帖子的实时特征喂给上游 AI 模型。等下一秒成千上万个同类型的陌生读者下拉刷新首页时,AI 给他们算出来的“预测点赞概率、预测复制链接概率、预测关注概率”就会水涨船高!所以最准确的区别是:最终融合打分公式不会按“实际点赞数 × 0.66”给你记死账,但真实的互动数据会喂给上游模型和其他环节,撬动下一波读者的预测概率!84
为了让你直观感受到“预测概率 × 权重系数”是怎么打破常规直觉的,我们拿真实代码里的两个参数算一笔账:
在当前公开默认值里,一般回复(Reply)的权重系数是 5,而复制链接(Share via copy link)的权重系数高达 20。光看系数,复制链接是回复的整整 4 倍对吧?
但假设现在读者张三刷首页,AI 根据张三平时的习惯,预测他看到你这篇帖子有 2%(0.02) 的概率会留言回复,但只有 0.1%(0.001) 的概率会去点“复制链接”(且假设不涉及互关等额外加成)。那么在给张三算分时:
- 回复项贡献的分数 = $5 \times 0.02 = \mathbf{0.10}$ 分;
- 复制链接项贡献的分数 = $20 \times 0.001 = \mathbf{0.02}$ 分。
你看!虽然复制链接的权重系数(20)比回复(5)大得多,但由于发生概率差了 20 倍,在这次打分里,反而是系数较小的“回复项”帮你的帖子拿到了 5 倍于复制链接的分数!(注:这是帮助理解乘法逻辑的示意计算,不是对特定真实账号的线上预测。)21
7 停留系数增加了 50%,这次能找到前后版本
网上传言“10 月份 X 把阅读停留权重提高了 50%,点赞权重涨到了历史最高点 0.66”,这回是不是真的?
如果只看同一个 Git 提交快照,你会发现一个有趣的现象:在 Home Mixer 服务里,连续停留时间系数(ContDwellTimeWeight)的默认值是 0.006;而在另一个 VM Ranker 服务里,同名参数的默认值却是 0.004。虽然 0.006 比 0.004 正好高出 50%,但我们绝不能拿同一时刻两个不同微服务之间的默认差值,来证明“这个月涨了五成”。要证明它在时间上涨了 50%,必须顺着同一个文件 home-mixer/params/param.rs 的 Git 修改历史往前翻。12 15 27
为此,我沿着 home-mixer/params/param.rs 的提交记录,逐一核对了整个 10 月份的 20 个参数快照:
- 在 10 月 9 日的快照里,
ContDwellTimeWeight的值确实还是0.004; - 到了 10 月 13 日的快照里,它被正式改成了
0.006(实打实增加了 50%)! - 同一时期,点赞权重
FavoriteWeight先是在 10 月 13 日从0.5升到了0.6,紧接着在 10 月 14 日又从0.6升到了0.66;而“不感兴趣(NotInterestedWeight)”的负向惩罚也同步加重了 10%。
前后的代码历史完全证实了“连续停留系数在 10 月份上调了 50%”这一事实(同样要提醒的是:表里的日期是公开代码快照的提交日期,不代表线上每一个实验分桶都在同一秒钟切换)。15
| 首次在已查节点观察到的日期(UTC) | Home Mixer 参数 | 前一个已查值 | 该公开快照的值 |
|---|---|---|---|
| 2026-10-13 | ContDwellTimeWeight | 0.004 | 0.006;系数增加 50% |
| 2026-10-13 | FavoriteWeight | 0.5 | 0.6 |
| 2026-10-13 | VideoOpenWeight | 0.07 | 0.02 |
| 2026-10-14 | FavoriteWeight | 0.6 | 0.66 |
| 2026-10-14 | NotInterestedWeight | −47.52 | −52.272;负向系数绝对值增加 10% |
来源 15
至于网上传的“点赞权重 0.66 创下历史最高”,说话必须留好边界:0.66 确实是我们核查过的 10 月份 20 个公开快照里最高的 FavoriteWeight,但由于没有 X 诞生以来所有未公开历史配置的数据,不能满口保证它是“全历史最高”。更关键的是,哪怕涨到了 0.66,点赞在所有正向行为里依然只是个“弟弟”——一般回复、带评论引用(Quote)和私信分享的系数都是 5,关注作者是 4,复制链接和符合互关条件的原创帖回复预测更是高达 20!15 27
7.1 两处公开默认值,有哪些差别
为了让你随手就能查到当前代码里每一项行为的真实权重,我把 Home Mixer 和 VM Ranker 两个服务里全部 24 项预测参数的公开默认值并列整理成了下面这张大表,并在最后一栏用大白话写清了每一项到底该怎么读:14 21 27
| 预测项目 | Home Mixer 默认值 | VM Ranker 默认值 | 如何理解 |
|---|---|---|---|
| 点赞 Favorite | 0.66 | 0.5 | 乘个性化点赞预测概率;绝不是每收到一个赞就入账 0.66 分 |
| 一般回复 Reply | 5 | 5 | 乘读者留言回复的预测概率 |
| 符合互关条件的回复预测项 | 5+15=20 | 5+15=20 | 候选必须不是 reply、不是 retweet(即必须是原创帖),且读者与作者互相关注 |
| 普通转发 Retweet | 1 | 1 | 指直接点转发(Repost),与带评论的引用(Quote)分开计算 |
| 引用 Quote | 5 | 5 | 带评论转发的预测系数是 5;但不能由 5 比 1 直接推出曝光必然是普通转发的五倍 |
| 私讯分享 Share via DM | 5 | 5 | 系数乘私信分享预测概率,不是每私信发一次就加五分 |
| 复制链接 Share via copy link | 20 | 20 | 最大的普通正向系数之一;与合资格的互关回复项并列高达 20 |
| 点击 Click | 0.3 | 0.3 | 乘普通点击预测;不等于读者点开秒退时的最终总分 |
| 打开视频 Video open | 0.02 | 0.07 | 两个服务默认值不同;也仅代表打开视频这一项,不是视频全部作用的总和 |
| VQV(视频品质观看) | 0 | 0 | 这个具名打分项默认系数为 0,但不代表所有视频观看时长在系统里都没用 |
| 停留事件 Dwell | 0.05 | 0.05 | 基础停留事件的二元预测概率,与连续停留秒数、点击停留分开算 |
| 连续停留 ContDwellTime | 0.006 | 0.004 | 乘模型预测的连续停留时间数值(秒) |
| 点击停留 ContClickDwellTime | 0.4 | 0.4 | 点开后深度停留达标的预测概率(门槛值 10.0);注意:这个 10 的单位、以及模型输出怎么转成打分字段,公开代码没交代(见第 11.3 节),别当成“看满 10 秒就加 0.4 分” |
| 关注作者 Follow author | 4 | 4 | 预测读者看完帖子后顺手关注作者的概率;并非按你现有粉丝数每人固定加四分 |
| 不感兴趣 Not interested | −52.272 | −47.52 | 乘当前读者的“点不感兴趣”负向预测概率;不是全站共同扣点 |
| Post unexplored | 0.015 | 0.02 | 这是名字就叫 Post unexplored 的一项预测;是否包括关系网外候选另有条件,不是每篇帖子的保底探索曝光额度 |
| 一般分享 Share | 2 | 2 | 独立于私信分享和复制链接的系统分享动作,乘对应预测值 |
| 打开外链 Open link | 0.2 | 0.2 | 乘读者点击打开外部链接的预测概率;不是帖子只要带 URL 就白送 0.2 分 |
| 展开图片 Photo expand | 0.05 | 0.05 | 乘读者点击展开查看大图的预测概率 |
| 点击被引用帖子 Quoted click | 0.05 | 0.05 | 乘点击内部被引用原帖卡片的概率,与引用行为本身及普通点击分开 |
| 屏蔽作者 Block author | −31.2 | −31.2 | 乘当前读者拉黑屏蔽作者的预测概率 |
| 静音作者 Mute author | −58.8 | −58.8 | 乘当前读者静音(Mute)作者的预测概率 |
| 举报 Report | −234 | −234 | 乘当前读者举报帖子的预测概率(全场最重惩罚),不能直接按实际举报次数扣点 |
| 未停留 Not dwelled | −0.02 | −0.02 | 乘读者一眼划走(未停留)的预测概率;与“看了但没点赞评论”完全不是一回事 |
看到这里你可能会好奇:“为什么同一套代码库里,Home Mixer 和 VM Ranker 会存着两套略有不同的默认参数?到底哪一套才是算数的主力?”
顺着调用链(home-mixer/scorers/vm_ranker.rs)查下去,它们俩的配合流程是这样的:
Home Mixer会先用自己的本地参数算出一份初步分数,并据此做好**小账号冷启动(Cold Start)**的提拔决策;- 紧接着,
Home Mixer会发起一次远程调用(RPC)去请VM Ranker服务做最终打分——发过去的请求里带着各项预测概率(prediction heads),并要求计算价值模型(compute_value_model); VM Ranker收到请求后,会从它自己的vm-ranker/params.rs里读取权重系数来算分(如果某个候选帖身上已经带了缓存好的加权分数weighted_score,共用程序也可以直接沿用);- 如果这次 RPC 调用成功返回,
Home Mixer就会采用VM Ranker算出来的分数;万一 RPC 调用失败超时,才会退回(fallback)使用Home Mixer自己刚才算的本地分数!因此,分析具体路径时,到底读哪个服务、有没有命中缓存、以及线上实时配置开关(feature switches)怎么设,都会决定最终用哪组数字。12
同时,我们也得客观认识这些“公开默认值”的含金量:官方在仓库 README.md 里明确说明,他们使用定时任务(cron)把生产环境里的主要正式默认配置自动同步到公开代码库中,并尽量让占用显著流量比例的实验在代码里可见;比如在 5ed7963 快照的 home-mixer/params/param.rs 文件第一行注释里,就清楚印着最后一次自动同步的时间戳:2026-10-27T16:00:37Z。这说明表里的数字绝不是程序员随手乱填的假范例,而是货真价实的生产环境基准参考;只不过线上真实请求依然会动态读取配置中心(configuration system),公开快照没办法把每一位读者当下命中的灰度实验开关全都列出来。12
7.2 系数涨了五成,总分会涨多少
看到“连续停留时间权重从 0.004 涨到 0.006,暴涨 50%”,有些做长文的博主欢呼雀跃,以为自己的长文总分和曝光量马上也要原地暴涨 50%。
我们不妨动笔算一道小学算术题,帮你瞬间冷静下来:
固定一个假设场景:AI 模型预测某位读者会在你的帖子上停留阅读 5 秒钟,而点赞、回复、点击等其他所有项目的原始加权和加在一起合计为 0.20 分。
- 当连续停留系数是旧版
0.004时,停留这一项贡献 $0.004 \times 5 = 0.020$ 分,加上其他项0.20,原始总和是0.220分; - 当连续停留系数涨了 50% 变成
0.006时,停留这一项贡献 $0.006 \times 5 = 0.030$ 分,加上其他项0.20,原始总和变成了0.230分。
在还没套用后续的分数平移(offset)、同作者多样性衰减与其他调整之前,整体原始总分只是从 0.220 变成了 0.230,实际总分只增加了约 4.5%(而不是 50%)!这还是保持其他预测值不变的纯算术演示(真实线上模型升级后,预测出来的秒数本身也会变)。15 27
假设预测停留 = 5 秒,其他原始加权项合计 = 0.20
旧值:0.20 + 0.004 * 5 = 0.220
新值:0.20 + 0.006 * 5 = 0.230
停留项增加 50%;这个假例的原始总和增加约 4.5%
以上尚未套其他排序处理,也没有换算曝光。
用同样的道理去看权重表里的其他数字,你就不会再被忽悠了:
- “复制链接
20”、“关注作者4”、“不感兴趣-52.272”,统统都是乘在预测概率上的系数,不是每发生一次实际动作的计件奖罚; - 读者“点开你的帖子看了一眼就退出去”,也不能简单算成“白赚
0.3分点击分”——因为融合公式是把所有正负预测项加在一起算的,如果他点开秒退,模型对他算出来的深度停留概率就会极低,甚至可能伴随较高的负向预测; - 至于诱人的“互关好友回复预测
5 + 15 = 20”,代码硬性规定只作用于**原创候选帖(!is_reply && !is_retweet)**本身被回复的概率预测——如果你跑到大 V 帖子底下发评论抢前排,你发的那条评论本身是is_reply = true,直接被排除在外,一分钱互关加成都拿不到!27
所以,10 月份的参数对比真正告诉我们的是:系统确实越来越重视“读者愿不愿意停下来把内容读进去”,阅读信号值得跟互动信号放在同等重要的位置上看待;但它绝没有证明“在开头写十句废话硬拖够多少秒”、“疯狂找人互关”、或者“在文末求每个人点一下复制链接”就能稳拿高曝光。要验证哪种写法真正涨流量,还得看账号实测数据和受控对比,本文不做脱离证据的玄学承诺。
8 转发和只看不互动,差距真有二十倍吗
很多写深度干货的创作者盯着上面的权重表,心里会咯噔一下:普通转发(RetweetWeight)的默认权重是 1.0,而基础停留事件(DwellWeight)的默认权重只有 0.05——下面是直接从 home-mixer/params/param.rs 里摘出来的两行源码:21
param!(RetweetWeight, f64, "rust_home_mixer_retweet_weight", 1.0);
param!(DwellWeight, f64, "rust_home_mixer_dwell_weight", 0.05);
看到 $1.0 \div 0.05 = 20$,不少人立马得出一个悲观的结论:“完了!转发一次的权重比只看不互动高了整整 20 倍!我的长文大家都是默默看完不转发,在算法眼里岂不是亏到姥姥家了?”
代码核对并重算后的真相,恰恰跟你想的相反!
首先,这两项乘的都是预测发生概率。没错,如果其他项不变,把转发预测概率提高 1 个百分点(+0.01),原始加权和会增加 $1.0 \times 0.01 = 0.01$ 分;把基础停留概率提高 1 个百分点,则增加 $0.05 \times 0.01 = 0.0005$ 分,“20 倍”仅仅是这两个“每增加 1% 概率”的增量比例,绝不能换算成“现实中 1 次转发抵得上 20 次阅读观看”!2
为什么?因为在现实生活里,一个读者刷到好帖子“停下来阅读”的概率,远远高于他顺手点“转发”的概率!
我用本地重写的计分程序跑了一组最常见的算例:假设对某位读者,AI 预测他转发你这篇帖子的概率是 2%(0.02),而预测他停下来阅读(触发基础停留事件)的概率是 60%(0.60)。那么:
- 普通转发项贡献的分数 = $1.0 \times 0.02 = \mathbf{0.02}$ 分;
- 基础停留事件贡献的分数 = $0.05 \times 0.60 = \mathbf{0.03}$ 分!
你看,哪怕只比这单一一项,不管用 Home Mixer 还是 VM Ranker 的公开默认值算出来,系数只有 0.05 的基础停留项(得 0.03 分),当场就反超了系数为 1.0 的普通转发项(得 0.02 分)!(注:这是固定假设概率后的局部算例,未使用真实账号线上数据。)
更何况,当一个读者“只看不点赞、不评论、不转发”时,在推荐系统的代码里,他触发的根本不止 0.05 那一个指标,而是整整一串“阅读停留家族”同时叠加发力! 把普通转发和与阅读相关的预测项放在一起对比,你会看得更清楚:21
| 预测项目 | Home Mixer | VM Ranker | 读法 |
|---|---|---|---|
| 普通转发 Retweet | 1.0 | 1.0 | 乘读者点普通转发的概率 |
| 停留事件 Dwell | 0.05 | 0.05 | 乘基础停留事件的概率 |
| 连续停留 ContDwellTime | 0.006 | 0.004 | 乘模型预测的连续停留秒数(比如看 30 秒就是 0.006 × 30 = 0.18) |
| 点开后停留 ContClickDwellTime | 0.4 | 0.4 | 乘点开帖子后深度停留(超过阈值 10)的概率(另外普通点击 Click 还有 0.3) |
| 未停留 Not dwelled | −0.02 | −0.02 | 乘读者一眼划走(未停留)的概率 |
千万别把“读者看完了但没点赞没评论”当成表里倒数第一行的“未停留(Not dwelled)”!
- “未停留(
Not dwelled,权重-0.02)”:指的是读者在时间线上看到你的帖子一眼略过、手指头都不带停顿地直接划走了; - “默默读完但没互动”:读者不仅没有触发
-0.02的划走惩罚,反而会同时触发普通点击(Click0.3)+ 点开后深度停留(ContClickDwellTime0.4)+ 基础停留(Dwell0.05)+ 连续停留秒数(ContDwellTime0.006 × 秒数),甚至在第一步抓候选时还会激活新增的ld深度阅读召回分支(权重0.75)!把这几层加在一起,一个“只看不说话”的深度读者贡献的排序分数,往往是普通转发的好几倍!(当然,前台显示的公开观看数 Views 也不能直接拿来代入上面某一项去换算固定分数。)2 28
「点开后停留」(CLICK_DWELL_TIME,系数 0.4)在模型里是一个「达标/不达标」的二选一判断——原始数值严格大于门槛 10.0 就算达标,模型算出来的是「这位读者达标的概率」(0 到 1 之间),再乘上 0.4 进总分。有两个地方公开代码没交代:一是这个原始数值到底以什么为单位(常识上猜是秒,但生成它的上游代码没公开);二是模型算出的概率、转成 Home Mixer 里 click_dwell_time 字段的那段中间转换代码(adapter)也没公开。所以别把 0.4 理解成「每多看一秒就加 0.4 分」,更不能拿它去算「一次转发等于看几秒」。它跟前面 0.05 的基础停留是两个独立的判断,不要混在一起。28
既然“默默阅读”在打分时这么能打,那“普通转发(Retweet)”真正的独家价值到底是什么?
答案不在打分表里,而在第一步的**“关系网召回通道(Thunder)”里!
假设读者甲根本不认识你(也没关注你),但甲关注了你们行业的同行大 V 乙。当同行乙觉得你的干货有用、顺手点了一下“普通转发(Retweet)”之后,会发生什么?
在 thunder/posts/post_store.rs 里,系统会把乙的这笔转发记录写进乙的个人动态索引库。当乙的粉丝甲下拉刷新首页时,Thunder 采购员按甲的关注名单去进货,就会把乙转发的这篇你的帖子,直接作为“甲关注圈内的候选帖”抓进甲的临时篮子里**!也就是说,别人转发你的帖子,相当于在 AI 算法推荐之外,直接借用转发者的粉丝关系网给你额外打开了一扇“跨圈层大门”(当然,被抓进甲的篮子之后,依然要经过已读过滤和打分排序,不保证乙的每一个粉丝都100%看到)。29
看明白这两条腿走路的逻辑,你写长文时的心态就彻底稳了:
- 对占大多数的“沉默读者”:踏踏实实给足案例、数据表和实操步骤,让他们愿意点开停下来读完,靠 4 层阅读停留信号帮你把帖子的排序基本盘撑起来;
- 对“同行与大 V”:在文章里做一张一目了然的方案对比图或避坑清单(比如讲报价教程时,直接附一张完整的“原方案 vs 缩减方案对照表”,而不是干巴巴喊一句“和客户沟通很重要”),方便同行觉得“这张表对我粉丝也有用”而顺手点转发,借他们的关注流帮你破圈!
另外别忘了,代码里把**“普通转发(Retweet,直接点转发,权重 1.0)”和“带评论引用(Quote,转发时写一段自己的评论,权重 5.0)”**分成了两个完全独立的预测项。Quote 的预测权重系数虽然是普通转发的 5 倍,但同样因为乘的是各自的预测发生概率,不能机械地宣称“转发时随便敲几个字就能拿到 5 倍曝光”。21
8.1 转发能不能出圈,要看是谁的圈子
前面我们看到一条网传说法:“只有原创帖才能触达陌生人,普通转发(Retweet)会被圈外过滤器一刀切砍掉,所以转发根本不能破圈。” 这句话之所以把无数人绕晕,是因为说话的人把**“到底是谁的关注圈(In-Network)”**这个主语给吞掉了!
我们把一场转发里的三个人——甲(写原帖的你)、乙(帮你点转发的大 V)、丙(只关注了乙、没关注你的陌生读者)——摆在桌面上,对照 in_network_candidate_hydrator.rs 和 oon_retweet_reply_filter.rs 的源码,看看候选帖里的数据字段到底是怎么填的:30
| 角色 | 这个例子中的关系 | 候选资料如何表示 | 可得到的结论 |
|---|---|---|---|
| 甲:原作者(你) | 读者丙没有关注甲 | 甲的原文 ID 保存在这笔转发的 retweeted_tweet_id 字段里 | 甲的内容完全可以借由乙的转发,送到不认识甲的陌生读者丙面前! |
| 乙:转发者(同行大 V) | 读者丙关注了乙 | 这笔转发候选帖的直接作者 author_id 填的是乙! | 当系统检查“候选作者乙在不在读者丙的关注名单里”时,判定结果是圈内(In-Network)! |
| 丙:读者 | 只关注了乙,没关注甲 | Thunder 按丙的关注名单,把乙的这笔转发抓进丙的候选池 | 成功绕过圈外拦截进入候选池(至于最后排第几,仍由后续过滤与打分决定) |
来源 30
你看清代码里的玄机了吗?
在 oon_retweet_reply_filter.rs 里,确实有一条铁律:直接移除所有“候选帖的 author_id 不在当前读者关注名单内(!in_network)”的普通转发(is_retweet)(而且哪怕把回复豁免开关打开,也不会豁免普通转发)。
- 如果这句话限定的是**“转发者乙的这笔转发,能不能在普通推荐管线里直接推给既没关注甲、也没关注乙的纯路人丁”,或者“你自己点普通转发自己的老帖子,能不能推给没关注你的陌生人”**——那代码确实会把它一刀拦死!因为在这两种情况下,转发人的
author_id都不在读者的关注名单里,属于圈外转发(OON Retweet),必被过滤!(后面第 24 章我们会专门拆解“自己转发自己老帖子”的 5 道关卡。) - 但如果是别人(乙)转发了你的原帖,对于乙的粉丝丙来说,这笔转发候选帖的
author_id是乙(丙关注的人),在系统眼里它属于堂堂正正的圈内候选(In-Network),根本不会触发圈外过滤器的拦截!对于原作者甲(你)来说,乙的粉丝丙就是完完全全的“圈外陌生读者”。所以,把“圈外过滤器拦截未关注者的转发”歪曲成“别人转发你的帖子也没法帮你触达陌生人”,纯属把“转发者”和“原作者”的主语给搞反了!30
这也再次提醒我们:当你写一篇研究摘要或工具评测、希望同行大 V 顺手转发时,正文一定要把研究对象、核心结论和适用边界写清楚,让大 V 的粉丝(这群原本不认识你的陌生人)哪怕第一次刷到,也能一眼看懂你在干什么。至于大 V 转发后他名下有多少粉丝最终能刷到,则由每位粉丝各自的已读过滤和模型打分决定。30
8.2 回复能否进入陌生人的候选,还要看开关和来源
说完了普通转发,那“回复贴(Replies,包括你在别人底下的评论,以及你自己串文的第 2 条往后)”能不能进入未关注陌生人的 For You 推荐候选池呢? 在代码里,回复贴的待遇比普通转发稍微留了一扇小窗户,不能和普通转发合并成一个绝对的“永远不行”。
在当前公开默认参数(home-mixer/params/param.rs)里,控制圈外回复的开关 EnablePhoenixOonReplies 默认值是 false(关闭)——如果线上按这个默认值跑,普通推荐管线确实会把所有未关注作者的回复帖统统过滤掉。
但程序员在代码里写好了一段条件式放行分支:一旦线上配置把 EnablePhoenixOonReplies 开关设为 true,只要这条回复贴同时满足以下条件,就能免于被 oon_retweet_reply_filter.rs 杀掉:30
- 它的召回进货来源必须属于指定的 Phoenix 推荐源(
ForYouPhoenixRetrieval或冷启动源ForYouPhoenixRetrievalCold); - 如果另一个开关
PhoenixOonRepliesRootOnly同时被打开(公开默认为false,但线上实验可随时调整),那这条回复还必须是直接回复主帖根节点的“一级回复”(不能是楼中楼回复); - 这条回复必须已经成功补齐了可用的对话祖先数据(
ancestors,如果缺祖先数据照样会被移除)。30
OON 回复要走这个例外,须同时符合:
EnablePhoenixOonReplies 开启
来源属指定 Phoenix home retrieval 类型
若 root-only 开启,必须直接回复 root
回复仍须有可用 ancestors
来源:30
你看,就算线上把例外开关打开,也不是随随便便一条回复都能冲进陌生人的首页。所以不管是写串文还是写评论,永远要把最核心的问题和判断放在第一条(根帖),同时保证后面的每一条回复都有充足的上下文背景,千万别把全文最精华的底牌全押在陌生人极大概率刷不到的串文末尾。30
8.3 首页的一组对话,可能附带其他帖子
关于转发和回复的出圈逻辑,代码里还有一层非常隐蔽的机制:单条通过筛选的候选帖,和最后端上读者屏幕的“整组对话模块”,并不是同一个数据单位!
怎么理解这句话?比如 Thunder 关注流召回一条回复候选帖时,会顺带保存它的直接父帖(parent)和对话根帖(root);等到最后一步界面组装(convo_marshaller.rs)时,系统会把“根帖 + 有限的中间祖先帖 + 当前入选帖”拼成一个对话卡片一起展示出来。也就是说,如果读者关注的人回复了某条帖子,读者在屏幕上看到的那组对话卡片里附带的根帖或父帖,并不是按它自己的作者关系单独去走一遍相同的圈外候选过滤的(当然,所有附带展示的内容依然要单独过一遍 vf_candidate_hydrator.rs 的安全与可见性检查,违规删帖照样出不来)。30
而且 Thunder 对回复楼层的深度也有严格限制(thunder/posts/post_store.rs):“直接回复一篇原创根帖”和“在楼中楼里回复别人的回复”,准入资格并不完全相同;更深一层的回复会检查父帖与根帖的关系、被回复的人是不是当前读者关注的对象等条件。所以我们也不能把对话组装机制反过来吹成“随便找人借一条回复,就能让任何八百年前的旧帖子无条件绕过全站限制”。30
另外,在 For You 首页最顶层的流水线组装(for_you_candidate_pipeline.rs)里,除了常规的打分候选流(ScoredPosts),旁边还并列着一个叫 PushToHomeSource(push_to_home_source.rs)的特殊来源。它是根据请求里明确指定的 push_to_home_post_id 直接取帖子数据的,并不跟普通候选帖一起挤同一串 PostCandidate 过滤器。这说明我们在普通候选管线里看到的过滤规则,并不是整个首页所有入口的唯一总开关(更管不到对话详情页、搜索页和个人主页);但至于什么样的帖子才能被塞进 push_to_home_post_id,公开代码并没有披露上游触发逻辑,我们也不能拿它当成创作者能自己手动调用的后门。30
9 陌生读者为什么会遇到你这一篇(兼谈中英双语多语言发布怎么选)
搞懂了上面的过滤规则,我们再来看一个让所有创作者着迷的问题:对于一个从来没关注过我的陌生读者,AI 到底是怎么在茫茫帖海里,把我的这篇帖子精准抓进他的临时篮子里的?
举个具体例子:假设你今天发了一篇干货,标题叫《网站设计报价被客户嫌贵,如何通过缩小交付范围保住订单》。此时此刻,陌生读者甲最近几天经常在 X 上看自由职业接单与客户沟通的内容;而陌生读者乙最近几天一直在看索尼和佳能的相机测评。 在 X 的推荐系统里,根本不需要先把你的文章随机撒胡椒面推给全站所有人试水——在甲和乙下拉刷新的第一步(召回阶段),系统就能根据他们俩近期的行为序列,把你的文章精准抓给甲,而给乙抓去镜头测评!(注:这里用甲和乙做个性化机制的直观说明,并非两个真实账号的线上实测。)31
打开 retrieval_sequence_query_hydrator.rs 和 phoenix_source.rs 就能看到这套精准匹配的底层代码:
- 当读者下拉刷新时,程序会传入当前这位读者的 ID(
query.user_id),去捞取这位读者最近干过的所有历史互动行为序列(点过什么、读过什么、搜过什么、收藏过什么),然后把这个行为序列打包发给 Phoenix 双塔召回模型; - 而在另一端,你的帖子在进入候选库时,模型(
recsys_two_tower_model.py)会把帖子的多模态语义表示(Semantic ID,由 Grox 多模态模型提取你的文字和图片生成)与经过哈希处理的作者 ID 结合在一起,生成代表你这篇帖子的候选向量。 一边是“这位读者近期在看什么”,另一边是“你这篇帖子在聊什么、你是谁”——两边向量一做相似度匹配,哪怕甲从来没听说过你,只要你写的正是他最近在琢磨的痛点,Phoenix 采购员一伸手就把你的帖子捞进甲的临时篮子里了!31
看懂这段代码,就能顺手破除一个流传很广的“刷垂类养号玄学”:
很多教程教创作者:“你想做科技博主,平时自己刷 X 时就只能看科技帖、给科技帖点赞,这样算法就会把你发的文章推给科技圈读者!”
错!你看代码里读的是谁的历史?读的是 query.user_id(当前正在刷首页的读者)的历史,不是作者的浏览历史! 你自己连续一个星期只看科技帖、只给科技帖点赞,改变的是**“你自己作为读者刷首页时会看到什么”**,这段召回代码里没有任何逻辑说“因为作者昨天看了十篇科技帖,所以今天把作者发的文章定向推给科技读者”(当然,作者 ID 本身仍是候选侧的输入特征之一,所以也不能绝对断言作者的历史身份完全无关)。31
这对我们平时写稿有什么启发?最大的启发就是:别起空洞宽泛的玄学标题,要把标题和开头第一段直接钉在目标读者正在处理的“具体对象 + 具体任务”上!
- 别写《自由职业接单人的必修课》 → 改成**《网站设计报价被嫌贵时,如何缩小第一阶段交付范围》**;
- 别写《AI 大模型又迎来重大进步了》 → 改成**《用 AI 生成会议纪要漏掉了客户否决条件,怎么用 3 句话验证》**。 当你把研究对象和解决的具体任务写清楚了,多模态模型生成的语义向量(Semantic ID)靶心就极其精准,正文也自然知道该摆什么证据。
同理,假如你的账号上周写的是“客户嫌报价贵怎么谈”,这周写的是“客户接受报价后不断追加修改怎么防”,这两篇看似换了细分题目,但服务的明明是同一群自由职业读者!你完全没必要被所谓的“账号垂直度 80% 红线”吓住,生怕换个具体问题就会触发什么“重置账号标签”——查遍公开召回和打分路径,根本没有“80% 同主题纯度”、“固定带几个 Hashtag 才垂直”、或者“跨题发一篇就重置账号权重”的数学公式。31
9.1 同一个内容用多国语言发布(比如中英双语发布)会怎样?
很多做技术、出海和开源项目的创作者经常问我一个非常纠结的实操问题:“我写了一篇干货,想同时覆盖中文读者和英文读者,到底应该把中文和英文上下混排塞在同一条帖子里发,还是拆成一条纯中文帖、一条纯英文帖分开发?”
结合刚刚讲完的“读者历史序列匹配(query.user_id)”、“同作者 0.625 衰减”、“V8.2 的 4,000 字符截断”以及后面第 28 章要讲的“PTOS 英语专属安全规则”,我们把这两种发法在代码里会遇到的真实待遇彻底算清楚:
9.1.1 发法 B:拆成“一条纯中文帖”+“一条纯英文帖”分开发布
**先说结论:同一个内容拆成一条纯中文帖、一条纯英文帖分开发,完全没问题,几千字的长内容就该这么发。**在代码里的实际待遇是:
- 对只看单一语言的读者(占绝大多数):两条各走各的读者群
别忘了前面刚讲的核心机制:Phoenix 召回模型读取的是当前读者自己的历史行为序列(
query.user_id)!
- 对平时只刷中文圈的读者张三来说,他的召回序列只会把你的纯中文版抓进他的临时篮子里,英文版压根不会进他的池子——所以按同作者乘数的算法,中文版在张三这里不会被英文版占掉名额;
- 对平时只刷英文圈的老外读者 John 来说,他的召回序列只会把你的纯英文版抓进他的临时篮子里——所以按同样的算法,英文版在 John 这里也不会被中文版占掉名额。两边互不占名额——这是按召回和计数机制推的,线上是不是完全这样跑,没有日志可证。31
- 对中英文都看的“双语读者 / 已关注你的老粉丝”:连发会同池竞争!
如果你在同一分钟把纯中文版和纯英文版脚前脚后连着发出来,对于已经关注了你的粉丝(
Thunder关注流会按你的author_id把你刚发的两条都抓进去)或者中英双语都刷的读者来说,这两条帖子带着同一个author_id掉进同一个临时篮子,排第二的那条就会吃0.625同作者衰减,甚至在跨语言语义高度重合时还可能在 DPP 多样性选择(dpp_model.rs)里互相竞争!2 85
9.1.2 发法 A:同一条帖子里“上半截中文、下半截英文”混排发布
- 有没有“中英混写扣分”?没有! 公开代码里没有任何“检测到多语言混写就固定扣分”的规则,语言标识只是喂给模型的普通特征之一。31
- 但是!长文混写会直接撞上两个隐形大坑:
- 第一坑:4,000 字符无情一刀切(
MAX_POST_TEXT = 4000)! 后面第 17 章我们会看到,V8.2 内容理解处理器(renderer_v82.py)在读取帖子正文post.full_text时,只截取前 4,000 个字符送往多模态 embedding 服务。如果你写了一篇深度测试,上半截写了 3,500 字中文,下半截接着放了 3,500 字符的英文翻译——对不起,从第 4,000 个字符往后的英文主体会被直接切掉,根本进不去这条内容向量生成流程!47 - 第二坑:英语专属的自动审查规则(
FOSNR_ABUSE_INSULTS)! 后面第 28 章安全规则里有一条硬代码:在 Grox PTOS 自动打标路径中(Grox 是 X 内部负责「看懂内容」的 AI 系统,PTOS 是它里面专门管安全审查、给违规内容打标签的那套流程),HateOrAbuseInsultsWithTarget(带目标的侮辱攻击分类)明确要求当帖子语言被识别为英语(English)时,才会自动给非高 PageRank(PageRank=系统按影响力给账号算的权重分,分越高越被当成大号,后文多处豁免都看它)/灰标账号(灰标=政府/机构账号的灰色认证徽章,不是花钱买的蓝标)写入FOSNR_ABUSE_INSULTS限制标签(在HomeRecommendations拦截全部陌生人推荐)。如果你写的是尖锐的产品测评或批评,按这条路径的条件推测:如果双语帖的语言被识别成英语、措辞又过激,就更容易撞上这条自动打标线——语言到底怎么判,代码里没有给双语帖的明确说法。77
9.1.3 多国语言发布到底怎么做?
- 如果是几千字的技术长文、深度评测或教程:请务必拆成“纯中文帖”和“纯英文帖”两条独立发布!并且建议把两条的发布时间错开半天左右(具体隔多久,代码里没有规定)(比如北京时间中午发中文版,等到北京时间深夜、欧美白天活跃高峰时再发英文版)——这样既能让中文版和英文版各自用满 V8.2 的 4,000 字符语义额度、匹配各自语种的陌生读者,也尽量错开双语老粉丝的刷新时段,避免两条长文在同一个临时篮子里自己打自己!
- 如果是两三百字的简短动态或配图短帖(中英加起来远远不到 4,000 字符):可以直接放在同一条帖子里上下对照发,省事且互动集中在一处;
10 阅读信号在找候选时就已经有用
很多写技术教程、做数据整理的创作者经常郁闷:“我花三天做的实测对比表,读者看完直接存图拿去用了,评论区冷冷清清没几个人吵架留言,算法是不是觉得我的帖子没人爱看?”
千万别慌!评论区安静,绝不代表读者没有在系统里帮你投票。 在 2026 年 10 月 13 日的官方 README 更新说明里,X 团队专门宣布了一件大事:Phoenix 召回模型(也就是第一步去仓库里捞候选帖的采购员)正式开始学习找出“人们会真正读下去的帖子”!32
顺着这条公告追进双塔召回模型的配置文件 phoenix/xrex/configs/xrecsys_two_tower.py,你会看到:除了原有的 home(常规互动)和 immersive(沉浸式视频)两个分支外,代码里实打实新增了一个叫 ld(Long Dwell / 深度阅读停留) 的独立分支,它用来训练模型的正例信号(Positive Actions)直接写着下面这一行:32
"ld_positive_actions": [recsys_pb2.ActionName.CLIENT_TWEET_RECAP_DWELLED],
而且这绝不是写在注释里的PPT概念——顺着模型代码 recsys_two_tower_model.py 和推理入口 model_runner.py 一路查到底,这个 ld 分支既有完整的训练损失计算,又在实时召回推理时按权重参与打分!
这意味着,读者的“停留阅读信号”现在在算法里会在两个环节各起一次作用:
- 第一次在“第一步抓候选(召回)”:
ld分支专门帮采购员学会分辨哪些帖子是大家愿意停下来读进去的,直接把你的干货帖从海量库里捞进读者的临时篮子; - 第二次在“第二步排座次(排序)”:进到篮子后,前面讲的
0.4点击停留和0.006连续停留系数再帮你把总分往上推!
当然,我们也得守住严谨的证据边界:CLIENT_TWEET_RECAP_DWELLED 这个客户端事件在手机 App 前端到底是按什么公式触发的,公开仓库里并没有放出前端源码,所以我们不能信口开河把它吹成“读者必须一字不落 100% 读到文章最后一个标点符号”,也不能把后面点击停留目标的“阈值 10”硬套到这个事件头上。32
这对创作者来说是一颗巨大的定心丸:像工具教程、配置报表和方案对照这类干货,读者的正常反应本来就是“静静看完、截图保存、照着操作”,本来就没啥好在评论区吵架的。千万别因为评论少,下一篇就焦虑地改写没营养的引战骂街帖! 与其花心思在每段结尾塞一句“真正核心的重点还在后面,千万别划走”来骗停留,不如检查一下文中的表格有没有直接回答痛点、操作步骤能不能照着跑通、例外情况有没有交代清楚——把干货写扎实,阅读召回分支自然会认出你。
10.1 阅读召回何时加入,只对小账号有效吗
围绕这个新增的 ld 阅读召回分支,网上还有两个传言:一是有人根据 10 月底的公告以为这是 10 月 28 日才刚上线的新功能;二是有人看到配置里有个 HOME_COLD,就宣称“阅读召回只对小账号有效,大号享受不到”。
我们直接拉出 Git 仓库的提交时间线和源码配置,把这两个疑问一次性查个水落石出:33
| 时间与版本 | 公开资料显示的变化 |
|---|---|
2026 年 10 月 8 日,35650fb | 当时的双塔召回具名配置里只有 home 与 immersive 两个分支,还没有 ld。 |
2026 年 10 月 13 日 08:05:54 UTC,e1a0375 | 公开提交正式加入 ld_positive_actions、ld 分支与分支权重 w_ld = 0.75,模型训练与推理代码也在同一次提交里同步上线。 |
2026 年 10 月 28 日,5ed7963 | 官方在 README.md 里补写了更新说明,将“找出人们会读到底的帖子”明确标示为 10 月 13 日的更新。 |
来源 33
你看,代码早在 10 月 13 日就已经合入公开库了,10 月 28 日只是在 README 文档里补了一笔记录(当然,公开提交时间依然不等于线上所有流量分桶在同一秒切换,如果某天你的阅读量波动,不能单凭日期就咬定是这次更新干的)。33
再看第二个问题:ld 阅读召回是不是只给小账号开的小灶?完全不是!
在 xrecsys_two_tower.py 的具名配置里,ld 分支与 home、immersive 并列(在 home-only 的具名版本里也同时保留了 home 与 ld),里面没有任何检查“作者粉丝数少于多少才启用”的小账号限制条件;而且它读取的数据集同时涵盖了 HOME、HOME_COLD、HOME_HOT,根本不是只针对其中某一个!
更重要的一点辟谣:千万别望文生义,把代码里的 HOME_COLD 翻译成“小粉丝账号专区”!
打开 phoenix/xrex/data/cold_pool_filter.py 源码一看就明白了:HOME_COLD(冷帖子池)筛选时读取的是单篇帖子的点赞数(fav_count)、观看数(view_count)以及帖子刚发出来的新鲜度!也就是说:
- 作者是个几百万粉的大 V还是几百粉的小号(作者粉丝数)、
- 正在刷首页的读者是不是刚注册的新用户(读者行为历史)、
- 这篇帖子本身是不是刚发出来还没攒够赞和观看的新帖(
HOME_COLD真正查的东西), 这三者在代码里是完全独立的三码事!哪怕是一个十万粉的成熟账号,刚发出一篇新文章时,只要符合冷帖筛选条件,一样会进HOME_COLD;而无论大号小号,都能享受ld阅读召回分支的训练与推理机制。33 34
具名 combined 配置:head_names = ["home", "immersive", "ld"]
w_ld = 0.75
通用模型设置:w_ld = 0.0;是否有 ld,仍取决于实际配置。
来源:33
这里顺带解释一下 w_ld = 0.75:这个 0.75 是这份具名双塔召回配置里 ld 分支的向量打分组合权重,绝不是“读者每读完一次就给帖子加 0.75 分”;同时,基础通用模型类里的默认 w_ld 写的是 0.0,说明线上具体某次请求用不用 ld、权重给多少,依然由该请求加载的具体配置文件决定。33
最后还要记住:双塔模型在训练时(recsys_two_tower_model.py),只是直接读取数据表里现成的 CLIENT_TWEET_RECAP_DWELLED 0/1 动作标记,模型自己并没有在训练代码里拿把尺子去量读者到底滑到了第几段。我们作为作者最该做的,是在第一段把要解决的痛点亮出来,在正文里老老实实兑现承诺的干货——代码里可没有任何“只要逼读者滑到 100% 底部就自动触发二轮全站爆推”的魔法开关。33
11 模型怎样区分不同长度的停留
既然系统这么看重“停留阅读”,那 AI 模型到底是怎么预测一个读者会在你的帖子上停留 3 秒、15 秒、还是 90 秒的?
前面我们提过,点击停留(CLICK_DWELL_TIME)在代码里只是一个简单的“二元判断(判断原始数值有没有跨过阈值 10.0)”。而在 2026 年 10 月 8 日官方宣布的“停留时间预测改进”中,真正挑大梁的黑科技叫做 CREAD(多门槛分类与连续时间重建)——在 home_direct_packed 排序模型配置中,AI 会把停留时间切成 30 道精细的时间刻度门槛来同时学习,最后再把预测概率还原成具体的阅读秒数!11 13 14 56
11.1 把停留时间拆成一组门槛
为什么要把停留时间切成 30 道门槛,而不是让 AI 直接猜一个秒数?因为不同读者的阅读停留时间跨度极大(有人扫一眼 2 秒划走,有人看长文或长视频看两三分钟),直接让神经网络回归预测一个秒数很容易被极端值带偏。
打开 phoenix/xrex/configs/xrecsys.py 和损失函数 loss_recsys.py,我们可以看到 CREAD 的切分方法非常巧妙:
- 对于普通信息流(非 Gallery)的停留预测头(head),系统从 2 秒到 120 秒(2 分钟) 之间,按**对数间隔(Log-spaced)**切出了 30 个时间门槛;
- 对于媒体画廊页(Gallery Page)的沉浸式停留预测头(immersive head),系统则从 2 秒一直延伸到 240 秒(4 分钟),同样按对数间隔切出 30 个时间门槛。
什么叫“对数间隔”?说白了就是**“前面刻度密、后面刻度疏”**——在 2 秒、3 秒、5 秒这些短停留区间,门槛切得非常密集(差一两秒就是一道新坎);而到了几十秒、上百秒的长阅读区间,门槛之间的跨度就变大了。(注意:这里的 120 秒和 240 秒仅仅是这两个模型预测头的刻度上限,绝不是说你的帖子字数或视频长度不能超过 2 分钟或 4 分钟!)13
# 概念重述,并非逐字源码;30 个门槛,k=0 到 29
threshold_k = 2.0 * (norm_scale / 2.0) ** (k / 29)
# 非 Gallery:norm_scale = 120.0
# Gallery Page:norm_scale = 240.0
# 以下一行为标签判断源码
targets = (gt_raw[..., None] > threshold_arr).astype(jnp.float32)
来源:13
你看最后一行源码:当系统拿真实阅读时长 gt_raw 去生成训练标签时,用的比较符号是严格大于(>)——只要观察到的真实停留时间严格超过了第 $k$ 道门槛,这道门槛的标签就记为 1,否则记为 0(刚好卡在门槛值上也是 0)。通过这种方式,AI 模型就能同时分别预测出:“这位读者在你帖子上停留超过 2 秒的概率是多少、超过 5 秒的概率是多少、超过 30 秒的概率是多少……”,再也不会把“看 11 秒”和“看 100 秒”粗暴地混成同一种结果了!13
11.2 再把这些概率还原成时间
既然 AI 预测出了 30 个门槛各自的过关概率,那在打分时,怎么把这 30 个概率变回一个具体的“预测停留秒数(比如 18.5 秒)”去乘那个 0.006 的连续停留权重呢?
打开模型推理代码 recsys_model.py,解码还原公式非常漂亮:先把 30 个门槛的输出值(logits)通过 sigmoid 函数变成 0 到 1 之间的过关概率 phi,然后拿每个门槛的过关概率,去乘以它和前一个门槛之间的“时间跨度(deltas)”,最后把 30 段加起来(第 1 个门槛的前置基准设为 0 秒)。正因为每一格对应的秒数宽度完全不同,千万不能把 30 个概率直接加在一起当成“最高加 30 分”或“30 次有效阅读”!13
# 公式重述,并非逐字源码
phi = sigmoid(cread_logits)
deltas = [t1 - 0, t2 - t1, ..., t30 - t29]
restored_time = sum(phi_k * deltas_k)
来源:13
我们用只有 3 个门槛的简化例子算一遍,你一秒钟就能看懂这个积分还原的思想:
假设 3 道门槛分别是 2 秒、5 秒、10 秒,那么它们相邻的时间跨度(deltas)依次是:$2-0=\mathbf{2}$ 秒、$5-2=\mathbf{3}$ 秒、$10-5=\mathbf{5}$ 秒。
现在 AI 预测某位读者看你的帖子,停留超过 2 秒的概率是 0.8(80%),超过 5 秒的概率是 0.5(50%),超过 10 秒的概率是 0.2(20%)。那么还原出来的预测停留时间就是:
$$0.8 \times 2\text{秒} + 0.5 \times 3\text{秒} + 0.2 \times 5\text{秒} = 1.6 + 1.5 + 1.0 = \mathbf{4.1\text{秒}}$$
然后再拿这个还原出来的 4.1 秒,送到后面去乘 0.006 的连续停留权重!(注:这里用 3 个门槛做算术演示;正式的 home_direct_packed 配置用的是 30 个对数门槛。)13
而且在训练这个模型时,程序员不仅考核 AI 对那 30 道二元选择题答得准不准(分类损失),cread_loss_compute 函数还会把还原出来的预测秒数和真实停留秒数放在一起对比,额外算一笔「总秒数算得准不准」的误差(时间重建误差,Restoration Loss)。算之前先把真实停留时间截断在量程内(120 秒或 240 秒);算误差用的是 Huber Loss(一种遇到极端值时不会被带偏太多的误差算法;相对权重 0.5、Huber 门槛 5.0 秒,另配合有效样本遮罩与负例权重),逼着模型把总秒数也算准。
在 home_direct_packed 的公开基础配置里,普通停留和沉浸式停留的 CREAD 损失权重(dwell_cread_loss_weight 与 dwell_cread_immersive_loss_weight)都被设为了 0.1,而老旧的 dwell_tweedie_loss_weight 与 dwell_mae_loss_weight 则被设为了 0(正式退役)。我们要分清:CREAD 损失权重 0.1 管的是模型训练阶段怎么学准停留秒数;而 Home Mixer 里的 0.006 管的是模型预测出秒数之后,在最终排座次时给每秒钟乘多少系数。13 15
11.3 四个容易混淆的“停留”指标
写到这里,我们已经遇到了四个长得很像、都跟“看帖子 / 停留”有关的指标。很多二传手文章把它们张冠李戴,我专门做了一张对照表帮你彻底厘清它们各自管哪一摊事:13 14 35 36
| 名称或字段 | 所在环节 | 这次查到的定义 | 仍不能推理的事 |
|---|---|---|---|
DWELL_TIME/CREAD | 排序模型训练与连续时间解码 | 30 个对数门槛分类 + 时间重建(120 秒/240 秒量程),输出预测停留秒数供 ContDwellTime(0.006)相乘 | 把文章字数硬拉长一倍,就能自动拿到双倍预测停留时间或双倍曝光 |
CLICK_DWELL_TIME | 具名排序模型的点击停留二元目标 | 二分类(binary),阈值 threshold = 10.0;输出为原始值严格大于 10.0 的概率,供 ContClickDwellTime(0.4)相乘 | 读者只要真实看满 10 秒,系统就当场给这篇帖子记账加 0.4 分 |
CLIENT_TWEET_RECAP_DWELLED/ld | Phoenix 第一步召回的正例及分支 | 双塔召回的 ld 分支把该事件列为训练正例(分支权重 w_ld = 0.75) | 这个前端事件一定代表 100% 读到全文末尾,或者直接共用上面那个 10.0 门槛 |
view_count_on_home | 小账号冷启动资格与探索抽样 | 候选帖身上携带的内部 Home 首页曝光累计次数;< 200 是冷启动的 5 大硬条件之一 | 它直接等于创作者在前台看到的总观看数(Views),或是系统保底白送 200 个独立读者的测试配额 |
表格第二行还有一处缺口要交代清楚。能追通的是两头:模型那边(model_runner.py)确实返回这个「达标概率」;Home Mixer 这边(scoring.rs)确实读了名叫 click_dwell_time 的预测字段,乘上 0.4。中间把模型返回值转成这个字段的那段转换代码(adapter),公开仓库里没有放出来。55
gt_binary = (gt_raw.astype(jnp.float32) > threshold).astype(jnp.float32)
我在本地 CPU 上直接调用原函数传入 [9, 10, 10.0001, 20] 跑过实测验证,输出的标签依次是 0, 0, 1, 1——证实了刚好等于 10 时依然是 0(必须严格大于 10 才为 1)。但要说清这次测试证明了什么、没证明什么:它只证明了数学上的边界——必须严格大于 10,刚好等于 10 不算。至于这个 10 的单位是什么、点开 Article 算不算进去、最后能换来多少曝光,上游代码没公开,这次测试答不了,我们只按代码写的说「超过阈值 10」。98
把这些代码逻辑落实到我们平时写稿上,道理其实朴素得不能再朴素了:你想让读者在你的帖子上多停留一会儿,你首先得在帖子里摆出真正值得他看上二三十秒的硬货!
- 拿写“怎么跟客户谈报价”来说:你在第一句话里答应给读者看“原方案与缩减方案的报价对照”,那正文紧接着就得把两份报价单亮出来;答应讲“降价不减量怎么翻车的失败案例”,就老老实实把当时客户是怎么一步步扯皮的过程写出来。读者眼里有实打实的材料可看,停留时间自然就上去了。
- 反过来,如果你本来只有三句话的干货,为了迎合算法硬把它注水拉长成十段,中间每隔两段就写一句车轱辘话:“大家先别急,真正决定成败的第三个重点在最后面……”——这根本不是在增加阅读价值,而是在消耗读者的耐心,极大概率让人直接划走(触发
-0.02的Not dwelled惩罚)甚至反手点一个“不感兴趣(-52.272)”! - 配图也是同一个道理:如果你放了一张方案对比表,字号一定要调到在手机屏幕上能轻松看清“左边删了哪几项、右边省了多少钱”。如果图片字缩得像蚂蚁一样小,读者点开大图(哪怕触发了
Photo expand0.05)放大还是糊成一团看不清,他来你帖子里想解决的问题没解决,下次刷到你的名字就不会再点开了。
11.4 读者多花的时间,要有东西可读
所以,日常创作时千万别把“怎么在开头设套路把读者骗满 10 秒钟”当成写作目标:
- 如果一张清晰的对照表让读者花 6 秒钟就找到了他急需的参数、心满意足地收藏离开,那这 6 秒就是高质量的有效停留;
- 如果一篇深度测评报告确实需要读者花 90 秒才能看完,那就把测试样本、对比数据和翻车反例铺陈扎实,让读者每往下滑一段都能读到新信息。
官方在更新日志里说 CREAD 让停留时间预测变得“更准更好”,公开代码也让我们亲眼看到了这套 30 门槛对数重建的精妙设计;但由于官方没有一并公开评测数据集、误差下降百分比和线上 A/B 实验结果,我们可以把 CREAD 的运作原理讲得明明白白,但绝不凭空捏造“准确率提升了百分之多少”、“长文流量从此暴涨多少倍”、或者宣称“短帖从此彻底失宠”。11 13
12 第 1 个赞和第 32 个赞,究竟触发了什么
网上有一句流传很广的“破圈密码”:“帖子发出后,拿到第 1 个赞(1fav)就能进入初级推荐池;攒够第 32 个赞(32fav)就能解锁高级陌生人流量池!”
去翻公开代码库,1fav 和 32fav 这两个名字确实白纸黑字地写在索引模块里,所以这句传言并不是凭空编造的。但问题在于:二传手们把**“触发索引更新”、“写进某个数据库名单”、“被召回采购员读取”和“最终展示在陌生人首页上”**这四个完全不同的步骤画上了等号!单靠一条入库条件,系统可从来没给任何人承诺过保底曝光。37 38 34
我们先顺着“有人给你的帖子点了一个赞”那一刻往后看:
在 phoenix-rankall-strato/columns/favoriteEventProcessor.strato 里,有一个专门监听点赞事件的处理器叫 favoriteEventProcessor。当它收到一笔 Favorite(点赞)事件时,首先得能从事件数据包里正常读出当前的累计点赞数(favorite count),如果读不到计数就直接放弃这次更新请求(注意:非点赞事件比如取消赞在这个处理器里会被直接忽略,但不能由此夸大成整套 X 系统完全不处理取消赞)。
接着,程序会去查缓存记录:这篇帖子之前有没有送出过索引更新? 根据“还没有缓存记录(第一次触发)”和“已经有缓存记录(后续触发)”,它会分别走两套截然不同的检查条件:37
| 事件情况 | 这里实际检查什么 | 边界 | 不能推成什么 |
|---|---|---|---|
| 尚无更新缓存(首次触发) | 帖子还没超龄,且当前点赞数低于系统计数上限 | 帖子年龄必须严格小于 49 小时;点赞数小于 $2^{30}$ | 并不是只有 count == 1 才能第一次送出索引请求(如果第一次处理时已经 3 个赞了也照样过) |
| 已有更新缓存(后续更新) | 点赞数达到了下一个二次幂门槛;距离上次更新已经过了至少 1 分钟;距离首次更新和帖子本身都没超龄 | 更新间隔 ≥ 1 分钟;距首次更新 ≤ 48 小时;帖子年龄 < 49 小时 | 绝不是每多收 1 个赞就立刻刷新一次索引或扩大一次分发 |
| 计数缺失 | 无法从事件数据包里读出 favorite count | 直接跳过,不发送这次索引请求 | 前台界面显示有人点赞了,不代表后台每个内部索引步骤都已经同步跑完 |
| 建立时间缺失 | 计算帖子年龄时,如果缺失创建时间则默认填 0 | 在当前年份(2026 年)减 0 会直接判定为几十年老帖(超龄淘汰) | 不能把缺失时间戳误以为是“不受年龄限制、永久有效” |
来源 37
已有缓存时,必须同时符合:
距首次索引更新 <= 48 小时
帖子年龄 < 49 小时
目前赞数 >= nextTriggerThreshold
目前赞数 < 2^30
距最近索引更新 >= 1 分钟
来源:37
你看上面这几行硬代码里的不等号,每一处都有讲究:
- “距离第一次索引更新”用的是
<= 48 小时(超过 48 小时才排除); - “帖子本身的发布年龄”用的是
< 49 小时(一满 49 小时就排除); - 两次索引更新之间还卡了一道
>= 1 分钟的节流阀(1 分钟之内的密集点赞绝不重复触发更新)。 这些数字只管favoriteEventProcessor这一个点赞事件处理器“要不要往后发送索引更新请求”,跟后面首页候选池的 48 小时年龄过滤(AgeFilter)各管各的摊子,千万别把它们揉成一个统一的“发帖倒计时闹钟”。37 39
12.1 到了 32 个赞,索引也未必立刻更新
为什么大家总是提到 1 和 32 这两个数字?因为在 favoriteEventProcessor.strato 里,每当成功发送一次索引更新后,程序就会把“下一次触发更新的点赞门槛(nextTriggerThreshold)”设定为高于当前点赞数的下一个 2 的次方(二次幂)!
- 当你拿到 1 个赞更新后,下一道门槛就设为 $2^1 = \mathbf{2}$ 个赞;
- 后面依次是 4、8、16、32、64、128……
- 假如某次事件处理时,你的帖子一口气涨到了 33 个赞,程序算出来的下一道门槛同样是 64 个赞,而不会倒回去补跑中间跳过的数字。37
count > 0 时:
nextTriggerThreshold = 2^(floor(log2(count)) + 1)
count == 0 的公开特例:
nextTriggerThreshold = 2
来源:37
看懂了这个“2 的次方门槛 + 1 分钟节流阀”,我给你举个完全符合代码逻辑的真实场景,你就明白为什么盯着前台“第 32 个赞”毫无意义了:
假设你的帖子刚发出来挺受欢迎,在拿到 16 个赞的那一刻刚刚触发了一次索引更新(此时系统把下一道门槛设为了 32)。结果才过了 30 秒(半分钟),你的帖子就迅速冲到了 32 个赞!
请问:这第 32 个赞会触发索引更新吗?
不会! 因为虽然你的点赞数已经达到了 nextTriggerThreshold(32 赞),但距离上一次(16 赞时)的更新还不到 1 分钟(才过了 30 秒),直接被 距最近索引更新 >= 1 分钟 这道节流阀给拦下了!至于 1 分钟之后还能不能补上更新,得看后面还有没有新的点赞事件进来、以及何时处理成功。(注:这是严格按照源码条件推导的算例,未使用真实账号线上日志。)37
所以,当你看到自己帖子的点赞数停在 31、32 或者 33 个赞时,千万别神神叨叨地诊断说“哎呀,我的帖子正在等第 32 个赞解锁新流量池”,更别到处拉群求朋友帮你点满 32 个赞——认真在评论区回答读者的具体问题、补充有用的资料才实在;代码里根本没有“凑满 32 个赞就自动发一批陌生人流量”的机制。37 34
12.2 1fav 和 32fav 各自怎样收录内容
当点赞更新请求顺利通过了前面那道门,被送到下一站候选处理器 phoenixRankAllCandidateProcessor.strato 后,程序并不会闭着眼睛直接入库,而是会重新去数据库读取一遍这篇帖子的最新详情与互动计数,然后按照事件来源、是不是社群(Community)帖子、是不是回复或转发、以及安全可见性条件进行分流:
在普通合格原创帖的点赞分支(Fav 分支)里,程序会先建立 1fav、备份与主题相关索引,然后再单独判断够不够资格写进 32fav 和专属视频索引。也就是说,光有一笔点赞事件,绝不等于所有索引名单都会把这篇帖子收进去:38
| 索引 | 可见的主要入库条件 | 重要细节 | 对运营说法的限制 |
|---|---|---|---|
1fav | 进入一般合格帖子的 Fav 分支 | build1FavIndex 函数内部并没有再卡一道 赞数 >= 1;甚至重新读到 0 赞时,只会记一笔竞态日志,照样把帖子送进 1fav 索引! | 虽然名字叫 1fav,但后台不同服务间的点赞计数在收到第 1 个赞时未必毫秒级同步 |
32fav | 进入一般合格帖子的 Fav 分支,且重新读取到的 favoriteCount >= 32 | 判断条件是 >= 32(大于等于 32),不是只认准第 32 个赞那一次事件 | 写进 32fav 索引只代表存进了这个数据桶,绝不能直接换算成陌生人曝光量 |
search_unfiltered | Fav 事件、非社群帖子、非普通转发,且计数 >= 1 | 排在后面的回复分流与一般可见性过滤之前建立 | 进了搜索索引库,不能拿来当成已经放行进入 For You 推荐流的证据 |
1fav_reply/32fav_reply | Fav 事件下的合格回复帖;明确排除作者自回自评(self-reply)与在此处被过滤的回复 | 32fav_reply 另外要求重新读到的点赞数 >= 32;回复帖走的是自己独立的索引名 | 就算建了回复专属索引,也不证明线上每个首页召回源都在读取它 |
post_creation | 一般合格帖子的 PostCreation(发帖创建)分支 | 在你刚刚按下发帖键(0 赞)时就会另外建立这个索引 | 铁证如山:绝不能把“拿到第 1 个赞”当成整套推荐系统所有索引的共同唯一起点! |
来源 38
build1FavIndex 的计数竞态处理:
若重新读到的 favoriteCount == 0:记录 1fav_uec_count_race
然后仍送出 indexName = "1fav" 的索引事件。
来源:38
你看上面这段源码细节有多真实:在 build1FavIndex 函数里,程序员甚至专门写了一段处理“重新读到的点赞数为 0”的代码——当发现事件触发了、但另一边数据库查出来的 favoriteCount 还是 0 时,系统会记录一条叫 1fav_uec_count_race(点赞计数读写竞态不同步)的监控指标,然后照样把这篇帖子写进 indexName = "1fav" 的索引里!这再一次告诉我们:后台分布式系统的计数同步本来就有微小延迟,千万别把手机屏幕上显示的点赞数字当成精密无误的“算法进度条”(当然,这只是处理读写延迟的兜底逻辑,不代表系统故意把所有零赞帖子都无脑塞进 1fav)。38
同时还要注意:普通帖子的这条主索引流程,会直接跳过社群(Community)帖子与普通转发(Retweet),回复帖(Reply)则被分流到独立的 1fav_reply 分支;如果帖子带有可见性限制或成人内容(NSFW)标记,也会被分流到特定分支处理。这些前置资格缺一不可,绝不能掐头去尾简写成“只要是原创帖,拿到 1 个赞就会全网推流”。38
12.3 索引建好了,还要查谁在读取它
把帖子写进索引库,就好比把商品摆进了仓库货架;货架上有货,还得看前面的“召回采购员”去不去这个货架拿货!
我们顺着代码去查数据消费端(phoenix-rankall/src/config/mod.rs 和 phoenix/xrex/data/retrieval_dataset.py):
在 rankall 的公开时间窗口配置里,确实同时定义了 1fav 的 24 小时与 48 小时窗口,以及 32fav 的 24 小时窗口,写入的索引事件也会被路由到对应的数据桶里。但当我们去查**“普通 For You 首页到底在读哪个数据文件”**时,发现了最关键的证据差异:34
| 数据层 | 公开程序中已追到的内容 |
|---|---|
1fav 的生产与存储 | 合格点赞事件会产生 1fav 索引事件,存储层设有对应的 24 小时/48 小时窗口。 |
| 普通 Home 推荐流的消费 | RetrievalDataset 里的三大主力数据集——HOME、HOME_COLD、HOME_HOT——全部白纸黑字地明确引用 1fav_1day.parquet(即 1fav 的 24 小时库)! |
| 冷/热 Home 池的切分 | HOME_COLD 与 HOME_HOT 都是从同一个 HOME(1fav_1day.parquet)数据源读进来的,只是再按“冷帖子条件(点赞数、观看数、新鲜度)”切分成两半——根本不是 HOME_COLD 代表 1 赞、HOME_HOT 代表 32 赞! |
32fav 的生产与存储 | 确实有 favoriteCount >= 32 的入库条件、索引事件与 24 小时存储窗口(32fav_1day)。 |
普通 32fav 的消费端(证据缺口) | 在这份公开的 For You 代码树里,自始至终没有找到任何一个具体的普通首页召回服务在读取 32fav_1day!(此处严格保留为证据缺口。) |
你看:在 RetrievalDataset 枚举列表里,唯一一个名字里带 32Fav 的读取项叫做 IMMERSIVE32FavVideo14To30Day,它读取的文件是 32fav_video_14to30day.parquet——那是专门给沉浸式视频流准备的“14 到 30 天老视频库”,根本不能拿来给普通图文帖的“第 32 个赞解锁 For You 大流量池”圆场!当然,本着严谨原则,普通 32fav_1day 也许被公开仓库之外的某个内部服务读取,或者由未公开的线上配置调用;但在公开代码能证明的范围里,我们只能确认“系统生产并存储了 32fav”,绝不能替未知的部分打包票说“满 32 个赞必得一波新推荐”。34
哪怕是实打实被 HOME 读取的 1fav_1day.parquet,帖子被采购员抓进临时篮子后,也照样要过已读过滤、关注关系、48 小时年龄限制、模型预测打分和同作者衰减等一连串关卡。你在账号后台分析(Analytics)里看到的曝光数,只是这一切跑完之后的最终结果;至于某篇帖子到底进了哪个库、为什么在某次刷新里输给了别人的帖子,没有内部服务器请求日志谁也看不见,千万别拿面板上的几个赞去生搬硬套。34
13 收藏没有独立加权项,系统仍然会用它
很多做干货教程、工具清单的博主都会注意到一个现象:自己的帖子经常是“点赞只有十几个,但收藏(Bookmark)却有上百个”。可是一翻前面的 24 项融合打分权重表(xai-value-model/weights.rs 和 scoring.rs),心又凉了半截:主计分表里居然压根没有 bookmark(收藏)这一项!网上甚至因此传言“收藏在 X 算法里是 0 分,一丁点用都没有”。
别被“主计分表里没单列”骗了! 当一位读者把你的干货模板点进收藏夹,往往意味着他准备过两天干活时翻出来照着用。我们顺着收藏数据流(BookmarkMetadata)在代码库里一路往下追,揪出了收藏在推荐系统里的两大隐藏核心用途!2 40
第一个隐藏用途,在个性化相似内容召回(SimClusters)里:
打开 explicit_engagement_signals_query_hydrator.rs 和 simclusters_source.rs,你会看到:当读者刷首页时,系统不仅会读取他最近点过赞、转发过的帖子,还会专门读取他最近的收藏记录(BookmarkMetadata)!然后,SimClusters 采购员会把这位读者最近收藏过的帖子 ID 和其他互动帖子合并在一起,当成**“寻找相似好帖的种子(Seeds)”**,去全站捞取跟这些收藏帖主题高度相似的新帖子!(这条路的公开开关默认全部开启;能不能生效,还要看这个召回源当次启没启用、种子数量、种子年龄和候选筛选这几项条件。)40
这里要注意作用对象:假设读者甲收藏了你写的《中文发票整理与自动对账教程》,那么你这篇帖子的 ID 就会变成甲的“兴趣种子”。等甲明天、后天再刷首页时,SimClusters 就会拿着你这篇帖子的种子去帮甲找相似的效率工具新帖——找回来的可能是同行写的同类干货,也很可能是你接下来刚发的下一篇财务自动化新帖!(当然,还要看后续过滤和打分,代码没有写成“只要甲收藏了你的旧帖,就100%保送你的下一篇”。)40
13.1 收藏也会参与召回模型训练
除了在 SimClusters 里当相似召回种子,收藏还有第二个更硬核的用途:直接作为双塔召回大模型的训练正例!
打开 phoenix/xrex/configs/xrecsys_two_tower.py,在双塔召回模型的沉浸式分支正例清单(immersive_positive_actions)里,CLIENT_TWEET_BOOKMARK(客户端收藏帖子动作)赫然在列,与点赞、回复、转发、视频品质观看、关注作者和分享等核心正向动作平起平坐!模型在训练时会直接拿包括收藏在内的正负例计算损失函数——也就是说,虽然收藏不在最后一步的融合公式里按“每个收藏加几分”算死账,但它直接教会了上游召回大模型“什么样的帖子是用户喜欢存下来的好内容”!41
immersive_positive_actions 包含:
recsys_pb2.ActionName.CLIENT_TWEET_BOOKMARK
来源:41
把“收藏(Bookmark)”在整套算法库里的三个位置摆在一起对比,你就再也不会被“收藏零分无用论”误导了:41
| 位置 | 收藏在这里怎么用 | 作用对象 | 不能保证的结果 |
|---|---|---|---|
共用融合打分公式(scoring.rs) | 没有单独列出 bookmark 权重字段 | 最终排序打分环节的加权和计算 | 绝不能因为这一处公式没列字段,就扩大成“整套 X 算法完全不看收藏” |
SimClusters 相似内容召回 | 读者收藏帖子的 ID 会并入相似内容查询种子(每类最多保留最近 15 笔) | 点下收藏按钮的那位读者本人,及其后续刷首页时的候选召回 | 不保证再把已读原文推一遍,也不算作给作者存下了固定的“流量兑换券” |
双塔模型 immersive 分支训练 | CLIENT_TWEET_BOOKMARK 被明确列入该分支的训练正例(Positive Actions) | 训练召回模型学会识别哪些候选内容值得被捞回 | 这是模型训练目标,不等于普通首页每多一个收藏就立刻给单篇帖子加固定分数 |
来源 41
我们再把 SimClusters 这条收藏种子路径的边界数字抠清楚(home-mixer/params/param.rs 与 simclusters_source.rs):
- 数量上限:公开参数里,每类显式互动信号最多保留读者最近的 15 笔(且要求
SimClusters召回源启用、当前请求不是仅限圈内关系网请求、不是已带缓存帖子的请求,并存在可用信号); - 两个年龄限制(90 天 vs 48 小时):作为种子的那篇被收藏帖子,它本身的发布年龄必须在 90 天以内;而用这颗种子去捞出来的相似新候选帖,按公开默认则限制在发布 48 小时以内(并受相似度分数门槛与返回数量上限约束)。
这里有一个非常容易搞混的时间细节:90 天种子有效期,查的是“被收藏那篇原帖自己的发布时间(tweet_id 创建时间)”,而不是“读者点收藏按钮的那一天”!
打个比方:假如读者今天翻到了你两年前写的一篇老教程,觉得太棒了,今天顺手点了收藏——虽然收藏动作发生在今天,但因为那篇老帖本身的年龄已经超过了 90 天,在 SimClusters 这道种子年龄检查里它依然会被排除掉。先说清这句的范围:这只说明它在 SimClusters 这一条路里当不了种子,不代表收藏旧文章在其他模型特征里也完全没用。另外这里讲的是公开默认开关,代替不了线上每次请求的实际配置。。41
所以,当我们写工具模板、配置指南和避坑清单时,最好在文末清晰标出**“这张表在什么场景下用、每个字段代表什么意思、最后更新于哪一天”**——这样收藏你的读者过半个月回来翻收藏夹时能立刻用上,而你在 48 小时内继续发布同系列的深度内容时,也更容易接住 SimClusters 顺着收藏种子捞过来的精准读者!41
13.2 给读者一个下次还会用到它的理由
怎么把一篇普通的观点帖,改造成让读者忍不住想点“收藏”和“复制链接”的实用工具帖? 我们拿写**“如何挑选 AI 会议纪要/录音转写工具”来举个实操例子:如果整篇帖子只是主观地给 A、B、C 三款工具排个名(“第一名某某、第二名某某”),读者扫一眼记住名字就划走了,根本没必要收藏。 但如果你在帖子里给出一套读者下次自己测试任何会议工具时都能直接拿去套用的“3 句话试金石对照表”——教读者看 AI 摘要会不会漏掉否决条件**、能不能分清讨论提案与最终决议、会不会把待确认事项瞎编成已拍板定案,甚至连测试用的 3 句标准输入台词都帮读者准备好了:
| 检查项目 | 可用的范例输入(可直接喂给工具测试) | 核对 AI 摘要时重点看什么 | 记录测试结果 |
|---|---|---|---|
| 否决条件 | “若需要把客户原始资料上传到外部公有云,这个方案就不采用。” | 摘要里是否完整保留了前提条件与“不采用”的底线 | 通过/漏记/写反 |
| 提案与决议 | “刚才说的只是建议下个月先小范围试用,今天还没同意正式采购。” | 摘要是否把“建议试用”错误写成“已决定采购” | 通过/漏记/写反 |
| 待确认事项 | “具体的年度预算额度,等下周三财务核对后再最终确认。” | 摘要是否擅自脑补写成“预算已核准通过” | 通过/漏记/写反 |
每当你评测一款新工具,就把这三句话喂进去,在最后一栏填上实测结果,并注明工具版本号、测试日期和适用语种。在帖子结尾,你根本不需要干巴巴地求读者“大家记得点赞收藏啊”,只需要自然地写上这样一段话:
可以这样结尾: “下次你们团队选型任何 AI 会议纪要工具,都可以先拿上面这三句带陷阱的原话测一遍,再对照录音原文核查。别光看 AI 生成的排版顺不顺眼,重点看它有没有把‘还没定的提议’瞎写成‘已经拍板的决议’。”
你看,这样一段结尾直接告诉了读者**“这张表什么时候拿出来用、具体怎么测”**,任何有选型需求的读者看到,第一反应就是点一下“收藏(Bookmark)”存进自己的工具箱,或者点一下“复制链接(Share via copy link,预测权重高达 20)”发进公司的飞书/微信工作群!当然,如果是发一条突发新闻快讯或临时通知,就没必要硬拗成工具表了,形式永远为内容服务。
这里也顺便把“私下传播”的机制拎清楚:在主计分表里,**私信分享(Share via DM,权重 5)和复制链接(Share via copy link,权重 20)**拥有极高的独立预测权重,这和上面讲的“收藏进入 SimClusters 种子”是两条并行的路径。很多深度的行业分析帖,表面上看公开转推(Retweet)不多,但大家都在疯狂点“复制链接”往私密群里转,这种帖子在模型眼里照样是含金量极高的优质内容(只不过仅凭公开代码,我们在前台看不到别人的帖子一共被点了多少次复制链接或私信分享)。2 21 40
14 互相关注的加成,对哪位读者生效
在前面的 24 项权重表里,有一项高达 20 的巨额权重特别吸睛:“符合互关条件的回复预测项(5 + 15 = 20)”。
不少人看到这个 20,马上衍生出两套江湖打法:
- 第一套打法:“那我见人就互关(Follow back),攒几千个互关好友,发什么帖子岂不是所有互动权重都翻 4 倍?”
- 第二套打法:“我和几个大 V 互相关注了,那我天天蹲在大 V 的评论区抢沙发留言,我的这条回复就能拿到 20 倍权重冲上热评第一!”
我们直接把 xai-value-model/inputs.rs 和 weights.rs 里的判断源码拿出来对质,这两套幻想当场就破灭了:42
!self.is_reply && !self.is_retweet && self.is_mutual_follow_author
请逐字看清上面这行 Rust 代码里的三个 &&(必须全部同时满足):
!self.is_reply:当前被打分的这篇候选帖子,绝对不能是一条回复贴(Reply)!!self.is_retweet:当前被打分的这篇候选帖子,绝对不能是一条普通转发(Retweet)!self.is_mutual_follow_author:当前正在刷首页的这位读者,与这篇原创帖的作者之间,必须是**双向互相关注(Mutual Follow)**关系!
只有当这三条铁律同时成立时,程序才会把“预测这位互关读者给你留言回复”的权重系数,从基础的 5 加上互关加成 15,变成 20!
注意看它的边界:
- 它只给**“回复预测”**这一项加 15 分,并不是把点赞、转发、停留等所有互动项一起乘以 4;而且代码里专门有一个“互关停留额外加成”参数,在当前公开默认值里设的是
0(一分不加)! - 这项加成是**“因读者而异”**的!假设你发了一篇原创帖,当你的互关好友李四刷到它时,如果 AI 预测李四有 2%(
0.02)的概率会留言回复,那么在李四的篮子里,回复项贡献的分数会从5 × 0.02 = 0.10暴涨到20 × 0.02 = 0.40;但同一秒钟,当一个还没关注你的陌生读者王五刷到同一篇帖子时,王五和你不互关(is_mutual_follow_author = false),在王五的篮子里回复系数依然是普通的5!42
| 同一个回复概率假设 | 采用系数 | 符合互关条件 | 这个项目的贡献 |
|---|---|---|---|
| 预测读者回复为 2%(非互关读者) | 5 | 不适用 | 0.10 |
| 预测读者回复为 2%(互关好友) | 5+15 | 适用 | 0.40 |
固定同一个 2% 的回复预测概率,在互关好友面前,单单回复这一项的得分确实从 0.10 变成了 0.40(涨了 4 倍);但由于总分里还有其他二十多项正负预测和后续调整,这绝不等于全站总曝光翻了 4 倍。42
14.1 普通关注关系还有另一项乘数
除了“互关好友看原创帖时回复权重变 20”,关注关系在 VM Ranker 里还有另一道非常关键的乘数:圈外候选乘数(Out-Of-Network Multiplier,简称 OON 乘数)。
在 vm-ranker/params.rs 的公开默认值里,针对“读者尚未关注该作者”的普通关系网外候选帖,系统设置了一个默认值为 0.75 的 OON 乘数!
我们来算一下这个 0.75 意味着什么:如果固定其他所有条件不变,只对比这一项乘数,一篇来自陌生人的“圈外帖子(乘 0.75)”,在套用乘数之前的原始分数必须达到“已关注作者圈内帖子(乘 1.0)”的 $1 \div 0.75 \approx \mathbf{1.3333}$ 倍(即高出约 33.3%),打完折之后的最终分数才能和圈内帖子打个平手!86
当然,这是在同一个候选池里比拼分数的数学条件,不能粗暴翻译成“陌生人曝光一定比粉丝少 25%”。(有两个例外记在这里:主题请求 Topic Request 用的是它自己的一套配置;另外代码也允许把这套乘数设置,用到一部分圈内回复和转发上。)把“粉丝圈内 1.0 vs 圈外 0.75”和前面的“互关好友原创帖回复系数 5 + 15 = 20”结合起来看,你会明白关注关系在不同环节各司其职,但绝不是一张“账号每多一万粉丝就固定加多少分”的等级表。86
特别是前面提到的“去大 V 评论区抢前排留言”:当你在大 V 帖子底下发了一条回复,你发出去的那条东西本身就是一条 Reply(is_reply = true),在前面第一关 !self.is_reply 就被直接踢出局了!哪怕你和那个大 V、或者和刷评论区的读者互相关注,你的这条评论也绝对拿不到 5 + 15 = 20 的互关加成(它依然可以在对话详情页里被点开评论区的人看到,但别拿互关 20 倍权重来给“到处抢热评一楼”当理论依据)。24 42
14.2 让熟悉这个问题的人有话可接
看懂了“互关好友对原创帖的回复预测高达 20”,那我们真正该怎么用好这个机制?
答案不是去搞僵尸粉互关群(僵尸粉根本不会看你的专业内容,AI 预测他们回复你的概率接近于 0,乘以 20 还是 0!),而是要和真正同领域的同行、老读者建立互关,并在写原创帖时“留出让内行同行有话可接的专业话头”!
举两个最接地气的例子:
- 假如你是做小型餐饮创业内容的:别发那种“今天又是努力搬砖的一天,餐饮人加油”的万能正确的废话——改成直接列出两款真实外卖打包盒在送汤面时的成本与漏汤率对比,然后抛出一句同行每天都在面对的真问题:“你们店里送带汤米粉时,用的是卡扣碗还是封口膜?哪一种更容易被顾客投诉洒漏?” 关注你的餐饮同行一看到这个问题,手痒痒立刻就会在底下回一段自己的实测经验!
- 假如你是做程序员技术开发内容的:遇到一个诡异的报错,别光发一句“终于修好了”,而是把报错日志截图、运行环境版本号、以及你已经排除掉的三个假原因列出来,让同样踩过这个坑的同行能顺着你的排查思路补上他遇到过的边界案例。
当互关的同行在评论区补上了极有价值的反例或新场景,你核对属实后,又可以把它整理进下一篇原创帖里。这样你的互关圈子就变成了一个真正高活跃度的“专业智库”——每当你发出一篇新原创帖,系统在算这批互关同行会不会回复时,用的是 5 + 15 = 20 这个系数——乘的仍然是每位读者各自的预测概率,系数大不等于一定推得起来,总分还要看其他二十多项。
15 读者点进主页后,为什么要关注你
很多创作者发现后台数据里有很多“个人主页点击(Profile Clicks)”,以为只要把人骗进主页,这篇帖子的算法分数就能大涨。
我们直接看 home-mixer/params/param.rs 和 scoring.rs 里的公开默认权重表,这两项的待遇天差地别:43
| 预测项目 | 这组公开默认的直接系数 |
|---|---|
点进作者个人页面(profile_click) | 0 |
关注作者(follow_author) | 4 |
你看:单纯“点进作者个人主页(profile_click)”在主融合打分公式里的直接权重系数是 0 分!而“关注作者(follow_author)”的预测权重系数则是整整 4 分(比点赞的 0.66 高出 6 倍多)!
(当然,同样要说明边界:这不等于每涨一个粉丝给帖子记账加 4 分,而且 VM Ranker 另有个人页停留等相关参数,个人页点击也是促成关注的前置动作,可能在模型的其他特征里被使用。)43
不仅如此,在同一个算法库的 V8.2 内容理解代码(grox/flows/mm_emb/renderer_v82.py)里,当 AI 模型去理解你发的帖子时,除了读帖子的正文和首图,还会把**作者的显示名称(Display Name)、账号名(Username / Handle)以及个人简介(Bio,按字符上限截断后)**一并拼进文本输入里喂给多模态大模型!这证明了:你的个人简介(Bio)不仅给点进主页的真人读者看,在这条流程里也是 AI 大模型直接看得到的输入资料!(不过代码里只是把 Bio 读进去做语义理解,没有任何“在简介里塞满热门关键词就能额外加分”的作弊公式。)44
15.1 把帖子、简介和置顶连起来看
既然“点进主页本身是 0 分,点进主页后愿意点关注才有 4 分的高权重”,那我们必须想明白一件事:一个陌生读者刷到你的一篇好帖子,好奇地点进你的个人主页,他在那 3 秒钟里看到了什么,才会决定按下“关注(Follow)”按钮?
设想一个最常见的翻车现场:
假设你持续在做“AI 办公工具实测”,今天刚发了一篇硬核好帖《实测某会议纪要 AI:居然漏掉了客户的否决条件》,吸引了一大批做项目管理的读者点进你的主页。结果人家一进你主页,看到你的个人简介(Bio)写着八个大字:“热爱科技,探索未来,感悟人生”;再往下看你的置顶帖,是一条半年前转发的锦鲤抽奖或者不知所云的心情吐槽。
这位读者脑子里立马打出一个问号:“这人到底是个刚巧写了一篇测评的路人,还是以后会持续输出这类工具实测?” 他拿不准关注你以后会刷到什么,干脆关掉主页走了——你白白拿了一个 0 分的主页点击,丢掉了一个权重高达 4 分的“关注作者”转化!
怎么改?把你的**单篇爆款帖、个人简介(Bio)和主页置顶帖(Pinned Post)**串成一条严丝合缝的证据链:
个人简介(Bio)可以改成这样具体、可验证的承诺: “专注实测 AI 工具在真实中文办公流里的表现。每篇评测均保留原始测试样本、翻车反例与可复现的操作步骤。”
紧接着,在你的主页置顶位置,直接挂上你写得最扎实、证据最完整的一篇代表作(比如你的评测方法论总纲或最硬核的一期多工具横评,题目明确、数据可查、适用边界清楚)。 哪怕你是做美食食谱的账号,道理也一模一样:简介别写“唯爱与美食不可辜负”,改成**“专做一人食、一口平底锅搞定的快手晚餐,每道菜都标好超市随手能买的替代食材”**,然后置顶一篇最受好评的平底锅食谱合集去兑现这句话!
每次发完新帖子,不妨切到访客视角,把你刚发的这篇帖子、你的 Bio 简介和置顶帖连起来读一遍:被今天这篇帖子吸引点进主页的陌生人,能不能在 3 秒内看懂你接下来还会持续为他提供什么价值?(把简介改具体是为了提高真人读者的关注转化率、让 AI 更清晰地识别账号语义定位,但别轻信网上说的“只要改几个简介词就能一键重置账号受众池”。)
16 评论多了,也要看看是什么人在说什么
运营圈里还有一种很危险的套路:“既然一般回复(Reply)的权重高达 5 分(是点赞 0.66 的近 8 倍),那我故意在帖子里说一句极端偏激的话、或者留个低级常识错误,引诱全网来评论区骂我、纠正我,评论刷爆了流量岂不是起飞?”
千万别玩这种火!
打开 scoring.rs、home-mixer/params/param.rs 和 vm-ranker/params.rs 看看融合公式的下半部分你就知道为什么了:系统在算正向互动预测的同时,把四个一票否决级的负向惩罚项死死钉在了公式里:2 45
- 预测读者屏蔽拉黑你(
Block author):权重-31.2; - 预测读者点**“对这篇帖子不感兴趣(
Not interested)”**:权重-52.272(VM Ranker 为-47.52); - 预测读者静音你(
Mute author):权重-58.8; - 预测读者举报你(
Report):权重-234.0!
你看清这几个负数的量级了吗?
一条普通回复的权重是 +5,而一个“不感兴趣”的系数是 -52.272,一个“举报”更是 -234.0。注意,这几个数字乘的都是预测概率,不能换算成“顶多少条回复”;能说的只是:负向系数的量级比正向大得多。当你靠引战、攻击别人或低级钓鱼把评论区吵翻天时,回复预测概率确实涨了一点,但厌烦你的读者顺手点“不感兴趣、静音、拉黑、举报”的负向预测概率也会同步暴涨——正负一相抵,你的帖子总分当场就会被砸成负数!
更直接的惩罚还在后面:一旦某个读者真的因为看烦了你的引战帖,对你点下了静音(Mute)或屏蔽(Block),在后续所有推荐请求的评分前过滤阶段,关系过滤器 author_socialgraph_filter.rs 会直接查出这条已存在的拉黑/静音关系,只要这段关系还在,你的帖子就进不了这位读者的候选池。这可不是“模型预测他可能静音你”,而是实打实把路堵上了。45
比如你写一篇产品对比测评,你完全可以客观犀利地指出“某款软件官方宣传的 99% 识别率与我们的实测结果严重不符”,并把你的测试样本和翻车截图摆出来——这种就事论事的硬核批评,同样能引发热烈的专业讨论。你完全没有必要为了骗评论,在文章里开地图炮辱骂用这款软件的用户“智商低”,或者故意艾特(@)跟测试毫无关系的大 V 挑起骂战。靠骂战引来的评论,吸引来的根本不是你想留下的目标受众。
平时复盘两篇帖子的评论区时,别光数评论条数:要看大家是在评论区里补充测试边界、追问具体场景、分享自己的踩坑案例(这些全是你写下一篇爆款的绝佳素材),还是在单纯地互相攻击谩骂——后者的数字再热闹,算上背后的负向惩罚权重和静音流失,也是赔本买卖。45
17 同一篇长文,该发长 Post 还是 Article(含 64 赞拉图门槛与 V5/V8.2 实测拆解)
这几乎是每一个写深度内容的 X 创作者最纠结的问题:“我手头写好了一篇几千字的深度干货,到底是直接发成一条**长 Post(Longer Post)流量更好,还是放进专栏文章编辑器(Article)**里发布更容易被算法推荐?”
在把所有跟长 Post 和 Article 相关的代码文件翻了个底朝天之后,我的核心结论是:
- 在最终打分公式(
scoring.rs)里,没有任何看到is_article就给你额外乘几倍分数的“格式特权加分”; - 但是!这两种格式在底层的对象结构、AI 阅读器(V5 与 V8.2)抓取图文的方式、上游拉取图片的“64 赞门槛(
is_high_fav)”,以及草稿修改时的可见性过滤规则上,确实存在巨大的工程差异! 我们既不能笼统地说“两种格式在算法眼里一模一样”,也不能听信网上吹的“只要改成发 Article 曝光就自动暴涨 5.7 倍”。
如果先给一个最实用的省流结论,我平时自己发稿的判断标准非常明确:
- 围绕单一痛点、一条逻辑线就能一气呵成讲透的内容(比如三四千字以内) → 直接发 长 Post,并在普通图片栏挂 1 张最核心的结果对比图;
- 需要分多个章节、穿插多张图表和代码块、方便读者像查手册一样反复检索的重磅研究(比如像你现在读的这篇两万字长文) → 用 Article(或按问题分篇的 Articles)承载全文,同时务必在发布后单独发一条“带核心结果图的导读长 Post”去引用推广它!
为什么“Article + 一条带图导读 Post”是最稳妥的稳妥组合?看完下面代码里的 6 层硬核拆解,你就彻底明白了。
17.1 长 Post 和 Article 在系统里是什么
我们先确认长 Post 和 Article 在 X 产品和代码里的真实身份:
- 长 Post(Longer Post):在产品上依然是一条普通帖子(只是开通 Premium 后单帖字数上限放宽到了 25,000 个字符,并且可以用在普通发帖、回复和带评论引用里);
- Article(专栏文章):拥有独立的富文本编辑器,支持多级标题(H2/H3)、正文中内嵌多张图片/视频/其他帖子,发布后会专门收进你个人主页独立的 Articles 栏目里。(注意:我们这里对比的是这两种 X 站内原生格式,往帖子里塞一个跳去站外个人博客的链接,或者拆成十几条串文 Thread,都属于另外的玩法。)6 95
在后台代码里,系统是完全分得清这两者的:比如反滥用系统 BotMaker 的特征抽取器(FeaturesOfTweet.java)会分别提取 noteTweetId(长帖 ID)和 articleId(专栏文章 ID);而在 Grox 多模态与安全系统的 Post 数据模型(data_types.py)里,同一个帖子对象既保存了帖子文本 full_text,又有一个可选的 article_metadata(Article 元数据,里面装着 Article 标题、Article 封面图和 Article 正文内嵌媒体)。这证明系统底层绝不是靠“数数字数有多长”来认出 Article 的;只不过这些字段主要服务于内容理解与安全检查,并不是打分器里的“格式加分卡”。87
我把长 Post 和 Article 在代码里的 6 个核心层次列成了一张对比总表,先看全景,再逐层细拆:
| 比较层次 | 长 Post/普通帖子文本路径 | Article 相关路径 | 目前能作出的判断 |
|---|---|---|---|
| 对象与内容结构 | Post.full_text 保存传入的帖子文本;另有 noteTweetId 身份字段 | 同一个 Post 对象可以额外挂载 article_metadata(含标题、封面图、内嵌媒体) | 系统底层完全能区分两种格式,并非只数正文字数 |
| V8.2 内容理解(新版阅读器) | 对传入的 full_text 截取前 4,000 个字符;只从普通附件 post.media 取第 1 张可用图 | 额外读取 Article 标题(截取前 200 个字符);不遍历 Article 封面图和内嵌图! | 这是 V8.2 处理器的输入规则,不是全站人类阅读字数上限 |
| V5 内容理解(旧版阅读器) | 读取帖子文本及普通帖子媒体 | 按顺序读取:Article 标题 → Article 封面图 → 帖子文本 → 普通媒体 → Article 内嵌媒体 | 两代阅读器挑图规矩截然不同,不能共用同一句“只看首图” |
| 阅读与点击行为记录 | 普通点击、展开全文(Show more)、详情页曝光及停留分别设独立编号 | 协议里有 PAGE_ARTICLE 页面枚举,但从打开 Article 到训练标签的映射链未完全公开 | 不能打包票说“点开长 Post 展开”与“点进 Article 专栏”算成同一种停留事件 |
| 已核查的候选召回与计分 | 走通用候选来源、24 项预测融合和同作者 0.625 衰减 | 未找到任何仅凭 is_article 身份就生效的保底配额或固定加分乘数 | 代码里没有显式格式加分,但不排除上游模型从内容特征中学到隐性差异 |
| 可见性与安全过滤 | 走通用帖子安全规则和订阅受众资格检查 | 另有 ArticleTweetContent(拦截非 Published 已发布状态)、封面及内嵌媒体安全检查 | 这些是展示资格与风控规则,不是曝光奖励表 |
17.2 4000 字符处理的是哪个文本,Article 正文又在哪里
我们先看表格第二行:V8.2 内容理解阅读器(grox/flows/mm_emb/renderer_v82.py)是怎么读文字的?
把源码里跟文字截断和组装直接相关的几行核心代码抽出来(省略其余无关字段),真相就在眼前:47 83
MAX_POST_TEXT = 4000
MAX_ARTICLE_TITLE = 200
def _truncate(text: str, limit: int) -> str:
text = (text or "").strip()
if limit < 0:
return text
return text[:limit].rstrip()
if post.full_text:
blocks.append(
f"Post text: {_truncate(_strip_dangling_media_urls(post.full_text), MAX_POST_TEXT)}"
)
article = cls._article_block(post)
if article:
blocks.append(article)
请仔细看上面这段 Python 代码里的两个关键细节:
- 两个
if判断是上下并列执行的,根本不是“二选一(if ... else ...)”! 函数_article_block(post)负责读取article_metadata.title(Article 的标题,截取前 200 个字符)。如果一篇挂了 Article 元数据的帖子,它的post.full_text(承载这篇 Article 的外层帖子文本)也不为空,那么前 4,000 字符的post.full_text和前 200 字符的 Article 标题会同时被拼进输入块blocks里!网上有人把这段代码传成“发长 Post 会读正文,发 Article 就把正文丢掉只读标题”,那是连代码里的两个if都没看懂。83 4000是实打实的 Python 字符串切片字符数(text[:4000])! 无论是中文汉字、英文字母还是标点符号,在 Python3 字符串切片里,1 个字符就占 1 个位置(不是大模型按词根拆分的 token 数,也不是前端编辑器的 25,000 字发布上限)。截好之后的文本和挑出来的图片,会被一起打包送给embedder_v82.py服务,用来生成代表这篇帖子主题的多模态语义向量(Embedding)——注意,这里是用来做语义理解和匹配受众的,并不是在这里按字数直接给你算曝光量。47
为了验证这段逻辑毫不含糊,我在本地构造了填好字段的内存 Post 对象,直接调用公开的 renderer_v82.py 处理函数跑了实测(注:本地测试只检验该处理器吃进什么、吐出什么,不调用线上未公开权重的 embedding 模型服务):88
| 固定其他字段后的输入 | V8.2 的输出 | 这个检查说明什么 |
|---|---|---|
full_text 填入 4,000 个“字”,第 4,001 个字符填“尾” | 输出的 Post text: 恰好是 4,000 个“字”,“尾”字被无情切掉 | 4,000 字符截断边界严格按 Python 字符位置一刀切 |
| 保持前 4,000 个字符一字不动,只修改第 4,000 字符后面的内容 | V8.2 输出的文本块一字未变 | 在 V8.2 这条语义生成路径上,第 4,000 字符往后的文字完全不可见(其他系统模块不在此试验范围) |
同时填入 full_text 和长达 201 个字符的 Article 标题 | 最终输出里同时包含 Post text: 和 Article title:(标题保留前 200 字符) | 承载帖文本与 Article 标题在 V8.2 输出中完全共存,互不排斥 |
这里有一处要老实交代:公开代码没把「Article 正文到底怎么进模型」这件事讲全。已知的部分是:在公开的数据映射器(grox/core/data_loaders/post_mapper.py)里,上游传来的 post_metadata.text 被放进 Post.full_text;而 article_metadata 里只映射了标题(title)和媒体(cover_media/media),没有一个单独装 Article 正文全文的字段。不知道的部分是:线上真正的上游服务(Strato 是 X 内部后台服务的统称)怎么填这个 text 字段、Article 的万字正文有没有走别的内部通道喂给模型——这部分实现没公开。所以两个极端都不能说:不能因为字段名叫 full_text,就断定所有格式的正文全文都进去了;也不能因为 article_metadata 里没列正文字段,就断言全站所有模型都看不见 Article 正文。87
此外,在 home-mixer/models/content_features.rs 里,系统还会提取帖子的加权文本长度(weighted_text_len)和换行数(newline_count)等基础特征传给下游。这说明“帖子有多长、分了多少行”是模型能看到的特征,但代码里同样没有任何“字数越长加分越多”或“空一行加几分”的固定公式。46
不过,知道了 V8.2 的“前 4,000 字符正文 + 前 200 字符 Article 标题”读取规则,我们写稿时的铁律就已经非常清楚了:写长 Post 时,务必在前 4,000 个字符以内把研究对象、核心痛点和主要结论全部亮出来;写 Article 时,务必把前 200 个字符的标题和外层承载帖导语写得信息量拉满,绝不要把所有核心关键词都憋在文章最后两千字才揭晓!
17.3 Article 的封面和正文图片,不能照搬普通图帖的规则(彻底讲透什么是“64 赞 is_high_fav”与 V5/V8.2 差异)
很多朋友在看这一节时最容易卡壳:“到底什么是 Article 的 64 赞门槛(is_high_fav)?V5 和 V8.2 两个阅读器读 Article 的图片为什么不一样?我发 Article 时图片到底该怎么放?”
我们不甩干巴巴的术语,直接按**“当你按下发布 Article 按钮之后,X 后台按先后顺序发生了哪两步”**,用大白话一层层顺下来:
17.3.1 第一步:AI 想看懂你的图,得先有个“搬运工(MediaLoader)”把图从数据库拉过来
当你发出一篇内容,X 后台的 Grox 多模态大模型要去读你的文字和图片,生成代表这篇内容主题的“语义向量”,用来判断该推给哪些兴趣圈子的读者。
但是,去服务器下载和解析高清大图是非常消耗算力的!于是在负责拉取媒体数据的“搬运工”代码(grox/core/data_loaders/media_loader.py)里,程序员设了一个判断开关叫 is_high_fav(直译过来就是:“这是一篇高赞帖子吗?”),并在配置文件(grox/config/config.py)里把它的公开默认门槛设成了 64 个赞(deluxe_fav_count_threshold = 64)!89
这行代码具体干了什么事?
在 MediaLoader 这条媒体搬运路径上,只有当帖子满足了 is_high_fav 成立(也就是点赞数达到至少 64 个赞),并且同时符合待处理帖子选择、当前任务类型和已有媒体状态等条件时,搬运工才会走入专门的分支(media_loader.py#L293-L303),去拉取 Article 的专属封面图(cover_media)和 Article 正文里的内嵌图片(article_metadata.media)!
- 说人话就是:在你的 Article 刚刚发出来、还没攒够 64 个赞之前,走这条
MediaLoader搬运路径时,搬运工为了省服务器算力,可能压根不会去拉取你放在 Article 编辑器里的封面图和正文插图! - 同时必须守住严谨边界:这个
64赞仅仅管的是MediaLoader这条特定媒体拉取路径的公开默认参数,绝不代表“Article 必须先拿够 64 个赞才有资格进推荐流”!89
17.3.2 第二步:就算图片已经拉过来了,V5 和 V8.2 两代“阅读器”挑图的规矩也完全不同!
在公开代码库里,同时共存着两代多模态内容阅读器(Renderer):旧版 V5(renderer.py) 和新版 V8.2(renderer_v82.py)。它们俩对待 Article 图片的态度简直是天壤之别:88
- 旧版 V5 阅读器怎么读 Article: V5 非常勤快,它的读取顺序依次是:Article 标题 → Article 封面图 → 帖子文本 → 普通帖子媒体附件 → Article 正文内嵌媒体。当然,V5 受“图片数量预算(Budget)”的限制——如果某次调用把图片预算设为“只读 1 张图”,那排在第一顺位的 Article 封面图 就会独占这唯一一个名额,正文里内嵌的插图就轮不上了。
- 新版 V8.2 阅读器怎么读 Article(最大的坑在这里!):
V8.2 在处理 Article 时,文字部分会正常读入
post.full_text(前 4,000 字符)和 Article 标题(前 200 字符);但是!到了负责挑图片的函数_collect_post_media时,它只去翻“普通帖子的媒体附件栏(post.media)”,在源码里根本没有写任何循环去翻 Article 专属的封面栏(article_metadata.cover_media)和正文内嵌图栏(article_metadata.media)!
为了验证这个惊人的差异,我在本地写测试脚本,给同一个内存 Post 对象同时塞进了三张已经就绪的图片数据:① Article 封面图、② 普通帖子媒体附件(post.media)、③ Article 正文内嵌图,然后分别调用 V5 和 V8.2 的原版函数:
- 调用 V5 时:它乖乖按“封面图 → 普通附件 → 正文内嵌图”的顺序全部返回(当把图片预算设为 1 张时,就只返回 Article 封面图);
- 调用 V8.2 时:它只返回了“普通帖子媒体附件(
post.media)”!紧接着我做了一个更绝的测试——把普通帖子附件清空,只把图片放在 Article 封面和 Article 正文里(这正是大家平时直接在 Article 编辑器里发文章时的真实状态),结果调用 V8.2 时,返回的图片列表直接是空的(0 张图)!88 (注:这项本地实测证明的是 V5 与 V8.2 在「读哪些字段」上的代码差异;5ed7963与606b254两个版本里这段逻辑一致。但线上又是另一回事:上游会不会先把 Article 封面复制一份塞进post.media、哪些模型用 V5 的向量、哪些用 V8.2 的,取决于线上内部配置。所以不能下「线上所有 Article 都没有图片向量」这种绝对结论。)
17.3.3 发 Article 时到底该怎么做?(3 条实操动作)
既然普通多图帖是“别把核心数据藏在第 4 张图”,那到了发 Article(专栏文章) 时,为了同时兼容“未满 64 赞前的 MediaLoader”、“挑剔的 V8.2 阅读器”和“看封面的 V5 阅读器”,最稳妥的实操打法就是下面这三招:
- 动作一:Article 的“标题(前 200 个字符)”必须塞满核心干货词,千万别起文艺空洞的标题!
因为在你的 Article 还没攒够 64 个赞之前(
MediaLoader还没拉取 Article 图片),或者在走 V8.2 阅读器时(不读 Article 专属图片),AI 百分百能稳定读到的就是你的 Article 标题(前 200 个字符) 和外层承载帖文本!如果你起个标题叫《周日深夜的一点思考》,图片又没被读进去,AI 就彻底抓瞎了,完全不知道你这篇 Article 在聊什么;改成**《实测两款中文发票 OCR 工具:模糊扫描件下税额与日期字段的识别错误率对比》**,哪怕一张图都没读进去,AI 光靠标题这几十个字也能精准帮你匹配财税与技术圈的目标读者! - 动作二:Article 的“封面图”别放纯风景或抽象表情包,要放信息明确的主图。
因为一旦走 V5 阅读器(当图片预算为 1 张时),或者当你的 Article 点赞满 64 个触发了
MediaLoader拉取之后,排在第一顺位被 AI 读走的就是 Article 封面图,正文里嵌的第 2、3、4 张图都排在它后面。 - 动作三(最稳妥的稳妥组合):发完 Article 后,一定要单独发一条“导读长 Post”,并把最核心的 1 张结果对比图直接挂在这条导读 Post 的普通图片附件栏里!
为什么这一招最稳妥?因为导读 Post 本质上是一条普通长帖子,你挂在它上面的图片属于“普通帖子媒体附件(
post.media)”——它既不受 Article 那 64 个赞(is_high_fav)的拉取门槛限制,又能从第 0 个赞开始,立刻被 V8.2 阅读器把“前 4,000 字导读正文 + 第 1 张核心数据图”吃得干干净净! 这就是为什么懂行的大 V 每次发完万字 Article,一定会紧跟着发一条带核心结果图的导读 Post 去引用它!
17.4 展开长 Post、打开 Article、读到末尾,是不同的待核问题
很多创作者还会问:“读者在时间线上点‘展开全文(Show more)’看长 Post,和点进卡片打开一篇 Article 专栏,在算法后台算不算同一种点击和停留?”
我们去翻通信协议定义文件 phoenix/python/common/xai-proto/proto/recsys.proto,发现代码把这几种看似相近的动作编成了完全不同的独立编号(Action Enum):90
| 动作枚举 | 编号 | 名称能说明什么 |
|---|---|---|
CLIENT_TWEET_CLICK | 29 | 独立的普通帖子点击事件 |
CLIENT_TWEET_SHOW_MORE_EXPAND | 45 | 点击长帖的“展开全文(Show more)”,并没有和普通点击共用编号 29 |
CLIENT_TWEET_DETAILS_IMPRESSION | 72 | 点进帖子详情页的曝光被单独记录 |
CLIENT_TWEET_DETAIL_DWELL | 103 | 在帖子详情页里的停留也被单独记录 |
CLIENT_TWEET_RECAP_DWELLED | 11 | 前面讲的双塔召回 ld 分支专门使用的阅读停留正例事件名 |
你看,编号 45 的 CLIENT_TWEET_SHOW_MORE_EXPAND(展开更多)不仅有独立编号,还出现在历史互动特征集合(history_id_lists.py)和 IsShowMoreExpanded 映射(constants.py)里,说明系统在收集用户历史特征时确实认得“展开长帖”这个动作。
但是,当我们去查最终价值打分模型(xai-value-model/phoenix_scores.rs)时,里面既没有一个单独叫 show_more_score(展开加分)的字段,也没有一个叫 article_completion_score(Article 完读加分)的字段。所以我们既不能说“读者点展开全文一点用都没有”,也不能拍脑袋编造说“读者每点一次展开全文就固定加几分”。90 94
同样,在协议文件里也能查到专门代表 Article 的页面类型枚举:PAGE_ARTICLE(Article 正文页)和 PAGE_ARTICLE_PREVIEW(Article 预览页)。但“页面类型(Page)”和“动作类型(Action)”在协议里是两个不同的字段——能查到 PAGE_ARTICLE 这个名字,不代表公开代码已经把“读者点开 Article 页面 → 触发了哪个编号的动作 → 怎么折算成训练数据里的阅读时长标签 → 最终喂给哪个预测头”的完整映射链条交出来了。90
为什么这一段映射查不到?因为这正好卡在了公开代码库的边界之外:
公开出来的训练代码(recsys_batch.py)直接读取的是已经由上游处理好的行为向量和连续数值列,而 Home Mixer(scoring_sequence_query_hydrator.rs)也是直接向外部行为聚合服务伸手拿结果。至于手机客户端从哪一秒开始给 Article 计时、读者从 Article 退回首页后停留时长怎么归因、切到手机后台算不算停留、点长 Post 的“展开全文”会不会顺带同时触发一次编号 29 的普通点击,官方在 phoenix/README.md 里明确说明:生产环境的数据源与内部遥测聚合管线并未开源。91
最后把两个「停留」数据槽位分清。连续停留 DWELL_TIME 的单位有据可查:公开的 Rust 工具代码(xai-recsys-engine/src/util.rs)里明明白白把它从毫秒除以 1000 换成秒,用作 predicted_dwell_sec。但点击后停留 CLICK_DWELL_TIME(门槛 10.0)这边还差一截:它的原始数值到底是什么单位、读者点开 Article 的时长算不算进这个槽位,公开代码里没给出答案。这正是「Article 字数更长 → 读者停留一定更久 → 发 Article 一定比长 Post 多拿推荐」这条直线推不出来的原因:文章有多少字、读者实际看了几秒、AI 事前预测他会看几秒、有没有读到最后一段,本来就是四个不同的变量。91 98
17.5 没有找到 Article 固定加成,也没有证据证明两种格式待遇完全相同
为了彻底排查“发 Article 有没有隐藏的流量特权”,我把 Home Mixer 里的候选来源(sources)、过滤器(filters)、打分器(scorers)、参数表(params)和主候选流水线(phoenix_candidate_pipeline.rs)全部检索了一遍:
- 在
Thunder、Phoenix、TweetMixer、SimClusters等所有公开召回入口里,没有任何一个入口按“是不是 Article”分配专属保底名额(前面讲的FairShare也是按召回来源渠道分组,而不是按长 Post 或 Article 格式分组);94 - 在最终价值计分模型的输入结构体
CandidateScoringInputs(xai-value-model/inputs.rs)里,根本没有is_article或is_long_post这两个布尔字段! - 在开启同作者多样性衰减(
0.625)时,函数也只是按author_id累计同作者候选次数——也就是说,如果你上午发了一篇长 Post,中午又发了一篇 Article,它俩要是同时掉进同一个读者的临时篮子里,排第二的那篇照样吃0.625衰减,绝不会因为你换成了 Article 格式就把同作者计数器清零!2 94
当然,本着科学严谨的态度,“已公开的打分函数里没有写死 is_article 固定乘数”,只能帮我们证伪“算法代码直接给 Article 写了固定几倍加成”的谣言;它并不能排除上游深度学习模型通过学习内容特征对不同格式产生隐性偏好,也不能排除线上存在未公开的实验分流。
另外,很多创作者把另一件事搞混了:X 官方以前在创作者收益公告里确实提过,在计算创作者广告收益分成(Creator Revenue Sharing)或举办百万美元征文比赛时,可能会给 Articles 更高的收益分配权重;但那是分钱算稿费的权重,根本不是 For You 推荐流的排序系数!而且旧版的广告分成计划已经在 2026 年 9 月正式结束并切换到了新的 Original Content Rewards 规则,千万别拿老黄历里的“分钱权重”当成今天的“推荐算法加成”。97
17.6 Article 确有独立可见性处理,但先看触发条件和入口
虽然打分时没有 Article 专属加分,但在安全与可见性过滤系统(visibility-filtering)里,Article 确实有一条专属的拦截规则,而且藏着一个很多创作者不知道的**“改稿隐身坑”**!
打开 visibility-filtering/rules/tweet_rules.rs,里面有一条名叫 ArticleTweetContent 的规则:只要一条帖子关联了 Article,并且这篇 Article 当前的状态不是 Published(已发布状态),系统就会直接执行过滤拦截(Drop)! 公开测试样例(golden_corpus/article.rs)里明确测试了草稿(Draft)、软删除(SoftDeleted)、状态缺失以及已发布(Published)四种状态,只有 Published 能通过这道检查(注意两个边界:一,这条规则挂在 TimelineHomeHydration 这个检查级别上;Home Mixer 另一些地方用的是 TimelineHome、TimelineHomeRecommendations 另外两个级别,三个级别线上怎么串起来,取决于每次请求的实际配置。二,所以不能简单说:每篇 Article 在进 Phoenix 打分之前,都必定多过这一关。)。92
那为什么说这里有个**“改稿隐身坑”?
去查 X 官方的 Articles 帮助文档就会发现:当你对一篇已经发布的 Article 点击编辑修改时,系统的机制是先把这篇 Article 从已发布状态撤下来(变成未发布草稿状态),等你改完点击重新发布后,才恢复成 Published 状态**!
这就意味着:如果你发完一篇 Article 后,发现里面有几个错别字,于是撤下来慢慢改了半个小时却忘了点重新发布,或者一天之内反复撤下改稿好几次——在你撤下改稿的这段时间里,这篇 Article 的状态不是 Published,在触发 ArticleTweetContent 规则的入口就会被直接当成未发布内容拦截过滤掉! 所以发完 Article 如非必要别频繁撤下大改,改完更要第一时间确认它已经回到 Published 已发布状态!6 92
此外,Article 的封面图和正文内嵌媒体也会被合并计入可见性系统的“是否包含媒体(compound.rs)”判断里(这只是用来走对应的媒体安全规则,普通文章带张健康封面图绝不会因此自动降权)。而如果你把 Article 设为“仅限订阅者可见(Subscribers-only)”,通用过滤器 IneligibleSubscriptionFilter(ineligible_subscription_filter.rs)就会检查当前刷首页的读者有没有付费订阅你(subscription_author_id),没订阅的读者自然刷不到;同时 Article 媒体接口(article_client.rs)在没有权限时也会隐藏媒体字段——这是正常的付费墙权限控制,不能误判为“Article 图片丢了”或“被算法限流”。92 93
17.7 实际数据里 Article 表现更好,为什么还不能判定同稿必胜
这时候肯定有朋友会拿出一份数据反驳:“不对呀!第三方机构 NotPeople 在 2026 年 9 月刚发了一份实测报告,统计了 8 月份的数据,人家算出 Article 的浏览量中位数是普通帖子的 5.7 倍 呢!”
这份报告(NotPeople 原文)我也专门调出来逐表核对过。它的统计主表里一共包含了 42 篇 Articles、843 条带有 Article 链接的普通导流帖,以及 64 条不带 Article 链接的普通帖子。如果拿每位作者自己的平均帖子浏览量做基准归一化,那 42 篇 Articles 的归一化浏览量中位数确实达到了 5.7 倍。96
但是!你看清那两个数字的比例了吗:42 篇 Articles 背后,跟着整整 843 条普通导流帖! 报告原作者在文内自己都坦诚说明了:在这批创作者样本里,作为对照的绝大多数普通帖子其实是简短的“导流推广帖”,并不是拿同样一篇几千字的完整干货分别发成“长 Post”和“Article”做同稿对比;而且这批创作者每发 1 篇 Article,平均要在后面连发 6 到 28 条相关的普通帖子(摘录、短评、引用)去给这篇 Article 疯狂导流推广! 一边是花了重金和心血写出来、又连发十几条帖子众星捧月般导流了几个星期的旗舰 Article,另一边是随手发的日常短导流帖——这两者的题材分量、写作投入、导流推广力度和累积浏览量的时间窗口完全不在一个起跑线上!所以,这份样本能证明“采用【1 篇重磅 Article + 十几条导流帖】矩阵打法的创作者,其主 Article 攒下了很高的浏览量”,但绝对证明不了“把同一篇稿子从长 Post 粘贴进 Article 编辑器,什么额外导流都不做,曝光就会自动翻 5.7 倍”!96(至于前面提过的 Hootsuite 2024 年小实验,只比了 Thread 和长 Post,压根没测 Article。25)
17.8 要发布的这篇内容,具体怎么选
剥离了所有的水分和玄学之后,当你手头有一篇新稿子准备发布时,到底该选 长 Post、Article,还是 Article + 导读 Post?直接对照下面这张决策表对号入座:
| 你准备发布的材料 | 我会优先选什么格式 | 选择的具体理由 |
|---|---|---|
| 围绕一个明确判断,几段话+1 张对比图就能彻底说清;或者需要直接接在某条热门讨论底下回复/引用 | 长 Post | 一气呵成完成论证,且普通图片附件(post.media)从 0 赞起就能被 V8.2 直接读入,无需为形式硬拆章节 |
| 一份多章节深度调查、完整操作手册或工具指南,需要用到多级小标题、穿插多张图表供读者日后反复查阅 | Article | 多级标题层级和内嵌材料排版极佳,且永久沉淀在个人主页的 Articles 专栏里方便检索 |
| 完整研究报告非常长(比如上万字),同时又希望从未关注过你的陌生读者在刷首页时一眼看懂它解决了什么痛点 | Article(或分篇 Articles)+ 1 条带核心图的导读长 Post | 稳妥组合:用 Article 承载严谨全文,同时发一条挂着核心结果图的导读长 Post,既绕开 Article 64 赞拉图门槛与 V8.2 漏图问题,又让读者先拿到干货结论 |
| 同一篇三千字稿件在两种格式里都排得通,你唯一的目的只是想知道在自己账号上哪种自然曝光更高 | 用自己账号的可比样本做交替测试 | 目前公开代码与外部研究都没有“同稿必胜”的铁证,自己账号的实测受众反馈最准 |
| 需要面向付费订阅读者定期交付深度研究或专属资料 | 开启相应订阅受众控制的 Article | 按交付对象选择;但记住付费墙是权限过滤(IneligibleSubscriptionFilter),不会给公开推荐加分 |
我们还是拿前面聊过的**“中文发票 OCR 识别工具测评”**来举个一锤定音的例子:
- 如果你这次测试的发现非常集中——仅仅是发现**“当发票扫描件有折痕模糊时,税额这一栏极容易把 8 识别成 3”**——那你只需要放 1 张模糊发票原图、1 张两款工具的识别结果对比表,外加三段文字讲清适用条件,直接发一条长 Post 就够了!
- 反过来,如果你这次做的是全方位横评——要交代 50 张不同画质的发票样本分组、两款工具的 API 参数设置、日期/税额/买方税号等多个字段的准确率大表、典型翻车案例以及二次复测记录——那就把这份完整报告放进 Article 里发布,紧接着单独发一条带核心结果图的导读长 Post!
这条配套的导读长 Post 千万别写成“我刚发了一篇发票 OCR 深度好文,大家快点进链接看全文!”(这种空洞导流没人爱点),而是应该写成一条哪怕读者不点进 Article 也能立刻学到一招的独立干货帖:
导读长 Post 示范文案(同时在普通图片栏挂上最核心的 1 张税额识别对比图): 评估中文发票 OCR 工具能不能直接对接财务入账系统,千万别只看厂商宣传的“全文总字符准确率 99%”。
一定要把开票日期、税额、买方税号三个字段拆出来单独测:哪怕一整张发票上百个字里只认错 1 个数字,只要那个数字刚好落在“税额”栏里,这张凭证入账就会直接报错!
我用同一批带折痕的真实中文发票,对两款主流 OCR 工具做了逐字段盲测,把测试原图、各字段错误率对比表以及必须转人工复核的边界条件整理成了下面这篇完整专栏。正在做财务自动化选型的朋友,建议直接先看里面的税额对照表👇
你看上面这段导读(这是写法示范,里面的测试要换成你自己真做过的事,没做过别照抄):它本身已经把“别看全文准确率,要拆税额字段单独测”的核心干货交付给了读者,挂在普通图片栏的首图又能从第 0 个赞起直接喂给 V8.2 阅读器;真正有财务选型需求的读者看完导读,自然会点进下方的 Article 把整套表格抱走。官方帮助页推荐的“用摘录帖子引向完整 Article”指的就是这种组织方式(当然,这是科学的图文分发配合,不是每发一条导读系统就白送一份流量配额)。6
顺便提醒一句排版实操细节:如果你准备把像本文这样包含大量代码块、数学公式和复杂 Markdown 表格的长稿放进 Article 编辑器,发布前一定要在预览界面逐段检查!Article 编辑器虽然支持富文本,但直接粘贴复杂的 Markdown 语法或 LaTeX 公式进去,有时会出现表格错位或公式渲染失败。如果整篇报告加附录太长,完全可以按“能够独立回答的完整问题”拆成上下两篇 Articles,或者在文末附上完整版 Markdown / PDF 文档的下载入口,千万不要为了硬塞进一条普通帖子里而把改变结论的关键边界条件给删掉。
17.9 怎样比较自己的结果,才不会把浏览量当作读完人数
如果你打算在自己的账号上亲手测一测“长 Post”和“Article”到底哪个效果更好,怎么测才不会被假数据骗了?
- 第一步:先定准你要考核的真实业务指标,别拿前台公开浏览量(Views)当成“读完全文的人数”!
官方帮助文档(
View counts)写得明明白白:前台显示的帖子浏览量(Views),只要有人在时间线上划过看到就算 1 次,而且同一个读者反复刷到、甚至你自己点开看,都会重复计入浏览量,还混杂了搜索、主页等不同入口!面板上有 10,000 次浏览,既不能证明有 10,000 个独立活人点开了你的全文,更不能证明他们读到了最后一段。如果你想测“破圈拉新”,就重点记录主页访问量、新增关注数;如果你想测“干货转化”,就重点记录收藏数、有效咨询私信或资料下载点击量。59 - 第二步:做“同档题材交替对比”,并且把导流投入算清楚。 挑出 6 到 10 篇选题难度、目标受众和写作投入差不多的原创干货,单数篇发长 Post,双数篇发 Article,并且都固定在同一个活跃时间段发布:
- 第一轮测试:两边都只发主帖、都不发额外导流帖,纯粹观察两种格式本身的自然曝光与收藏转化差异;
- 第二轮测试:拿“1 篇 Article + 2 条带图导读 Post”去和“单发 1 篇长 Post”对比——这时候你要记住,前者一共发了 3 条内容、多花了两倍的宣传精力,记账时要把整组投入和单篇表现分开记,更不能把导读帖的浏览量和 Article 的浏览量直接相加当成“去重总读者数”!
- 第三步:看 24 小时与 7 天中位数,千万别把“同一篇稿子连发两遍”当成严格 A/B 测试!
每篇统一记录发布后 24 小时和 7 天的核心数据(同时备注期间有没有遇到大 V 转发、热点事件或付费推广),对比多篇样本的中位数,别让某一篇偶然爆款带偏了平均值。尤其注意:千万不要把同一篇稿子上午发一遍长 Post、下午原封不动再发一遍 Article,然后管这叫“严格控制变量 A/B 测试”! 因为上午已经看过你长 Post 的核心老粉,下午刷到一模一样的 Article 根本不会再点开第二次;而且要是这两篇同时掉进某些读者的候选池,还会直接触发同作者
0.625衰减和 DPP 相似内容置零!
18 第一张图,最好就能说明这篇的发现(兼谈长文带一张漫画图片会怎样)
很多做图文测评或教程的朋友,习惯照搬公众号或小红书的排版审美:一条帖子挂 4 张图,第 1 张图放一张花里胡哨的纯标题海报或搞笑封面,第 2 张图才开始交代背景,第 3、4 张图才把真正核心的测试结果表格放出来。
真人读者有没有耐心往右滑到第 4 张图,还得看你的封面吸不吸引人;但在推荐算法的 V8.2 内容理解流程(grox/flows/mm_emb/renderer_v82.py)里,AI 到底读了哪张图,源码早就写死了!
打开 _collect_post_media 函数,它从你的第 1 张媒体附件开始往后循环检查:只要先遇到一段可用视频,就抽取一组视频帧然后立刻返回;只要先遇到第一张有可用图像数据的静态图片,立刻执行下面这行代码直接返回(return):1
return "Post image:", [medium.convo_image.content]
看清楚了吗?对于一条挂了 4 张静态图片的纯图帖,这个函数根本不会把 4 张图全部收走,而是拿到第 1 张能正常读取的图片就立刻收工下班了!(随后本帖选出的媒体会与被引用帖的媒体合并、受总图片预算上限约束,再由 embedder_v82.py 送往多模态向量服务。当然,严谨地说,这是 V8.2 内容理解这一条主路径的做法,不能夸大成 X 全站所有模型永远只看第 1 张图——比如前面讲过的同库旧版 V5 renderer.py 就会按预算逐张处理图片。)1
18.1 长文带一张漫画图片会怎样?权重是按图片算,还是按长文算?
讲到这里,很多喜欢给长文配插图的创作者会问出一个非常具体的问题:“如果我写了一篇几千字的深度长文,为了版面好看,顺手配了 1 张搞笑漫画或手绘插图,推荐系统会不会把我的帖子判定成‘图片帖’,结果把我长文本身的阅读停留权重给吞掉了?”
我们对照 scoring.rs 的计分公式和 renderer_v82.py 的多模态代码,给你吃一颗定心丸,同时指出一个必须避开的大坑:
- 在打分排序环节(
scoring.rs):绝对不是“图文二选一”,而是“长文阅读分 + 图片展开分”全部叠加! 系统的融合计分公式对所有候选帖一视同仁:你写了深度长文,前面讲的 4 大阅读停留加分项(普通点击Click0.3、点开后深度停留ContClickDwellTime0.4、基础停留Dwell0.05、连续停留每秒ContDwellTime0.006)该算的都会算;同时,公式里本来就有一项展开图片的预测(Photo expand,系数0.05,乘的是这位读者会点开看图的预测概率)。所以,给长文配一张漫画插图,不会吞掉长文本身的停留项,但也别把 0.05 理解成配图就送的分。2 21 - 真正受影响的是“AI 多模态模型怎么理解你这篇帖子的主题”(
grox/flows/mm_emb): 在 V8.2 处理器里,程序会把两样东西打包在一起送去生成帖子的语义向量(Semantic ID):截取前 4,000 个字符的正文文本(Post text:) + 挑出来的第 1 张可用图片(Post image:)。这里分两种情况:
- 情况 A(整篇长文只配了这 1 张漫画图):只要你长文的前 4,000 个字符把核心研究对象和结论写得清清楚楚,配一张贴合文章主题的漫画插图完全没问题(公式里本来就有一项图片展开预测,系数
0.05,乘的是读者点开看图的概率,不是谁配图就送的分)!唯一要忌讳的是:正文开头两百字还在云山雾罩地抒情,配的那张漫画又是跟正文毫无关系的搞笑猫猫表情包——图文语义对不上,就会干扰多模态向量的精准度。 - 情况 B(既有 1 张装饰漫画,又有 2 张实测数据表——90% 创作者踩过的大坑!):千万记住上面那行
return "Post image:"源码!如果你一条长文挂了 3 张图,把搞笑装饰漫画放在第 1 张,把真正核心的实测数据对比表放在第 2、3 张——完蛋了!V8.2 的_collect_post_media看到第 1 张漫画能正常打开,直接拎着这张漫画就return交差了,你后面第 2、3 张图里的硬核测试数据,在这条多模态理解流程里被彻底无视了!1
18.2 四张测评图可以怎么重排
明白了“V8.2 只抓第 1 张可用图”的底层逻辑,我们平时发 4 张图的测评帖或长文配图时,该怎么安排图片顺序? 还是拿“测试两款 OCR 工具识别中文发票”举例:
- 错误排法(传统海报流):第 1 张放一句悬念大字报《震惊!测完这两款 OCR 我沉默了》(或者放一张搞笑漫画),第 2 张放测试环境说明,第 3 张放准确率表格,第 4 张放模糊发票报错案例——这样排,不管是匆匆划过的时间线读者,还是只取第 1 张图的 V8.2 流程,都抓不到你这期测试的核心干货。
- 正确排法(结论首图流):
- 第 1 张图(首图):直接做成一张清晰易读的**“核心结果对比卡”**——图上直接写明被测的两款工具名称与任务,放上最能说明差距的“模糊发票税额识别一正一错对比图”,并用醒目字体标出核心结论:“当扫描件有折痕时,工具 A 税额栏需人工复核”;
- 第 2 张图:交代 50 张发票的样本分组与测试参数设置;
- 第 3 张图:放其余字段(日期、买方税号)的完整汇总数据表;
- 第 4 张图(或装饰漫画):补充适用边界、极端失败案例或调节气氛的插图。
当然,把首图做成“核心结果卡”,绝不是让你把整篇论文密密麻麻几千个小字硬塞进一张图里(字太小谁都看不清)。首图只需要聚焦最核心的 1 个发现,把工具名、对比条件和结论对象标清楚就够了;如果某个结论必须附带二十条免责注脚才能成立,说明这个问题在首图里切得还不够细。 同时,正文前几段也要用文字把首图里的核心发现同步写出来——这样万一读者网络卡顿图片没加载出来,光看文字也知道你测出了什么;图片加载出来后,图文又能互相印证,再也不会把全篇最值钱的宝贝藏在算法根本没去读的第 4 张图里了。
19 视频的几个“十秒”,分别管什么
做视频内容的创作者一定听过一句铁律:“发在 X 上的视频必须超过 10 秒钟,否则算法不推流!”
去翻公开代码库,“10 秒(10000 毫秒)”这个数字居然在好几个不同的地方同时出现了——但它们管的根本不是同一件事!有的管视频品质观看(VQV)的计分资格,有的管三个核心沉浸式视频索引库的入库生死线,还有的管长视频安全审查的裁切片段。我们把这几个“10 秒”拆开看,你就知道视频到底该剪多长了。
先看第一个“10 秒”:视频品质观看(VQV,Video Quality View)的资格判断。
在 home-mixer/util/candidates_util.rs 和参数文件 param.rs 里,系统在判断一条视频候选帖够不够资格算 VQV 分数时,会先检查视频本身的长度是否超过设定门槛,公开默认值确实是 10000 毫秒(10 秒)(注意:这里是以毫秒明确标注的视频总片长条件,跟前面讲的点击停留阈值 10.0 不是一回事)。48
但是,光满足了这个 VQV 资格,能让你在打分表里多拿分吗?
不能!原因非常具体:在当前公开版本里,无论是 Home Mixer 还是 VM Ranker,VqvWeight(视频品质观看权重)的默认值统统都是 0!(部分延续观看项的公开默认系数也是 0;只有“打开视频 VideoOpenWeight”保留了非零权重 0.02/0.07。)当然,某处直接权重为 0 绝不代表视频观看行为没用,因为在双塔召回模型的沉浸式分支(immersive_positive_actions)里,依然把视频品质观看列为了核心训练正例。48
同时,在 V8.2 多模态理解流程(renderer_v82.py)里,AI 会读取已抽取的视频画面帧(Frames)和语音转录文字(Transcript)来理解你的视频在讲什么;但代码里没有任何“加了字幕就固定加分”或“1080P 全高清画质就给固定奖励”的公式,更不能把 V8.2 抽取的视频帧数上限歪曲成“整个推荐系统只看视频里的四个瞬间”。1 44 48
19.1 三类视频索引,确实要求片长超过十秒
虽然打分表里的 VqvWeight 默认是 0,但第二个“10 秒”却是实打实卡住视频入库脖子的生死线!
在负责建立推荐索引库的 phoenix-rankall-strato/lib/eventProcessing.strato 里,程序员直接写死了下面这两行片长检查代码:49
minLongVideoDurationMillis = 10 * 1000
videoInfo.durationMillis > minLongVideoDurationMillis
来源:49
请把放大镜对准第二行代码中间的那个大于号 >(严格大于)!
程序检查的是视频文件自带的总时长 videoInfo.durationMillis 是否严格大于 10000 毫秒(10 秒)!
这意味着什么?意味着如果你在剪辑软件里卡着表,把视频剪成了整整 10.000 秒(10000 毫秒)——对不起,10000 > 10000 为假(false),直接不通过! 至少要 10001 毫秒(10.001 秒,为了防止转码掉帧,实操中建议一律剪到 11 秒以上) 才能跨过这道门槛!(注意:这里查的是视频本身的文件总时长,不是量读者看了几秒。)49
更要命的还在后面——实际调用这个 10 秒检查的函数叫做 hasValidImmersiveVideo,它的代码逻辑里藏着一个让无数人翻车的**“图文混排大坑”:
这个函数首先要求帖子里至少存在一个可接受的视频媒体,紧接着,它对这条帖子里挂载的每一个媒体附件(each media entity)使用了 forall(全部满足)检查**——要求每一个媒体都必须是 TweetVideo 或 AmplifyVideo 类型、带有 VideoInfo,且时长全部严格大于 10 秒!
这意味着两个极其重要的实操铁律:49
- 多视频同发时:如果你一条帖子里挂了 2 支视频,1 支 30 秒、另 1 支只有 8 秒,因为 8 秒那支不达标,
forall检查直接全军覆没! - 千万别在同一条帖子里搞“1 支视频 + 1 张静态图片”混排! 如果你一条帖子里放了 1 支 20 秒的干货视频,又顺手塞了 1 张静态截图混排在一起,因为静态图片不是视频类型、通不过
forall检查,整条帖子会因为那张静态图片,直接失去进入下面三个核心视频索引库的资格!
到底是哪三个核心视频索引库在调用 hasValidImmersiveVideo?我把它们的调用链路列在了表里:49
| 索引名称 | 直接调用的构建函数(Builder) | 这条路径的触发情况 | 十秒条件的地位 |
|---|---|---|---|
1fav_video | build1FavVideoIndex | 一般合格帖子的点赞(Fav)分支 | 直接调用 hasValidImmersiveVideo;时长 > 10秒 是入库硬资格之一 |
video | buildVideoIndex | 一般合格帖子的点赞(Fav)或发帖创建(PostCreation)分支 | 同样调用 hasValidImmersiveVideo(注意:发帖创建时就能触发,不是非要等拿到赞才建库) |
nsfw_video | buildNsfwVideoIndex | 特定成人视频的点赞(Fav)分支(构建函数还会另查成人标记) | 同样要求 hasValidImmersiveVideo;其余来源与内容条件也须同时满足 |
来源 49
你看,1fav_video、video、nsfw_video 这三大视频索引的构建函数,全都死死卡在 hasValidImmersiveVideo 上。只要你的视频不超过 10 秒、或者跟静态图片混排了,在这三个视频索引库门前就会被直接拒之门外(当然,进库之后依然要经过后续的召回和打分排序)。49
19.2 两个都叫 Evergreen 的名称,读的未必是同一份数据
进到视频索引库之后,系统还会按发布天数切分成不同的时间窗口(phoenix-rankall/src/config/mod.rs):比如 1fav_video 有 2 天、2 至 4 天、4 至 14 天、4 至 30 天等窗口,video 和 nsfw_video 也有各自的天数窗口(这些天数指的是数据库保留或选取的时间跨度,跟视频片长 10 秒是两码事)。50
而在双塔召回的数据集配置(retrieval_dataset.py)里,有几个名字特别容易让人看走眼,尤其是名字里带 EVERGREEN(长青视频) 的项:50
| 召回数据集名称 | 实际读取的文件 | 所属 Index | 可见的十秒链路 |
|---|---|---|---|
IMMERSIVE2Day | video_2day.parquet | video | 可沿 video 构建函数直接追到严格大于 10 秒 |
IMMERSIVE4Day | video_4day.parquet | video | 同上,严格大于 10 秒 |
EVERGREEN | video_4to14day.parquet | video | 虽然枚举名字叫 EVERGREEN,但实际读的仍是 video 索引的 4–14 天窗口,同样受 > 10 秒限制 |
IMMERSIVENSFW | nsfw_video_2day.parquet | nsfw_video | 可沿 nsfw_video 构建函数追到严格大于 10 秒 |
IMMERSIVE32FavVideo14To30Day | 32fav_video_14to30day.parquet | 另一个独立数据集名称 | 完整上游生产链路未在公开树追齐,不能仅凭名字脑补条件 |
来源 50
你看表格第三行:召回数据集里的枚举名虽然叫 EVERGREEN,但它底层读取的文件其实是 video_4to14day.parquet(也就是 video 索引的 4 到 14 天老视频窗口),所以它照样受前面 > 10000 毫秒 的严格限制!
但在同一个索引处理器里,另外还有两个真正名叫 evergreen_video 和 evergreen_nsfw_video 的索引——它们走的是独立的 EvergreenVideo 事件分支,只调用了 hasImmersiveVideo(只检查是不是视频类型,没有检查 durationMillis > 10000!)。这说明代码并没有把 10 秒门槛一刀切加到所有分支上(不过上游 evergreen 事件名单是怎么生成的并未开源,所以也不能反过来保证短视频一定能进 evergreen)。
同样,用 Grok 生成的 AI 视频索引 buildImagineIndex 检查的是 isImaginePost(看媒体里的 Grok 元数据),也没有调用 hasValidImmersiveVideo。把这些分支摆出来,是为了帮大家精确分清“哪三个视频库卡 10 秒”、“哪些分支另有规矩”。50
19.3 五秒视频仍可能进入一般帖子索引
那么问题来了:如果我手头有一支只有 5 秒钟的软件操作动图视频,发出来是不是在 For You 首页就彻底成了“死帖”、一个陌生人都刷不到了?
并不会彻底死掉!
我们顺着普通合格帖子的点赞(Fav)分支(phoenixRankAllCandidateProcessor.strato#L506-L524)往下看:当一条 5 秒视频帖收到点赞时,程序会先执行普通帖子的 build1FavIndex(建立普通 1fav 索引)、主题索引和 32fav 索引,然后再去尝试建立视频专属索引!
而在普通帖子的 build1FavIndex 函数里,压根没有任何视频时长检查!
这意味着:你这支 5 秒钟的短视频,虽然因为时长不够 10 秒进不了 video 和 1fav_video 那三个专属视频库,但它完全可以正常进入普通帖子的 1fav 索引库(1fav_1day.parquet)!而前面我们已经证明过,普通 For You 首页的三大主力数据集(HOME、HOME_COLD、HOME_HOT)读取的恰恰就是 1fav_1day.parquet!(注:这是根据源码分支推导的程序条件说明,不是 5 秒视频的线上曝光实验。)38 34 50
所以,关于视频时长的实操结论非常清晰:
- 如果你演示的是一个 5 到 8 秒就能一眼看懂的极简小技巧,保留短小精悍的 5 秒版,它依然能走普通帖子的
1fav通道上首页,没必要为了凑时长在片尾硬塞 5 秒钟黑屏或无意义空镜(硬塞空镜反而拉低完播体验); - 但如果你希望这支视频同时进入
video和1fav_video等沉浸式视频专属流量通道(包括IMMERSIVE2Day、IMMERSIVE4Day和 4–14 天的EVERGREEN窗口),那就一定要把前后对比、操作步骤或适用边界展开讲讲,把视频实打实剪到 11 秒以上(严格大于 10,000 毫秒),并且绝不要在同一条帖子里混塞静态图片!49 50
19.4 另一个十秒判断,目前还没找到完整调用路径
为了保证代码核对的完整性,这里顺带记录一处公开树里的“孤儿代码”:在 eventProcessing.strato 里还有一个叫 isMediaEligible 的函数,里面也写了 > 10000 毫秒的判断并要求媒体非 NSFW,随后被 getTweetypieResponse 组装成 hasEligibleMedia(外加作者非 NSFW 条件)。但在整棵公开代码树里,只能找到 getTweetypieResponse 的定义和导出,找不到任何下游模块调用它。因此我们把它诚实列为“可见但下游未追齐的条件”,证明视频 10 秒铁律时,一律以我们上面完整追通的 hasValidImmersiveVideo 调用链为准。49
20 64 个赞和 512 个赞,对应不同的视频安全任务
网上传言:“视频帖拿到 64 个赞会触发第一轮流量助推,拿到 512 个赞会触发第二轮超级大推流!”
去源码里一搜 64 和 512,这两个赞数门槛还真的一字不差地写在 grox/flows/ptos 目录下——但让人哭笑不得的是:它们根本不是什么“流量奖励池门槛”,而是视频安全与违规审查机器人(PTOS)的启动门槛!51 52 53
你看下面这张表,64 个赞和 512 个赞在三条专门抓违规视频的审查流水线里,各自扮演着非常具体的审查角色:
| 安全审查任务名称 | 64 个赞的角色 | 512 个赞的角色 | 还要核对什么前置条件 |
|---|---|---|---|
SpecialVideo(特殊动态画面视频审查) | 触发该审查的默认最低点赞门槛 | 此任务无 512 赞切换 | 必须有视频,且必须命中 motion_reveal 动态闪现筛查 |
MediaInjected(夹带成人/红外垃圾视频检测) | 触发该审查的默认最低点赞门槛 | 满 512 赞时开启深度推理(use_reasoning) | 先前未判 NSFW、成功提取视频帧、且能载入违规参考视频库 |
AdultContentLeadingFrames(长视频前 10 秒涉黄审查) | 此过滤器未使用 64 赞门槛 | 满 512 赞后不再要求先前出现过 AdultContent 分类 | 视频时长 >= 30秒(或直播)、已有前置 PTOS 结果且尚未标 NSFW |
20.1 64 个赞是部分任务的最低资格
为什么安全审查要卡 64 个赞?道理跟前面讲 Article 图片搬运工一模一样:用大模型逐帧扫描视频太烧显卡算力了,所以系统重点盯防已经开始起量的视频!
在第一条任务 SpecialVideo(task_safety_ptos_special_video_filter.py)里,过滤器先检查:能获取到作者信息、帖子里(含本帖或被引用帖)有视频,并且当前帖子的点赞数 post.get_fav_count() 不低于 deluxe_fav_count_threshold(公开默认值为 64)。
跨过 64 赞门槛后,程序会为视频开启 motion_reveal(动态画面突变检测,专门抓那种“前几秒正常、中间突然闪现一帧违规画面”的套路),拉取视频数据后还要先过一道 task_special_video_screen.py 初筛:只有真的检测到了 motion_reveal_frames 信号,才会继续往后送去做内容分类、违规政策判定与交叉验证。所以“满 64 赞”只是触发了这道动态安检的入场条件,绝不等于每条满 64 赞的视频都会把全套模型跑到底,更不代表会被判违规。51
20.2 512 个赞在这条流程里用于开启 reasoning
再看第二条任务 MediaInjectedAdultInfraredVideoSpamDetection(专门抓在正常视频里恶意注入成人画面、红外透视或垃圾水印的作弊视频):
它的过滤器同样要求有作者、本帖或引用帖含视频、点赞数至少达到 64 个赞,并且先前的审查还没把它标为 NSFW。等到真正执行大模型推理时(task_safety_ptos_media_injected_adult_infrared_video_spam_detection.py),必须确认已经提取到视频帧,并加载“已确认违规的黑名单参考视频库”来做比对(如果没取到帧或参考库加载失败则无法完成比对)。
那么 512 个赞在这里干了什么?
当视频点赞数达到 512 时,程序会把 use_reasoning(开启大模型思维链深度推理) 开关设为 true,切换提示词与输出模式,让 AI 先写出推理过程再做违规比对!一旦被判违规,它会生成 SpamManipulatedMedia(操纵媒体垃圾)分类送往公共写入池(走普通 Spam 分支的作者资格判断,不会直接触发后面讲的“5 条里有 3 条封号”规则)。52 54
20.3 检查开头画面,还要满足片长和先前结果的条件
第三条任务 AdultContentLeadingFrames(长视频片头涉黄检查)更是把 30 秒、10 秒、512 赞 三个数字串在了一起:
- 它首先要求有作者信息,且本帖或引用帖里有时长至少 30 秒(
>= 30秒)的长视频(或有可用标识的直播broadcast),同时要求这条帖子已经有过前置 PTOS 初审结果(如果没有前置 PTOS 结果,哪怕已经 1 万个赞也会在这个过滤器被跳过),且尚未被正式打上 NSFW 标签; - 满足上述前提后,只要符合以下两个条件中的任意一个,就会正式启动片头深度检查:
- 要么先前的任意一条标注里曾经出现过
AdultContent(成人内容)嫌疑分类; - 要么当前帖子的点赞数已经达到至少
512个赞!
- 要么先前的任意一条标注里曾经出现过
- 一旦进入检查,程序会把这支长视频(或直播)设置为专门裁切前 10 秒钟的开头画面,送去做内容分类、政策判定,并和另一个独立的
sex-and-nudity视觉模型做双模型交叉验证(Cross-validation)(如果两个模型结论不一致,会走仲裁流程再定;有些不支持直接硬拦截的特殊视频任务,交叉验证没通过时会改走较轻的「软处理」,最后按保留下来的政策分类写入标签)。53
20.4 跨过赞数门槛,不等于那一刻必然完成检查
同时要注意,这三条视频安检流水线是由不同的 Kafka 消息队列(Kafka=系统内部传递任务消息的队列通道,可以理解成后台的传送带)触发的,并且都配了 60 秒去重限流缓存(task_rate_limit.py)。公开代码展示的是消费端收到任务后怎么过滤和审查,并没有保证每条视频在前台跳到第 64 个赞或第 512 个赞的那一毫秒,上游都会实时发一条消息过来。51 52 53
但把这三段代码看完,你至少彻底看清了一件事:视频的 64 赞和 512 赞,完完全全是安全审查系统的“安检升级线”,跟“解锁下一级流量奖励池”半毛钱关系都没有! 平时发视频时,不仅要注意自己拍的视频封面和前 10 秒画面,连你随手转发引用(Quote)的别人视频素材也要看清楚干不干净——因为上面这三条安检线,全都把**本帖视频和被引用帖视频(Quoted Video)**一并纳入了扫描范围!51 52 53
21 小账号的 200 次 Home 曝光,究竟是什么门槛
这一节是所有中腰部创作者和刚起步的新号最关心的话题:“听说 X 算法给粉丝少于 5 万的小账号开了一条绿色通道——新帖发出来前 2 小时有 200 次曝光的冷启动扶持!这到底是怎么运作的?我作为小号该怎么接住这波流量?”
在之前的版本里,如果只列一堆参数名,大家看完还是云里雾里。我们直接用大白话把这套冷启动机制还原成一个形像的场景:“打分房间里的小账号直升电梯(author_cold_start.rs)”!
先看那个著名的 200 在源码(home-mixer/scorers/author_cold_start.rs)里是怎么写的:57
&& c.view_count_on_home
.is_some_and(|imp| imp < params.impression_threshold)
公开默认参数里,impression_threshold 确实等于 200,判断符号是 <(严格小于 200)。我在本地重写这段函数做边界验证时,固定其他条件不变,传入 199 时返回通过(true),传入 200 时当场返回不通过(false)!
但请注意两个极其关键的真相:
- 这不是“每发一篇新帖,系统先保底白送给 200 个读者看,测完好坏再决定升不升级”的分发流水线;恰恰相反,它是说**“当你的新帖已经在某位读者的临时篮子里,只要它目前在全站 For You 首页累计被刷到的次数还不到 200 次,它就有资格参加这次直升电梯的抽签”**!
- 代码里查的字段叫
view_count_on_home(纯 For You 首页推荐曝光数),根本不是你在帖子底下看到的公开总观看数(Views)! 你在前台看到的 Views,包含了别人点进你个人主页看的次数、搜索看到的次数、外部链接点进来的次数,甚至包含了你自己反复点开看自己的次数!所以当你看到前台显示已经有 210 次 Views 时,后台纯粹的view_count_on_home是多少,外人看不到——它跟前台的这个数不是一回事,不能拿前台数字判断冷启动还在不在。千万别盯着前台数字一过 200 就自己吓自己说“完了,200 次冷启动测试没过,这篇废了”!57 58 59
21.1 两小时以内、Home 曝光少于 200,要同时满足
想要坐上这台“小账号直升电梯”,你的这篇候选帖子必须同时满足以下全部硬条件(代码里全是用 && 串联的,缺一个都不行;而且早在 10 月 9 日的公开快照里就已经是这套规则了):35 60
# 条件重述,并非逐字源码;代入所读公开默认
cold_start_base_eligible(candidate, follower_cap)
&& cold_start_corpus_eligible(viewer_arm, author_corpus)
&& age.is_some_and(|age| age <= max_post_age)
&& position_among_nonzero < floor(0.97 * nonzero_count)
&& view_count_on_home.is_some_and(|imp| imp < 200)
我们把上面这 5 行代码翻译成你能逐条对照的 5 张入场门票:
- 门票一(作者体量与原创性):作者的粉丝数必须已知且不超过 50,000 人(
<= 50000,刚好 5 万粉也算合格);并且这篇帖子绝对不能是回复贴(!is_reply),也绝对不能是普通转发(!is_retweet)!(注意:代码这里只检查没有回复 ID 和普通转发 ID,并没有排除带评论引用quoted_tweet_id——也就是说,你发原创帖或者发 Quote 引用帖,都能拿这张门票!) - 门票二(实验分组匹配):系统做实验时会把读者和作者各自分组,这次刷首页的读者所在的分组(
viewer_arm),要和作者所在的那一组内容池(author_corpus)对得上;同时冷启动总开关是开着的,而且这次请求不是主题请求(Topic Request)。 - 门票三(2 小时窗口):帖子发布至今的年龄必须不超过 7,200 秒(
<= 2 小时)! - 门票四(不能是彻底垫底的烂帖):在当前这个临时篮子所有非零分候选帖里,这篇帖子的初步得分排名必须在前
floor(0.97 × 非零候选总数)名以内(也就是剔除掉得分最垫底的大约 3%)。 - 门票五(首页曝光未满 200 次):这篇帖子目前累积的内部首页曝光数
view_count_on_home必须严格小于 200 次(< 200)!(另外,这套直升电梯只能提拔已经先被召回采购员抓进当前临时篮子、并通过了已读和拉黑过滤的候选帖。)35 61
为了让你一眼看清这几张门票是怎么卡人的,我们列一张 6 种常见情况的实测判定表:35
| 假设其他资格都符合 | 需要核对的值 | 这一道资格的结果 | 原因 |
|---|---|---|---|
| 帖子刚发了 1 小时 | 内部 Home 曝光 199 次 | 通过资格! | 199 < 200 且年龄 ≤ 7200 秒(至于最后抽不抽中它,看下一步抽样) |
| 帖子才发了 10 分钟 | 内部 Home 曝光刚到 200 次 | 直接出局! | 代码写的是 < 200(严格小于),一到 200 立刻毕业下车 |
| 帖子已经发了 3 小时 | 内部 Home 曝光只有可怜的 10 次 | 直接出局! | 曝光再少也没法抵消年龄超过 2 小时(&& 必须同时满足) |
| 作者粉丝数刚好卡在 5 万整 | followers = 50000 | 通过粉丝条件! | 代码上限使用的是 <= 50000,包含 50,000 本身 |
前台公开观看数(Views)显示 180 | 不知道内部 view_count_on_home | 无法用前台数字直接判定 | 代码读的是内部专属的 Home 首页曝光字段,不能直接拿前台 Views 代替 |
| 这是一条去别人底下评论的回复贴 | in_reply_to_tweet_id 有值 | 直接出局! | 第一关 !is_reply 直接拦死,发得再早、曝光再低也没资格进冷启动 |
来源 35
还要顺便提一个技术细节:在 engagement_counts_hydrator.rs 里,系统去拉取一般 view_count 和专属 view_count_on_home 时,是分成两个独立字段拉取的,而且配了一个 60 秒有效期(TTL = 60s)的计数缓存。这说明后台计数本身就有最多 60 秒的缓存刷新间隔,再一次印证了没必要死盯前台数字跳到 200 的那一秒钟。35
21.2 合格之后,还要从候选里选一篇
好了!假设现在读者张三下拉刷新首页,他的临时篮子里有好几篇来自不同小作者的新帖,全都同时集齐了上面那 5 张门票。但直升电梯每次最多只能保送 1 篇帖子上去!系统该挑哪一篇呢?
打开 author_cold_start.rs#L236-L333,这里用了一套非常经典的强化学习探索算法——Thompson Sampling(汤普森采样,基于 Beta 分布的概率抽样),而且分两步挑出最终的幸运儿:36
# 公式重述,并非逐字源码;代入所读先验默认
n = impression_scale * view_count_on_home
x = min(max(fav_count, 0), n)
alpha = 0.75 + x
beta = 49.25 + max(n - x, 0)
sampled_reward = sample(Beta(alpha, beta))
# 默认:先留下抽样值最高的 2 篇
# 再从这 2 篇中挑目前观众的 ranking score 最高者
来源:36
别被 Beta(alpha, beta) 吓到了,我用大白话给你翻译一下这几行代码在干嘛:
- 第一步:看“历史首页点赞率”摇号抽出前 2 名(
top_k = 2) 程序会直接读取每篇合格新帖目前真实收到的点赞数(fav_count)和内部首页曝光数(view_count_on_home)(注意:这里实打实用到了真实点赞数!)。 在还没有任何曝光(n = 0, x = 0)时,系统给每篇新帖设了一个默认先验参数(先验=还没看到任何真实数据之前,先假设的一个起点值):alpha0 = 0.75、beta0 = 49.25。算一下先验平均值:$0.75 \div (0.75 + 49.25) = 0.75 \div 50 = \mathbf{1.5%}$! 换句话说:系统默认对一篇小作者新帖的基准预期,大约是“每在首页曝光 100 次,能拿到 1.5 个赞(1.5% 首页点赞率)”!(注:这是 Beta 分布的先验均值,不是保底给 1.5% 流量。) 随着你的新帖在首页被几十个人刷到,如果你的实际首页点赞率高于 1.5%,你的alpha变大,摇出高数字的概率就会大幅增加;但因为是随机抽样(保留探索不确定性),刚发出来 0 曝光的新帖也有机会摇出高点数。摇完号后,系统会先留下抽样点数最高的 前 2 篇(默认top_k = 2)!36 - 第二步:在这前 2 名里,挑出“当前这位读者最感兴趣(预测分
score最高)”的那 1 篇! 这第二步设计得太精妙了:摇号进决赛圈的有 2 篇新帖,最后谁能真正坐上电梯?系统不再看谁的点赞率高,而是直接比拼**“对此时此刻正在刷首页的这位读者张三来说,哪一篇的模型预测排序分(ranking score)更高”**,挑出分高的那 1 篇保送上楼!(如果当次篮子里本来就只有不超过 2 篇合格新帖,top_k = 2会把它们全留下来,直接按当前读者的模型预测分挑最高的那篇。)36
看懂这个“先按首页点赞率摇号选 2 篇,再按当前读者预测分二选一”的机制,你就明白为什么**“拉微信群找朋友点进主页互赞”对冷启动几乎没用**了:
- 第一,群友顺着链接或点进你个人主页给你点的赞,虽然让
fav_count加了 1,但群友不是在 For You 首页刷到你的(分母view_count_on_home规则不同),而且你在群里找来的朋友跟你目标陌生读者的画像完全不搭; - 第二,哪怕你靠刷赞混进了前 2 名的决赛圈,最后二选一PK的依然是陌生读者张三的 AI 模型预测分!如果你的内容本身跟张三的阅读历史不匹配,在决赛圈照样会被刷下来!35 36
21.3 程序里的第十六名,怎样变成一个目标分数
那被选中的这唯一 1 篇幸运新帖,“坐直升电梯”到底会被保送到第几名呢?
打开参数文件 home-mixer/params/param.rs 和 author_cold_start.rs:公开默认设置里,ColdStartSlotMin = 15、ColdStartSlotMax = 16。程序在抽取目标位置时,调用的是左闭右开区间的随机函数 random_range(15..16)(上界 16 不包含在内)——也就是说,在公开默认配置下,它唯一锁定的目标位置就是从 0 开始计数的 index 15,也就是当前候选排行榜的第 16 名!(如果整个非零分池子里的帖子总数还不到 16 篇,则不执行提拔。)35 60
紧接着,程序会拿出当前排行榜第 16 名那篇帖子的分数作为“目标分数(Target Score)”,然后把你这篇被选中的小号新帖的分数改写成 max(你原来的分数, 第 16 名的目标分数)!
也就是说:如果你本来就能排进前 15 名,系统不会动你的高分;如果你本来排在第 500 名,系统就会直接把你的分数强行拔高到第 16 名的水平!(另外前面提过门票四:position_among_nonzero < floor(0.97 * nonzero_count),比如池子里有 100 篇非零分帖子时排除最后 3 篇,有 20 篇时取整排除最后 1 篇,“排除垫底约 3%”是它的直观说法。)35 36 60
不过要注意,在冷启动把你的分数抬到第 16 名水平之后,在 VM Ranker 的共用流程里,后面还会接着套用同作者 0.625 多样性衰减与 0.75 圈外 OON 乘数,最后还要过可见性过滤并与广告、对话卡片一起混排(blender_selector.rs)。所以这相当于给了你一张冲进前排视野的“强力助推器”,而不是把你焊死在每个人手机屏幕的第 16 个格子里。12 60
所以,对于粉丝不到 5 万的创作者来说,发帖后的前 2 个小时(7,200 秒)就是冷启动窗口:尽量挑你目标受众最活跃的时段发布原创干货帖(或高质量 Quote 引用帖),前两小时有人在评论区指出漏了什么条件就及时补充,但完全没必要像机器人一样在评论区无限刷屏回复,更不要因为前十分钟前台观看数没动就慌忙删帖重发!35 36
21.4 NewUser 在这里指新读者
在结束冷启动这一节前,必须顺手辟一个害苦了无数新手的谣言:“新注册的 X 账号千万别直接发帖,必须先装成普通读者每天刷帖、点赞、评论‘养号’满 7 天,否则过不了 NewUserMinEngagementFilter(新用户最低互动过滤器)!”
去把 home-mixer/filters/new_user_min_engagement_filter.rs 的源码打开看一眼,你就会发现造谣的人连主语都没看懂:
- 这个过滤器检查的变量叫
query.user_id——在整套Home Mixer代码里,query.user_id代表的永远是**“此时此刻正在下拉刷新首页的这位读者(Viewer)”**,根本不是发帖的作者(candidate.author_id)! - 更何况,在公开参数配置(
param.rs#L832-L860)里,这个过滤器的启用开关默认值是false(关闭状态)!
拿着一个“默认关闭、且本来是用来查刷首页的新读者”的过滤器,去忽悠新作者“前七天不准发帖先去给别人点赞养号”,纯属指鹿为马!如果你刚注册了一个新账号,第一天就把头像、具体清晰的 Bio 简介弄好,直接发出你精心准备的第一篇干货原创帖并置顶,粉丝不到 5 万的新帖,前 2 小时有冷启动的资格窗口,第一篇就该拿准备好的干货去用。57 58 62
22 “新帖不再先被砍”,实际改的是来源名额分配
在 10 月下旬的算法更新里,除了上面的“打分房间里的直升电梯(author_cold_start.rs)”,官方还在**“进打分房间之前的检票口”**新增了一道对新帖和小号非常友好的保护机制——这就是网上传的“10 月底更新后,新帖在进模型打分前不会再被先砍掉了(FairShareRankingFilter)”。
我们先查它的准确出生时间:在 home-mixer/filters/fair_share_ranking_filter.rs 的提交历史里,这个过滤器是在 2026 年 10 月 21 日(提交 7f2ca2b) 第一次写进代码的,当天默认开关是 false(关闭);紧接着在第二天——2026 年 10 月 22 日(提交 989fb91),公开默认开关 EnableFairShareRanking 就被正式改成了 true(开启),模型打分预算 PhoenixScoresResultSize 默认设为 2800!16 61
| 公开提交 | UTC 时间 | 洛杉矶时间(PDT) | 公开默认 |
|---|---|---|---|
7f2ca2b914cadac591ea7fceec0c477e473d3dee | 2026-10-21 00:52:08 | 2026-10-20 17:52:08 | 新增 FairShare 过滤器;开关 false;打分预算 2800 |
989fb91254d461bf4b9df53fb12d5c9a61c2b354 | 2026-10-22 06:49:38 | 2026-10-21 23:49:38 | FairShare 开关正式改为 true;打分预算仍为 2800 |
来源 16
22.1 按来源分组,再分配名额
很多朋友之前看不明白 FairShareRankingFilter 到底是干嘛的,我用一句话给你讲透:
每次读者刷首页,各个采购员(关注流 Thunder、常规推荐流 Phoenix、冷启动流 ForYouPhoenixRetrievalCold、零赞流 ZeroFav 等)抓进临时篮子里的候选帖加起来可能有 3,000 多篇;但是,负责精细算命打分的 AI 大模型(Phoenix Scorer)算力有限,每次最多只肯看 2800 篇(PHOENIX_CLIENT_MAX_CANDIDATES = 2800)!
- 在 10 月 22 日之前怎么砍人? 检票员不管三七二十一,直接把所有渠道送来的帖子按列表平铺排成一队,只留前 2,800 个,排在第 2,801 往后的直接一刀砍掉! 结果那些排在队伍尾巴上的“冷启动渠道(
ForYouPhoenixRetrievalCold)”或“零赞新帖渠道(ZeroFav)”送来的小作者新帖,连见 AI 裁判一面的机会都没有,在门外就被团灭了! - 10 月 22 日启用
FairShare之后怎么检票? 检票员先把所有候选帖按它们的出身渠道(served_type)分成不同的小组,然后严格按照每个渠道送来的帖子数量占总数的比例(外加最大余数法),把这 2,800 张打分入场券公平分给每一个渠道!61
# 流程重述,并非逐字源码
total = sum(source_counts)
if total <= budget:
keep every candidate
else:
allocation_i = floor(source_count_i * budget / total)
distribute remaining slots by largest remainders
keep the first allocation_i candidates within each source group
来源:61
我们拿一个具体的数字例子算一遍,你就彻底看懂它的威力与边界了:
假设某次刷新,临时篮子里一共进了 3,000 篇 候选帖(超出了 2,800 的打分预算,必须砍掉 200 篇)。其中主力大渠道 A 送来了 1,200 篇,大渠道 B 送来了 1,200 篇,而排在列表最末尾的**冷启动渠道 C(Cold)**送来了 600 篇:
| 假设来源 | 进入初筛的候选数 | 以前按列表硬砍的结果 | 现在 2800 名额按比例分配(FairShare) | 仍被此步移除的数量 |
|---|---|---|---|---|
| 主力来源 A | 1200 | 留下 1200 | 1120 | 80 |
| 主力来源 B | 1200 | 留下 1200 | 1120 | 80 |
| 冷启动来源 C(排在队尾) | 600 | 只剩 400(被砍掉 200 篇!) | 560(保住了 560 篇!) | 40 |
| 合计 | 3000 | 2800 | 2800 | 200 |
来源 61
你看上面这张表:
- 以前按列表顺序一刀切,排在最后的冷启动渠道 C 要独自吞下全部 200 个裁员名额,600 篇新帖里直接被砍掉 200 篇,只剩 400 篇能进场;
- 现在有了
FairShare按比例分配,主力渠道 A 和 B 各自让出 80 个名额,冷启动渠道 C 成功保住了 560 个进场打分的名额(比原来多了 40% 的进场机会)! 同时,你也看到了严谨的边界:冷启动渠道 C 里排在最后面的那 40 篇 候选帖,在这一步依然会被裁掉(因为组内依然是保留原有顺序的前allocation_i篇,并没有在组内按帖子新旧或点赞率重排)。所以最准确的说法是:FairShare保护了冷启动与零赞等弱势渠道按比例进场见裁判的公平机会,但并不是给全站每一篇新帖发了“绝对不被裁员”的免死金牌(如果某次篮子里的总候选本来就不超过 2,800 篇,则一篇都不砍,全部进场)。61
22.2 2800 个候选名额,和 200 次 Home 曝光无关
这里顺手帮大家把代码里几个容易撞车的数字彻底拎清:
2800(PhoenixScoresResultSize/PHOENIX_CLIENT_MAX_CANDIDATES):是某一位读者单次刷新首页时,送进 Phoenix 打分模型的候选帖子数量上限;- 第一个
200(PhoenixColdStartMaxResults = 200):是向 Phoenix 召回服务要货时,单次最多要回多少篇冷候选帖的请求参数; - 第二个
200(ColdStartImpressionThreshold = 200):是我们上一节讲的,你自己的那篇新帖在全站 For You 首页已经累积被刷到了多少次的冷启动资格上限。 这三个数字管的是完全不同的环节,千万别听信某些营销号瞎编的“新帖先进 200 人冷启动池,合格后再升入 2,800 人中级流量池”——把“单次打分候选池能塞 2,800 篇帖子”当成“把你的帖子推给 2,800 个观众”,那是连“帖子数”和“观众数”都没分清!16 35 61
23 重要更正只补在旧帖下面,原来的读者可能刷不到
平时我们发完一篇技术测评或教程,第二天突然发现里面有个数据算错了、或者漏了一个重要前提,绝大多数人的第一反应都是:“我赶紧去昨天那条原帖底下,自己回复自己补一条勘误说明吧!”
千万注意!如果你只把重要更正补在旧帖的评论区里,昨天已经看过你那条旧帖的成千上万名老读者,在他们的 For You 首页上极大概率根本刷不到你这条新更正!
为什么?我们直接打开负责过滤“已读帖子”的源码文件 home-mixer/util/candidates_util.rs 和 previously_seen_posts_filter.rs,答案就在下面这三行代码里:20
std::iter::once(candidate.tweet_id)
.chain(candidate.retweeted_tweet_id)
.chain(candidate.in_reply_to_tweet_id)
你看清这三行代码是怎么查“已读记录”的了吗?
当系统检查一条候选帖该不该被“已看过滤器(PreviouslySeenPostsFilter)”拦下来时,它不仅检查这条候选帖自己的 ID(candidate.tweet_id),还会顺着铁链(.chain)一并检查它的转发原文 ID(retweeted_tweet_id)以及它直接回复的父帖 ID(in_reply_to_tweet_id)!只要这三个 ID 里有任意一个命中了这位读者本次请求带入的已看记录(包括明列的 seen_ids 列表或近似的布隆过滤器 Bloom filter(一种快速判断“好像看过”的近似名单,偶尔会认错);另外 previously_served_posts_filter.rs 也会用同样逻辑检查本次会话已下发过的 ID),整条候选帖就会当场被当成“已读旧闻”直接过滤踢走!20
我们拿一个具体场景走一遍这三行代码:
假设你昨天发了一篇《数据库性能压测报告 A》,反响很好,有 1 万名读者在首页刷到并看过了这篇帖子 A(此时,帖子 A 的 ID 就写进了这 1 万名读者的 seen_ids 已读记录里)。
今天早上,你突然发现昨天的压测漏掉了“重启后冷缓存(Cold Cache)”这个关键条件,结论完全反过来了!于是你在昨天的帖子 A 底下,直接点“回复”发了一条重要更正说明 B。
请问:今天这 1 万名看过 A 的老读者刷新首页时,能刷到你的新更正 B 吗?
刷不到! 因为新更正 B 是直接回复 A 的,所以 B 身上的 in_reply_to_tweet_id 字段填的正是昨天那篇旧帖 A 的 ID!当 B 进入那 1 万名老读者的候选池过安检时,previously_seen_posts_filter.rs 一查发现:“咦?B 的父帖 A 已经在读者的已看名单里了!” 咔嚓一刀,直接把你今天刚发的新更正 B 给过滤掉了!20
23.1 一般补充留在对话里,改变结论的结果单独发
看懂了这三行代码,以后遇到内容补充和勘误,你就知道该怎么分情况处理了:
- 如果是读者在评论区问的局部小问题(比如有人问“你测试脚本的启动命令是什么?”、“第三行配置是不是少打了个分号?”):直接在原帖评论区里回复他就够了,方便后来点进评论区的读者顺着楼层往下看。
- 如果是足以改变原文核心结论的重大更正、补测反转或新版发布:绝对不能只补在旧帖评论区里!必须同时做两件事:① 在旧帖底下留一条简短的更正指路链接;② 单独发一条全新的独立原创帖(或者用带评论引用 Quote 原帖的方式发出来)!
(为什么单独发新帖或者用 Quote 引用原帖不会被拦?因为上面那三行代码只查
tweet_id、retweeted_tweet_id和in_reply_to_tweet_id,并没有查quoted_tweet_id!)
当你单独发一条独立更新帖时,开头千万别写得没头没尾,要让“没看过昨天旧帖的新读者”和“看过昨天旧帖的老读者”都能一眼看懂:
独立更正新帖的开头示范: “更正说明:昨天的数据库性能压测漏掉了一个关键条件——重启后的冷缓存(Cold Cache)。
今天补完冷缓存测试后,原本关于‘首次查询响应耗时’的结论需要修正。这篇把最新的测试条件、修正后的对比表格,以及原报告中依然成立的部分完整列在下面,供大家核对。”
这样一来,昨天看过旧帖 A 的老读者能在首页正常刷到这条独立新帖,避免被错误结论误导;而今天刚刷到你的新读者,也能直接拿到最完整、最准确的最新测试数据!20
24 旧内容可以重新介绍,已看记录却不会随转发消失(彻底讲透自己转发 Repost 老帖子的 5 道关卡与 Quote 破圈法)
很多创作者看到“普通候选帖超过 48 小时就会被年龄过滤器(AgeFilter)淘汰”,同时又听说“转发(Repost / Retweet)会生成一个新的 tweet_id”,脑子里立马就会冒出一个绝妙的点子:
“那我每隔两天,把我自己以前写过的干货老帖子直接点一下‘普通转发(Repost / Retweet)’顶上来,岂不是能让我的老帖子无限复活、源源不断推给全站陌生人?”
在之前的讨论里,很多朋友专门让我把**“直接点普通转发(Repost)自己的老帖子,在代码里到底会发生什么”彻底掰开讲透。 今天我们就顺着源码,带你亲眼看看当你按下“Repost(普通转发)”自己 5 天前的老帖子时,这笔转发在推荐管线里会接连撞上哪 5 道关卡,以及为什么“跨时区补漏用 Repost,破圈找陌生人必须用 Quote(带评论引用)”**!63
24.1 直接普通转发(Repost)自己的老帖子,在代码里会经历哪 5 道关卡?
- 第一关(48 小时年龄关
AgeFilter):确实能顺利通过! 在home-mixer/filters/age_filter.rs里,AgeFilter只保留发布时间不超过 48 小时(MAX_POST_AGE = 48 * 60 * 60 秒)的候选帖。但它检查的是当前候选帖自己的tweet_id(由thunder_source.rs把你今天点转发生成的全新 ID 填在tweet_id里,而把 5 天前的老帖原文 ID 存在retweeted_tweet_id里)。因为你今天刚点的转发拥有一个今天刚出生的tweet_id,所以它确实能顺利绕过 48 小时年龄限制,不会被AgeFilter当场砍死。39 63 - 第二关(陌生人破圈关
OONRetweetReplyFilter):直接被一刀毙掉,根本去不了陌生人面前! 这是粉碎“靠自己 Repost 老帖破圈”幻想的最关键一步! 还记得我们在第 8 章讲过的圈外过滤器oon_retweet_reply_filter.rs吗?它有一条毫无商量余地的铁律:直接移除所有“候选作者(author_id)不在当前读者关注名单内”的普通转发(is_retweet)! 别人(同行大 V 乙)转发你的老帖之所以能帮你破圈,是因为对乙的粉丝丙来说,转发人乙是丙关注的人(属于圈内 In-Network),不会被这个过滤器拦住;但当你自己点普通转发自己的老帖时,转发人还是你自己!对于全站所有还没关注你的陌生人来说,你依然是“圈外人(Out-Of-Network)”,所以你自己点的普通转发,在普通推荐候选管线里会被 100% 拦截,根本不可能被推给未关注你的陌生人!30 - 第三关(自家老粉丝已读关
previously_seen_posts_filter.rs):看过的老粉丝绝对不会再看见第二次! 既然去不了陌生人那里,那推给已经关注我的自家粉丝总行吧?这里又严格分成了两拨粉丝:
- 5 天前已经刷到过你那篇老帖的粉丝:刚刚上一节才看过源码,已读过滤器会把新转发的
tweet_id和老帖原文的retweeted_tweet_id绑在一起查!只要这位粉丝 5 天前已经刷到过你的原帖,他的已读记录(seen_ids)里就已经记下了你老帖的原文 ID,今天你点的这笔新转发会被当场拦下,他在首页绝对不会刷到第二次! - 5 天前刚好没上线漏看的老粉丝,或者这两天刚关注你的新粉丝:他们关注了你(走圈内
Thunder通道,不被第二关拦),而且他们的已读记录里还没有那篇老帖的 ID(不被第三关拦)——只有这群“漏看的老粉 + 新涨的粉丝”,才会在首页刷到你对自己老帖的普通转发!20 39
- 第四关(同池去重与
0.625抢权重关):会跟你今天发的新帖子自己打自己! 如果你今天既发了一篇全新的原创帖,又随手点了一下普通转发自己的老帖子,这两条动态头顶上的作者 ID(author_id)全是你自己!对于那些还没看过你老帖的粉丝来说,这两条动态会同时掉进他的临时篮子里,在 VM Ranker 打分时直接触发0.625同作者衰减(老帖转发抢了你今天新帖的满分名额,或者新帖把老帖转发压到0.625)! 另外,如果原帖发出来还没满 48 小时你就去点普通转发,RetweetDeduplicationFilter(retweet_deduplication_filter.rs)还会按原文 ID 把原帖和转发合并去重,绝不会让你在同一个篮子里占两个坑;而且前面讲的小账号冷启动 200 次曝光扶持(author_cold_start.rs)和互关好友 20 倍回复加成(inputs.rs)都明确写了!self.is_retweet,普通转发统统拿不到!2 35 42 63 - 第五关(安全标签连坐关):如果老帖带敏感标签,转发会把雷直接引爆到今天!
后面第 28 章会详细讲“最近 5 条帖子里有 3 条带
NSFW_HIGH_PRECISION标签就给账号打上账号级标签”的规则(safetyLabelToUserLevelAggregationV2Processor.strato)。在这段代码里,当扫描你的时间线遇到普通转发时,程序会调用originalTweetForRetweet去查那篇老帖原文身上的安全标签,但却用今天这笔新转发的 ID 来算 60 天有效期窗口!也就是说,如果你把一两个月前曾被贴过敏感标签的老帖手欠点了一下转发,它会直接占掉你当前最近 5 条帖子的计数名额,甚至直接凑够 3 条触发账号级标签!79 80
24.2 这次重新介绍,给它一个现在的用途(Repost 与 Quote 的正确分工)
把上面这 5 道关卡看完,“怎么让以前写过的优质老干货重新发光发热”,最科学的实操标准答案就已经呼之欲出了:
- 什么时候直接点“普通转发(Repost / Retweet)”?——只在“跨时区补漏”时点一次! 比如你在北京时间中午 12 点发了一篇重磅长文,国内白天的粉丝看完了;到了北京时间晚上 11 点(北美和欧洲时区的中文读者刚刚起床刷手机),你可以顺手点一下“普通转发(Repost)”,专门把这篇干货补喂给白天没上线漏看的海外时区老粉丝,以及今天刚点关注的新粉丝(发完记得别跟自己的下一篇新原创帖撞在同一分钟发)。
- 想让三个月前的老干货重新破圈、触达全站“未关注你的陌生人”?——千万别点普通转发,一定要用“带评论引用(Quote Post)”!
为什么 Quote(带评论引用) 能完美避开普通转发的所有死穴?
因为在代码底层,Quote 帖拥有自己独立的正文和全新的
tweet_id,它的is_retweet字段是false(老帖 ID 存在quoted_tweet_id字段里)!这意味着:
- ① 完美通过陌生人破圈关:它不是
is_retweet(也不是is_reply),所以完全不会被OONRetweetReplyFilter拦截,能像全新原创帖一样正常推给全站未关注你的陌生人! - ② 完美通过已读过滤关:前面看过的
previously_seen_posts_filter.rs那三行代码只查tweet_id、retweeted_tweet_id和in_reply_to_tweet_id,根本没有查quoted_tweet_id!所以哪怕是以前看过原帖的老读者,也能在首页刷到你带新评论的 Quote 帖! - ③ 满血享受冷启动与高权重:它不被
author_cold_start.rs的!is_retweet排除,小账号发 Quote 帖照样能拿前 2 小时 200 次 Home 曝光的直升电梯扶持;而且 Quote 本身的互动预测权重高达5.0(是普通转发1.0的 5 倍)!20 21 30 35
当然,用 Quote 重新介绍三个月前的老帖子时,千万别只在上面敲四个字“重温旧文”或者每天机械地复读“这篇很重要”——一定要结合读者当下的新场景,给老干货赋予一个“今天就要用”的新理由! 比如你三个月前写过一份《租房退租交接检查表》,到了毕业搬家季,你用 Quote 引用那篇老帖,配文写上:“最近到了退租高峰期,退租扯皮最常出在这三处角落。退房交钥匙前务必按这份表格逐项拍照留底,已根据今年常见扯皮点补充了水电表读数核对项👇”(如果原表格有内容过时了,记得先更新并标明修订日期)。这样发出来,不管是算法还是真人读者,看到的都是一篇解决当下燃眉之急的满血新干货!
顺便说一句“直接点击编辑(Edit)修改已发帖子”的规则:在可见性系统 visibility-filtering/models/tweet.rs 和 tweet_rules.rs 里,有一条专门过滤“已经被新编辑版本取代的旧版本帖子(stale edited version)”的规则——它的作用仅仅是保证读者刷到的是你改完之后的最新版,而不是那个还没改错别字的旧残影!网上有人把它传成“帖子发出来只要点编辑改一个错别字,整篇帖子就会被算法降权作废”,纯属自己吓自己(当然,点编辑也不会帮你把 48 小时的帖子年龄重置回 0 秒;发现了影响结论的硬伤,第一时间改好让读者看到正确内容才是最重要的)。64
24.3 一天、两天和 49 小时,各自限制什么
一路读到这里,你已经先后见到了 24 小时(1 天)、48 小时(2 天)和 49 小时 这好几个跟帖子寿命有关的时间数字。为了防止你把它们混成同一个“全站统一的帖子死亡倒计时”,我把它们在源码里各自管的地盘汇总成了下面这张表:37 34 39
| 所在代码位置 | 检查的具体对象 | 公开代码里的条件 | 这个条件没有回答(不能瞎推)的事 |
|---|---|---|---|
普通候选管线的 AgeFilter | 当前候选帖自己的 tweet_id 所对应的创建时间 | 保留 age <= 48 小时;严格超过 48 小时才排除 | 没有直接拿 retweeted_tweet_id(被转发老帖原文)的年龄做这项比较 |
普通 HOME 召回数据集 | 指定的 Parquet 索引数据文件 | HOME/HOME_COLD/HOME_HOT 引用 1fav_1day.parquet(24 小时窗口) | 不能由这一个枚举反推线上所有请求与其他召回源(如 Thunder)都只抓 24 小时内的内容 |
rankall 索引存储窗口 | 各个 Index 的数据保留范围 | 1fav 有 24/48 小时窗口;32fav 有 24 小时等窗口 | 某个数据桶的存储窗口,不等于一篇内容在全站所有入口的总曝光寿命 |
Favorite 点赞事件更新器 | 帖子本身年龄,以及距离首次索引更新的时间 | 帖子年龄 < 49 小时;已有缓存时距首次更新 <= 48 小时,更新间隔 >= 1 分钟 | 这只管“收赞后还更不更新索引”,不能代替候选帖最后过不过 AgeFilter |
AgeFilter 实际使用:
is_within_age(candidate.tweet_id)
保留条件:age <= MAX_POST_AGE
MAX_POST_AGE = 48 * 60 * 60 秒
来源:39
你看 AgeFilter 的源码:它用的是 age <= 48 * 60 * 60 秒(小于等于 48 小时保留,超过 48 小时才移除)。把这个细节摆出来,是为了帮我们准确描述代码边界,而不是让你去卡着 47 小时 59 分 59 秒搞什么玄学操作。20 39
24.4 其他入口也有自己的资格
最后还要记住:普通候选管线的 48 小时 AgeFilter,只管 ScoredPosts 这条常规候选流。前面我们提过,在 For You 顶层流水线里并列的 PushToHomeSource(按指定帖子 ID 推送),以及沉浸式视频数据集里长达 4 天、14 天甚至 14 到 30 天 的视频窗口(video_4day、video_4to14day、32fav_video_14to30day),都有各自独立的时间窗口和准入规则。所以千万别拿视频的 14 天窗口去证明普通图文帖能免除 48 小时限制,也别因为普通候选有 48 小时限制就以为两天前的长文在全站彻底消失了——学会用 Quote(带评论引用)+ 当下新痛点 把沉淀下来的老干货二次激活,才是长效运营的正道。30 50 39
25 回复质量还有另一套评估
前面我们聊了“回复贴能不能进陌生人的首页候选池”,以及“主计分表怎么给别人回复你的概率算分”。但在算法库的 grox/flows/reply_spam 目录下,其实还藏着另一套专门针对**“评论区回复内容本身的质量与垃圾评估系统”**——这两套系统千万不能混为一谈。65
在 classifier_reply_ranking.py 和 task_write.py 里,程序会把整段对话上下文、互动信号和作者粉丝信息打包送给 Grox 大模型,让模型给这条回复打一个回复质量分(ReplyRankingScore),部分低质结果还会触发有条件的风险打标(不过具体用来评判好坏的大模型提示词 prompts.py 并未开源,因此我们能确认评论区另有大模型质量评估,但不能瞎编“超过几个字或用哪个固定句式就必死”)。65
即便不看未公开的提示词,我们把评论区里最常见的两种回复摆在一起对比,高下立判:
- 假设一位同行发帖贴出了一张“文件格式转换报错”的截图,你在底下回一句万能正确的废话:“写得太棒了!很有启发,感谢博主的无私分享!”(甚至是用 AI 批量生成的二十句同义词夸奖)——这种回复对原帖讨论没有任何信息增量;
- 反过来,如果你在回复里直接指出:“这个报错码是因为输入文件名带了中文括号,对应转换脚本的第 3 步;我在 macOS 15 + v2.4 版本下重现过,把路径先做一次引号转义就能跑通”——你的这条回复直接给整个讨论串补上了可验证的排查材料。如果用 AI 辅助写评论,也是先让 AI 帮你提取原帖的痛点、已有结论和缺失条件,再由你填入自己亲历的实测细节,而不是拿 AI 当复读机到处刷屏。
25.1 在别人帖子下连续回复自己,什么分数可能被写成零
很多人在做评论区引流时喜欢用一个套路:跑到粉丝很多的大 V 热门帖底下抢个前排留言,然后为了放自己的推广链接或长篇大论,在这条留言底下连续“自己回复自己”盖起三四层楼。 网上传言:“在大 V 底下连续回复自己会被判定为垃圾号,直接把你的账号权重或者大 V 原帖的分数清零!”
我们去翻 grox/flows/reply_spam/task_multi_step_reply_spam.py 和 classifier_multi_step_reply_spam.py 的源码,先把“到底是谁的什么分数被清零”说清楚:一旦被这条规则判定为“多层自回自评垃圾推广(Multi-Step Reply Spam)”,程序写成 0.0 分的是你那几条被判为垃圾的回复贴自己的 ReplyRankingScore(评论区排序分),既不会扣掉人家大 V 原帖的分数,也不会把你整个账号的主页推荐分数清零!66 67
25.2 对话结构检查与模型判断的先后
这套专门抓“在别人底下盖楼自回自评”的过滤器叫 TaskMultiStepReplySpamFilter(task_multi_step_reply_spam.py)。并不是你在评论区回自己一句就立刻触发大模型审查,它必须先过一道非常具体的**“对话结构门槛”**:66
- 祖先链完整且排除官方 AI:当前回复必须有完整的对话祖先链(不能含缺失项),当前帖、直接上一条父帖与最顶层根帖都能取到作者资料,且排除
@grok和@gork账号; - 关键豁免——排除“根帖作者自己写串文(Thread)”:如果当前回复的作者就是最顶层根帖(Root Post)的作者本人,直接跳过不查!这证明了:你在自己的主帖底下连续回复自己写串文(Thread),绝对不会触发这条自回垃圾规则!
- 三层楼结构 + 直接父帖同作者:整段对话必须至少有 2 条祖先帖(也就是至少形成了“别人发的根帖 → 你的第一层回复 → 你接着回复自己的第二层回复”这三层结构),并且直接上一条父帖的作者必须和当前回复的作者是同一个人(你自己回你自己)!
- 根帖作者粉丝门槛是 1,000 粉:最顶层那篇根帖的作者,粉丝数必须至少达到 1,000 人(
>= 1000)(代码里写的就是明确的数字1000,不是什么模糊的“超级大 V”);同时,如果当前回复者本人拥有高 PageRank V2 或灰标认证(政府/机构灰标),也会被这个过滤器直接豁免跳过。66
把这组结构条件画成一张表,你就看明白什么叫“在大 V 底下盖楼自回”了:66
| 同一条示例对话的楼层 | 发帖作者 | 在 TaskMultiStepReplySpamFilter 里的角色 | 光靠结构是否就已经判为垃圾? |
|---|---|---|---|
| 第 1 层:最顶层根帖(Root) | 另一位粉丝数 >= 1000 的博主 | 提供讨论起点的他人主帖 | 否(受系统严格保护) |
| 第 2 层:一级评论回复 | 你自己 | 当前回复的直接父帖(Direct Parent) | 否 |
| 第 3 层:在自己评论下接着回复自己 | 依然是你自己 | 满足“至少两层祖先+父子同作者”的待检回复 | 否!结构达标只是送进大模型做内容判断 |
来源 66
你看表格最后一列:满足了“在千粉博主底下自己回复自己”的结构,仅仅意味着触发了送交大模型审查的资格,绝不等于自动被判为垃圾! 比如别人发了一道技术难题,你第 1 条回复贴了排查步骤,紧接着第 2 条回复自己补充了不同系统版本的兼容性差异——虽然结构上一模一样,但只要大模型看完内容认为你是正常补充讨论,就不会判你违规(当然,由于分类器的具体 Prompt 未公开,我们不去瞎编“连回几条必死”或“控制在多少字以内绝对安全”的假口诀)。66
25.3 模型圈出的帖子,还会经过一次筛选
就算大模型看完了整串对话,圈出了一批它觉得像垃圾推广的楼层(Flagged set),程序在真正下手写 0.0 分之前,还在 classifier_multi_step_reply_spam.py 里设了三道严密的防误伤筛子:67
- 必须包含最新这一条回复:如果大模型只圈出了你前面的旧楼层,却没有把当前正在评估的最新这一条回复圈进去,程序会认为不构成持续多层垃圾,直接把整组结果全部丢弃,一条都不罚!
- 剔除无辜路人且至少保留 2 条:程序会先把对话里其他作者发的帖子全部剔除掉(只留你自己的回复);剔完之后如果发现只剩下孤零零的 1 条,不满足“多步(Multi-step)”定义,同样整组丢弃不罚!
- 根帖铁桶保护:在把对话喂给大模型时,程序不仅在文本里把第 0 层明确标为
root post提醒模型不准标记,在解析模型返回结果时还写了硬代码只接受index > 0的楼层,从物理上彻底排除了把千粉博主的原帖(Root Post)误伤标黑的可能!67 (顺便提一个模型视野限制:如果整串对话的祖先楼层超过 10 层,这个分类器只会截取最前面 5 层 + 最后面 5 层 + 当前最新回复,且每条最多读 2 个媒体附件;这说明它看的是头尾抽样,不是把百层高楼一字不漏全读完。)67
25.4 写成零的是被判为垃圾的回复记录
只有穿过上面所有筛子最终保留下来的那几条你自己的垃圾回复 ID,写入器(task_multi_step_reply_spam.py#L151-L198)才会挨个先尝试给它们打上 RiskyHighVizReply(高曝光风险回复)标签,然后发布下面这行将评论排序分归零的指令(仅在正式生产环境 production 模式下执行):67
ReplyRankingScore(
score=0.0,
reasoning=reasoning[-500:]
)
来源:67
注意这里“打 RiskyHighVizReply 标签”和“把 ReplyRankingScore 写成 0.0”在代码里是前后两步动作:负责打标的辅助函数(task_write.py)内部还会再查一遍高 PageRank/信用分、灰标与测试账号豁免;就算因为豁免没打上那个标签,外层函数依然会继续往下走、把 score=0.0 的分数发布到缓存、Kafka 和 Strato 数据库里。(公开代码里能追到这个 0.0 分的生成与发布,但下游各个评论区排序入口具体怎么消费它未完全公开,所以我们严格按源码称之为“将该垃圾回复的 ReplyRankingScore 归零”,而不夸大成账号被封杀。)66 67
对我们创作者来说,道理再简单不过:去别人评论区留言时,如果有新的数据、步骤或反例要补充,大大方方把背景写清楚;如果是为了在别人的热门帖底下挂羊头卖狗肉,一层接一层地自己回自己贴卖课广告或引流二维码,那正是 TaskMultiStepReplySpamFilter 瞄准的活靶子!
26 引用别人的原文,也会遇到可见性条件
很多做行业点评、热点分析或辟谣的博主,最常用的一招就是**“带评论引用(Quote Post)”**别人的帖子。大家往往觉得:“只要我自己写的这段评论没违规,这可是堂堂正正的原创 Quote 帖(权重 5.0),流量稳得很!”
但你很可能忽略了一条隐藏在 home-mixer/candidate_hydrators/vf_candidate_hydrator.rs 和 ancillary_vf_filter.rs 里的**“附带内容连坐规则”:
当你的候选帖准备上读者首页时,可见性系统不仅检查你这条帖子本身,还会顺带检查它身上挂载的所有附带内容(Ancillary Tweets)——包括你引用的原帖(Quoted Tweet)、转发的原帖以及对话祖先帖!
如果被你引用的那条别人发的原帖,后来被原作者自己删掉了,或者因为违规被平台判了移除处置(代码里明确检查 Drop、Tombstone 墓碑屏蔽或 NotEvaluated(尚未评估);注:一般的折叠警告软处置不在此列),ancillary_vf_filter.rs 就会直接把你这条引用帖(整个候选)也一起从推荐候选池里一刀移除!**68
想想看这个场景有多冤:
假设你看到网上有人发了一条漏洞百出的谣言帖,你义愤填膺地点了“引用(Quote)”,在上面只敲了一句话:“这人纯属胡说八道!真实数据根本不是这样的,大家千万别信!”
结果两小时后,那个造谣的人心虚把原帖删了,或者原帖被平台封禁变成了墓碑(Tombstone):
- 在算法推荐层面:因为被引用原帖触发了
Drop/Tombstone,你的这条辟谣引用帖在ancillary_vf_filter.rs这一关直接跟着陪葬,从陌生人的推荐候选池里消失了; - 在真人读者层面:哪怕有粉丝点进你的个人主页看到了这条帖子,由于底下的被引用原帖卡片已经变成了一块灰色的“该帖子不可用”,而你的正文只写了一句“这人纯属胡说八道”,读者根本不知道你在反驳谁、对方说了什么、真实数据又是什么!
所以,每次当你准备用 Quote 去点评或反驳别人的帖子时,务必在自己的正文里把“对方原来的核心主张是什么、为什么错、你的真实证据和原始出处是什么”完整交代清楚(甚至可以把核心争议点客观总结在你的首图里);如果是一个非常重要且对方随时可能删帖跑路的辟谣选题,干脆直接发一条完全不挂引用卡片的纯独立原创帖,这样你的心血之作就永远不会被别人的删帖或违规牵连下水!68
27 发外链前,先确认它最后把读者带到哪里
关于在 X 上发外部链接(External URLs,比如你的独立博客、GitHub 仓库、Substack 电子报或 Notion 模板下载页),网上流传着两条最让人头疼的传言:
- 传言一:“只要帖子里带了外部链接,算法就会固定扣除 30%–50% 的曝光!”
- 传言二:“只要把外链从主帖正文挪到第一条评论(首条回复)里,就能完美骗过算法、逃避外链惩罚!”
我们把公开代码库里所有跟外链相关的模块翻出来对质:这两条传言在公开代码里统统不成立!真正决定你发外链会不会出事的,根本不是“放正文还是放评论区”,而是你这条链接跳转链条上的“网址信誉评级(URL Reputation)”以及你有没有把坏链接挂在主页置顶上!69 70
先看计分表:在 home-mixer/models/content_features.rs 里,系统确实提取了一个叫 has_url(是否包含链接)的布尔特征传给下游;但在最终打分公式(scoring.rs)里,没有任何“只要 has_url == true 就乘以 0.5 或扣 30% 分数”的惩罚代码!恰恰相反,在 24 项权重表里,“预测读者点击打开外部链接(Open link)”还拥有 +0.2 的正向加分权重!21 69
27.1 检查电子报、作品集和下载入口
既然带正常外链不扣分,那为什么现实中确实有人发了外链之后流量暴跌? 因为他们的链接撞上了反垃圾系统(BotMaker)专门抓低质量/恶意跳转链接的审查机器人! 在日常发外链(比如发你的电子报、作品集或资料下载入口)之前,请务必养成一个保命习惯:亲自从草稿或测试帖里点开一次你准备发的链接,盯着浏览器地址栏看它中间跳转了几次、最后落到了哪个域名上,并核对落地页内容是不是和你在正文里承诺的一模一样! 比如你正文答应给读者一份 Excel 报价模板,结果短链接点进去先跳了两个莫名其妙的广告统计域名,或者你三年前买的老作品集域名早就过期被博彩网站抢注篡改了——这种跳转链失效或域名易主,才是触发外链风控的头号元凶(当然,肉眼检查能帮我们排除死链和被篡改的域名,但 X 内部网址信誉库对某个域名的具体评级数值,在网页外观上是看不出来的)。
同时,在正文里要把“点开这个链接会看到什么”交代得明明白白(比如写清“点击下方 GitHub 链接可直接下载包含 3 个字段的 CSV 测试样本,对应 v2.1 版本”)。如果你为了正文排版清爽,选择把链接放在一楼评论区,也要在主帖结尾指路让读者找得到——但千万别指望“挪到一楼评论区就能躲开低质链接审查”,为什么?看下面 v1 和 v2 机器人的源码对比你就懂了!
27.2 置顶里的问题链接,可能给整个账号打上标签
更凶险的一颗雷藏在你的个人主页置顶帖(Pinned Post)里:
在 botmaker-rules/scarecrow/bot/PinnedLowQualityOrBadUrl.bot 里,有一条专门盯着“更换置顶帖”的账号级规则!一旦你把一条带有 BAD 或 LOW_QUALITY 评级链接的帖子设为了主页置顶(且满足作者条件),系统不会只罚那一条置顶帖,而是会直接给你的整个账号打上长达 7 天的 SPAM_HIGH_RECALL 账号级限流标签!
一旦背上这个账号级标签,在接下来的整整 7 天里,你发的所有新帖子(哪怕一字外链都不带)在陌生人推荐入口(HomeRecommendations)都会被直接拦截!所以如果你突然发现自己连续好几篇新帖的陌生人曝光断崖式归零,第一件事就是回头检查:最近是不是换过主页置顶帖?置顶帖里挂的旧链接是不是出问题了?(配合后文教你的官方 Under the Hood 工具,可以直接查出报告期内有没有背上这个标签。)71 72
27.3 文件名里的“陌生人”条件,v2 已经不再要求
为什么网上会流传“把外链放到第一条回复(评论区)就能免罚”?
因为这帮写攻略的人看的还是老掉牙的 v1 旧版规则,压根不知道代码库里早就升级到了 v2 新版规则!
我们把 botmaker-rules/scarecrow/bot/ 目录下的旧版 LQ_Tweets_With_LQ_URL_Verdict_At_Mention_To_NonFollower.bot(v1)和最新版 ..._v2.bot(v2)并排放在一起对比,真相大白:73
| 检查条件 | 旧版 v1 规则 | 最新版 v2 规则 | 对创作者的真实意义 |
|---|---|---|---|
帖子里 @(Mention)了未关注你的陌生人 | 要求至少 @ 了一名非粉丝 | 已彻底删掉此条件! | 虽然 v2 文件名还留着历史名字,但代码里根本不再查有没有 @ 陌生人 |
回复贴(isReply)/转发贴(isRetweet)豁免 | 明确排除回复和转发(放回复里确实不查) | 已彻底删掉排除条件(回复和转发照查不误)! | “把低质外链塞进首条评论就能逃避处罚”在 v2 里已经彻底失效! |
网址跳转链质量判定(redirectionChain) | 跳转链整体评级符合 LOW_QUALITY | 跳转链中任意一跳含 LOW_QUALITY,且最后一跳不是 GOOD 或 WHITELIST(白名单) | 哪怕最终落地页正常,只要中间用的短链跳转服务被判 LOW_QUALITY 照样中招! |
| 命中后写入的惩罚标签 | 帖子级 SPAM_HIGH_RECALL | 帖子级 SPAM_HIGH_RECALL | 在 HomeRecommendations 推荐入口对该帖执行直接移除(Drop) |
来源 73
你看上面这张表第二行和第三行:
- 在旧版 v1 时代,代码里确实写了排除
isReply和isRetweet,所以当年把外链塞进评论区确实能钻空子;但在最新版 v2(判断时只看三样输入——发帖人的 ID、帖子 ID、非空的跳转链记录——再排除掉测试号、高 PageRank、临时豁免名单与灰标号)里,程序员已经把“排除回复和转发”以及“必须@陌生人”的条件删得一干二净了!只要你用了被标为LOW_QUALITY的短链或跳转域名(且最终落地页不在白名单或GOOD名单里),不管你是放主帖正文,还是偷偷塞进一楼评论区,v2 机器人照抓不误,当场给那条帖子打上SPAM_HIGH_RECALL标签! - 反过来,如果你发的是干干净净、信誉良好的正规网址(比如直接放 GitHub、主流媒体或正常备案的高信誉站点),哪怕直接放在主帖正文里,也根本不会命中这条规则(当然,正常的短网址、UTM 统计参数或正规联盟链接只要域名信誉没变黑也不会无故挨罚)。73
27.4 七天从写入标签时起算
我们再把前面那个凶险的**“置顶帖坏链接炸弹(PinnedLowQualityOrBadUrl.bot)”的触发细节抠清楚:
这个机器人监听的是用户资料修改事件(user_modification)。只有当你的置顶帖 ID 列表(pinnedTweetIds)发生了变化(修改后的 after 值存在、不为空、且跟修改前的 before 值不一样),它才会去抓取你新换上去的那条置顶帖里的所有展开链接(expanded URLs),解析它们的真实落地去向与网址信誉(Reputation)。只要其中任意一个链接包含 BAD 或 LOW_QUALITY(且作者不属于测试账号、高 PageRank、AutoExpiringTempSkipList 临时豁免名单或政府机构灰标 Grey Badge**——注意:普通花钱买的蓝标 Premium 绝不等于这里的灰标,没有免死金牌!),就会立刻给整个账号写入 SPAM_HIGH_RECALL 标签!74
这里有两个关乎切身利益的时间细节:
- 7 天封禁期从哪一秒算起?
代码里写的是
CurrentTimeMs() + 7天(一周),也就是从你换上这条问题置顶帖、触发机器人写入标签的那一秒钟开始往后数整整 7 天(跟那条老帖子本身是什么时候发的无关,也跟你哪天打开后台看到报告无关)。 - 如果我发现不对劲,马上把置顶帖取消(Unpin)掉,7 天限流标签会立刻消失吗?
不会立刻自动消失! 在
PinnedLowQualityOrBadUrl.bot这份规则文件里,只写了“换上问题置顶帖时新增 7 天标签”的逻辑,根本没有写“一旦取消置顶就立刻删除该账号标签”的对应分支!(当然,我们也不能排除后台其他申诉或人工修正服务会提前介入处理;而且等 7 天标签到期自动消失后,新帖依然要正常过召回、已读和打分流程,代码没有承诺第 8 天早上流量自动补偿翻倍。)所以,在点下“置顶到个人主页(Pin to profile)”按钮之前,花 5 秒钟亲手点一下里面的链接确认能正常打开,能帮你省去整整 7 天的无妄之灾!74 75
28 同一个安全标签,在不同入口会怎样处理
很多创作者一听到“我的帖子或账号被打了安全标签(Safety Label)”,第一反应就是:“完了,我是不是全网彻底黑号了?连关注我的老粉丝都看不到我了?” 还有人会找一个已经关注自己的铁粉朋友问:“兄弟,你点进我主页或者刷关注流,能看到我刚发的帖子吗?” 朋友看了一眼说:“能看到呀!” 于是他就放心地以为自己根本没被限流。
这两种想法全都错了!
在 X 的架构里,“安全系统给帖子或账号贴标签(Safety Labeling)”和“可见性过滤系统决定怎么拦截(Visibility Filtering)”是上下游分开的两套系统。同一个安全标签,在“老粉丝刷的主页(TimelineHome)”、“给陌生人推流的入口(HomeRecommendations)”以及“点进详情或主页(HomeHydration)”里,受到的待遇完全不同!76 77 75
先交代一个版本问题,免得有人拿代码改动乱传限流:我把 10 月 28 日(5ed7963)和 10 月 29 日(606b254)两个版本的安全与可见性代码对过一遍,本文后面要讲的自动打标、5 帖聚合、视频和回复审查,规则和结构都没变。可见性过滤那个目录倒是重构过一次——重复的规则被抽成可复用的列表,散落的开关改写成统一的 ClientSwitch 集合——但我把重构前后的 14 组规则列表逐项展开核对,所有入口的过滤规则和执行顺序都一致。(这是按结构核对的结论,不是逐字节比对。)所以别把程序员正常的一次代码整理,传成「10 月 29 日又搞了一轮全网大限流」。76
28.1 侮辱标签限制哪些读者、哪些入口
我们先拿一个最典型的帖子级标签——FOSNR_ABUSE_INSULTS(辱骂与人身攻击标签;FOSNR 的全称,公开代码里没有给出)——来看看它在三个不同检查入口的真实待遇:
为什么这个标签在代码规则里写的适用对象是 NonAuthors(除了作者本人以外的所有人),但在实际效果上却变成了“老粉丝还能看见,唯独陌生人完全刷不到”?
秘密就在 Home Mixer 的分流逻辑(vf_candidate_hydrator.rs)里!
当 Home Mixer 把候选帖送去做安全检查时,它会先看这位读者有没有关注你:
- 如果读者已经关注了你(
in_network = true),你的帖子会被送去TimelineHome安全级别做检查——而在TimelineHome的规则表里,压根没有配置“遇到FOSNR_ABUSE_INSULTS就直接移除”的规则!所以你的老粉丝在首页依然能刷到! - 如果读者还没有关注你(
in_network = false,圈外陌生人),你的帖子会被送去TimelineHomeRecommendations安全级别做检查——而在这个陌生人推荐入口里,白纸黑字配了“对作者本人以外的所有人(NonAuthors)直接移除候选(Drop)”!77 75
把 FOSNR_ABUSE_INSULTS 标签在各个检查入口的待遇列成表,你就看懂这个标签在不同入口的待遇差别了:77
| 安全检查入口 | 当前读者身份或客户端条件 | 对 FOSNR_ABUSE_INSULTS 标签的处置 | 这一步说明什么 |
|---|---|---|---|
TimelineHome(圈内关注流入口) | 只考虑这一个标签时 | 没有配置该标签的移除(Drop)规则 | 老粉丝走这个入口不会被这条规则拦下(但若同时带其他违规标签或拉黑仍会被别的规则拦) |
HomeRecommendations(圈外陌生人推荐入口) | 作者本人以外的所有人(NonAuthors) | 直接移除候选(Drop)! | 这正是“陌生人推荐流量彻底归零”的罪魁祸首! |
HomeHydration(数据补齐层) | 未关注你的陌生人(且客户端支持 FOSNR 规则) | 直接移除(Drop) | 受客户端开关(FosnrRules 默认开启)控制 |
HomeHydration(数据补齐层) | 已关注你的粉丝(且客户端支持 FOSNR 规则) | 软干预提示(Soft intervention) | 粉丝能看到,但可能会附带提示层 |
HomeHydration(数据补齐层) | 作者本人(且客户端支持 FOSNR 规则) | 展示可申诉的处置提示信息 | 你自己看自己的帖子完全正常,甚至带申诉入口(旧版客户端若触发 FosnrFallbackDrops 则对所有人移除,但该 fallback 默认关闭) |
同时,自动打上这个 FOSNR_ABUSE_INSULTS 标签在 Grox PTOS 写入路径(task_write_safety_post_annotations_result_sink.py)里也有三个明确的前提条件:
① 模型必须判定帖子属于 HateOrAbuseInsultsWithTarget(针对特定目标的仇恨或侮辱攻击);
② 帖子的语言必须被识别为英语(English);
③ 作者不是高 PageRank 或灰标账号(测试账号更早被排除)。
(当然,这只说明这一条自动写入分支要求英语,绝不代表你用中文骂人就不受其他自动规则或人工举报的约束。)所以平时写锐评或技术反驳时,对事不对人、摆数据讲逻辑,别图嘴快加人身攻击词汇,否则一旦挂上这个标,老粉丝虽然还能在评论区跟你互动,但整篇帖子的陌生人破圈通道就彻底关门了。77
28.2 LOW_QUALITY 和 MISINFO:警告给谁看,限制哪些操作
网上还有一句传言:“只要帖子被贴上 LOW_QUALITY(低质量)或者 MISINFO(不实信息)标签,系统就会对所有非粉丝弹出警告遮罩,并且直接锁死点赞和转发分享按钮!”
去核对 visibility-filtering/rules/tweet_rules.rs、rule_spec.rs 和 verdict.rs 的源码,警告遮罩(Interstitial)和互动按钮锁死(Limited Engagements)确实存在,但传言把适用对象和触发条件搞错了三个地方:78
- 适用受众是所有人(
Everyone),不只是非粉丝! 这条名叫PUBLIC_INTEREST_LABEL_INTERSTITIAL的规则,针对的是 2019 年 4 月 1 日之后发布的、带有帖子级LOW_QUALITY标签,或者带有四种不实信息标签(MISINFO_CIVIC公民选举、MISINFO_GENERIC通用不实、MISINFO_MEDICAL医疗健康、MISINFO_CRISIS危机事件)的帖子——它的展示受众写的是Everyone(所有人,连粉丝也一样会看到警告)! - 到底锁死哪几个互动按钮,取决于标签的来源(
source)与策略配置!
- 如果是
LOW_QUALITY标签,程序会直接选用NonCompliant(不合规) 作为互动限制等级——在公开测试预期(limited_actions_policy.rs)里,NonCompliant确实是最狠的“全家桶锁死”:回复、普通转发、点赞、表情回应(React)、私信发送、加入收藏夹、加入 Moments、置顶、查看帖子数据、系统分享和复制链接,统统被禁止! - 但如果是四种
MISINFO标签,程序会先去读这个标签身上的source(来源字段):比如当source为limited_replies时,它只会选用ConversationControl(对话控制),在测试预期里仅仅限制“回复(Reply)”这一项,点赞和转发分享根本没锁死! - 不过这里有一个极容易漏看的保底陷阱(Fallback):如果一条
MISINFO标签身上压根没有填source字段,虽然在第一步生成警告时留空了限制项,但到了第二步LabelInterstitial组装最终互动限制原因(verdict.rs#L77-L83)时,代码会自动退回(Fallback)使用最严厉的NonCompliant全家桶锁死!所以千万别以为“没填 source 就不会被锁互动按钮”。(另外,代码里把普通转发、引用、私信、系统分享、复制链接算成几个不同的独立动作;线上到底锁哪几个按钮,由一份实时配置(limited_actions_policy_limited_actions)决定,公开代码里的是测试预期。)。78
- 分清两个名字都叫
LOW_QUALITY的东西: 这里触发全套按钮锁死的LOW_QUALITY,是贴在帖子身上的帖子安全标签;而上一节我们讲外链时提到的LOW_QUALITY,是网址信誉库给域名打的网址评级(网址评级命中后给帖子写的是SPAM_HIGH_RECALL标签)。千万别因为名字一样,就以为自己随手发一条字数少、写得普通的日常动态也会被贴上LOW_QUALITY锁死点赞键!78 73
28.3 账号标签会影响多篇帖子,但要看具体名称
比单篇帖子标签杀伤力大得多的,是直接贴在你账号头上的账号级安全标签(Account Labels)——因为在陌生人推荐入口,账号一旦背上清单里的标签,你名下发的候选帖会在这个入口被整批拦下,根本不需要再逐篇审查你的新帖内容(粉丝那边的待遇不同,见下文)!
打开 visibility-filtering/rules/levels.rs 和 author_rules.rs,在陌生人推荐入口 HomeRecommendations 里,系统列出了长长一串会直接把该作者所有候选帖一刀移除(Drop)的账号级标签清单:75
- 成人与敏感类:作者自行标记为敏感账号(NSFW self-flagged)、管理员标记 NSFW 状态,以及
NSFW_HIGH_RECALL(高召回涉黄)、NSFW_HIGH_PRECISION(高精度涉黄)、头像涉黄(Avatar)、背景横幅涉黄(Banner)、近乎确定涉黄(Near-certain)等账号标签; - 垃圾与违规类:
SpamHighRecall(高召回垃圾号)、Compromised(账号被盗/存在安全风险)、ReadOnly(只读封禁状态)、ImpersonationHighPrecision(高精度冒充他人)、AbusiveHighRecall(高召回辱骂滥用)以及DoNotAmplify(禁止算法放大推荐)。
但是,即便背上了上面这些吓人的账号标签,网上那句“任何一个账号标签都会彻底断绝所有非粉丝触达”依然说得太绝对了:
因为代码里每一条规则都明确指定了受众(有的是 NonAuthors,有的是 NonFollowers),而且老粉丝刷的 TimelineHome 并没有整套照搬上面这张拦截清单;正如官方 Under the Hood 报告里对其中多个标签的准确定义——它们的作用是**“不向未关注该账号的非粉丝推荐其帖子(Do not recommend posts from this account to non-followers)”**,并不是把你在搜索框、个人主页直接访问、对话详情页或直接点链接等全站所有入口全都物理抹除掉。75
28.4 “最近五条里有三条”,到底在数什么
在所有账号级标签里,最让创作者心惊肉跳的莫过于这条“五三封号铁律”:网上传言“只要你最近发的 5 张图片里有 3 张涉黄(或者最近 5 条带图/视频的帖子里有 3 条涉黄),整个账号就会被直接封禁推荐 7 天!”
我们直接把 safety-label-user-agg/postToUserLabelRules.strato 里的公开默认 JSON 规则源码端上来,看看程序到底是怎么数的:79
"windowSize": 5,
"minimumMatchingPosts": 3,
"maxPostAgeDays": 60,
"mediaOnly": false,
"postLabels": {"anyOf": ["NSFW_HIGH_PRECISION"], "allOf": []}
来源:79
请把眼睛钉死在第四行:"mediaOnly": false(只数媒体帖 = 否)!
这行代码直接戳破了网上的两个重大误区:
- 它数的单位是“几条帖子(Posts)”,根本不是“几张图片”,也不是只数带图片/视频的帖子!
处理器(
safetyLabelToUserLevelAggregationV2Processor.strato)会从你的个人时间线接口(userTimeline)按时间倒序取出你最近发的帖子,先截取最前面的 5 条帖子(windowSize: 5),然后数这 5 条帖子里有几条在 60 天内并且身上带着NSFW_HIGH_PRECISION安全标签! 我们用一张 5 条帖子的时间线算例表,帮你一眼看懂它到底怎么记账:79 80
| 你时间线倒序的位置 | 帖子形式 | 身上的 NSFW_HIGH_PRECISION 标签 | 这条规则算几笔? |
|---|---|---|---|
| 最新第 1 条 | 一条视频帖子 | 有 | 计 1 笔 |
| 倒数第 2 条 | 一条纯文字日常吐槽(无任何图片视频) | 没有 | 计 0 笔(但它占掉了前 5 条窗口里的 1 个位置!) |
| 倒数第 3 条 | 同一条帖子里一口气放了 4 张敏感图 | 有 | 只计 1 笔!(4 张图装在 1 条帖子里,只算 1 条帖子) |
| 倒数第 4 条 | 一条普通图文更新 | 没有 | 计 0 笔 |
| 倒数第 5 条 | 另一条单张图片帖子 | 有 | 计 1 笔(累计满 3 笔,触发账号级标签) |
来源 79
你看懂上面这张表里的门道了吗?
- 第三条帖子里哪怕塞满了 4 张 敏感图片,因为它只是一条帖子,在这条规则里只算 1 笔(不会因为一条帖子放了 4 张图就当场凑够 3 笔封号);
- 第二条哪怕是一句纯文字帖子,因为
mediaOnly默认是false,它照样占掉了“最近 5 条窗口”里的 1 个名额!如果连发两条纯文字正常帖,原本排在第 4、第 5 位的老敏感帖就会被挤出前 5 条的检查窗口——这是计数方法的结果说明,不是躲避方法:触发看的是标签事件,别拿窗口当配方用。(注:表格仅演示代码计数逻辑,未使用真实账号线上数据。)
- 第二个细节:不需要等发满 5 条才开始查!
代码里用的是
take(5)(最多取前 5 条),然后直接判断匹配数量是否>= 3(minimumMatchingPosts: 3)。哪怕一个新号总共只发了 3 条帖子,只要这 3 条全带NSFW_HIGH_PRECISION,当场就够 3 条触发,绝不是“必须发满第 5 篇才启动检查”,也不是按 60% 百分比算的!79
28.5 六十天、七天、十分钟,别混成一个倒计时
围绕这条“5 条里有 3 条”的规则,代码里还有 60 天、7 天、10 分钟 三个时间参数,以及前面提过的**“转发老帖引爆地雷”**机制:
- 什么时候触发检查(60 天窗口)?
并不是你每发一条普通帖子都会跑一遍这个检查,它是由
Applied(某条帖子被新打上安全标签)事件触发的。公开默认要求触发事件对应的那条帖子在最近 60 天内,且新打上的标签正是NSFW_HIGH_PRECISION。触发后,程序先截取你userTimeline最前面的 5 条帖子,再数里面有多少条同时满足“年龄 ≤ 60 天”且“带有NSFW_HIGH_PRECISION标签”。79 80 - 转发(Retweet)会怎么查?
正如我们在第 24 章警告过的:当扫描你前 5 条时间线遇到一笔普通转发(Retweet)时,处理器会调用
originalTweetForRetweet去读取被转发原帖身上的安全标签,但用来计算“是否在 60 天内”的帖子 ID 用的却是你时间线上这笔新转发的postId!所以千万别手欠去转发别人(或自己以前)带NSFW_HIGH_PRECISION标签的敏感帖,否则等于把别人的雷直接背到自己最近 5 条的计数窗口里!80 - 没有高 PageRank 或灰标豁免!
在这条 3/5 聚合规则的默认配置里,虽然排除了
nsfwAdmin = true的账号和已经背着NSFW_HIGH_PRECISION账号标签的账号,但nsfwUser(已自行标记敏感内容的用户)排除开关设为了false,highPageRankOrGreyBadge(高权重或灰标大号)排除开关也设为了false! 也就是说,在这条规则面前,哪怕你是灰标大 V,或者已经在设置里勾选了“我的媒体包含敏感内容”,只要前 5 条凑够 3 条NSFW_HIGH_PRECISION,照样会给你整个账号打上账号级标签。这条写入路径在公开代码里带的公开 TTL 是 7 天,从写入那一刻起算——这是这条路自己的设置,跟置顶路的 7 天不是一回事(见第 31 条的区分)。(另外,事件转发器safetyLabelToUserLevelAggregationV2Forwarder.strato设置了 10 分钟延迟delay和 20 分钟最大延迟目标maxLag,所以是从第 3 条帖子被打标大约 10 分钟后才异步聚合到账号头上,不是第 3 条刚发出来的第 1 秒钟就立刻变天。)79 80
28.6 三条命中的默认规则,也能被配置覆盖
当然,我们也得保留配置层面的严谨性:上面的“前 5 条中 3 条、mediaOnly: false”来自代码里的 defaultRulesJson(公开默认配置),而程序运行时会通过 feature switch 读取 configuredRulesJson,随时可以动态覆盖这个默认值(比如把某组实验改成 mediaOnly: true)。
同一个文件里甚至还写了一条名叫 possibly_nsfw_account 的规则:它的开关 enabled 虽然是 true,但里面的参数居然写着**“在 10 条窗口(windowSize: 10)里要求至少匹配 11 条(minimumMatchingPosts: 11)”**——从 10 条里找 11 条在数学上是永远不可能达成的(不可达默认),这多半是程序员用修改阈值的方式在默认配置里把这条规则软停用了(线上可通过配置覆盖激活)。79
此外,在 botmaker-rules/scarecrow/ 下还有另一条更早的 NSFW 媒体事件聚合路径(NsfwTweetMediaProcessor.bot 与 ApplyNsfwUserLabel.df),它是按帖子 ID 把媒体事件放进 HLL 计数器(HLL=一种只数“大概有多少个不重复项目”的计数器),检查 1 天之内是否超过 2 笔,再送去打标或人工审核。这说明系统里抓成人内容的防线不止一条,千万别把“穿插发两条文字帖把敏感帖挤出前 5 条”当成永远不会被封的免死金牌。75 79 80
29 重复内容、互动诱导和 hashtag,能查到什么
29.1 能查到 COPYPASTA_SPAM 的写入,查不到完整的相似度门槛
很多做矩阵号、或者习惯把同一段文案反复发的朋友最关心:“X 算法是怎么抓复制粘贴(Copypasta)重复内容的?我们写中文没有英文那种空格分词,是不是就抓不到中文重复了?”
千万别抱侥幸心理!专门抓中文(中日韩 CJK 字符)重复的机器人就明晃晃地写在代码库里!
打开 botmaker-rules/scarecrow/bot/BBQDuplicateTextProd.bot 和专门管评论区的 BBQDuplicateTextRepliesProd.bot,你会看到这两个机器人接收上游定时任务跑出来的重复帖子聚类(tweetIdCluster),而上游任务(Job)的名字清清楚楚地列着两个:81
duplicate_text_unigrams(针对英文等按词切分的重复文本检测);duplicate_text_characters_cjk(专门针对中日韩汉字按字符切分的重复文本检测)! 而且连评论区回复都有独立的对应任务!一旦命中并通过资格检查(排除已处理或已带该标签的帖子、检查特定推广卡片、排除测试号/高 PageRank/临时豁免与灰标号,并受写入速率限制),机器人就会直接给帖子打上COPYPASTA_SPAM(复制粘贴垃圾) 标签!81
这里我们必须诚实守住两个代码边界:
- 查不到“到底重复多少个字、相似度百分之多少才算违规”:因为公开的这两个
.bot文件是从“收到上游已经聚好类的tweetIdCluster”才开始往下走的,上游离线任务到底用什么阈值、跨多少小时、重复几次才把帖子打包成一个 Cluster,代码并未放入公开仓库。因此,正常文章里引用同一句名言或同一个专业术语绝不等于必被打标,我们也绝不瞎编“重复满 15 个字必死”或“把句号改成叹号就能防查重”的假口诀。81 COPYPASTA_SPAM的下游消费端缺口:在这次公开的Home Mixer、VM Ranker和visibility-filtering代码树里,我们能确认机器人实打实地写入了COPYPASTA_SPAM这个标签,但还没有找到直接读取这个标签名并执行扣分或 Drop 的下游代码(可能由未公开的规则或服务消费)。我们如实把“确有 CJK 重复打标机器人”和“下游具体扣分比例未公开”这两件事原原本本摆出来,但不管怎么说,把同一段引流话术复制粘贴到十几个不相关的帖子底下刷屏,既容易招来这个标签,更会招来真人的举报(Report的系数是-234.0,乘的是预测概率)。76 81
29.2 三类互动诱导,没有这项高 PageRank/灰标豁免
平时刷 X 经常看到有人发这种骗互动的帖子:“同意的打 1,不同意的扣 2”、“转发这条锦鲤,评论区留下你的愿望,我抽十个人送……”。
在 Grox PTOS 的安全写入代码(task_write_safety_post_annotations_result_sink.py#L233-L248)里,程序员专门把三类互动诱导行为拎出来开了“严打通道”:54
SpamEngagementBaiting(互动诱饵/钓鱼骗互动);SpamEngagementFarming(互动农场/刷赞刷评养号);SpamCardManipulation(恶意操纵外链预览卡片骗点击)。
这三类违规在代码里的待遇有多狠?
对于其他普通的 Spam 垃圾类别,程序在打标前还会先看一眼作者是不是“高 PageRank 大号”或者“灰标认证号”,如果是就网开一面跳过不打标;唯独当大模型判定你的帖子属于上面这三类(Baiting、Farming、CardManipulation)之一时,程序直接把 should_label_for_spam 设为 true,当场跳过高 PageRank 和灰标豁免检查,哪怕你是高权重账号也照样给你贴上 SpamHighRecall 垃圾标签(直接从陌生人推荐流里移除)!54
当然,触发这条严打的前提是 PTOS 大模型在正式生产模式下先把你的帖子归入了这三类(具体判定的 Prompt 未公开,所以并不是你在干货长文末尾正常写一句“你们在实际项目里遇到过吗?欢迎在评论区聊聊”就会被判违规)。怎么提问才叫高质量互动?比如你测完两款软件后问读者:“上面这三项测试条件里,哪一项跟你们公司真实的部署环境不一样?欢迎贴出你的版本号和报错案例,我挑典型场景做下一期复测。” 这种问题有具体锚点、服务于内容本身,跟空洞的“扣 1 领资料”完全是两码事。54
29.3 有 hashtag 特征和滥用分类,没有通用的最佳数量
最后我们把创作者常问的另一个问题彻底讲透:“发帖子时带 # 话题标签(Hashtag),到底是有助于算法推荐,还是会被当成垃圾降权?一条帖子带几个 # 标签最合适?”
对照源码里的三处确凿证据,关于 # 标签的真相是这样的:54
- 带
#标签有用吗?有用,但不是直接加分项! 在主计分表里,没有任何“每加 1 个#标签就加几分”的公式;但在 Phoenix 模型的用户历史行为特征清单(history_id_lists.py与id_list_features.py)里,明确包含了一项叫CLICK_HASHTAG(用户点击过的#标签历史) 的特征!这证明系统在给读者做个性化召回和排序时,确实会参考用户平时爱点哪些#标签的行为信号,绝不能说#标签完全零价值。 - 代码里的硬上限是 4 个(
MaxHashtagsPerTweet = 4)! 在SimClusters的帖子实体抽取器(simclusters_v2/summingbird/common/TweetEntityExtractor.scala)里,程序员明确定义了一个常量:MaxHashtagsPerTweet = 4——当它从你的帖子文本里提取话题标签实体来构建兴趣社区关联时,最多只保留前 4 个#标签,从第 5 个#标签开始往后,在这条路径里会被直接丢弃无视!(注:这个4是该抽取器的读取上限,不是说带满 4 个就一定比带 1 个流量高,也不是说第 5 个就开始扣分。) - 乱塞无关热门标签会触发
SpamHashTagAbuse惩罚! 在 PTOS 的违规分类枚举(grox/flows/ptos/state.py)里,专门设有一项罪名叫SpamHashTagAbuse(话题标签滥用)。如果你写了一篇卖茶叶或聊开发的帖子,却在文末一口气堆上十几个当天最火的娱乐明星、体育赛事或币圈热门#标签想蹭流量,一旦被大模型判定为SpamHashTagAbuse(且无高 PageRank/灰标豁免),就会直接给帖子写上SpamHighRecall垃圾标签,在陌生人推荐流里把你彻底毙掉!54
所以,平时发帖用 # 标签的准则很简单:普通日常帖完全不需要硬凑标签;只有当你的文章确实围绕某个明确的专有名词、开源项目名、具体产品或行业活动展开时,自然地放上 1 到 2 个(这条抽取路径最多读前 4 个,第 5 个起就不读了)高度相关的 # 标签即可,千万别在文末堆砌一串跟正文八竿子打不着的热搜词!
30 曝光异常时,怎样用已有资料排查
聊完了所有的加分项和防风控雷区,万一哪天你精心写了一篇干货,发出去一看只有几十次观看,心里直犯嘀咕:“我到底是没进召回池、打分输给了同行、撞上了已读过滤,还是不小心踩雷被贴了安全限流标签?” 光盯着那几十次观看数猜来猜去毫无意义,因为不同原因需要看完全不同的证据。5 59 20 72
好消息是:在这次公开的算法仓库 README.md 和 under-the-hood 目录下,X 官方直接公开了一个专门给创作者查自己“到底有没有被贴安全与限流标签”的官方透明度后台——Under the Hood(点击直接访问:x.com/i/jf/under_the_hood)!
这是官方目前正在试行(Pilot)的账号透视镜工具,登录你的 X 账号后打开这个链接,就能直接查出在报告统计期内,你的**账号(Account)和帖子(Posts)**到底有没有被系统贴上影响可见性的限制标签!72
30.1 报告期间与可用性
在使用这个官方自查后台时,先注意代码(underTheHoodReport.User.strato)里写的两个规则:72 82
- 先看右上角的统计月份(
Period):页面默认展示的是上个月的月度汇总统计(如果上个月的数据还没生成完毕,服务会自动退回展示更前一期的数据)。所以打开页面后,第一件事是看清Period写的是哪个月份以及生成时间——千万别拿一份 9 月份的旧汇总报告,去解释你今天早上刚发的帖子为什么没流量! - 如果打不开或提示暂无报告,别慌,不代表你被封号了! 源码里写得很清楚:这个工具目前处于试行阶段(受服务开关控制),并且设置了明确的报告生成资格门槛——通常要求你的账号注册账龄满 1 年左右,并且在统计的那个月里至少发布了 10 条符合统计条件的合格帖子,系统才会为你生成月度报告。如果你是刚注册两个月的新号,或者上个月总共只发了 3 条帖子,看不到报告仅仅是因为没达到生成报表的统计门槛,跟你的账号有没有推荐资格毫无关系。82
30.2 分清帖子标签和账号标签
打开 Under the Hood 报告后,你会看到上下两块核心统计数据——Post labels(单帖级标签)和Account labels(账号级标签),它们的计量单位在源码(report.tsx)里是完全不同的:72
| 报告项目 | 里面的数字和百分比到底代表什么 |
|---|---|
Post labels(帖子标签) | 在该统计月份内,你发的所有合格帖子里有多少篇帖子被贴上了该标签,以及占当月总发帖数的百分比 |
Account labels(账号标签) | 在该统计月份内,你的整个账号一共有多少天背着该标签,以及占当月总天数的百分比 |
我们拿两个具体数字教你怎么读这张表:
- 假如你在
Post labels里看到某标签显示“3 篇(7.5%)”:这代表你上个月发的 40 篇帖子里,有 3 篇帖子曾被贴上这个标(占发帖数的 7.5%),绝不是说你整个账号被扣掉了 7.5% 的流量! - 假如你在
Account labels里看到某标签显示“5 天(16.1%)”:这代表在 31 天里,你的账号有 5 天时间背着这个账号级标签,但也不代表那 5 天里你在全站所有页面都人间蒸发了。72
具体怎么看它对流量的真实影响?请直接看报告里紧挨着标签名称旁边的两栏官方解释:What it means(这个标签代表什么原因) 和 Effect on visibility(对可见性的具体影响)!
在 underTheHoodLabels.strato 源码里,官方把每个标签的具体处置写得一清二楚:有的标签写的是**“不向未关注你的非粉丝推荐该帖/该账号”,有的写的是“附加内容警告遮罩”,有的写的是“特定国家或地区受限”**。
这就再次解释了我们前面说的:千万别找一个已经关注你的粉丝朋友问“你能不能看到我的帖子”来测试自己有没有被限流! 因为绝大多数限流标签只拦截“向非粉丝陌生人推荐(HomeRecommendations)”,你的老粉丝在关注流或点进你主页当然看得见你!只有对照报告里的 Effect on visibility,才能准确知道到底拦了哪扇门。72
30.3 报告没有列出标签,也不能解释每次排名
如果查完报告发现了标签,就把报告月份、标签英文原名和官方说明截图保存下来,回想一下那几天是不是换过失效的置顶外链、是不是连发过带敏感图的帖子、或者在评论区刷过重复内容;如果确属误判且界面提供了申诉入口,就按流程申诉。
反过来,如果你的报告里干干净净、显示没有任何受限标签(0%),那就说明你的账号和帖子在安全合规层面是完全健康的(注:代码标注该报告为 best effort 尽力而为统计,且月报存在时间滞后)。既然安全层面没被贴标拦截,那某篇帖子观看量低,问题就出在候选召回匹配度、首图与前 4,000 字的信息提取、或者打分排序时的停留与互动预测上——这时候我们就可以放心大胆地回到内容本身做单变量优化了!82
30.4 比较下一篇时,只先改一个主要因素
排除了安全标签嫌疑后,怎么一步步把账号的自然推荐流量拉起来? 先对照我们前面讲过的代码铁律,给手头的草稿做一次“五步体检”:
- 标题和前两百字有没有直接写出具体的研究对象和解决的任务(别写空洞的文艺口号)?
- **第 1 张图(首图)**放的是不是核心结果对比表(别把搞笑漫画或纯文字海报放第 1 张,把干货藏在第 4 张)?
- 开头第一段答应给读者的材料,在正文里有没有立刻兑现(别搞注水铺垫骗 10 秒停留)?
- 如果是发万字 Article,前 200 字标题有没有塞满关键词?发完有没有单独配一条挂着普通结果图的导读长 Post?
- 如果是补充重大更正或翻新老帖,有没有单独发新原创帖或用 Quote 引用(别只回复在已经 1 万人看过的旧帖底下,也别对老帖只点普通 Repost)?
在做优化实验时,最忌讳的就是“一上来同时改掉题材、格式、配图风格、发帖时间和受众方向”——五个变量一起改,就算下一篇阅读量涨了 3 倍,你也根本不知道到底是哪一招起了作用! 每次只改 1 个核心变量:比如这周同样发两篇难度和受众相近的 AI 工具测评,只把第 1 张图从“标题大字报”改成“核心结果对比表”,保持发布时段和推广动作完全一致,直接用账号自带的后台分析数据(Analytics)做对比记录(千万别自己瞎编一套“点赞×0.5+转发×1”的民间积分公式去算总分):59
| 建议记录的字段 | 具体怎么用来复盘 |
|---|---|
| 帖子链接、具体选题、发布格式(长 Post/Article/Thread)、发布时间、是否 Quote、外链位置 | 用来把任务相近的帖子归到同一组对比,避免拿“突发吃瓜帖”去和“硬核代码教程”硬比总浏览量 |
| 发布后满 24 小时、满 48 小时的后台可见数据 | 锁死统一的观察时间窗口(同一篇帖子的 24h 和 48h 是前后追踪记录,不能当成两篇独立样本) |
| 后台实际提供的分享、回复、主页点击、新增关注、收藏等细分指标 | 严格按后台字段定义记录(拿不到的内部停留秒数直接留空,千万别填成 0) |
| 带来的有效私信咨询、资料下载点击或实际业务转化 | 有些专业干货虽然总曝光平平,但吸引来的全是精准客户和铁粉关注(权重 4),比泛流量更有价值 |
| 同期是否蹭上行业热点、是否修改过稿件、以及 Under the Hood 已知标签记录 | 记录外部干扰因素,避免把行业大热点带来的自然暴涨错误归功于某次排版微调 |
对比多篇帖子时,多看中位数和整体分布,别被某一篇偶然被大 V 转发的爆款拉偏了均值。如果你刚开始建立自己的发布节奏,可以试试这套稳扎稳打的**“四周实战迭代法”**:
- 第一周(打地基):用前文的方法改好具体清晰的个人简介(Bio),检查并换上一篇最硬核、无死链的代表作当置顶帖,统计过去十篇帖子的各项中位数作为你的基线(Baseline);
- 第二周(稳产能):在保证干货质量不注水的前提下,按你自己能长期坚持的节奏(比如每天 1 篇,如果精力不够宁可改成每周 3 到 5 篇高质量原创,也别硬凑水贴)稳定输出;
- 第三周(单变量对照):固定题材难度,只挑 1 个核心动作做前后对比(比如专门对比“首图放结果对比表 vs 首图放标题封面”,或者对比“长 Post vs Article+带图导读”);
- 第四周(汰弱留强):回头盘点这一个月里,哪类选题、哪种首图排版真正给你带来了最高的收藏数、复制链接分享和主页关注转化,把它沉淀成你账号的专属标准模板!
31 把这些发现用在下一篇工具测试里
为了让你看清上面所有代码规则合在一起是怎么指导一篇具体文章从 0 到 1 诞生的,我们最后来做一次完整的实战沙盘推演——假设你明天准备发一篇**《用同一批真实中文发票,横评 A、B 两款 OCR 识别工具》**(A、B 为代称,下面演示的是怎么根据算法代码编排文章结构,不预设哪款工具赢):
31.1 读者准备拿这篇做什么
动笔写第一行字之前,先想清楚刷到你帖子的目标读者(比如财务主管或企业开发工程师)到底要拿你这篇帖子干嘛?
他们要么正在为公司选型采购 OCR 接口,要么已经在用其中一款、正头疼哪些字段老出错需要安排人工复核。
所以,你的开头第一段(直接决定前 4,000 字符语义向量与读者前 3 秒会不会划走触发 -0.02 惩罚),绝对不能写成“近年来 AI 视觉大模型发展迅猛,今天我们来聊聊 OCR 识别到底有多强”这种废话,而是直接开门见山切入具体字段与痛点:
开头第一段实战草稿: “这次测试只盯死中文增值税发票最容易出事的三个字段:开票日期、税额、买方税号。
我拿同一批带折痕和印章遮挡的真实发票原图,对工具 A 和工具 B 做了盲测对比,原始报错案例和参数设置都在下面。如果你正准备把 OCR 识别结果直接接入财务自动入账系统,建议先看哪几个字段目前还必须保留人工复核。”
紧接着第二段,立刻把测试样本张数、两款工具的具体版本号、测试日期、发票图片分辨率和判定对错的标准列出来(没测过的发票类型明确说没测,绝不瞎吹普适结论)。 然后看配图与格式选择:
- 第 1 张图(首图,会被 V8.2 的
_collect_post_media第一个抓走并返回):直接放一张最直观的**“带印章遮挡发票原图 + A/B 两款工具税额识别结果一正一错同框对比卡”**!如果这个错误只在“红章盖住金额数字”时发生,就直接把“红章遮挡场景”六个大字标在首图上,让只看第一张图的读者和 AI 一眼就能抓准核心发现;后面第 2、3 张图再依次放完整统计表和边界反例。 - 格式选择:如果这次测试只讲“红章遮挡税额报错”这一个具体发现,直接发成一条 长 Post 即可;如果是一份涵盖 5 种发票类型、30 页数据的深度报告,就发布为 Article(前 200 字标题写满核心词),并单独发一条挂着上面那张首图的导读长 Post(或者 3 条以内的精炼摘要串文 Thread:第 1 条给核心结论、第 2 条给对比表、第 3 条给适用边界与全文入口,确保每一条去掉上下文都能独立看懂,不怕
convo_marshaller.rs的1、9、10截断)。18
写到文章中段时,回头扫一眼:有没有哪一段是在车轱辘话重复标题、或者写“重点在后面大家别走开”?发现这种注水句子立刻删掉,换成具体的反例数据(比如“当图片压缩到 72 DPI 以下时,工具 B 的税号识别错误率从 2% 飙升到了 18%”)。让读者在 CREAD 的每一个时间刻度上都有实打实的干货可读。
31.2 让完整资料找得到、查得回去
如果你在文末提供了一份可供读者下载复现的测试脚本或 Excel 完整对照表:
- 在表格和正文里清晰标明文件名、测试日期和字段说明,给读者一个点下**“收藏(Bookmark,进入
SimClusters种子与沉浸式训练正例)”和“复制链接(Share via copy link,系数20,乘的是预测概率)发给同事”**的充分理由; - 附上外部下载链接前,亲手点开检查一遍跳转链,确认直接落到 GitHub 或正规网盘页面、没有任何失效或低质中转域名(如果需要注册或付费才能下载,提前在正文里坦诚说明);如果这篇测试后来成了你的代表作、准备设为个人主页置顶(Pin),更要定期检查里面的链接有没有过期变质,严防触发
PinnedLowQualityOrBadUrl.bot的账号标签(这条路写进去的标签带 7 天有效期); - 挑你的目标读者(财务与技术人员)真正刷手机的活跃时段点击发布——冷启动的探索机会只在发出后前 2 小时、内部首页曝光(
view_count_on_home)还不到 200 次时存在,时段选对才用得上。
31.3 发布后,按问题补充和更正
帖子发出去之后:
- 如果有同行在评论区问:“你们测试那张模糊发票时,有没有开启工具 A 的自动倾斜矫正参数?” —— 赶紧去核对测试日志,如果只是局部细节补充,直接在他的评论底下认真回复,把讨论区做成内行人的高质量交流场;
- 如果核对后倒吸一口凉气:“哎呀!测试时真的把工具 A 的倾斜矫正开关忘打开了,打开重测后工具 A 的错误率下降了一大半,原帖的核心结论反过来了!” —— 千万记住
previously_seen_posts_filter.rs的父帖已读过滤规则!不要只把这么重大的更正偷偷摸摸回在旧帖评论区里,而是立刻在旧帖留下更正指路,同时单独发一条全新的原创帖(或用 Quote 引用旧帖)把补测后的修正结论端出来! - 哪怕你今天上午已经发过两篇帖子了,只要下午这第三篇是实打实的补测新发现,也根本不用管什么“一天最多发两三篇、隔四小时恢复权重”的假口诀,随时改完随时发!
这条我对自己执行得比建议别人时严。我的规矩是 X 上已发布的帖子不原地编辑,改过的帖子曝光数据会归零;真发现错了,宁可另发一篇,讲清改了哪里。2026 年 10 月底我真干过一次:一篇帖子首发时把来源链接放进了正文,违反我自己定的规矩,我删掉重发了一遍,没有点编辑。博客不一样,博客是母本,错了就直接改,改完在 X 上发一篇更正帖,指向改好的版本。
最后,把下一篇的首图和开头单独拿出来看看,我给自己定的标准就一条:一个不认识你、也不会点开整串的读者,只看这两样,就能知道你发现了什么、这件事为什么与他有关。达不到,就改完再发。
这篇手册我会跟着 X 的公开代码更新继续修订。我会一直跟踪算法库的更新,一旦有更新,我会同步更新这份文档和 skill 库(https://github.com/alexliyu7352/for-you-skills),你收藏的永远是最新版。这个博客不追热点,只放我亲手拆过、核对过的东西,AI、安全、开源三条线都有。觉得这篇对你有用,欢迎订阅或收藏,下一篇更新你能第一时间看到。
仍待确认的问题(49 项“代码已证实真相 vs. 线上待查盲区”大白话全解)
很多朋友看技术报告最头疼的就是:报告最后列了一堆“待确认问题”,里面全是像天书一样的缩写词(什么 TTL、CREAD、ld、adapter、OON、HLL),既没解释这个词是什么意思、有什么作用、对流量有什么影响,也没说清楚到底哪一半是真的、哪一半是瞎吹的。
为了让你哪怕单独跳着看这 49 个问题中的任意一条,都能在 30 秒内彻底看懂前因后果,我把这 49 个核心问题全部重新改写了一遍。每一条都严格按以下四步用大白话讲透:
- 先说人话(这到底在问什么、有什么作用与影响):先把题目里的工程术语翻译成大白话,告诉你这个机制是干嘛的、对你的帖子曝光有什么实际影响;
- 代码已证实的真相(已知):公开源码里已经白纸黑字写死、100% 跑不掉的规则是什么;
- 代码还看不见的盲区(待查):哪一部分数据是因为官方没公开线上服务器日志或前端代码,导致谁也没法替你打包票的;
- 给创作者的实操结论(判断):搞懂了已知和盲区后,我们平时发帖到底该怎么做、千万别信哪句谣言。
01 海外博主常喊的“X 今天(today)又改算法了”,究竟指哪一次更新?
- 先说人话(这在问什么、有什么影响): 平时我们在 X 上经常看到海外大 V 发帖惊呼:“X 今天(today)刚刚更新了算法,大家赶紧改发帖方式!”很多创作者一看就慌了,以为今天全站规则大洗牌。其实,“算法更新”可能指三种完全不同的事:① 程序员往 GitHub 公开代码库里传了一份新代码(Commit);② 官方在说明文档(README)里补写了一条更新公告;③ X 后台服务器真正把新规则切换给全站用户使用。搞不清对方说的“今天”指哪件事,就容易被带节奏瞎改发帖习惯。
- 代码已证实的真相(已知):
我们核对的两份核心代码快照,公开上传(Commit)的精确时间分别是:第一份基准快照
5ed7963上传于世界标准时间(UTC)2026-10-28 02:49:03(换算成美国加州洛杉矶时间是 10 月 27 日晚上 19:49:03);第二份最新快照606b254上传于 UTC 时间2026-10-29 02:57:55(换算成洛杉矶时间是 10 月 28 日晚上 19:57:55)。与此同时,官方在README.md更新日志里另外标注了 10 月 8 日和 10 月 13 日两个功能更新日期。11 - 代码还看不见的盲区(待查): 发帖喊“today”的那位海外博主当时处在哪个时区、精确在几点几分发的帖,以及他口中的“今天更新”到底是指看到了 GitHub 上的代码提交、看到了补写的公告,还是指某项内部灰度实验,外人无法从静态代码里得知。
- 给创作者的实操结论(判断): 由于存在时差(UTC 的 10 月 29 日凌晨其实就是美国加州的 10 月 28 日晚上),我们把两个时间都列出来方便核对;更重要的一条铁律是:代码上传到 GitHub 的时间,只代表“公开给你看的时间”,绝不等于“全球几亿用户今天同一秒钟全都换上了这套新规则”,千万别看到一句“今天算法变了”就自乱阵脚。
02 代码库里写的“公开默认权重”,是不是此时此刻每个读者刷首页时真正用的配置?
- 先说人话(这在问什么、有什么影响):
我们在正文里列出了点赞
0.66、回复5、复制链接20、连续停留0.006等一长串“公开默认参数(Default Params)”。这些参数的作用是在给候选帖子算总分时,决定每一种预测行为占多大分量。大家自然会问:代码文件里写的这些默认数字,是不是线上每个读者刷手机时 100% 正在运行的数字? - 代码已证实的真相(已知):
首先,官方在
README.md里明确承诺:他们用自动定时任务(cron)把线上生产环境里的主要正式默认配置同步到公开代码库中(比如Home Mixer参数文件第一行就印着同步时间戳2026-10-27T16:00:37Z),所以这些数字是货真价实的正式环境基准。其次,在同一个代码版本里,Home Mixer(负责统筹组装与冷启动)和VM Ranker(负责调用价值模型算分)两个微服务里的同名默认参数确实存在细微差异(比如点赞一个是0.66、一个是0.5),且代码里有远程调用(RPC)、直接使用缓存分数以及调用失败时退回本地算分(fallback)的不同分支。12 27 - 代码还看不见的盲区(待查): X 线上有一套实时配置中心(Feature Switches / Configuration System),随时可以把某一部分读者分进不同的灰度测试桶(A/B Test)里试用微调过的参数,还会动态切换不同的 AI 模型权重文件(Checkpoint)——这些针对具体用户的实时实验开关,在公开代码库里是看不到的。
- 给创作者的实操结论(判断):
代码里的“公开默认参数”完全可以作为我们判断行为轻重缓急的权威基准参考(比如复制链接
20、回复5、点赞0.66,量级差得很明显;但系数还要乘各自的预测概率,不能只比系数大小就断定哪种行为一定更值钱),绝不是程序员随手乱填的假数字;但同时也要明白线上存在灰度实验,不要拿计算器去死抠小数点后四位,以为全球每个读者的算分公式分毫不差。
03 10 月份“停留时间权重系数上涨 50%”,会让长文的总分和曝光量也跟着暴涨 50% 吗?
- 先说人话(这在问什么、有什么影响):
在打分公式里,有一个叫
ContDwellTimeWeight(连续停留时间权重系数)的参数,它的作用是:AI 预测读者会在你的帖子上停留阅读多少秒,就拿那个秒数乘以这个系数,加进帖子的总分里。10 月中旬,这个系数从0.004调高到了0.006,涨幅正好是 50%。很多博主据此欢呼:“长文的算法总分和曝光量要直接暴涨 50% 了!”这是真的吗? - 代码已证实的真相(已知):
翻查同一个参数文件
home-mixer/params/param.rs的修改历史可以 100% 证实:10 月 9 日快照里该系数确实是0.004,到了10 月 13 日快照正式升到了0.006,这一个单项系数的涨幅千真万确是 50%!但是在scoring.rs的总分公式里,一篇帖子的总分是由 24 个预测项加在一起算出来的(还要经过分数平移、同作者0.625衰减和同池对手比拼)。如果假设 AI 预测读者看你的帖子 5 秒钟、其他互动项加权和为0.20分,系数从0.004涨到0.006只会让停留项从0.020分变成0.030分,整篇帖子的原始总分只是从0.220变成了0.230,仅上涨了约 4.5%!15 27 60 - 代码还看不见的盲区(待查): 线上真实环境里,把这个系数调高 50% 之后,全站长帖和短帖的真实曝光量到底各自涨跌了多少百分比,需要看官方内部的线上 A/B 实验统计报表,而这份运营报表并未公开。
- 给创作者的实操结论(判断): 系数上调 50% 是一个明确的利好信号,证明系统更加看重“读者愿不愿意停下来把内容读进去”;但因为总分是多项求和,单一系数涨 50% 绝不等于总分涨 50%,更不等于曝光量或广告收益直接涨 50%。写扎实干货吸引真实阅读是对的,靠开头写十行废话硬拖时间则毫无意义。
04 点赞权重涨到 0.66,是不是创下了 X 有史以来的“全场最高权重”?
- 先说人话(这在问什么、有什么影响):
FavoriteWeight(点赞权重系数)管的是“AI 预测读者会给你点赞的概率”在总分里乘多少倍。10 月份它从0.5一路调高到了0.66。网上立刻有人说:“点赞权重到了历史最高点,以后又是点赞为王的时代了!” - 代码已证实的真相(已知):
我们把 10 月份全部 20 个
Home Mixer参数历史快照挨个查了一遍,在 10 月这一个月里,0.66确实是FavoriteWeight出现过的最高值(10/9为0.5→10/13为0.6→10/14为0.66)。但是,横向对比同一张表里的其他正向行为,点赞的0.66依然排在很后面:复制链接是20、互关好友对原创帖回复是20、一般回复是5、带评论引用(Quote)是5、私信分享是5、关注作者是4、系统分享是2、普通转发是1!15 27 - 代码还看不见的盲区(待查): Twitter / X 过去十几年所有未公开的历史代码版本、内部测试分支里有没有给点赞设过更高的数字,没有全历史档案无法查证。
- 给创作者的实操结论(判断):
准确的表述是“10 月公开快照中点赞系数的最高值”;千万别被“历史最高”四个字忽悠去刷赞,因为在算法眼里,一个能让读者关注你(
4)、写评论讨论(5)或复制链接分享给同事(20)的帖子,权重系数依然远远甩开单纯的点赞(0.66)。
05 “点击后停留(CLICK_DWELL_TIME)”的 10 秒门槛与 0.4 分权重,在代码里是怎么衔接的?
- 先说人话(这在问什么、有什么影响):
当读者在首页点开你的帖子(比如点开长文或点进详情)并停下来阅读时,系统里有一个专门的加分项叫
ContClickDwellTime(点击后深度停留),它的权重系数是0.4(普通点击是0.3;系数乘的是预测概率,不能换算成顶多少个赞)。大家最关心的是:读者点开后到底要看满多少秒才算达标?达标后是不是立刻给帖子加0.4分? - 代码已证实的真相(已知):
在公开代码库里,我们能追通两头的铁证:① 在上游 AI 排序模型的训练配置(
xrecsys.py)和损失函数(loss_recsys.py)里,有一个叫CLICK_DWELL_TIME的二分类预测目标,它的判断标准是“原始标签数值是否严格大于阈值10.0”(刚好等于 10 还不算,必须> 10.0),模型推理时会输出一个 0 到 1 之间的达标预测概率,并由推理服务(model_runner.py)返回;② 在下游Home Mixer的总分融合公式(scoring.rs)里,程序会读取候选帖身上的click_dwell_time预测字段,乘以0.4的权重加进总分。14 - 代码还看不见的盲区(待查):
中间有两小段代码官方没有放进公开仓库:① 上游数据管线在生成
CLICK_DWELL_TIME的原始标签时,物理单位到底是不是纯秒数、点开 Article 专栏算不算在里面;② 把模型服务返回的预测值赋值给Home Mixer里click_dwell_time字段的那段中间转换代码(Adapter)没有公开。98 - 给创作者的实操结论(判断):
首先,乘以
0.4的依然是 AI 事前预测这位读者“点开后停留跨过10.0门槛的概率”,而不是事后每看满 10 秒记账加0.4分;其次,虽然中间转换层未开源,但0.4的高权重明明白白告诉我们——“骗读者点开却让他 2 秒钟失望退出”是拿不到这笔大分的,点开后有真材实料让他看进去才是关键。
06 10 月 8 日上线的 CREAD 停留预测黑科技,到底是怎么算阅读时间的?能让长文流量翻倍吗?
- 先说人话(这在问什么、有什么影响):
以前算法预测读者看多久可能比较粗糙;10 月 8 日官方宣布上线了 CREAD 模型来改进停留时间预测。它的作用是:精准估算这位读者会在你的帖子上停留多少秒(比如 4.1 秒还是 45 秒),然后把这个预测秒数拿去乘
0.006的连续停留权重。很多人问:这套新模型是怎么算秒数的?它上线后是不是意味着写得越长的文章就稳赢短帖? - 代码已证实的真相(已知):
从
xrecsys.py、loss_recsys.py和recsys_model.py源码中,我们完整还原了 CREAD 的计算过程:它把停留时间按“前面密、后面疏”的对数间隔切成了 30 道时间刻度门槛(普通信息流从 2 秒到 120 秒,画廊沉浸流从 2 秒到 240 秒)。AI 先分别预测读者停留时间跨过这 30 道门槛各自的百分比概率(sigmoid),然后再拿每一格的过关概率乘以相邻门槛的秒数宽度(deltas)加总,还原出一个具体的预测停留秒数(训练时还加了 Huber 时间重建损失来校准总秒数)。11 13 - 代码还看不见的盲区(待查): 官方没有公开 CREAD 上线前后的内部评测数据集、预测误差具体下降了百分之几,也没有公开全站长帖与短帖因此发生了多少流量转移的 A/B 测试报告。
- 给创作者的实操结论(判断): CREAD 的 30 道刻度设计,说明系统现在能极其细腻地区分“扫一眼 2 秒划走”、“看 10 秒短干货”和“读 90 秒深度长文”的区别。但要注意:AI 预测的是“这位读者实际愿意看几秒”,而不是“你这篇文章一共写了多少字”!如果一篇三千字的水文读者看 3 秒就划走了,CREAD 预测出来的照样是两三秒的低分;只有每一段都有高密度干货,CREAD 预测出来的停留秒数才会高。
07 10 月 13 日新增的 ld 深度阅读召回分支,是不是要求读者必须 100% 滑到文章最后一行才算数?
- 先说人话(这在问什么、有什么影响):
前面说过,推荐分两步:第一步是采购员去仓库捞候选帖(召回),第二步是裁判算分排座次(排序)。10 月 13 日,X 在第一步“双塔召回模型”里专门新加了一个叫
ld(Long Dwell,深度阅读停留) 的分支,权重设为0.75。它的作用是:哪怕一篇深度干货帖点赞评论不多,只要它是那种“读者刷到后会静下心来读进去”的好文章,采购员在第一步就会优先把它捞进更多人的候选池里! 网上有人据此传言:“必须让读者 100% 滑到文章最末尾,才会触发这个ld奖励!” - 代码已证实的真相(已知):
在
xrecsys_two_tower.py和recsys_two_tower_model.py里,ld分支用来训练模型的正例信号(ld_positive_actions)明确指定为一个叫CLIENT_TWEET_RECAP_DWELLED的客户端事件;这个分支在训练和实时推理召回时都有完整的代码路径。官方 README 在介绍这次更新时,用的通俗描述是“找出人们会读到底的帖子”。11 14 - 代码还看不见的盲区(待查):
CLIENT_TWEET_RECAP_DWELLED这个事件是由你手机上的 X App(客户端前端)上报给服务器的,而手机 App 的前端源码并未开源。因此,手机端到底是看“停留满多少秒”、还是看“屏幕滚动到了第几段”才发送这个事件标记,在后端算法库里是看不到的。 - 给创作者的实操结论(判断): 不需要去搞什么“在文章最底部藏一个暗号逼读者滑到底”的歪门邪道。只要你的文章开头直接切中痛点、正文表格和案例让人愿意停下来细读,就会自然触发这个阅读停留正例,在第一步召回和第二步排序里各起一次作用。
08 我看到自己帖子的浏览量(Views)刚跳到 200,是不是代表小账号冷启动扶持已经结束了?
- 先说人话(这在问什么、有什么影响):
对于粉丝不超过 5 万的小账号,系统有一个“前 2 小时、200 次曝光以内”的冷启动扶持机制(
author_cold_start.rs),能把你的新帖直接保送到读者候选池的第 16 名!很多小号创作者发完帖就死死盯着帖子底下的公开浏览量(Views),一看数字跳到了200,就叹气说:“完了,200 次冷启动额度用光了!” - 代码已证实的真相(已知):
在
author_cold_start.rs和数据拉取器engagement_counts_hydrator.rs里,代码检查的那个< 200的字段名叫view_count_on_home(纯 For You 首页推荐曝光次数),而你在帖子下方看到的公开总浏览量对应的是另一个字段view_count!而且拉取这两个计数的服务设有一个 60 秒有效期(TTL = 60s)的缓存。35 - 代码还看不见的盲区(待查):
对于你的某一篇具体帖子,前台显示的
view_count(总浏览量)里面到底混进了多少次个人主页点击、搜索查看、外部链接点击和作者自己刷新,只有后台内部数据库有逐笔明细。 - 给创作者的实操结论(判断):
前台总浏览量(Views)到了 200,不等于后台真正的首页推荐曝光(
view_count_on_home)也到了 200——后者是多少,外人看不到,两者不是一个数。 再加上还有 60 秒的计数缓存延迟,所以发帖后前 2 个小时内千万别盯着前台的 200 数字焦虑,更别以为一到 200 就立刻失宠而删帖重发。
09 当好几篇小账号新帖都符合冷启动条件时,系统到底挑哪一篇保送到第 16 名?点赞率最高的一定赢吗?
- 先说人话(这在问什么、有什么影响): 当一位读者下拉刷新首页时,他的临时篮子里可能同时有 10 篇来自不同小作者的新帖,全都符合“粉丝 ≤ 5 万、发布 ≤ 2 小时、首页曝光 < 200 次”的冷启动条件。但这台“直升电梯”每次刷新最多只能保送 1 篇帖子上第 16 名!很多人以为:“谁的点赞率最高,系统就一定挑谁上去,所以我赶紧找群友刷几个赞就能稳赢!”
- 代码已证实的真相(已知):
打开
author_cold_start.rs的源码,挑选过程其实是分两轮走的:① 第一轮(摇号初选 2 篇):系统读取每篇新帖目前的点赞数(fav_count)和首页曝光数(view_count_on_home),以1.5%的默认首页点赞率(alpha0=0.75, beta0=49.25)为基准跑一次 Thompson Sampling(Beta 分布随机概率抽样),抽出点数最高的 前 2 篇(默认top_k = 2);② 第二轮(按读者兴趣二选一):在这留下的 2 篇新帖里,系统不再看谁的点赞率高,而是直接对比**“当前正在刷首页的这位读者对哪一篇的模型预测分(ranking score)更高”**,挑预测分最高的那 1 篇保送上第 16 名!35 36 60 - 代码还看不见的盲区(待查): 线上某位读者刷新时篮子里到底有几篇合格新帖、当次随机数摇出了多少点、以及模型给这位读者算出的实时分数,属于单次请求的动态运行数据。
- 给创作者的实操结论(判断):
这里有一个直接能戳破“刷赞必胜论”的代码反例:如果某次篮子里本来就只有 2 篇合格新帖,第一轮
top_k = 2会把两篇全留下来,到了第二轮100% 选的是对当前读者预测分更高的那篇,而不是表面点赞率更高的那篇!所以别去搞微信群互赞(群友从链接点进来既不算首页曝光,画像也跟陌生读者不匹配),把内容写得精准切中目标受众痛点,才能在第二轮二选一里真正胜出。
10 10 月 22 日启用的 FairShare 比例分配,是不是保证新帖从此再也不会在打分前被裁掉了?
- 先说人话(这在问什么、有什么影响):
每次读者刷首页,各个进货渠道抓进临时篮子的帖子可能有 3,000 多篇,但负责精细打分的 AI 大模型每次最多只看 2,800 篇。以前按列表顺序一刀切,排在队尾的“冷启动新帖渠道”经常还没见着裁判就被砍光了。10 月 22 日,系统默认开启了
FairShareRankingFilter(公平份额初筛过滤器),改成了按各个渠道送货数量的比例来分配这 2,800 个名额。网上有人把这解读为:“新帖从此有免死金牌,100% 不会被提前截断了!” - 代码已证实的真相(已知):
从
fair_share_ranking_filter.rs和param.rs的提交历史可知:该功能在10/21(7f2ca2b)加入、默认关闭,在10/22(989fb91)将公开默认改为开启(true),预算为2800。它按候选帖的来源渠道(served_type,其中冷启动渠道ForYouPhoenixRetrievalCold和零赞渠道ZeroFav都是独立分组)按比例加最大余数法分配 2,800 个名额。但是,在每个渠道小组内部,程序依然只是简单保留原有列表顺序的前 N 篇,排在该小组末尾的帖子照样会被裁掉!16 61 - 代码还看不见的盲区(待查):
线上真实请求中各个渠道每次送来多少篇帖子、组内原本按什么顺序排列,以及开启
FairShare前后全站小号新帖的整体曝光上涨了多少百分比,需要内部 A/B 测试日志才能得知。 - 给创作者的实操结论(判断):
就像我们在正文算过的例子(3,000 篇进 2,800 篇,冷启动渠道从原来剩 400 篇提高到保住 560 篇,但仍有 40 篇被裁),
FairShare实打实地大幅提高了小作者新帖“进打分房间见裁判”的公平机会,但不能神化成“每一篇新帖都100%不被淘汰或必得保底流量”。
11 “互关好友回复预测权重高达 20”,是不是说明我疯狂找人互关(Follow back)就能让流量起飞?
- 先说人话(这在问什么、有什么影响):
在打分表里,普通读者给你留言回复的预测权重是
5;但如果刷到你帖子的这位读者和你互相关注(Mutual Follow),且你发的是原创帖,系统就会在5的基础上额外加上15分互关加成,变成20!很多人一看:“翻了 4 倍!那我赶紧去互关大厅见人就互关,凑几千个互关好友,流量岂不是翻 4 倍?” - 代码已证实的真相(已知):
在
xai-value-model/inputs.rs和weights.rs里,拿到这+15分加成的条件写得极其严格:必须同时满足!self.is_reply && !self.is_retweet && self.is_mutual_follow_author(即:① 候选帖本身不能是回复贴;② 不能是普通转发;③ 当前刷首页的读者与作者双向互关)。而且它只给“预测这位互关读者会留言回复的概率”加权重,点赞、转发、停留(互关停留加成为0)等其他项一分钱都不多加!27 - 代码还看不见的盲区(待查): 如果一个账号到处乱加毫无共同兴趣的互关粉,到底会把上游模型的作者受众画像带偏到什么程度,没有公开的受控实验数据。
- 给创作者的实操结论(判断):
千万别去搞无脑互关群!因为
20乘的是**“AI 预测这位互关好友看到你这篇帖子后会写评论的概率”**——如果你互关了三千个根本看不懂你专业内容的僵尸号或无关账号,AI 预测他们回复你干货帖的概率接近于0,20 × 0还是0!更何况如果你跑去大 V 底下抢沙发留言,你发的那条评论本身是is_reply = true,当场失去资格。真正有用的做法,是只和同领域的真实创作者、核心读者互关,并在原创帖里抛出内行人才接得上话的专业问题。
12 10 月 29 日最新代码里加的“视频轮播停留公式”,是不是已经开始给所有视频发流量红利了?
- 先说人话(这在问什么、有什么影响):
在 10 月 29 日(
606b254)的最新代码提交里,有人发现视频轮播栏(Video Carousel)的算分文件video_carousel.rs里新加了一行公式:把“视频被打开的概率”乘上“沉浸式观看停留时长”,再乘一个新权重系数。于是网上马上有人发快讯说:“10 月 29 日起,视频只要观看时长久就能拿到全新的轮播加分!” - 代码已证实的真相(已知):
公式确实写进了
video_carousel.rs里;但只要同时打开配套的参数文件home-mixer/params/param.rs(#L1191-L1269)就会看到:这个新增乘项的公开默认权重系数VideoCarouselOpenTimesImmersiveDwellWeight写的是0.0(乘 0 等于啥也没加),而且整个视频轮播栏的总开关EnableVideoCarousel默认也是false(关闭)! 同次提交新增的immersive_page_rl_cread训练配置也只是把配置文件放进了仓库。17 - 代码还看不见的盲区(待查):
线上有没有拿出 1% 或 5% 的小流量测试桶把这个开关设为
true并填入非零系数做实验,以及实验效果如何,在静态代码里是看不到的。 - 给创作者的实操结论(判断): 这是典型的“兵马未动,代码先行”——工程师先把公式代码推上线、默认开关设为关闭或 0,等待后续灰度实验。看代码一定要同时看公式和参数开关,绝不能一看到新公式名字就宣称“全站视频今天已经拿到新优待了”。
13 双塔召回里的 CLIENT_TWEET_RECAP_DWELLED 事件,在模型训练时是怎么被使用的?
- 先说人话(这在问什么、有什么影响):
前面第 07 题提到了 10 月 13 日新增的
ld(深度阅读)召回分支。有些喜欢钻研技术的读者会问:在双塔召回大模型的训练代码里,模型到底是自己去计算读者读了多少字、滑到了百分之几,还是直接读取现成的标记? - 代码已证实的真相(已知):
打开
phoenix/xrex/models/recsys_two_tower_model.py(#L621-L647与#L2711-L2739)可以看到:模型在训练时,根本没有在模型代码里去算字数或滑动百分比,而是直接去读训练数据表里现成的动作标记——只要某次曝光记录里带有CLIENT_TWEET_RECAP_DWELLED这个动作标记,就把它当成ld分支的正样本(Positive Action)来计算训练损失。33 - 代码还看不见的盲区(待查):
上游客户端和日志管线在什么精确条件下才会给一条曝光记录打上
CLIENT_TWEET_RECAP_DWELLED标记(怎么结合可见面积、字数、展开动作和秒数),这块上游规则不在公开仓库内。 - 给创作者的实操结论(判断): 明确知道“模型认的是停留阅读正例标记”,我们写文章时就专注于让读者停下来把干货读进去,而不必轻信任何“必须凑够多少字”或“必须逼读者滑到最后一行”的民间偏方。
14 新增的 ld 阅读召回分支是不是“小账号专属福利”?代码里的 HOME_COLD 又是什么意思?
- 先说人话(这在问什么、有什么影响):
网上有人看到双塔召回配置里有一个叫
HOME_COLD(冷池)的数据集,又看到官方说新加了ld阅读召回分支,就把这两件事拼在一起造了个谣:“10 月份的阅读召回升级只对小粉丝账号(冷账号)有效,大号享受不到!” - 代码已证实的真相(已知):
第一,在
10/13(e1a0375)公开的具名配置(combined与home-only)里,ld分支同时覆盖了HOME、HOME_COLD、HOME_HOT三大数据集,且代码里没有任何检查“作者粉丝数少于多少才启用ld”的条件;第二,打开phoenix/xrex/data/cold_pool_filter.py源码一看就明白:HOME_COLD(冷帖子池)筛选时检查的是“单篇帖子自己的点赞数(fav_count)、观看数(view_count)和发布新鲜度”,根本不是查“作者有多少粉丝”!33 34 - 代码还看不见的盲区(待查):
线上各个集群加载哪份具名配置(因为基础通用模型类里也保留了
w_ld = 0.0的默认选项)、何时全量切换,未公开线上部署表。 - 给创作者的实操结论(判断):
不管是几百粉的小号,还是几十万粉的大号,刚发出来还没攒够赞和观看的新帖子都会进
HOME_COLD;具名配置里ld不挑账号大小,但线上每组读者实际加载哪份配置、用不用ld,公开代码定不了,不能说全员都已经享受到了。千万别把“冷帖子(刚发的新帖)”错当成“小粉丝账号”。
15 为什么说“攒够第 32 个赞(32fav)就能解锁 For You 大流量池”在公开代码里缺少关键一环?
- 先说人话(这在问什么、有什么影响):
几乎所有 X 运营教程都会告诉你:“发帖后第 1 个赞进
1fav初级池,第 32 个赞进32fav高级池,一旦满 32 个赞,For You 首页就会给你灌一大波陌生人流量!”这个说法到底有几分真、几分假? - 代码已证实的真相(已知):
一分为二看:① 前半截“存进数据桶”是真的:在
phoenixRankAllCandidateProcessor.strato里,当一条合格普通帖收到的点赞数>= 32时,程序确实会生成一条indexName = "32fav"的索引事件,并且在存储层设有 24 小时窗口(32fav_1day);② 但后半截“谁来读这个桶”却出了意外:当我们去查双塔召回的数据集定义retrieval_dataset.py时,发现负责普通 For You 首页推荐的三大主力数据集——HOME、HOME_COLD、HOME_HOT——全都在读1fav_1day.parquet(1 赞库)!38 34 - 代码还看不见的盲区(待查):
在整棵公开的 For You 代码树里,除了一条专门针对 14–30 天老视频的
IMMERSIVE32FavVideo14To30Day(读32fav_video_14to30day.parquet)之外,找不到任何一个普通图文首页的召回服务在读取32fav_1day这个数据桶!(不知道是线上某个未开源的内部服务在读,还是目前公开配置压根没启用它。) - 给创作者的实操结论(判断):
拿到第 1 个赞进入
1fav_1day确实是进入普通首页主力召回库的关键一步;但对于普通图文帖来说,千万别迷信“凑满 32 个赞就能自动打开新世界大门”,更没必要为了凑够 32 个赞到处找人互赞——因为公开代码里连谁去读普通帖的32fav都没见到影儿。
16 为什么前台刚跳出第 1 个赞或第 32 个赞时,后台索引库未必立刻同步更新?
- 先说人话(这在问什么、有什么影响):
有些创作者发完帖后死死盯着点赞数,觉得只要有人点下第 1 个赞或第 32 个赞的那一秒钟,后台的
1fav或32fav索引库就会在同一秒钟立刻刷新,马上开始推流。 - 代码已证实的真相(已知):
在点赞事件处理器
favoriteEventProcessor.strato和eventProcessing.strato里,写着好几道节流阀和边界条件:① 1 分钟节流阀:如果这篇帖子已有更新缓存,距离上一次索引更新必须**满 1 分钟(>= 1 分钟)**才允许送出下一次更新!比如你在第 16 个赞时刚更新过索引,才过了 30 秒就冲到了 32 个赞,这第 32 个赞因为没满 1 分钟会被直接拦下不更新!② 48/49 小时寿命线:距首次更新须<= 48 小时且帖子年龄< 49 小时;③ 读写不同步竞态:在build1FavIndex里甚至专门记了一笔1fav_uec_count_race日志——当点赞事件传过来了,但去数据库重读计数却还是0时,记下竞态日志后仍送出1fav事件。37 38 - 代码还看不见的盲区(待查): 你发的某一篇具体帖子在线上遭遇了多少毫秒的跨服务同步延迟、哪一次点赞事件刚好撞上了 1 分钟节流阀,没有后台服务器日志是看不到的。
- 给创作者的实操结论(判断): 后台是一个庞大的分布式系统,有 1 分钟节流阀、二次幂跳跃门槛(1、2、4、8、16、32、64……)和计数同步延迟。别把手机前台显示的点赞数当成毫秒级同步的“推流开关”,专心做好内容和评论区互动即可。
17 帖子成功写进了 1fav 推荐索引库之后,是不是就能保证一定被陌生读者刷到?
- 先说人话(这在问什么、有什么影响):
什么是“写进索引库(Indexing)”?你可以把 X 的推荐系统想象成一个超级大超市:“写进
1fav索引库”,意思就是你的帖子拿到第 1 个赞之后,仓库管理员把你的帖子摆上了超市的后备货架。很多教程把这一步吹成了:“只要拿到 1 个赞进了1fav库,系统就保证把你推给成千上万个陌生人!”那摆上货架,真的等于已经被顾客买回家(在读者手机屏幕上曝光)了吗? - 代码已证实的真相(已知):
在公开源码里,从“摆上货架”到“出现在读者屏幕上”中间隔着整整五道生死关:① 索引入库(
phoenixRankAllCandidateProcessor.strato把帖子写进1fav);② 数据集加载(retrieval_dataset.py读取1fav_1day.parquet);③ 第一步双塔个性化召回(phoenix_source.rs根据当前读者的阅读历史,从几十万篇帖子里挑出跟这位读者兴趣匹配的几百篇放进他的临时篮子——如果不匹配,你在货架上根本不会被拿下来);④ 初筛过滤(砍掉已读、超 48 小时、拉黑以及超出FairShare2,800 名额的候选);⑤ 模型打分与排座次(算 24 项预测概率加权总分,分高的前几十名才能真正出现在读者屏幕上)。37 38 34 - 代码还看不见的盲区(待查): 你的某一篇具体帖子在货架上躺着的时候,今天到底被多少个读者的“召回采购员”挑中过、又在多少个读者的篮子里因为打分不够高而沉底淘汰,这些内部漏斗数据在创作者后台是看不到的。
- 给创作者的实操结论(判断): “进索引库”只是拿到了参加比赛的“入场资格证”,绝不是“保底曝光承诺书”! 拿到第 1 个赞让你上了货架,但要想被采购员抓走并排在前面,靠的还是清晰的主题语义(前 4,000 字+首图)和能让读者停下来细读的干货质量。
18 读者点了“收藏(Bookmark)”之后,系统是不是就保证把我的下一篇新帖推给他?
- 先说人话(这在问什么、有什么影响):
我们在正文里讲过,虽然主计分表里没有单独列“收藏加几分”,但收藏(Bookmark)在后台有两个隐藏大用处:一是作为
SimClusters相似内容推荐的“兴趣种子”,二是作为沉浸式召回模型的“训练正例”。有些创作者听完后就问:“既然收藏会当成种子,那只要读者张三今天收藏了我的一篇帖子,是不是代表明天我发新帖子时,系统就 100% 保证把我的新帖推给张三?” - 代码已证实的真相(已知):
打开
explicit_engagement_signals_query_hydrator.rs和simclusters_source.rs可以看到:当张三刷首页时,系统确实会把张三最近收藏过的最多 15 篇帖子(要求原帖发布年龄在 90 天以内)拿出来,和张三最近点赞、转发过的帖子混在一起组成“兴趣种子包”,然后去全站寻找发布在 48 小时以内、且内容相似度达标的候选新帖。同时在xrecsys_two_tower.py里,收藏(CLIENT_TWEET_BOOKMARK)也被列为immersive召回分支的训练正例。41 - 代码还看不见的盲区(待查):
当
SimClusters拿着张三收藏的你那篇帖子的 ID 去找“相似新帖”时,找回来的名单里到底有几篇是你刚发的新帖、有几篇是同行写的同类主题好帖,以及它们进篮子后谁的打分更高,取决于当次请求的实时计算结果。 - 给创作者的实操结论(判断):
读者点收藏,本质上是告诉算法**“我对这类具体问题(比如中文发票 OCR 或 AI 会议纪要测评)极感兴趣”**。如果你接下来继续围绕同一受众的痛点发高质量新帖,确实极容易被
SimClusters顺着收藏种子捞进他的篮子里;但这不是一张“只要收藏一次就强制绑定推流作者下一篇”的卖身契,持续输出同领域的连贯干货才是接住收藏流量的关键。
19 为什么说“回复贴(Replies)能不能被未关注你的陌生人刷到”,得看线上开关怎么设?
- 先说人话(这在问什么、有什么影响): 什么是“圈外回复(OON Reply,Out-Of-Network Reply)”?只要你发的是一条回复贴(包括你去别人帖子底下写的评论,以及你自己写串文 Thread 时从第 2 条开始往后的所有分帖),对于还没有关注你的陌生读者来说,这条回复就叫“圈外回复”。它能不能出现在陌生人的 For You 首页推荐里,直接决定了“在大 V 底下神评能不能被路人刷到”以及“串文后半截能不能直接破圈”。
- 代码已证实的真相(已知):
在
oon_retweet_reply_filter.rs和参数文件param.rs里,程序员写了两手逻辑:① 在公开默认配置下,控制是否放行圈外回复的总开关EnablePhoenixOonReplies设为了false(关闭)——按这个默认值跑,所有未关注作者的回复贴在这一关都会被直接过滤踢走;② 但程序员在代码里同时保留了一扇“条件放行后门”:一旦线上把EnablePhoenixOonReplies开关设为true,只要这条回复来自指定的 Phoenix 推荐渠道(ForYouPhoenixRetrieval或Cold)、补齐了对话祖先数据,并且在开启PhoenixOonRepliesRootOnly时属于直接回复主帖的“一级回复”,就能被放行过关!30 - 代码还看不见的盲区(待查):
线上此时此刻针对不同地区、不同实验分桶的读者,到底给多少比例的人打开了
EnablePhoenixOonReplies开关,属于线上动态配置中心的实时数据。 - 给创作者的实操结论(判断):
既然公开默认开关是
false(关闭),我们在做内容规划时就必须按最稳妥的底线来设计:千万别把全篇最重要的干货结论藏在串文(Thread)的第 5 条或第 10 条里,一定要放在第 1 条(根帖 Root Post)! 因为第 1 条根帖是纯正的原创帖,不受这个回复过滤器的限制——它拦的是回复帖;根帖能不能被陌生人刷到,还要看召回和打分。
20 代码里有两个名字都带“Evergreen(长青视频)”的东西,为什么一个卡 10 秒时长、另一个没写 10 秒检查?
- 先说人话(这在问什么、有什么影响): 什么叫“Evergreen(常青/长青视频库)”?普通帖子发出来超过 48 小时就很难进常规推荐池了,但对于优质视频,系统专门建了一个“长青视频库”,把发布 4 到 14 天 的好视频留着继续推给读者!很多做视频的朋友问:“进这个长青视频库,是不是也必须遵守视频长度严格大于 10 秒(10,000 毫秒)的铁律?”
- 代码已证实的真相(已知):
去翻代码,你会发现有两个地方都出现了
Evergreen这个词,但它们根本不是同一个东西:① 在第一步召回模型读取的数据集清单(retrieval_dataset.py)里,有一个大写枚举叫EVERGREEN——看它底层读取的文件路径,读的其实是video_4to14day.parquet(即video核心视频索引库的 4 到 14 天窗口)!而要写进video索引库,在phoenixRankAllCandidateProcessor.strato里必须先通过hasValidImmersiveVideo函数,100% 严格要求视频时长> 10000 毫秒(超过 10 秒)!② 但在同一个文件里,另外还有两个小写名字的索引叫evergreen_video和evergreen_nsfw_video,它们走的是独立的EvergreenVideo事件分支,在那个分支里只调用了hasImmersiveVideo(只检查是不是视频格式,没有再写一遍> 10000 毫秒的判断)。49 50 - 代码还看不见的盲区(待查):
上游系统在什么条件下才会产生第二种
EvergreenVideo事件(是不是在上游就已经筛过一轮时长了),那段上游生成代码并未公开。 - 给创作者的实操结论(判断):
既然主力召回数据集
EVERGREEN明明白白读的是video_4to14day.parquet(严格受> 10 秒限制),如果你想让自己的干货视频享受长达 4 到 14 天的长尾推荐寿命,请务必把视频剪到 11 秒以上(严格大于 10,000 毫秒),并且绝不要在同一条帖子里混放静态图片!
21 视频召回库里的 32fav_video_14to30day(满 32 赞的 14–30 天老视频库),是怎么生产出来的?
- 先说人话(这在问什么、有什么影响):
我们在查数据文件时发现,沉浸式视频流居然还有一个保质期更夸张的仓库——名字叫
IMMERSIVE32FavVideo14To30Day,读取的文件是32fav_video_14to30day.parquet。名字看起来是给 14 到 30 天之间的视频留的库,还带着 32fav 的字样;但它到底按什么条件生产,公开代码没追齐,不能光凭名字就定它的入库门槛。大家自然好奇:我的视频要满足什么条件才能进这个能活整整一个月的养老金库? - 代码已证实的真相(已知):
在双塔召回的数据集配置文件
phoenix/xrex/data/retrieval_dataset.py(#L247-L282)里,确实白纸黑字定义了IMMERSIVE32FavVideo14To30Day并指向32fav_video_14to30day.parquet这个文件。34 50 - 代码还看不见的盲区(待查):
在当前公开的
phoenix-rankall-strato代码树里,我们能看到1fav_video的各个天数窗口,但还没有找到直接负责生成32fav_video_14to30day.parquet这个特定文件的完整上游构建函数(Producer)。 - 给创作者的实操结论(判断): 第一,这证明了优质视频在 X 上的推荐寿命远远不止 48 小时,甚至存在长达 14 到 30 天的长尾召回池;第二,要注意这是专属视频数据集,千万别拿它去给“普通图文帖满 32 个赞解锁新流量池”当证据。
22 代码里另一个叫 isMediaEligible 的“视频大于 10 秒”检查函数,到底是干嘛用的?
- 先说人话(这在问什么、有什么影响):
在翻查代码时,我们除了找到卡住三大视频索引库的
hasValidImmersiveVideo(要求视频> 10 秒)之外,还在同一个文件里发现了另一个长得很像的函数叫isMediaEligible,里面也写了“视频时长必须大于 10,000 毫秒且非成人内容”。这俩函数是什么关系? - 代码已证实的真相(已知):
在
phoenix-rankall-strato/lib/eventProcessing.strato(#L125-L204)里,isMediaEligible明确检查VideoInfo.durationMillis > 10000且媒体不带 NSFW 标记;随后另一个函数getTweetypieResponse调用了它(组装成hasEligibleMedia并要求作者非 NSFW)。49 - 代码还看不见的盲区(待查):
在目前公开的这份代码树里,只能看到
getTweetypieResponse被定义和导出(Export),但搜遍全库没看到有下游文件调用它(可能是给未开源的外部 Strato 列调用的)。 - 给创作者的实操结论(判断):
我们已经追通调用链的
hasValidImmersiveVideo,门槛写的是> 10000毫秒(严格大于 10 秒);这个备用的isMediaEligible里也出现了同样的 10 秒写法,但它下游谁在用还没追到,只能说明代码里又出现了一次同样的门槛,不能拿它给全系统的标准加码。
23 既然 5 秒钟的短视频也能进普通帖子的 1fav 库,那它的曝光机会和 11 秒以上的视频一样多吗?
- 先说人话(这在问什么、有什么影响):
我们在第 19 章帮大家辟了一个谣:如果你发了一支只有 5 秒钟的短视频,它并不是完全进不了推荐库——它进不了专属视频库(
video/1fav_video),但依然能正常进入普通帖子的1fav索引库(被普通首页HOME读取)。于是有人问:“既然 5 秒视频也能进普通首页库,那我以后发 5 秒视频和发 11 秒视频,拿到的曝光机会是不是完全一样?” - 代码已证实的真相(已知):
从
phoenixRankAllCandidateProcessor.strato的代码分支可以确认:5 秒短视频在普通Fav分支里能顺利通过build1FavIndex(因为该函数不查视频时长),进入1fav_1day.parquet;但紧接着往下走到build1FavVideoIndex和buildVideoIndex时,就会因为不满足> 10000 毫秒被直接拦在专属视频库门外。38 34 49 50 - 代码还看不见的盲区(待查):
少进了
video和1fav_video这两个专属视频库(以及对应的IMMERSIVE2Day、IMMERSIVE4Day、EVERGREEN4–14 天长尾视频通道),在线上最终会让一支视频少拿百分之多少的曝光,需要线上对照实验数据。 - 给创作者的实操结论(判断): 5 秒视频是“只有一条腿走路(只能走普通帖的 24/48 小时通道)”,而 11 秒以上的视频是“两条腿走路(既能走普通帖通道,又能进专属沉浸式视频流和 4–14 天长青视频库)”! 所以只要内容撑得住,把干货视频剪到 11 秒以上(且不混排静态图片),拿到的推荐入口明显更宽、寿命也更长。
24 我把超过 48 小时的老帖子直接点“普通转发(Repost)”,到底能不能让老帖子重新获得推荐?
- 先说人话(这在问什么、有什么影响):
因为普通帖子发出来超过 48 小时就会被年龄过滤器(
AgeFilter)拦在候选池外,很多创作者就想:如果我把三天前或上个月写过的老帖子直接点一下“普通转发(Repost / Retweet)”,能不能靠这笔新转发把老帖子重新推给全站读者? - 代码已证实的真相(已知):
我们在正文第 24 章用代码完整还原了这笔转发会撞上的 5 道关卡:① 能过年龄关(
AgeFilter):因为age_filter.rs查的是这笔新转发自己的tweet_id(今天刚生成的,不到 48 小时),不会因为老帖原文(存在retweeted_tweet_id里)超龄而砍掉它;② 但过不了陌生人破圈关(OONRetweetReplyFilter):oon_retweet_reply_filter.rs会无条件移除所有“转发者不在读者关注名单内”的普通转发(is_retweet),所以在普通推荐管线里,你自己转发自己的老帖,进不了未关注你的陌生人的候选池;③ 也过不了已读老粉关(previously_seen_posts_filter.rs):已读过滤器会同时查tweet_id和retweeted_tweet_id,以前看过你原帖的老粉丝,今天这笔转发会被直接拦下,只有上次漏看的老粉或刚关注你的新粉才能刷到(此外还会和你今天发的新帖抢0.625同作者权重,且拿不到冷启动扶持)。39 - 代码还看不见的盲区(待查): 你名下到底有多少百分比的粉丝上次漏看了那篇老帖、今天点一次 Repost 具体能捡回多少次漏看曝光,取决于你账号粉丝的上线重合度。
- 给创作者的实操结论(判断):
直接点“普通转发(Repost)”自己的老帖,只适合做“跨时区补漏”(比如中午发的干货,半夜点一次转发喂给海外时区没看过的粉丝和今天新涨的粉丝);如果你想让老干货突破 48 小时限制重新推给全站“未关注你的陌生人”,千万别点普通 Repost,必须用“带评论引用(Quote Post,配一段当下的新使用场景)”! 因为 Quote 帖在代码里
is_retweet = false,能像全新原创帖一样畅通无阻地推给全站陌生人!
25 代码里的 PushToHomeSource 或长视频窗口,能不能被我们用来当成普通图文帖绕过 48 小时限制的后门?
- 先说人话(这在问什么、有什么影响):
有些仔细翻过代码目录的人发现:在 For You 首页最顶层流水线里,有一个叫
PushToHomeSource的特殊通道,它居然不经过普通候选帖的 48 小时AgeFilter年龄检查!还有前面说的视频库有 14 天甚至 30 天窗口。于是有人问:“我们创作者能不能用什么暗号或操作,把自己的普通旧文章塞进PushToHomeSource里,强行绕过 48 小时限制上首页?” - 代码已证实的真相(已知):
在
for_you_candidate_pipeline.rs和push_to_home_source.rs里,PushToHomeSource确实与常规打分流ScoredPosts并列,它是根据服务端请求里专门传入的push_to_home_post_id参数去拉取指定帖子的,不走普通候选的AgeFilter;而长周期窗口(4 天、14 天、30 天)则明确绑定在视频索引数据集上。30 50 39 - 代码还看不见的盲区(待查):
X 内部系统到底在什么条件下才会往
push_to_home_post_id里塞入某条帖子的 ID(比如是不是系统级精选推送或特定通知联动),上游触发代码并未公开。 - 给创作者的实操结论(判断):
PushToHomeSource是系统内部服务端传入的参数通道,普通创作者在发帖界面没有任何按钮或技巧能手动把自己塞进去;视频的 14 天窗口也救不了纯图文帖。想让旧图文重新上首页,唯一靠自己就能 100% 掌控的正道就是上一题讲的 Quote Post(带评论引用翻新)。
26 安全与风控模块里写的“公开默认规则”,是不是线上每个账号每一秒都在执行的唯一铁律?
- 先说人话(这在问什么、有什么影响): 在安全与防限流章节里,我们查出了很多具体的数字:比如“最近 5 条帖子里有 3 条涉黄就给账号贴标签”、“视频满 64 赞和 512 赞触发专项安检”等。大家会问:这些数字在线上是写死的唯一标准,还是后台也能随时偷偷改?
- 代码已证实的真相(已知):
首先,我们完整比对了
5ed7963(10 月 28 日)和606b254(10 月 29 日)两份最新快照:安全打标、5 帖聚合、外链 bot 和视频/回复审查代码,在两份快照间核对到的规则与结构没有变化;可见性过滤模块虽然把规则抽成了列表并改用ClientSwitch集合表达,但展开核对全部 14 组规则列表后,拦截逻辑和先后顺序一致(这是把规则逐组展开对照的结论,不是逐字比对)。其次,README.md和代码注释也明确说明:像postToUserLabelRules.strato里的 5 帖聚合规则,除了代码里的默认 JSON(defaultRulesJson),还支持通过配置开关读取configuredRulesJson动态覆盖,且部分核心反垃圾 bot 规则与大模型提示词(Prompts)并未开源。76 79 51 54 - 代码还看不见的盲区(待查):
线上配置中心当下有没有针对特定高风险地区或特定账号群体动态修改过
configuredRulesJson,以及未开源的那部分 bot 规则长什么样,外人无法从公开仓库看到。 - 给创作者的实操结论(判断): 公开代码里的安全规则(如 5 帖中有 3 帖涉黄、置顶坏链接封 7 天、外链 v2 查评论区、CJK 中文重复检测)是我们能亲眼看到的真实防线底牌,踩上去极大概率出事;但同时千万别拿这些默认数字去搞“精准卡线擦边(比如以为每发 2 条敏感帖插 3 条水贴就绝对封不到我)”,因为线上随时可以用动态配置覆盖窗口大小!
27 一旦帖子或账号被贴了“侮辱标签”或“账号限流标签”,是不是连未关注我的路人点进我主页也看不到了?
- 先说人话(这在问什么、有什么影响):
什么是“安全标签(Safety Label)”?就是系统发现某条帖子有辱骂(比如
FOSNR_ABUSE_INSULTS),或者发现某个账号发垃圾/涉黄(比如SPAM_HIGH_RECALL、NSFW_HIGH_PRECISION),给帖子或账号贴上的“违规封条”。很多人一听说自己被贴了标签,就以为:“完了,所有没关注我的陌生人,不管是在搜索框搜我、点别人转发的链接、还是直接点进我的个人主页,全都看不到我的帖子了!”事实真的这么绝吗? - 代码已证实的真相(已知):
在
visibility-filtering/rules/levels.rs和vf_candidate_hydrator.rs里,X 把安全拦截分成了好多扇完全不同的“门(检查入口)”:- 第一扇门叫
TimelineHome(给已经关注你的老粉丝刷首页用的门):这扇门对很多标签(比如FOSNR_ABUSE_INSULTS侮辱标签,以及多项账号级限流标签)压根没有配置直接移除(Drop)规则!所以你的老粉丝刷首页时照样能看到你; - 第二扇门叫
HomeRecommendations(专门把你的帖子推荐给“还没关注你的陌生人”的 For You 推荐大门):在这扇门上,只要检测到上述标签,系统就会对作者本人以外的所有人(NonAuthors或NonFollowers)直接执行移除(Drop)! 而在官方透明度后台的代码(underTheHoodLabels.strato)里,对这些标签的官方效果说明写的也是:“不向未关注你的非粉丝推荐该帖/该账号(Do not recommend… to non-followers)”。77 75
- 第一扇门叫
- 代码还看不见的盲区(待查): 至于搜索结果页、别人直接点进你的个人主页(Profile Timeline)、对话详情页或直接打开帖子链接等其他页面,各自挂载了哪个安全级别、在不同客户端版本下怎么展示,公开仓库并未提供全站所有页面的完整调用图。
- 给创作者的实操结论(判断):
看懂这两扇门的区别,你就明白了两件大事:
第一,这些常见标签的真正杀招是**“切断 For You 首页向陌生人推荐你的水龙头(只保留言论自由,不给破圈推荐流量)”**,而不是把你的账号从地球上抹掉;
第二,怀疑自己被限流时,千万别去找一个已经关注你的老粉丝问“你还能不能看见我发的帖”——因为老粉丝走的是
TimelineHome那扇门,他能看见你,根本证明不了你在陌生人推荐门(HomeRecommendations)那边没被一刀砍掉!要查就用官方的 Under the Hood 工具查!
28 写帖子批评别人时,到底什么样的句子或语言会被自动贴上 FOSNR_ABUSE_INSULTS(侮辱限流标签)?
- 先说人话(这在问什么、有什么影响):
上一题刚说了,一旦帖子被贴上
FOSNR_ABUSE_INSULTS(辱骂与人身攻击标签),这篇帖子在陌生人推荐流(HomeRecommendations)里就会被直接拦截移除,彻底失去破圈流量。那写犀利测评、行业批评或反驳别人时,到底什么情况会触发这个标签?用中文写和用英文写待遇一样吗? - 代码已证实的真相(已知):
打开 Grox PTOS 的安全标签自动写入代码
grox/flows/ptos/task_write_safety_post_annotations_result_sink.py(#L175-L268),在这条自动打标流水线里,要写下FOSNR_ABUSE_INSULTS必须同时满足三个硬条件:① PTOS 大模型先把帖子判定为HateOrAbuseInsultsWithTarget(针对特定目标的仇恨或侮辱攻击);② 帖子的语言必须被识别为英语(English);③ 作者不是高 PageRank 大号或灰标认证号(且非测试账号)。76 77 - 代码还看不见的盲区(待查): 第一,PTOS 大模型内部用来区分“正常尖锐批评”和“人身攻击侮辱”的提示词(Prompt)没有开源;第二,除了这条要求英语的 PTOS 自动分支外,后台还有没有其他未公开的多语言自动规则或人工举报审核通道会写同一个标签,在公开库里看不到。
- 给创作者的实操结论(判断):
如果你经常用英文发帖(或者发中英双语混排帖被系统识别为英语),在写产品锐评或反驳别人时要格外注意措辞——只针对测试数据、产品缺陷和逻辑漏洞开火,绝不要带针对个人的脏话或人格侮辱词汇;同时,虽然这条特定自动分支写了英语条件,但用中文发帖同样不能搞人身攻击,因为一旦招来读者反手点举报(
Report系数-234.0,量级远大于正向项)或触发其他风控,照样得不偿失。
29 帖子要是被贴了 LOW_QUALITY(低质量)或 MISINFO(不实信息)标签,真的会被锁死点赞和转发按钮吗?
- 先说人话(这在问什么、有什么影响):
有时我们在 X 上会看到某些帖子外面蒙了一层半透明的警告遮罩(Interstitial),点开后发现底下的点赞、转发、评论按钮全都是灰色的,根本点不了!网上传言:“只要帖子被贴了
LOW_QUALITY或MISINFO标签,就会对所有非粉丝弹出警告,并且把点赞和所有分享按钮全部锁死!” - 代码已证实的真相(已知):
打开
visibility-filtering/rules/tweet_rules.rs、rule_spec.rs、verdict.rs和limited_actions_policy.rs核对后,真相是这样的:- 谁会看到警告遮罩?所有人(
Everyone)! 这条规则针对 2019 年 4 月 1 日之后发布的、带帖子级LOW_QUALITY或四种不实信息标签(MISINFO_CIVIC、MISINFO_GENERIC、MISINFO_MEDICAL、MISINFO_CRISIS)的帖子,受众明确写的是Everyone(连已关注你的粉丝也一样会看到警告遮罩,不只是非粉丝); - 到底锁死哪几个按钮?看标签类型和来源(
source)!- 如果是帖子级
LOW_QUALITY标签,直接启用最严厉的NonCompliant(不合规) 限制策略——在测试配置里,它会把回复、普通转发、点赞、表情回应、私信发送、收藏、置顶、系统分享和复制链接等 11 个互动按钮全部锁死! - 如果是四种
MISINFO标签,程序会先读取标签身上的source字段:比如当source为limited_replies时,只启用ConversationControl(仅锁死“回复”按钮,点赞和转发照常能点);但如果MISINFO标签缺失了source字段,在最后组装阶段(verdict.rs#L77-L83)代码会自动退回(Fallback)启用最严厉的NonCompliant全套 11 项按钮锁死!78
- 如果是帖子级
- 谁会看到警告遮罩?所有人(
- 代码还看不见的盲区(待查):
线上某条具体被贴标的帖子到底带了什么
source、以及线上实时配置给每个限制等级具体勾选了哪几个按钮,取决于服务端动态下发的策略。 - 给创作者的实操结论(判断):
这里最需要大家放宽心的一点是:千万别把这里触发全套按钮锁死的“帖子安全标签
LOW_QUALITY”,和我们前面讲外链时提到的“网址域名信誉评级LOW_QUALITY”搞混了! 平时你发一条字数少、写得普通的日常动态,绝对不会被贴上这个跟造谣(MISINFO)同级别的公共利益安全标签。
30 触发账号级 NSFW_HIGH_PRECISION 标签的“最近 5 条里有 3 条涉黄(3/5 规则)”,到底是怎么数的?纯文字帖和一条放 4 张图的帖子怎么算?
- 先说人话(这在问什么、有什么影响):
什么是“3/5 账号聚合规则”?平时如果你偶发一条带敏感图片的帖子,系统最多只给那一条帖子贴个成人标签;但如果你连续发敏感内容,触发了这条“5 条里有 3 条”的红线,系统就会直接给你的整个账号贴上
NSFW_HIGH_PRECISION(高精度成人账号) 标签。这个标签在陌生人推荐入口(HomeRecommendations)会把你的帖子拦下来——它管的是这一个入口、这一类读者,不是全站封死;它自己的有效期怎么算,跟置顶坏链接那条路的 7 天是两回事(见第 31、32 条),不能并成一句“全号限流 7 天”。 很多创作者一直没搞懂:这“最近 5 条里有 3 条”,到底是数我最近上传的 5 张图片?还是只数我最近发的 5 条带图/带视频的帖子? - 代码已证实的真相(已知):
打开
safety-label-user-agg/postToUserLabelRules.strato(#L395-L425)和safetyLabelToUserLevelAggregationV2Processor.strato,公开默认配置写得一清二楚:windowSize: 5(窗口大小 5)、minimumMatchingPosts: 3(最少匹配 3 篇)、maxPostAgeDays: 60(60 天内)、mediaOnly: false(只数媒体帖 = 否)! 这段代码实际的数法是:按时间倒序从你的个人时间线(userTimeline)里取出最前面的最多 5 条帖子,然后数这 5 条帖子里有几条身上带着NSFW_HIGH_PRECISION标签!这意味着三个确定的事实:- 按“几条帖子”数,不按“几张图”数:如果你在同一条帖子里一口气放了 4 张敏感图,它在这条规则里只算 1 条帖子(不会因为 4 张图就当场算 4 条触发封号);
- 纯文字帖也占 5 条窗口里的名额:因为
mediaOnly默认是false,如果你中间发了两条不带图的纯文字帖子,它们照样占掉前 5 条窗口里的 2 个位置; - 转发(Retweet)老帖也会算进去:如果前 5 条里有一笔你刚点的普通转发,程序会调用
originalTweetForRetweet去查被转发原帖身上的安全标签,并用这笔新转发的时间算 60 天窗口!而且代码用的是take(5)(最多取 5 条),哪怕新号总共只发了 3 条帖子且全带标,当场就满 3 条触发,不需要等凑满第 5 条才查!79 80
- 代码还看不见的盲区(待查):
上游
userTimeline接口在遇到删帖、分页时的实时返回细节,以及线上是否对特定账号通过configuredRulesJson把mediaOnly动态改成了true,在静态代码里看不到。 - 给创作者的实操结论(判断): 第一,如果某期内容确实包含敏感图片,同一批敏感图合成 1 条多图帖,只占窗口里的 1 个名额;拆成 3 条单图帖连发,就可能凑满 3/5 触发账号标签。这是在讲计数方法,不是在教绕规则——触发看的是标签事件本身,拿窗口当配方反复试探,线上配置一变就翻车;第二,千万别手欠去转发(Repost)别人或自己以前被贴过敏感标签的老帖子,因为转发会把原帖的敏感标签直接带进你当前前 5 条的计数窗口里!
31 什么是“账号限流标签”?什么是“10 分钟延迟”和“7 天 TTL 有效期”?到了第 8 天流量会自动恢复吗?
- 先说人话(先把“标签、有效期、作用、影响”四个概念彻底讲透):
先把这四个词串起来,用大白话把整个过程顺一遍:
- 什么是“标签(账号级安全标签 Account Label)”?
就像违章停车会被贴罚单一样,当你的账号触发了系统红线——比如刚刚第 30 题讲的**“最近 5 条帖子里有 3 条涉黄(触发账号级
NSFW_HIGH_PRECISION标签)”,或者第 39 题要讲的“把带劣质/失效外链的帖子设成了个人主页置顶(触发账号级SPAM_HIGH_RECALL垃圾标签)”——系统就会在后台数据库里,直接往你的账号ID头上**贴一张隐形的“违规封条”,这就叫账号级标签。 - 这个标签具体有什么作用?对你的流量有什么影响?
一旦你的账号头顶上贴了这张封条,在它生效期间,当推荐系统准备把你的新帖送进“未关注你的陌生人首页推荐池(
HomeRecommendations)”时,安检门一看你账号头上有这张封条,就会把帖子在这个入口拦下来(Drop)。 反映在你眼前的现象就是:已经关注你的老粉丝在关注流里还能看到你,但你的陌生人推荐流量(For You 破圈曝光)会大幅下滑! - 什么是“10 分钟延迟(10-minute delay)”?
假设你今天不小心连发了第 3 条带敏感图的帖子,凑够了“5 条里有 3 条”的触发线。这张账号封条是在你发出第 3 条帖子的第 1 秒钟就立刻贴到你头上吗?不是!后台负责把“单篇帖子标签”汇总升级成“整个账号标签”的传送管道(Forwarder),专门设置了一个 10 分钟的排队延迟(
delay = 10 minutes)。也就是说,从你第 3 条帖子被打标,到整个账号真正被贴上封条开始限流,中间至少隔着这段排队延迟。系统另有一个 20 分钟的maxLag服务目标,管的是“最多落后多少”;但具体哪一秒真正写到账号上,没有逐笔的实际记录,不能把这段时间当成一个 10 到 20 分钟的倒计时来用。 - 什么是“7 天 TTL 有效期(7-day Time-To-Live)”?
TTL是程序员术语,翻译成大白话就是**“这张封条的自动过期寿命”**。封条不是终身的:置顶坏链接那条路写进去的标签,代码里明确写了从写入那一秒起加 7 天到期;3/5 聚合这条路,正文记载的公开 TTL 同样是 7 天。但两条路的触发事件、计数方法和作者条件各不相同,第 32 条专门交代过,不能把它们并成一个“全站通用的 7 天窗口”。
- 什么是“标签(账号级安全标签 Account Label)”?
就像违章停车会被贴罚单一样,当你的账号触发了系统红线——比如刚刚第 30 题讲的**“最近 5 条帖子里有 3 条涉黄(触发账号级
- 代码已证实的真相(已知):
打开
safetyLabelToUserLevelAggregationV2Forwarder.strato、safetyLabelToUserLevelAggregationV2Processor.strato和PinnedLowQualityOrBadUrl.bot源码可以确认:- 延迟参数:聚合转发器明确设置了
10 分钟 delay以及20 分钟 maxLag(最大延迟服务目标); - 7 天倒计时起点:置顶外链垃圾标签这条路,写入时的过期时间公式写得很明确,是
CurrentTimeMs() + 7天(从系统真正把标签写入你账号数据库的那一秒钟起,往后加 7 天);3/5 涉黄聚合这条路,正文记载的公开 TTL 也是 7 天,但那是它自己的设置,两条路不是一条统一的公式; - 不重复无限叠加:在 3/5 涉黄聚合规则(
postToUserLabelRules.strato)里,默认把“当前已经背着NSFW_HIGH_PRECISION账号标签的作者”排除在外(即在 7 天受罚期内不会因为同规则每次跑又无限往后顺延 7 天)。79 80 74
- 延迟参数:聚合转发器明确设置了
- 代码还看不见的盲区(待查): 第一,10 分钟延迟和 20 分钟最大延迟是系统设定的目标值,线上服务器繁忙时具体哪一秒写入、哪一秒清理过期标签,没有公开实时监控日志;第二,满 7 天封条过期摘除之后,第 8 天你的真实曝光能恢复到原来的多少成,公开代码里没有历史对照数据。
- 给创作者的实操结论(判断):
搞懂了这套“贴封条 → 拦陌生人推荐 → 7 天自动过期”的完整机制,你遇到流量异常时就有了两条明确的行动指南:
- 如果不小心踩雷触发了账号标签:标签在身期间,你的新帖在陌生人推荐入口会被拦,重磅长文的破圈效果会打折。先修整账号、清理问题置顶链接或违规帖;要不要因此推迟发长文,看内容本身的时效,不必围着标签的到期日排日程——到期和恢复不是一回事(见第 2 条);
- 等标签过期之后:你的账号只是恢复了“允许重新进入陌生人推荐池”的资格,系统没有任何“到期自动给你流量补偿”的代码——过期之前发过的老帖子因为已经超过了 48 小时年龄线(
AgeFilter)不会起死回生;新发的帖子,重新走正常的召回与推荐。
32 除了“最近 5 条里有 3 条”,系统里还有没有别的通道会给账号贴上成人限流标签?
- 先说人话(这在问什么、有什么影响): 有些做擦边或艺术摄影内容的创作者看完第 30 题的 3/5 规则后,心里打起了小算盘:“既然它只查最近 5 条,那我每次发完 2 条擦边图片帖,就紧接着连发 3 条正经的早安纯文字帖把前 5 条窗口刷掉,是不是就永远不会被贴账号级成人标签了?”
- 代码已证实的真相(已知):
去翻代码库,你会发现“5 条里有 3 条”根本不是系统里唯一一条抓成人账号的防线!
- 在同一个
postToUserLabelRules.strato文件里,其实还写着另一条叫possibly_nsfw_account的规则(虽然它在公开默认 JSON 里设成了“在 10 条窗口里要求匹配 11 条”这种数学上不可达的软停用状态,但线上随时可以通过configuredRulesJson动态改回比如 10 条里匹配 4 条来激活它); - 更重要的是,在
botmaker-rules/scarecrow/目录下,还活着另一条完全独立的自动打标通道(NsfwTweetMediaProcessor.bot、ApplyNsfwUserLabel.df与ApplyNsfwUserLabelOrCreateReport.df):这条通道根本不管什么“最近 5 条帖子窗口”,而是直接按帖子 ID 把媒体涉黄事件塞进一个叫 HLL 的计数器里,专门检查**“在 1 天(24 小时)之内是否超过了 2 笔”**!一旦超过并满足模型分数与作者条件,同样会直接把账号送去打成人标签或人工审核!76 79 80
- 在同一个
- 代码还看不见的盲区(待查): 除了公开代码里能看到的这几条规则,X 内部还有多少条未开源的自动规则和人工巡查标准,以及各条规则在线上的触发比例,并未全部公开。
- 给创作者的实操结论(判断):
千万别耍小聪明去搞“发 2 条敏感图+插 3 条水贴卡窗口”的套路!因为你躲得过
postToUserLabelRules的 5 帖窗口,躲不过ApplyNsfwUserLabel.df的“24 小时内超 2 笔”计数!正常做非成人内容的创作者,则要注意连转推别人的擦边内容都要克制,避免一天之内多次触发媒体涉黄事件。
33 视频帖拿到第 64 个赞和第 512 个赞的那一秒钟,系统是不是必定会启动一次安全大检查?
- 先说人话(这在问什么、有什么影响):
我们在正文第 20 章揭露了一个真相:网上吹嘘的“视频拿到 64 个赞和 512 个赞会触发两轮流量奖励池”,在代码里其实是三条视频违规安全审查任务(
SpecialVideo动态闪现审查、MediaInjected夹带违规画面审查、AdultContentLeadingFrames长视频前 10 秒涉黄审查)的启动门槛!那是不是每支视频刚点到第 64 个赞或第 512 个赞的那一秒,安检机器人都100%会跑一遍? - 代码已证实的真相(已知):
在
grox/flows/ptos/目录下,我们能看到这三条视频安检流水线各自监听不同的 Kafka 消息队列入口(generators.py),并且全都配了 60 秒去重限流缓存(task_rate_limit.py)。当任务送进来时: - 代码还看不见的盲区(待查): 公开代码展示的是“安检消费端收到任务后怎么按 64 赞和 512 赞做判断”,而上游负责往 Kafka 队列里发送检查请求的生产端(Producer)到底是按什么频率、在哪些点赞节点触发发送的,上游生产代码并未公开。
- 给创作者的实操结论(判断): 不管上游是卡着第 64/512 个赞准时送检,还是每隔几分钟抽样送检,对我们创作者来说最核心的认知只有一条:64 赞和 512 赞是“视频火起来之后的深度违规安检线”,绝不是“流量奖励解锁线”! 只要你的视频(以及你 Quote 引用的别人视频)干干净净,没有在前 10 秒搞擦边、也没有在中间某几帧偷偷闪现违规二维码或色情画面,过几百赞的安检都不用怕。
34 视频安全审查到底是怎么抓“隐藏违规画面”的?把违规画面藏在第 11 秒能躲过去吗?
- 先说人话(这在问什么、有什么影响):
有些搞灰产或擦边引流的人,听说系统有条规则是“把 30 秒以上的长视频裁切前 10 秒去做成人审查(
AdultContentLeadingFrames)”,就自以为找到了漏洞:“那我把前 10 秒做成正经风景画面,把擦边或违规引流二维码藏在第 15 秒闪现一下,是不是就能完美骗过 AI 安检了?”一旦被抓到,会有什么后果? - 代码已证实的真相(已知):
翻开
grox/flows/ptos/目录下的源码,系统抓违规视频根本不是只有“裁前 10 秒”这一招,而是布下了三张天罗地网:- 动态突变帧捕捉(
SpecialVideo):专门用motion_reveal算法扫描整支视频里“画面突然剧烈变化的那几帧(motion_reveal_frames)”——哪怕你在正常视频中间只闪现了 0.5 秒的违规画面或二维码,也会被精准揪出来送审; - 黑名单参考库比对(
MediaInjected):把抽出来的视频帧拿去和官方已确认的“违规/红外/垃圾视频参考库”做深度特征比对(满 512 赞还开启大模型思维链推理),一旦命中就定性为SpamManipulatedMedia(恶意操纵媒体),送进公共写入池,走一般 Spam 分支的作者条件,再决定写哪些标签——不是这条任务直接给账号贴上某个具名标签。 - 双模型交叉会审(Cross-validation):针对成人内容,系统会同时跑 PTOS 大模型和另一个独立的
sex-and-nudity视觉模型做交叉验证,最后按确认的违规类别写下成人或垃圾标签。76 51 52 53
- 动态突变帧捕捉(
- 代码还看不见的盲区(待查): X 内部的黑名单违规视频参考库里存了哪些样本、视觉大模型的具体提示词(Prompt)以及交叉验证的判罚分数线,属于平台保密的反作弊资产,并未公开。
- 给创作者的实操结论(判断):
千万别信任何“前 10 秒放风景、第 11 秒放违规内容就能过审”的鬼话!因为
motion_reveal抓的就是中途突变画面。正常创作者只要保证自己的视频(以及 Quote 引用的视频)全程无违规插帧即可安心发布。
35 我在别人的热门帖子底下留言,自己又接着回复了自己两句,就会被当成“盖楼垃圾号”把评论分清零吗?
- 先说人话(这在问什么、有什么影响):
什么是“多层自回自评垃圾过滤(
TaskMultiStepReplySpamFilter)”?很多卖课或搞推广的人,喜欢去大 V 的热帖底下抢一楼留言,然后在这条留言底下自己回复自己盖起三四层楼(第 1 层留钩子、第 2 层放截图、第 3 层放引流微信号)。为了打击这种行为,系统专门写了一个过滤器:一旦判定你是在别人底下恶意盖楼发垃圾广告,就会把你那几条回复的评论区排序分(ReplyRankingScore)直接写成0.0分(沉到评论区最谷底没人能看见)! 那如果我们普通创作者在大 V 帖子底下正常讨论技术问题,一句话没写完、自己又接着回复了自己一条补充说明,会不会被误伤清零? - 代码已证实的真相(已知):
打开
task_multi_step_reply_spam.py和classifier_multi_step_reply_spam.py源码,系统把**“第一步:检查楼层结构”和“第二步:大模型看内容定性”**分得清清楚楚:- 哪些情况连审查都不会进(直接豁免)?
- 如果你是在**你自己发的主帖(Root Post)**底下连续回复自己写串文(Thread),100% 直接豁免不查!
- 如果被你回复的那个原帖作者粉丝数不到 1,000 人,不查!
- 如果你只回复了别人 1 条(没有在自己评论下再回自己形成三层楼),不查!
- 就算进了审查,还有三道防误伤保护:
只有当你在“粉丝
>= 1000的别人帖子”下“自己回复了自己”,才会把对话送给 Grox 大模型看(如果对话超过 10 层,只抽最前面 5 层+最后面 5 层+当前回复,每条最多看 2 张图)。大模型看完后,必须明确判定你是在发垃圾推广、且必须把你最新那条回复圈进去,剔除别人后至少还剩 2 条你自己的垃圾回复,程序才会真正动手罚你!66 67
- 哪些情况连审查都不会进(直接豁免)?
- 代码还看不见的盲区(待查): 大模型内部用来区分“正常分两楼补充技术细节”和“分两楼发垃圾引流广告”的具体提示词(Prompt)没有公开。
- 给创作者的实操结论(判断): 在自己的帖子底下写串文(Thread)100% 安全;去千粉大 V 底下正常讨论问题、哪怕分两层楼补充真实数据和报错日志,大模型能看懂你在正常交流,完全不用怕。唯一要戒掉的,就是在别人的热门评论区里一层接一层地自己回自己贴卖课广告或引流名片!
36 一旦评论被判为盖楼垃圾、ReplyRankingScore 被写成了 0.0 分,会连累我的整个账号或大 V 的原帖吗?
- 先说人话(这在问什么、有什么影响):
紧接着上一题,万一有人真的在千粉大 V 的评论区盖楼发推广被抓了,系统写下的那个
ReplyRankingScore = 0.0(评论排序分归零)到底有多大破坏力?会不会把人家大 V 的原帖热度搞垮?或者把我自己整个账号以后发主页帖子的权重也清零? - 代码已证实的真相(已知):
在
classifier_multi_step_reply_spam.py(#L157-L175)和task_multi_step_reply_spam.py(#L151-L198)里,代码写得非常克制:① 解析大模型结果时,程序用硬代码只接受index > 0的楼层,从物理上100% 保护了第 0 层(大 V 的原帖 Root Post)绝不会被误伤,同时也会把对话里其他无辜路人的评论全部剔除;② 最终写入ReplyRankingScore(score=0.0)并尝试打上RiskyHighVizReply(高曝光风险回复)标签的,仅仅是被模型圈出来的那几条你自己的垃圾回复 ID!67 - 代码还看不见的盲区(待查):
下游负责渲染帖子详情页评论区的服务在读到
ReplyRankingScore = 0.0后,是把它直接折叠进“显示更多可能含垃圾内容的回复”里,还是单纯排在最后一名,下游评论区展示代码未在公开库中完整列出。 - 给创作者的实操结论(判断): 这项惩罚是精准的“外科手术式打击”——只把那几条违规盖楼的评论按进水底(写 0 分),既不会连累无辜的原帖博主,也不会把你整个账号发原创帖的 For You 主页分数清零。
37 如果一条回复没有被贴上 RiskyHighVizReply 标签,是不是说明它的评论分数(ReplyRankingScore)也没被清零?
- 先说人话(这在问什么、有什么影响):
在上一题的代码里,当系统抓到盖楼垃圾回复时,会先后干两件事:第一件事是尝试给这条回复贴一个叫
RiskyHighVizReply的风险标签;第二件事是把它的ReplyRankingScore(评论排序分)写成0.0分发出去。有些大号博主就会问:“如果我是高权重账号,豁免了第一个风险标签,是不是连第二个 0 分惩罚也一起躲过去了?” - 代码已证实的真相(已知):
打开
task_write.py(#L39-L79)和task_multi_step_reply_spam.py(#L151-L198)对照执行顺序就能发现:“贴RiskyHighVizReply标签”和“把评论分数写成0.0分”在代码里是互相独立的两个步骤!负责贴标签的辅助函数(Helper)内部确实额外检查了高 PageRank/信用分、灰标和测试账号豁免;但是,就算这个辅助函数因为豁免条件没有贴标签就返回了,外层的主函数依然会继续往下走,照样把ReplyRankingScore(score=0.0)发布到缓存、Kafka 和 Strato 数据库里!(当然,真正的高 PageRank V2 或灰标号在更早的TaskMultiStepReplySpamFilter入口处就已经被跳过了,这里是针对中间信用分边界的独立逻辑。)66 67 - 代码还看不见的盲区(待查):
单条具体回复在线上数据库里的标签状态与内部
ReplyRankingScore数值,普通用户在前端界面上无法直接看到。 - 给创作者的实操结论(判断):
在官方 Under the Hood 报告里没看到帖子风险标签,并不等于你在别人评论区刷屏的回复没有被写
0.0分沉底。老老实实写有价值的评论,才是唯一不沉底的办法。
38 我发外链时,能不能光凭网址长什么样(比如是不是短链接),看出它会不会被 X 判为 LOW_QUALITY(低质量网址)?
- 先说人话(这在问什么、有什么影响):
什么是外链的
LOW_QUALITY或BAD评级?X 后台有一个庞大的“网址信誉黑名单库(URL Reputation)”。当你发一条带外部链接的帖子时,审查机器人(LQ_Tweets_With_LQ_URL_Verdict_At_Mention_To_NonFollower_v2.bot)会顺着你这根链接的跳转链条(redirectionChain)一路查过去:只要中间任意一跳的网址被信誉库标为LOW_QUALITY(低质量),且最终落地的网页不在GOOD(优质)或WHITELIST(白名单)里,机器人就会直接给你这条帖子贴上SPAM_HIGH_RECALL(高召回垃圾帖) 标签——哪怕你把外链藏在一楼评论区里,最新版 v2 机器人也照抓不误,直接把帖子从陌生人推荐流里移除! 那我们创作者在发链接前,能不能肉眼看出哪个网址会被 X 判为LOW_QUALITY? - 代码已证实的真相(已知):
从 v1、v2 外链机器人及置顶外链机器人的源码(
botmaker-rules/scarecrow/bot/)可以确认:机器人自己并不看网址字符串长短,而是直接读取内部网址信誉服务返回的评级枚举(BAD、LOW_QUALITY、GOOD、WHITELIST);并且最新版 v2 已经彻底删掉了旧版 v1“排除回复贴(isReply)、排除转发贴(isRetweet)以及必须@陌生人”的豁免条件!76 73 74 - 代码还看不见的盲区(待查):
X 内部的网址信誉库到底把全球哪些域名标成了
LOW_QUALITY或WHITELIST、多久更新一次名单,这份内部域名清单并未公开。 - 给创作者的实操结论(判断):
虽然我们看不到内部域名名单,但有三条铁律能帮我们避开 99% 的外链雷区:
- 彻底放弃“把外链塞进一楼评论区就能躲避审查”的幻想(v2 时代放评论区和放正文一样受审);
- 尽量直连高信誉大平台或正规主域名(如 GitHub、Substack、YouTube、正规备案官网),少用不知名的野鸡免费短链接服务做二次跳转(因为一旦那个免费短链域名被黑产滥用标为
LOW_QUALITY,哪怕你最终落地页是正规博客,只要最终页没进 X 的顶级白名单,中间这一跳就会把你连累死!); - 发帖前亲手点开链接测一遍,确保没有跳去过期被篡改的死域名。
39 如果我不小心把带坏链接的帖子设成了主页置顶、触发了带 7 天有效期的账号标签,我马上“取消置顶”能立刻解封吗?
- 先说人话(这在问什么、有什么影响):
我们在正文第 27 章讲过一个极其凶险的机器人叫
PinnedLowQualityOrBadUrl.bot(置顶劣质链接审查机器人):当你把一条帖子设为个人主页置顶(Pin)时,如果里面带的链接被查出是BAD或LOW_QUALITY(比如你置顶了一条两年前的旧帖,里面挂的个人网站域名早就过期被博彩网站抢注了),系统就会直接给你的整个账号贴上SPAM_HIGH_RECALL(高召回垃圾账号) 封条,让你接下来 7 天内发的所有新帖都进不了陌生人推荐流! 很多创作者问:“万一我中招了,我一发现流量不对劲,立刻把那条置顶帖取消置顶(Unpin)或者删掉,我账号头上的 7 天封条会不会马上自动消失?” - 代码已证实的真相(已知):
打开
botmaker-rules/scarecrow/bot/PinnedLowQualityOrBadUrl.bot(#L2-L44)源码从头读到尾,里面的逻辑只有单向的一条线:当检测到用户修改置顶帖(pinnedTweetIds的修改后after值存在且不等于修改前before值),且解析出新置顶帖里的链接含BAD或LOW_QUALITY时,直接调用SetUserLabel写入有效期为 7 天(CurrentTimeMs() + 7天) 的SPAM_HIGH_RECALL账号标签。在这份规则文件里,根本没有写任何“当用户把问题帖子取消置顶时,同步删除该账号标签”的代码分支!74 - 代码还看不见的盲区(待查): 至于 X 后台有没有其他未开源的定时复查任务,或者通过人工客服申诉能不能提前手动摘掉这个标签,在公开仓库里看不到。
- 给创作者的实操结论(判断): “请神容易送神难”!代码里只有换上坏链接置顶时“贴 7 天封条”的自动代码,没有取消置顶时“撕封条”的自动代码! 所以,如果真的中招了,虽然你肯定得第一时间把问题置顶帖撤下来防止 7 天后再次触发,但这 7 天多半只能等它到期——公开代码里没有自动摘除的分支,能不能提前解除,公开资料答不了。最好的办法就是:在每次点下“置顶”按钮之前,花 5 秒钟把帖子里的链接点开检查一遍!
40 中文帖子到底重复多少个字、或者复制粘贴几次,才会被抓进 COPYPASTA_SPAM(复制粘贴垃圾)名单?
- 先说人话(这在问什么、有什么影响):
什么是
COPYPASTA_SPAM?“Copypasta”在英文网络俚语里就是“到处复制粘贴的刷屏文案”。如果你为了省事,把同一段推广文案、或者同一句评论复制粘贴发了好多遍,系统里专门抓重复文本的机器人就会给你贴上COPYPASTA_SPAM垃圾标签。很多人问:“中文又不像英文那样用空格分词,系统抓得到中文重复吗?到底重复几个汉字、发几次才算违规?” - 代码已证实的真相(已知):
打开
botmaker-rules/scarecrow/bot/BBQDuplicateTextProd.bot(管主帖)和BBQDuplicateTextRepliesProd.bot(管评论区回复),代码里明明白白列出了专门针对中日韩汉字(CJK 字符)的检测任务名称:duplicate_text_characters_cjk和duplicate_text_characters_cjk_replies!只要上游定时任务把一批高度雷同的帖子打包成一个“重复帖子簇(tweetIdCluster)”送过来,且作者不是测试号、高 PageRank 或灰标号,机器人就会给这些帖子统统写上COPYPASTA_SPAM标签!81 - 代码还看不见的盲区(待查):
这两个
.bot文件是从“收到上游已经打包好的重复帖子簇(tweetIdCluster)”才开始执行的;至于上游那个duplicate_text_characters_cjk定时任务内部是规定“连续 20 个汉字相同”还是“余弦相似度超过 85%”、以及“重复发满 3 次还是 5 次”才打包送审,那段上游 SQL/离线查询代码并未开源。 - 给创作者的实操结论(判断): 千万别以为写中文没有空格就能逃过复制粘贴检测!但正常创作者也完全不用风声鹤唳——你在不同文章里正常使用同一个行业术语、或者固定的个人署名格式,绝不等于刷屏;只要戒掉“拿同一套话术模板去十几个帖子底下批量复制粘贴引流”的毛病,就根本不会撞到这个枪口上。
41 帖子一旦被贴上 COPYPASTA_SPAM(复制粘贴垃圾)标签,在推荐流里会被扣多少分、还是直接屏蔽?
- 先说人话(这在问什么、有什么影响):
紧接着上一题,假如某条帖子真的因为批量复制粘贴,被上面的机器人贴上了
COPYPASTA_SPAM标签,接下来这个标签在推荐系统里是怎么发作的?是扣 50% 分数,还是像SPAM_HIGH_RECALL那样直接在陌生人推荐流里一刀砍死? - 代码已证实的真相(已知):
在公开的
botmaker-rules目录里,我们能 100% 看到机器人把COPYPASTA_SPAM这个标签写进数据库的代码动作;但是,当我们拿着COPYPASTA_SPAM这个名字去搜公开的Home Mixer、VM Ranker和visibility-filtering(可见性过滤规则库)时,却没有在公开列表里看到直接读取COPYPASTA_SPAM的那一行代码。76 81 - 代码还看不见的盲区(待查):
为什么上游拼命打这个标签,下游公开代码里却没出现它的名字?正如官方在
README.md(#L440-L447)里专门声明的:为了防止黑产针对性绕过风控,公开仓库并没有放出全部的反垃圾规则与下游消费服务。这个标签极可能由未开源的外部召回过滤层或信用分扣减服务直接消费。 - 给创作者的实操结论(判断):
工程师绝对不会闲得没事干写两个专门抓中文和英文重复帖子的生产环境机器人(
Prod.bot)放在那里摆设。虽然下游具体扣多少分没公开,但看到BBQDuplicateTextProd.bot的存在,就足以断绝一切“靠群控脚本批量复制粘贴文案涨粉”的念头。
42 为什么说“诱导互动(Engagement Bait)”连高权重账号和灰标大号都不给豁免?平时文末提问怎么写才安全?
- 先说人话(这在问什么、有什么影响): 什么是“互动诱导(Engagement Baiting / Farming)”?就是帖子本身没什么干货,纯粹靠话术勾引读者刷点赞、刷评论、刷转发来骗算法权重(比如“看到这张图 3 秒内点赞今年必发财”、“想要的在评论区扣 888 我私发你”)。很多大 V 以为:“我的账号权重高(高 PageRank),平时发点小擦边或小广告系统都对我网开一面,搞点‘扣 1 领资料’应该也没事吧?”
- 代码已证实的真相(已知):
打开 Grox PTOS 的安全标签写入代码
task_write_safety_post_annotations_result_sink.py(#L233-L248),你会看到一段专门针对大号的“尚方宝剑”: 对于其他普通的垃圾违规类别,代码确实会先检查if not is_high_pagerank_or_grey_badge(如果不是高 PageRank 大号或灰标号才贴罚单);唯独当大模型判定你的帖子属于以下三大互动作弊罪名之一时——①SpamEngagementBaiting(互动诱饵)、②SpamEngagementFarming(互动农场刷量)、③SpamCardManipulation(恶意操纵预览卡片骗点击)——代码直接把should_label_for_spam设为true,完全无视你的高 PageRank 和灰标身份,照样当场给你贴上SpamHighRecall垃圾标签(直接从陌生人推荐流里移除)!54 - 代码还看不见的盲区(待查):
PTOS 大模型在后台到底用哪几句具体的提示词(Prompt)来划定“正常呼吁读者讨论”与“恶意互动诱导”的界限,该文件(
prompts.py)未开源。 - 给创作者的实操结论(判断):
不管你的账号粉丝再多、权重再高,在“骗赞骗评(Engagement Bait)”面前都没有免死金牌!
那平时写完干货,怎么在结尾引导读者评论才既安全、又能用上回复这一项?做法就是**“问具体场景,别要机械口令”**:
- ❌ 高危写法(机械口令):“想要这份 OCR 测试脚本的,先点赞关注,然后在评论区扣‘666’,满 100 人我统一发!”
- ✅ 安全且高权重的写法(专业场景讨论):“你们公司在处理中文发票自动入账时,最常报错的是税额栏还是购买方税号?如果遇到过更奇葩的印章遮挡案例,欢迎在评论区贴出来,我挑代表性的样本加进下一轮复测!”
43 发帖子带 # 话题标签(Hashtag)到底好不好?为什么说最多别超过 4 个?
- 先说人话(这在问什么、有什么影响):
很多从 Instagram、小红书或抖音转过来的创作者,发每条帖子都习惯在末尾塞满十几个
#AI #科技 #创业 #副业 #干货分享这样的话题标签,觉得标签越多被搜到和推荐的概率越大;而另一派老玩家则警告说:“X 算法最讨厌#标签,带 1 个标签就会被判定为垃圾号降权!”到底听谁的? - 代码已证实的真相(已知):
在公开源码里,我们找到了关于
#标签的三块拼图,刚好拼出完整真相:- 带标签绝不是“零价值或必降权”:在 Phoenix 推荐模型的用户历史行为特征清单(
history_id_lists.py与id_list_features.py)里,专门有一项叫CLICK_HASHTAG(用户点击过的话题标签历史)——说明系统在算读者兴趣时,确实会看他平时点过哪些#标签; - 代码里提取标签的硬上限是 4 个(
MaxHashtagsPerTweet = 4):在SimClusters兴趣社区的实体抽取器TweetEntityExtractor.scala里,写死了常量MaxHashtagsPerTweet = 4——它在提取你帖子里的标签时,最多只拿前 4 个,从第 5 个标签开始往后直接丢弃不看! - 胡乱堆砌标签确实有专属罪名(
SpamHashTagAbuse):在 PTOS 安全审查的违规分类(state.py)里,专门设有一项SpamHashTagAbuse(话题标签滥用),一旦被模型判定为乱塞无关标签蹭热度,就会被贴上SpamHighRecall垃圾标签,断送陌生人推荐流量!54
- 带标签绝不是“零价值或必降权”:在 Phoenix 推荐模型的用户历史行为特征清单(
- 代码还看不见的盲区(待查): 在主计分表里并没有“加 1 个标签加几分”的直接公式;至于带 1 个精准标签和不带标签在线上各大召回通道里的细微流量差异,没有公开的线上对照报告。
- 给创作者的实操结论(判断):
这三块代码拼在一起,给我们的实操铁律再清晰不过了:平时发普通观点或教程,完全可以 1 个
#标签都不带(靠正文前 4,000 字和首图,Grox 多模态模型足够看懂你在聊什么);只有当你的帖子确实属于某个明确的行业大会、开源项目或特定固定栏目时,自然地放上 1 到 2 个(这条抽取路径最多读前 4 个,第 5 个起就不读了)精准相关的#标签即可,永远不要在文末堆砌一排无关热搜词!
44 当我们发“长 Post”或“Article(专栏文章)”时,AI 到底读到了我们写的哪一部分文字?
- 先说人话(这在问什么、有什么影响):
当你写了一篇 8,000 字的深度长文(无论是用普通长 Post 发,还是用 Article 专栏编辑器发),后台的 Grox 多模态大模型(
mm_emb)必须先读懂你这篇文章在讲什么,才能生成“语义向量(Semantic ID)”去帮你匹配感兴趣的陌生读者。大家最关心的是:AI 是把我的 8,000 字从头到尾一字不落地全读完了,还是只读了前面一截? - 代码已证实的真相(已知):
在公开的
grox/目录源码里,我们核实了三件确定的事:- 在数据映射器
post_mapper.py里,程序把上游传入的post_metadata.text赋给了帖子对象的full_text字段;如果是一篇 Article,还会在article_metadata里额外装入 Article 标题(title)、封面图和正文内嵌媒体(注:在公开的article_metadata数据结构里,没有列出一个单独叫article_body正文全文的字段); - 在新版 V8.2 阅读器(
renderer_v82.py) 里,程序会对post.full_text执行严格的 Python 字符切片——只截取前4000个字符(MAX_POST_TEXT = 4000);如果同时带有 Article 元数据,还会并列追加读取 Article 标题的前200个字符(MAX_ARTICLE_TITLE = 200)! - 我们在本地用内存对象直接跑了 10 项函数实测验证:在 V8.2 里,第 4,000 个字符往后的文字改动完全不会改变输出文本;而旧版 V5 阅读器(
renderer.py) 则没有写这道 4,000 字符切口。87 88
- 在数据映射器
- 代码还看不见的盲区(待查):
线上生产环境的上游 Strato 服务在面对一篇万字 Article 时,到底有没有把 Article 的正文塞进
post_metadata.text里传过来,或者有没有通过其他未公开的内部通道读取 Article 全文,以及线上哪些模型用 V8.2、哪些用 V5,这部分上游代码未开源。 - 给创作者的实操结论(判断): 为了确保在任何阅读器路径下 AI 都能 100% 抓准你的文章主题,请死守两条写作铁律:① 写长 Post 时,务必在前 4,000 个字符以内把研究对象、核心结论和关键专业词全部亮出来;② 写 Article 专栏时,务必把前 200 个字符的 Article 标题和外层导语写得干货满满,千万别起《深夜的一点感悟》这种让 AI 一头雾水的文艺空洞标题!
45 读者在时间线上点长 Post 的“展开全文(Show more)”,和点进卡片打开一篇“Article 专栏”,在算法眼里算同一种阅读吗?
- 先说人话(这在问什么、有什么影响):
很多创作者纠结发长 Post 还是发 Article,是因为担心:“读者看长 Post 只需要点一下‘展开全文(Show more)’就能在时间线上顺着往下滑;而看 Article 却要专门点进卡片跳到另一个阅读页面。这两种点开阅读的动作,在算法算那个
0.4分的‘点击后深度停留(CLICK_DWELL_TIME)’和0.006的‘连续停留秒数(DWELL_TIME)’时,待遇一样吗?” - 代码已证实的真相(已知):
打开通信协议定义文件
recsys.proto和特征映射文件constants.py可以看到:系统在底层协议里把这些动作分得非常细——普通点击帖子是编号29(CLIENT_TWEET_CLICK),点击长帖的“展开全文”是独立编号45(CLIENT_TWEET_SHOW_MORE_EXPAND),进入详情页曝光是72,详情页停留是103;同时页面类型里也专门定义了PAGE_ARTICLE(Article 正文页)和PAGE_ARTICLE_PREVIEW(预览页)。此外,在服务端 Rust 工具代码(util.rs)里,能明确看到把连续停留时间DWELL_TIME从毫秒除以 1000 转换成秒的代码。90 91 98 - 代码还看不见的盲区(待查):
从手机客户端捕捉到读者“点开 Article 页面”或“点展开全文”,到上游日志聚合服务把时长算进
DWELL_TIME和CLICK_DWELL_TIME(阈值10.0)那两个训练数据槽位里,中间的客户端计时起止规则与上游聚合代码并未放进公开仓库(官方在phoenix/README.md中已声明生产数据源与内部遥测未开源)。 - 给创作者的实操结论(判断):
虽然客户端底层怎么归因计时没开源,但在最终的价值打分模型(
phoenix_scores.rs)里,既没有单独给“展开全文”设特权分,也没有单独给“打开 Article”设特权分,最终统一认的都是预测出来的阅读停留与互动概率。所以我们不用去赌“哪个按钮在计时器里占便宜”,而是按内容结构选格式。
46 把同一篇三千字干货从“长 Post”改成发“Article 专栏”,能不能靠格式本身直接让曝光翻 5.7 倍?
- 先说人话(这在问什么、有什么影响): 网上之前流传过一张很火的图表,说“2026 年在 X 上发 Article 专栏的浏览量中位数是发普通帖子的 5.7 倍”!于是很多创作者不管写长写短,哪怕只有一千字也硬塞进 Article 编辑器里发,以为只要套上 Article 这个壳子,算法就会自动给 5.7 倍的流量加成。
- 代码已证实的真相(已知):
第一,我们检索了
Home Mixer和VM Ranker涉及候选召回、初筛和最终打分的 103 个源码文件,在最终计分输入CandidateScoringInputs(inputs.rs)和加权函数(scoring.rs)里,根本没有is_article这个字段,没有任何“只要是 Article 就乘以 5.7 倍或额外加分”的代码!第二,我们去核查了那份“5.7 倍”数据的原始出处(第三方机构 NotPeople 的 8 月样本报告),发现人家统计的 42 篇 Articles 背后,每篇 Article 平均配套发了 6 到 28 条普通帖子(共计 843 条导流帖)去给它做摘录推广和引流,而且拿来做对比基准的恰恰就是那些简短的日常导流帖!94 96 - 代码还看不见的盲区(待查): 线上深度学习模型在读取内容特征后,会不会对带 Article 标题结构的候选帖产生细微的隐性预测偏好,或者线上是否存在未公开的小流量实验,无法仅凭静态代码完全排除。
- 给创作者的实操结论(判断): 所谓“5.7 倍曝光”,本质上是**“1 篇精心打磨的旗舰 Article + 连续十几条带图短帖矩阵导流”**共同砸出来的综合运营结果,绝不是算法代码里写死了 5.7 倍格式乘数!三四千字以内能一气呵成讲完的单一问题直接发 长 Post;上万字的多章节手册发 Article,并务必模仿那批高手的做法,单独发一条或多条带核心结果图的导读 Post 去引用推广它!
47 什么是 Article 的“64 赞拉图门槛(is_high_fav)”?V5 和 V8.2 两个阅读器读图片为什么不一样?
- 先说人话(这在问什么、有什么影响):
我们在正文第 17 章讲透了一个让无数发 Article 的创作者恍然大悟的真相:当你直接用 Article 编辑器发了一篇图文并茂的专栏文章时,为什么有时候感觉 AI 好像根本没看懂你放在 Article 里的封面图和正文插图?这背后的“搬运工 64 赞门槛(
is_high_fav)”和“V5/V8.2 阅读器挑图差异”到底是怎么配合工作的? - 代码已证实的真相(已知):
在
grox/目录的源码里,图片进入 AI 大模型要过两道关:- 第一关(搬运工
MediaLoader的 64 赞门槛):在grox/core/data_loaders/media_loader.py(#L130-L170与#L293-L303)里,负责从数据库拉取图片数据的搬运工为了节省算力,设了一个判断条件叫is_high_fav(高赞帖判断),其公开默认门槛在config.py里设为 64 个赞(deluxe_fav_count_threshold = 64)!在这条搬运路径上,只有当帖子满足了is_high_fav(满 64 赞)等条件时,程序才会进入专门去拉取 Article 封面图(cover_media)和 Article 正文内嵌图(article_metadata.media) 的代码分支!(注:这只管这条媒体拉取路径,绝不代表 Article 要满 64 赞才有推荐资格。) - 第二关(V5 与 V8.2 两代阅读器的挑图差异):我们在本地直接调用两代阅读器的原函数做了实测——旧版 V5(
renderer.py) 会按“Article 封面图 → 普通帖子附件 → Article 内嵌图”的顺序读图(若预算设为 1 张则只拿走 Article 封面图);而新版 V8.2(renderer_v82.py) 的挑图函数_collect_post_media只去翻“普通帖子的图片附件栏(post.media)”,压根没写代码去读 Article 的专属封面图和内嵌图!如果图片只放在 Article 编辑器里,V8.2 函数返回的图片列表直接是空的(0 张图)!88 89
- 第一关(搬运工
- 代码还看不见的盲区(待查):
线上生产环境里,上游数据服务在调用 V8.2 之前会不会把 Article 的封面图复制一份塞进
post.media字段里,以及线上各个下游模型消费 V5 向量和 V8.2 向量的具体比例,未在公开仓库中披露。 - 给创作者的实操结论(判断):
不管线上上游有没有做额外复制,我们用下面这 3 招实操动作,就能把能控制的部分都控制住:
① Article 的标题(前 200 字)塞满核心关键词(确保在未满 64 赞或 V8.2 没读到图时,AI 光靠标题就能精准匹配受众);
② Article 的封面图放核心信息图(确保走 V5 或满 64 赞后第一顺位读到干货);
③ 发完 Article 后,立刻单独发一条“导读长 Post”,并把最核心的那 1 张结果对比图直接作为“普通图片附件(
post.media)”挂在这条导读 Post 上——这样从第 0 个赞开始,就能绕开 64 赞门槛,让 V8.2 把你的前 4,000 字导读和首图吃得干干净净!
48 为什么说发完 Article 之后千万别频繁撤下改稿?ArticleTweetContent 规则在拦什么?
- 先说人话(这在问什么、有什么影响):
很多完美主义创作者发完一篇长 Article 后,发现里面有个标点或措辞不顺眼,就点进编辑器修改。但在 X 的产品设计里,修改一篇已发布的 Article 时,系统会先把这篇 Article 从“已发布(
Published)”撤下来变成未发布草稿状态,等你改完再次点发布后才恢复。这中间撤下改稿的几十分钟,在推荐系统的安检门里会发生什么? - 代码已证实的真相(已知):
在可见性过滤系统
visibility-filtering/rules/tweet_rules.rs(#L247-L252)和levels.rs里,有一条专门针对 Article 的硬规则叫ArticleTweetContent:只要一条帖子关联了 Article,并且该 Article 当前的状态不是Published(比如处于Draft草稿、SoftDeleted软删除或状态缺失),在TimelineHomeHydration安全级别下就会直接执行过滤移除(Drop)!此外,如果是设为仅订阅者可见的付费 Article,通用过滤器IneligibleSubscriptionFilter会拦截未付费订阅读者,且媒体接口(article_client.rs)也会对无权限者隐藏图片。92 93 - 代码还看不见的盲区(待查):
当你在线上点下“重新发布(Republish)”的那一秒,各个分布式缓存节点需要隔多少秒或多少分钟才能把状态全部同步刷新回
Published,取决于线上缓存配置。 - 给创作者的实操结论(判断):
千万别在 Article 发布后的推荐期里频繁撤下来慢慢改稿! 因为在你撤下改稿的这段“未发布空窗期”里,一旦触发
ArticleTweetContent规则,你的帖子就会被当成未发布草稿直接拦截隐身。建议在草稿箱里预览检查好代码块、公式和错别字后再一次性正式发布;万一必须改,改完务必第一时间确认它已经重新变回Published(已发布)状态!
49 创作者在后台看到的“浏览量(Views)”,能不能用来判断有多少人真正读完了我的长文或 Article?
- 先说人话(这在问什么、有什么影响): 发完一篇长 Post 或 Article 后,大家最喜欢盯着帖子右下角的那个“浏览量(Views,比如 5 万次观看)”看。很多人以为:“显示 5 万 Views,就代表有 5 万个读者点开了我的长文并把它读完了!”如果拿这个数字来做内容复盘,会掉进什么坑里?
- 代码已证实的真相(已知):
根据 X 官方帮助文档(
View counts)的定义以及源码(engagement_counts_hydrator.rs与recsys_batch.py)的字段区分:前台公开显示的Views(对应一般view_count)是一个极其宽泛的曝光计数——只要读者在时间线上匆匆划过你的帖子(哪怕连“展开全文”都没点、1 秒钟就划走了)也算 1 次 View;同一个读者早晚刷到两次算 2 次 Views;别人点进你主页看、搜索看到、甚至你自己点开看自己的帖子,统统都会重复累加进这个 Views 里! 它既不是“去重后的独立读者人数”,也不是前面冷启动查的内部view_count_on_home(纯首页推荐曝光),更不等于模型内部训练用的DWELL_TIME(阅读停留秒数)或CLIENT_TWEET_RECAP_DWELLED(深度阅读标记)。59 91 - 代码还看不见的盲区(待查):
X 创作者后台(Analytics)目前并没有向普通创作者开放“单篇长文的平均阅读秒数”、“滑到底部完读率百分比”或“内部
CLICK_DWELL_TIME达标人数”这些内部模型训练指标。 - 给创作者的实操结论(判断): 平时做内容复盘和格式对比时,千万别把表面虚高的总浏览量(Views)当成“读完文章的人数”! 要想判断一篇深度长文到底有没有被真正读进去、有没有打动目标受众,请重点看另外三个更实在的指标:① 收藏数(Bookmarks,代表读者觉得有用、想存下来反复查);② 复制链接数(读者把链接拷走发给别人——这一项的系数在表里最大,但系数乘的是预测概率,不能换算成值多少分);③ 点进主页后的净增关注数。看这三个数,是因为它们说明读者真的用了、存了、认了你;至于内容能推多远,代码里没有承诺。
研究范围与验证记录
本指南最后修订日期为 2026 年 10 月 29 日(美国洛杉矶时间)。全文基于公开算法库源码拆解、23 页技术核查报告与第 7 版修订稿整合而成:
- 核心代码基准:主报告基准固定于 Git 提交
5ed796374ea48ee26058aab66ab10c266bea2bef(2026-10-28 UTC),并将 10 月份的参数与架构变动一路追查核对至最新公开提交606b254b45be798bfaecfa8c23f5a9c51bc8000c(2026-10-29 UTC)。文中涉及跨日的关键提交均同时标出 UTC 时间与洛杉矶当地时间(PDT),官方更新说明日期则严格按README.md原文保留。 - 历史参数快照核对:针对 10 月份权重变化,我们沿着同一个文件
home-mixer/params/param.rs逐一比对了 20 个历史提交快照,并将同一提交下Home Mixer与VM Ranker两处默认值的异同并列呈现;针对606b254的可见性规则重构,我们将重构前后的 14 组规则列表与字段全部展开做了一致性核对,确认入口规则与执行顺序完全一致。 - 本地代码重写与函数实测验证:
- 原技术调研对排序与过滤核心逻辑用 Python 进行了等价重写验证,共通过 143 项断言测试(Assertions),覆盖 26 个源码文件的一致性核对;
- 成文阶段针对同作者候选计数、长短帖穿插、对话卡片组装(
convo_marshaller.rs)及后置对话去重,额外完成了 22 项局部断言测试(核对 8 个源码文件);针对转发与停留加权计算,完成了 14 项加权断言测试(核对 4 个源码文件); - 针对 CREAD 停留时间重建与
CLICK_DWELL_TIME二分类阈值(输入9, 10, 10.0001, 20),在本地 CPU 上直接调用了原始 Python/JAX 纯函数验证边界; - 针对 长 Post vs. Article 专题,对
Home Mixer的sources、filters、scorers、params、candidate_pipeline及可见性、行为协议接口进行了涵盖 103 个文件的有界检索;并对 V5 与 V8.2 内容理解处理器编写了轻量内存对象测试,直接调用原函数完成了 10 项输入输出实测检查(全部通过,验证了 4,000 字符截断、200 字符 Article 标题共存以及 V5/V8.2 对 Article 封面与内嵌图的抓取差异;对比两个提交间的 14 个内容路径文件,12 个文件二进制 blob 完全一致,另 2 个仅新增机构徽章字段)。
- 严谨性声明:上述本地断言与函数检查均用于 100% 确认公开源码的数学逻辑与分支条件,我们绝不将不同阶段的局部断言次数简单相加吹嘘成“官方线上整合测试”,也不在缺乏线上特征开关、未开源前端遥测与未公开模型权重的情况下,替任何单篇帖子捏造所谓的“官方推荐总分”或“保底曝光倍数”。文中的报价沟通、会议纪要工具测试、中文发票 OCR 测评与租房交接表,均为帮助理解的说明性情境与算例,不是作者亲历的实测记录。
参考资料
代码链接固定到文中所用的提交;第三方文章是被核查的对象,技术结论以相应的源码和官方资料为依据。
[1] V8.2 第一个可用媒体及视频帧。
[2] 新版加权计分与作者多样性。
[3] Hootsuite 的一般帖子频率建议 2025 年 4 月 18 日。
[4] 被核对的 X Algorithm Playbook 频率解读。
[5] 模型输入与推荐流程。
[6] X 官方长贴与 Articles 定义及分发建议。
[7] 被核对的 Gridlok 原文 2026 年 4 月 3 日。
[8] 被核对的 SocialPilot 原文 页面标为 2026 年 9 月。
[9] 被核对的 Bangerkit 原文 2026 年 10 月 8 日。
[10] X 官方 Premium 说明。
[11] 公开更新日期、固定提交与时区。
[12] 公开默认的同步方式,以及 Home Mixer 与 VM Ranker 的使用路径。
- 主要正式默认的 cron 同步说明
- Home Mixer 参数档的同步时间
- 本地加权、冷启动与 RPC fallback
- VM 请求包含 heads、缓存分数与 compute_value_model
- VM Ranker 从自身 params 取系数
- 有缓存加权分数时的处理
[13] CREAD 的多门槛训练与停留时间重建。
- 官方 10 月 8 日更新说明
- home_direct_packed 启用 CREAD 的配置
- 非 Gallery 与 Gallery 的 CREAD 范围及损失设置
- 产生对数间隔门槛
- 多门槛标签、分类与时间重建损失
- 以概率乘门槛间距重建时间
- 训练时使用 CREAD 损失
[14] 点击停留二元目标、ld 召回分支与不同的信号定义。
- 点击停留系数 0.4
- CLICK_DWELL_TIME 的阈值 10 二元配置
- 严格大于门槛及 sigmoid 概率
- Home Mixer 使用的 click_dwell_time 字段
- Phoenix 分数的候选读取入口
- ld 正例与多分支配置
- home 与 ld 具名配置
- 召回推理分支权重
[15] 同一路径的十月互动系数历史。
- 10 月 9 日 Favorite、Video open 与停留等默认
- 10 月 13 日 Favorite=0.6
- 10 月 13 日 Video open=0.02
- 10 月 13 日连续停留系数升至 0.006
- 10 月 14 日 Favorite=0.66
- 10 月 14 日 Not interested=-52.272
- 10 月 29 日公开快照中的同组系数
[16] FairShare 初筛在十月的新增与启用。
[17] 10 月 28/29 日快照中的新功能、开关及视频路径。
- 5ed7963 新增的 page logging、decode 与探索开关
- 606b254 的 page logging 默认
- 606b254 的 Carousel 开关仍为 false
- 606b254 新增的 open times immersive dwell 系数仍为零
- 606b254 的 Carousel 新公式
- 606b254 新增 immersive_page_rl_cread 配置
- Carousel 视频资格与直式比例
- VQV 的严格视频长度门槛
[18] 对话模块与祖先帖子的实际选择。
[19] 串文去重在评分之后。
[20] 已看过滤也检查父帖与转发原文。
[21] 权重与作者多样性公开默认。
[22] 时间窗口与特定来源上限 不等同每日发文配额。
[23] X 官方串文展示说明。
[24] 回复候选过滤的范围与开关。
[25] Hootsuite 长单帖与串文小实验 2024 年 1 月 31 日。
[26] 2023 年官方 Heavy Ranker 文件。
[27] 目前两处系数、概率乘法及互关的适用条件。
[28] 停留事件与点开后阅读是不同目标。
[29] 实际转发新增一条关系网召回路径。
[30] 原作者与转发者的粉丝圈、回复例外及附带内容。
- 按候选作者判断是否在读者关系网内
- OON 转发与回复的不同条件
- Phoenix OON 回复的公开开关默认
- 回复例外限定的 served types 与祖先补资料
- 转发按转发者放入 secondary 索引
- 按读者关注名单取候选
- 回复祖先与转发来源 ID 的保留
- Thunder 对不同深度回复的条件
- 对话模块组装 root、祖先及 focal
- 引用、转发及对话附带内容的可见性处理
- For You 上层组装的不同来源
- PushToHome 依请求指定的帖子建立资料
[31] 候选召回读取的是当前读者的历史。
[32] 长停留目标进入召回训练及推理。
[33] 读到底召回的公开时间、训练分支与适用范围。
- 官方标示为 10 月 13 日的更新
- 10 月 28 日 README 补记所在的公开提交
- 10 月 13 日加入 ld 的公开提交
- 10 月 13 日已公开的 ld 正例与三分支配置
- 10 月 8 日尚无 ld 的配置
- 现有具名配置的分支、权重与 HOME 数据集
- combined 与 home-only 具名配置
- 按动作正负例计算各分支的训练损失
- 推理时使用分支权重
- 模型读取动作标记而非自行判定全文读完
- 通用模型设置的 ld 正例与权重默认
- 冷帖子池按帖子赞数与观看数筛选
[34] 索引窗口与召回数据集:生产资料不等于实际送出曝光。
- Main 与 Sid 模式的索引窗口
- 按索引名称路由到对应窗口
- HOME、HOME_COLD、HOME_HOT 都引用 1fav_1day
- HOME_COLD 与 HOME_HOT 的同源资料分割
- Phoenix 来源启用条件与实际召回请求
- 召回后仍须过滤、评分及选取
[35] 冷启动资格、实验分组与资料边界。
- 两小时、Home 曝光、粉丝与 slot 等默认
- viewer arm 的判断
- 非回复非转发、粉丝上限及 author corpus
- 资格条件同时成立才进入选择
- topic request 与冷启动开关
- 十月九日快照已有相同主要门槛
- Home 计数与一般观看计数分栏
- 计数缓存 TTL 为六十秒
[36] 冷启动的 Beta 抽样与个人化二次选择。
[37] 点赞事件的索引更新门槛、节流与年龄边界。
[38] 1fav、32fav、搜寻与回复索引的实际生产条件。
- search_unfiltered、32fav 与 1fav 计数竞态
- 回复的 1fav_reply 与 32fav_reply 索引
- 建立时的 post_creation 索引
- 重新读取互动计数与作者资料
- 来源、社群、转发、回复及可见性的分流顺序
[39] 48 小时到底检查谁:候选 ID、来源窗口与转发原文。
- 48 小时常数
- AgeFilter 以候选 ID 计算年龄并使用小于等于
- 年龄过滤器所在候选流程
- 转发自己的 ID 与原文 ID 分列
- 核心资料 hydration 不将候选 ID 换成原文 ID
- 原文与转发按原文 ID 去重
- 已看检查所用的原文与父帖相关 ID
- 已看候选的判断
- 已送出候选的判断
- 转发原文等附带内容的可见性处理
- For You 上层来源与其过滤器
- PushToHome 来源的启用与资料建立
[40] 收藏与相似内容的后续召回。
[41] 收藏的三个位置:融合、个人后续召回与沉浸式训练。
- 共用融合权重字段没有独立 bookmark
- 共用加权公式的实际项目
- 按当前读者取互动资料并读取 BookmarkMetadata
- 互动信号开关、每类上限及候选年龄默认
- SimClusters 的公开启用默认
- SimClusters 种子年龄、分数及数量限制
- SimClusters 启用条件、种子与候选查询
- immersive 召回的正例包含收藏
- 模型设置中的 immersive 正例
- 每个分支使用自己的正负例进行训练
[42] 互相关注的回复预测条件加成。
[43] 个人页点击与关注作者是不同目标。
[44] 作者简介与内容表示。
[45] 负向预测与读者屏蔽静音的硬筛选。
[46] 长度与换行资料的建立及传递。
[47] V8.2 文字截断的局部范围。
[48] 视频目标与十秒资格的不同范围。
[49] 视频超过十秒的实际索引资格与三个 builder。
- 接受的视频类型与 10000 毫秒常数
- hasValidImmersiveVideo 的逐媒体条件
- 1fav_video 调用视频资格函数
- video 与 nsfw_video 调用视频资格函数
- Fav 与 PostCreation 调用视频索引的主流程
- 另一个 isMediaEligible 的十秒与媒体 NSFW 判断
- getTweetypieResponse 使用 hasEligibleMedia 的位置
[50] 视频索引的窗口、Evergreen 命名与不经同一十秒检查的分支。
- 视频 index 的 Main 与 Sid 窗口
- 视频召回数据集实际读取的文件
- evergreen_video 与 evergreen_nsfw_video 的 builder
- Evergreen event 仅调用 hasImmersiveVideo 的分支
- hasImmersiveVideo 与 isImaginePost 的条件
- Imagine 索引不调用 hasValidImmersiveVideo
- 一般 1fav 先建立、视频索引另做判断
- 一般 1fav builder 未加入视频时长条件
[51] 64 个赞的特殊视频资格与后续检查。
- deluxe_fav_count_threshold 的公开默认
- 作者、视频、赞数与 motion_reveal
- 视频取得后仍需通过 technique screen
- 特殊视频分类、交叉验证与写入顺序
- 特殊视频、开头帧、media-injected 的 Kafka 入口
- 相关任务的六十秒去重缓存
[52] 视频对照检查中的 64 与 512 各自代表什么。
- 含引用视频的候选、64 门槛与既有 NSFW 排除
- 512 的具名常数
- 有帧才推理,512 切换 reasoning 并比对参考视频
- 命中转为 SpamManipulatedMedia 分类
- filter、media、检查、sink 的执行依赖
- 已有 NSFW 结果的读取及失败处理
[53] 长视频开头检查与 512 门槛的其他资格。
- 十秒裁切、三十秒视频与 512 常数
- 作者、长视频/broadcast、prior、AdultContent 与 512
- 开头帧任务与交叉验证的依赖
- PTOS 与 safemodel 不一致时的交叉验证
- 交叉判定与 soft 类别的回写
- 最后按分类套用成人内容与垃圾标签
[54] 互动诱导、hashtag 滥用及正常 hashtag 特征。
- 测试账号、PageRank 与灰标的前置处理
- baiting、farming、card manipulation 与其他垃圾分支
- SpamHashTagAbuse 等具名类别
- 安全写入只在 PTOS production 执行
- 非 PTOS production 的停用条件
- 垃圾判断 prompt 未公开
- SimClusters entity extractor 最多取四个 hashtag
- Phoenix 历史资料包含 CLICK_HASHTAG
- CLICK_HASHTAG 所在的特征清单
[55] 阈值 10 的二元目标与标签函数。
[56] 其他停留目标与推理输出。
[57] 冷启动候选筛选及后续选择。
[58] 冷启动数值默认。
[59] 前台观看数的官方定义。
[60] 冷启动目标名次、作者多样性与最后展示。
- 非零分数位置
- 随机范围的上界不包含在内
- 对排名分数重放冷启动决策
- 作者次数按候选分数计算
- 冷启动之后再套作者与 OON 调整
- VM 的作者多样性默认
- Home Mixer 本地计分关闭作者多样性
- 广告与其他模块混排
[61] FairShare 的来源分组、比例分配与模型候选上限。
- 启用条件、预算与比例分配
- Cold 与 ZeroFav 使用独立 served type
- 模型评分前执行 FairShare
- Phoenix request 的候选上限
- 只取前 MAX_CANDIDATES 个建立 request
- 公开初筛预算与启用默认
- 召回数量 200 是另一项参数
- 冷候选数量实际传入召回请求
[62] 新读者条件不能变成新作者养号规则。
[63] 旧原文与新转发候选的年龄及去重。
[64] 编辑版本被取代的判断。
[65] 回复内容的模型评估与公开范围。
[66] 多层自我回复垃圾检查的完整资格。
[67] 回复分类器的保护条件与零分写入范围。
- 必须标记最新回复、只留同作者、排除单笔结果
- 长对话的取样、每贴媒体上限与根帖提示
- 祖先超过十笔时取头尾及输入内容
- 解析结果时排除根帖
- 只对被判垃圾的回复写 ReplyRankingScore 0
- RiskyHighVizReply 打标的额外作者与测试账号条件
- 分数发布至缓存、Kafka 与 Strato
[68] 引用原文与对话祖先的可见性依赖。
[69] 外部网址的公开特征与安全规则。
[70] 跳转链中的低品质网址。
[71] 置顶问题网址与账号标签。
[72] Under the Hood 官方入口与报告读法。
[73] 低品质网址 v1 与 v2 的实际条件。
- v1 的非回复、非转发与被 mention 者未关注作者
- v2 不查 mention,只查跳转链与作者条件
- SPAM_HIGH_RECALL 帖子标签的推荐处置
- 该帖子规则装入 HomeRecommendations
[74] 问题置顶网址的七日账号标签。
[75] 特定账号标签如何影响推荐资格。
- Home 与 HomeRecommendations 的作者规则不同
- NSFW、垃圾、冒充、滥用及其他具名账号规则
- NonAuthors 与 NonFollowers 的精确定义
- 账号标签的官方可见性说明
- 首页筛选区分移除与内容警告
[76] 安全规则的公开范围与 10 月 29 日重构核对。
- 公开默认、实验配置与未公开的 prompts/部分 bot rules
- 原版本 Home 与 HomeRecommendations 规则
- 最新版本相同入口的规则组合
- 最新 ClientSwitch 与原有默认
- 最新 insults 条件改为 ClientHas 的表达方式
[77] 侮辱标签的套用条件、读者范围与入口差异。
- insults、关注者、作者与旧客户端 fallback
- 圈内、圈外及附带内容分别查询可见性
- 相同标签在不同 safety level 的测试案例
- PTOS 的测试账号与作者资格判断
- 英语、具体侮辱分类与作者例外
- 官方报告对 insults 标签的效果说明
[78] LOW_QUALITY/MISINFO 警告、source 与互动政策。
- 适用 Everyone 的 public-interest 标签规则及时间条件
- LOW_QUALITY 与四种 MISINFO 的 source 分流
- 缺少 limit 时仍退回 NonCompliant
- MISINFO source 对应的限制原因
- 警告与最终 limited engagements 的组装
- 互动 action 从 feature-switch policy 解析
- NonCompliant 与 limited_replies 的测试政策
- label source、较早帖子与缺少 source 的测试
[79] 最近五笔中三笔的账号标签聚合默认。
- 三/五、mediaOnly=false、60 日、七日 TTL 与作者排除条件
- 取 window 后按现有帖子标签计数
- 触发事件与用户排除条件的判断
- mediaOnly 是可配置选项及其扫描范围
- 另一条可能 NSFW 默认为十笔中要求十一笔
- 公开 JSON 可由 feature switch 覆盖
[80] 账号聚合的事件、timeline、转发与到期时间。
- Applied 事件与依标签触发规则
- 倒序 userTimeline、转发原帖标签与事件时间
- 按目前时间加 TTL 写入账号标签
- 串流的十分钟 delay 与 maxLag 目标
- 另一路 NSFW 媒体事件
- 另一路以帖子 ID 聚合一天内事件
- 另一路打标或送审的条件及有效期
[81] 重复文字 cluster 到 COPYPASTA_SPAM 的处置。
[82] Under the Hood 的报告资格与资料期间。
[83] V8.2 的长帖文本和 Article 标题分别如何截断。
[84] Home 模型中的互动计数输入与融合函数。
[85] DPP 的内容多样性选择及其后续分数处理。
[86] OON 乘数、作者多样性与乘数应用时机。
[87] Article 与 NoteTweet 身份、正文输入字段及上游映射。
- NoteTweet ID 和 Article ID 分别抽取
- 两类对象的分派条件
- ArticleMetadata 与 Post 的字段
- post_metadata.text 赋给 full_text
- Article 标题和媒体映射
- 外部内容元数据获取入口
[88] V5 与 V8.2 内容和媒体处理差异。
- V5 的 Article 封面、文本和媒体读取顺序
- V5 图片预算和已有图像数据
- V8.2 文本、Article 和媒体组装
- V8.2 普通媒体选取和 Article 标题
- V5 处理结果交给 embedding 服务
- V8.2 计划中的媒体处理与向量生成
[89] Article 媒体获取的上游条件。
[90] 点击、展开、详情停留与 Article 页面标识。
- 点击、展开更多与 Recap dwell 动作编号
- 详情曝光与详情停留编号
- IsShowMoreExpanded 与 IsClicked 分别映射
- 展开更多属于历史互动事件集合
- DWELL_TIME 与 CLICK_DWELL_TIME 分槽
- Article 页面枚举
[91] 阅读标签到训练与服务的已知链路及缺口。
- 训练读取现成动作向量与连续值
- Home Mixer 从外部服务取聚合历史
- 公开仓库不含生产数据源和内部遥测
- CLICK_DWELL_TIME 的二分类阈值 10
- 标签严格大于阈值,输出概率
- 二分类输出不做连续量的反缩放
- 历史停留与点击停留的独立特征处理
[92] Article 发布状态和媒体可见性的规则范围。
- 关联 Article 且不是 Published 的过滤条件
- 规则注册于 TimelineHomeHydration
- 不同生命周期的公开测试样例
- Home Mixer 使用的另外两个安全级别
- Article 正文媒体与封面进入 VF 的媒体判定
- 下一份快照的相同 Article 规则
- 下一份快照的注册范围
[93] 订阅资格和 Article 媒体读取权限。
[94] 候选来源、格式字段与最终预测融合的检查范围。
- 公开 Phoenix 候选来源
- 评分与选择后的处理顺序
- FairShare 按候选来源分组
- 最终价值模型的候选输入字段
- 预测分数没有单列 Article 完读或 Show more 项
- 互动预测融合函数
[95] Longer Post 的回复与引用使用方式。
[96] 2026 年 8 月 Article 浏览量观察样本,非同稿格式实验。
[97] 历史 Article 收益安排与当前奖励计划,不能替代推荐系数。
[98] 停留值的单位证据与点击停留的上游缺口。