跳到主要内容

你的审核队列是自主权承诺消亡之地

· 阅读需 10 分钟
Tian Pan
Software Engineer

发布的 AI 功能带有一个完美的“安全方案”。任何置信度高于阈值的请求都会自动执行。任何低于阈值的请求都会进入人工审核队列。刚发布时,每天下午 5 点队列就会被清空。市场部门在幻灯片上写下“人工参与(human-in-the-loop)”。合规部门签字批准。大家打道回府。

六个月后,该功能的使用量增长了 10 倍,但审核团队并没有。队列里堆积了 72 小时的待办任务。一个需要“人工审核”的项目在未读状态下躺了三天,然后被一名疲惫的审核员批准——他平均处理一个决策只需 11 秒,因为只有这样才能保证队列不会在夜里翻倍。产品依然宣称“每项操作都经过审核”。现实情况是,“人工参与”已经退化成了“人工最终会在队列里看到”——这在功能上其实就是带有文书延迟的自主运行。

安全方案并不是因为 Bug 而失效,而是因为一个没人负责的人力资源计划而崩溃。

队列是运行时依赖,而非安全垫

错误在于将人工审核视为功能的一种属性(“我们有人工审核”),而不是该功能所依赖的一项服务。服务有容量。服务有延迟预算。当服务进度落后时,会自动呼叫相关负责人。

在大多数发布中,审核队列完全没有这些特性。它们只有一份写着“团队将审核被标记的操作”的 Notion 文档。那份文档里没有 SLO、没有增长模型、没有自动扩缩容,也没有降级行为。它只是一种“感觉”。

利特尔法则(Little's Law)在这里毫不留情。任何队列的平均长度等于到达率乘以平均等待时间。如果每天有 200 个项目进入,而一名审核员每天能处理 50 个,那么你至少需要四名审核员才能收支平衡——前提是审核员从不度假、从不休假、也不需要接受新政策培训。当到达率第一次翻倍(发布会、市场推广或病毒式传播)时,等待时间会呈非线性爆炸式增长。一个超出容量 10% 的队列并不是“有点慢”——而是一个预期等待时间无限长的队列,唯一能维持平均值为有限数的因素,就是客户最终选择离开或项目最终过期。

大多数发布带有“人工参与”AI 功能的产品团队,从未写下他们的 λ、μ 或目标 W。他们只写下了“我们会审核”。这不是容量计划。这只是一个关联了 Slack 频道的愿景。

正确的指标是延迟,而非存在

当审核出现问题时,人的本能反应是计数:我们审核了多少个项目?那个数字通常看起来不错,因为团队已经尽力审核了所有能审核的东西。失败模式并不是项目未被审核,而是审核得太晚,以至于失去了意义。

SLO 必须以延迟为单位,而不是以“是否存在”为单位。“P95 审核到执行时间低于 N 小时”是一个真正的承诺。而“每一项操作都经过审核”只是一个营销口号,在宇宙热寂时它在技术上或许是成立的。

根据操作的可逆性来选择 N。决定内容发布的内容审核可以容忍数小时;冻结客户账户的欺诈拦截确认不能容忍超过几分钟;客户正盯着加载动画看的退款审批则不能超过几秒钟。不同类别的操作分配不同的 N。它们共用同一个仪表盘,向同一组值班人员(on-call)发出告警,并在违规时触发相同的事故处理流程。

仪表盘规则很简单:如果你无法用一个数字告诉陌生人,队列中最慢的 5% 的项目等待了多久,那么你根本没有 SLO。你只有一个愿景。

容量触发器必须在方案崩溃前生效

有趣的问题不是“当‘审核到执行时间’超标时我们该怎么办?”那时已经太晚了——对于处于超标窗口期的所有人来说,安全方案已经失效。有趣的问题是“什么早期信号可以预测到这种超标,它又会自动触发什么动作?”

队列增长率就是那个信号。每天计算过去 N 天内到达量与完成量的比例。只要它低于 1.0,队列就在缩减。一旦它持续超过 1.0,你就陷入了不断累积的亏空,而你的等待时间数据(具有滞后性)在发生灾难性恶化之前看起来都会很正常。

当比例超标时,只有两种有效动作:要么扩充人力(增加审核员、延长工作时间、引入外包商),要么降低自动化程度(提高置信度阈值以减少进入队列的项目,或者收窄操作范围以减少符合条件的项目类型)。这两种方式都很痛苦,都需要成本或牺牲功能。错误的做法是等待——赌下周的任务量会回到上个月的平均水平。通常情况下它不会,而等到你确定这一点时,崩溃已经发生了。

这就是为什么触发器必须是一种策略,而不是一场会议。要么队列增长告警自动触发人力决策,要么自动收紧置信度阈值。如果一个团队每次在队列增长时都要开会讨论,他们会发现开会的速度永远赶不上队列增长的速度。

分层审核优于统一审核

另一种失败模式更为微妙:队列是一个扁平列表,每一项都受到相同的对待,而高风险项则被埋在大量日常事务中。一名每天处理 200 个项目的审核员,无法给一个涉及 2 万美元影响的欺诈标记比一个只需 10 秒就能解决的常规标签争议更多的关注。队列策略没有给他们提供这两个项目有所不同的信号。

分层策略通过在队列本身编码风险来解决这个问题。最简单的版本是三条路径:

  • 高风险路径:具有严格的延迟 SLO,并保证该路径中的项目不会与大宗工作交织。由于队列的设计如此,这些项目会得到审核员的全力关注。
  • 标准路径:承载大部分项目,具有较长但强制执行的 SLO。
  • 抽样路径:用于高置信度下自动处理的项目——这些项目从不阻塞,但会抽取一定比例进入审核流水线,以便在真实客户察觉之前检测到校准偏移。

抽样路径是大多数团队会跳过的,而它正是捕获缓慢失效的关键。如果模型的校准发生偏移,且某类决策在置信度阈值之上开始出错,你无法从排队等待审核的项目中了解到这一点(因为那些项目并未超过阈值)。你只能通过抽查自动处理的项目来发现。

当承诺破灭时,告知客户

大多数团队针对队列违约的事故预案都是对内的:呼叫团队、请求志愿者清理积压工作、写一份团队之外没人阅读的复盘报告。面向客户的沟通则是沉默。

沉默是一种赌博,赌客户不会注意到“你的行为已通过审核”与“你的行为在队列中躺了三天,然后因为审核员不堪重负而自动清理”之间的区别。这种赌博正变得越来越糟糕。客户确实会注意到——通过支持渠道、通过审计人员、通过在下次询问中提问“对于这 N 个客户行为,实际的审核延迟是多少?”的监管机构。

成熟的模式是将队列违约视为任何其他 SLO 违约:在状态页记录、通知受影响的账户,并在审计日志中明确区分“已审核”和“因容量原因自动清理”。如果自动清理行为是不可接受的,设计需要回退到“排队并阻塞”而不是“排队并默许通过”。这在违约发生的瞬间对客户来说更加痛苦,但它诚实地反映了安全叙事,而不是默默地违反它。

审计承诺,而非过程

最后一项纪律是大多数团队永远没时间做的:季度审计,只做一件事情,即对比营销文案的承诺与队列实际的表现。不是“我们是否审核了项目”,而是“对于面向公众承诺会由人工决策的项目,决策的中位时间是多少?P95 是多少?自动清理的比例是多少?由花费超过 30 秒的人员审核的比例又是多少?”

最后一个数字是捕获审核疲劳的关键。一名平均每项花费 11 秒的审核员并没有在进行人工决策;他们是在对 AI 的建议进行模式匹配。在那一点上,队列正在表演安全演戏——组织架构图上是“人在回路”,实际工作流中则是“橡皮图章”。解决方法不是责备审核员(他们正在做队列设计迫使他们做的事),而是承认队列已超负荷,要么增加人员,要么降低自动化程度,这还是之前提到的那两个杠杆。

季度审计不是过程审计,而是承诺审计。它问的是:我们在书面形式上做出的安全声明在运作中是否仍然真实?当答案偏向“否”时,正确的反应是在团队之外的人发现之前,更新其中之一。

架构转型

人工审核是当前 AI 部署中被过度使用的原语。它被作为“我们搞定了安全逻辑”的占位符丢进发布方案中,最终在没有任何工程严谨性的情况下,承担了真正的安全工程投入的工作。

必须发生的转变是将审核队列视为一项服务:它有接口(入队内容及元数据)、延迟 SLO(项目移动速度)、容量模型(利特尔法则加冗余空间)、自动扩缩容策略(当增长率超过 1.0 时增加人员或收紧阈值)、降级行为(故障关闭或故障开启,并伴随客户沟通)以及审计仪式(运营现实是否匹配公众承诺)。

做到这些的团队是将“人在回路”构建成了工程。一项都没做的团队是将“人在回路”构建成了营销。前者在下次流量激增时能挺得住。后者则距离发现其安全叙事只是一个没有 SLO 的队列仅剩一次发布的距离,而且在仪表盘显示绿色的同时,该队列已经默默地违反承诺数月之久。

自主权承诺不会在一次戏剧性的事故中消亡。它在没人关注的队列中,一个接一个项目地消亡,积压工作的增长速度慢到让任何独立的一天看起来都不像是出大事的那一天。

References:Let's stay in touch and Follow me for more thoughts and updates