影子模式与暗发布。
一次影子运行,量的是一个从不必为自己的错误买单的智能体——它弄坏的东西不会一直坏着,没有用户对它作出反应,而它走的每一步,起点都是一个由在位系统打扫干净的世界。这让结果成了一个上界,而不是一次预测;而且这个差距会随步数增长——偏偏那正是你指望影子模式给你吃定心丸的地方。该跑还是要跑,只是要把它读作一张筛掉灾难的滤网,而不是一份质量预测。
影子模式究竟替你买到了什么。
模式很简单:真实的生产输入送给在位方——一个人、一套规则引擎、一个更老的智能体——同时复制一份送给候选方,候选方的输出被记录下来然后丢弃。你由此拿到候选方在真实输入分布上的行为,而这恰恰是任何评测集都不具备的东西,且爆炸半径为零。
那个分布就是全部价值所在。一套评测套件是用你已知的失败搭起来的,而且会向病态输入漂移;生产流量里则有那段无聊的中间地带、格式错乱的请求、把整条邮件线程粘贴进来的客户,以及没人写过用例的季节性形状。一个在 300 条精选用例上看着没问题、却在 4% 的真实流量上翻车的候选方,是再普通不过的结果,而影子模式是在任何人受影响之前发现它的最便宜办法。
它不是一次带妆彩排。影子运行里缺了三样东西,而这三样都承重:智能体自己的错误从不会进入它未来的输入;从来没有人对它的输出作出反应;它做的任何事都不会改变它下一步要读的那个世界的状态。每一个过于乐观的影子结果,都能追回到这三样里的某一样。
对智能体而言,影子既不免费,也不无副作用。
"影子"这个名声是从分类器那里借来的:在那边,跑第二个模型的代价是一次前向传播,什么也不碰。智能体不是分类器。它会调用工具,而调用一个工具本身就是一种效果——哪怕你把答案扔掉:
- 伪装成读的写。会记录查询的搜索、会盖上"最近查看"的 CRM 查询、会把工单标记为已接触的客服工具、会把检索到的内容写下来的记忆层。这些里的任何一个,都会让影子运行对生产系统可见——而记忆写入最恶劣,因为它污染的是在位方自己未来的上下文。
- 配额与限流。把打向某个第三方 API 的流量翻倍,是让一次影子上线变成一次没人在测的系统里的事故的经典方式。给影子链路配它自己的凭证与自己的限额,这样耗尽额度只会降级这次实验。
- 真金白银。影子按全价付 token,换来的是没人会读的输出;对多步智能体来说,这不是零头。采样,而不是全量镜像;5–10% 的流量通常就能回答问题,而追踪采样与留存是同一套算术在上一层的应用。
- 通知类旁路。会发邮件、会呼叫、会往频道里发帖、会开工单的工具,必须被打桩,而不是被当成无害。正是这一条会催生一封道歉信。
所以,诚实的定义不是"智能体跑起来没有任何效果",而是:这些具体效果被压制、这些被允许,而被允许的那些代价如下。把这份清单写下来——它正是一次影子上线与一次不打招呼的部署之间的区别。幂等、重试与副作用安全讲的是如何把这条线画在工具层内部、而不是画在工具层外面的机制。
这份偏差会复利,并随轨迹长度增长。
下面这一段,正是让影子结果对智能体而言系统性偏乐观、而不只是有噪声的原因。
在单步任务上,影子几乎是诚实的:候选方看到与在位方相同的输入,产出可比的输出。在多步任务上,两者在第一个决策处就分岔——而从那之后,影子智能体跑在一个由在位方一直收拾着的世界里。它读到的是在位方已经改正过的记录。它查询的是在位方已经推进过的状态。它永远不会撞上"自己那第三步本该制造出来的烂摊子",因为那第三步根本没发生。
算术不留情面。若候选方每一步独立地有 97% 的成功率,一个十步任务约有 74% 的成功率——但这要在错误会复利的前提下成立。在影子里它们不复利,因为世界在每一步之下都重置了,于是观测到的逐任务成功率会逼近逐步成功率。你量的是能力,报的却是可靠性。任务时长正是让这条区分保持可见的那个概念。
有两种设计,而它们能主张的东西并不相同:
- 实时并行。候选方在实时状态上与生产并排跑。搭起来最便宜,受污染也最重:上面那一切都以满强度适用。
- 按轨迹回放。候选方跑在一份录制下来的快照上——工具响应被钉死、状态被冻结、输入被回放——于是它自己的动作能够改变它下一步看到的东西。更贵,而且它是唯一一种能对"一整条轨迹"作出主张的版本。夹具从哪来,见智能体的预发环境。
经验法则:用实时并行去比较单个决策,用回放去比较整次运行,而且永远不要拿一次实时并行影子里的逐任务数字去对外报数。
没有真值时怎么打分:只裁定分歧。
影子每条材料产出两个输出,却没有标签。诱惑在于去算与在位方的一致率,然后管它叫准确率。别这么做:一致率量的是与某个本身也时常出错的东西有多像,而且它恰恰在双方都轻易正确的地方最高——那正是你绝大部分的流量。
高效的设计,是只在两者不同的地方打标。一致率告诉你有多少活;而信息只住在分歧集里。对它采样,让人做盲裁——同时看到两个输出、但不知道哪个是哪个——并把结果记成三个桶:候选更好、在位更好、两者都可接受。第三个桶通常比所有人预想的都大,而且是最有用的一项发现,因为它说明两者只是不同,而不是有一方更差。
两点提醒。裁定本身也有其可靠度,如果你的两位评审只在 72% 的材料上意见一致,那么建立在一位评审意见之上的晋级决定就是噪声——这条约束见标注与打标运营。而如果你用模型裁判来放大这件事,记住裁判并没有解决问题,只是把它挪了个地方:在你信任一个被放大的数字之前,先拿人工裁定的那个子集去标定它,见以 LLM 作裁判。
分歧集同时也是你所能拿到的最好的新评测用例来源:真实输入、已被展示出来的行为差异,还附带一个人的判定。有意识地去收割它,而不是任它在仪表盘上过期。
影子模式根本看不见的东西。
有四样东西,按构造就对影子运行不可见;知道是哪四样,能让你不至于把一份干净的结果读过头。
- 人的反应。没人读影子输出,所以你完全学不到人们是否信任它、是否推翻它、是否上报,还是悄悄不再用这个产品了。信任是一项部署属性,不是模型属性。
- 反馈回路。一旦上线,智能体的输出就变成了输入——喂给它自己的记忆、喂给下游系统、喂给那些被它塑造行为的人。影子运行是这套系统一生中唯一那段回路是开着的时期。
- 对手的适应。攻击者是冲着"已部署的东西"来的。影子智能体没有被部署,所以没人在探它,这意味着一份干净的影子注入记录,对生产的第二周什么也说明不了。
- 错的代价。影子会数错误,却称不出它们的分量。一次不可逆的错误,可以压过一千次小的胜利,而只有线上系统才有赌注。错的代价正是这份权重被建起来的地方。
按写好的标准晋级,中间经过一次暗发布。
影子不是上线前的最后一站。真正有用的中间态是暗发布:智能体跑在真实流量上,但它的效果是在最后一米、而不是在工具层被压制的——它把回复写好、把工单草稿建好、把退款准备好——然后由一个人决定发不发。这样你就拿到了影子给不了你的那一样东西:一个人对真实输出作出的反应,而爆炸半径仍然只有一次点击。
在运行开始之前就把晋级标准写下来,否则它们事后就会被拿去与某个已经有人喜欢上的数字讨价还价。一套可用的标准:
promote when, over N days of shadow traffic: disagreement_rate < threshold agreed in advance candidate_worse_share < threshold (of adjudicated disagreements) catastrophic_count == 0 (defined before the run, not after) p95_latency within budget cost_per_completed_task within budget and then, over M days of dark launch: human_send_rate > threshold human_edit_distance trending down
两点运维提示。上线之后把影子继续跑着——一条常驻的、低采样率的下一个候选的影子,是你能拥有的最便宜的回归探测器,而且它与质量回归检测共用同一套管道。另外,提前决定你记录下来的那些影子输出该怎么办:它们含有真实客户数据,由一套没人复核过的系统产出,并且与任何其他追踪一样受同样的留存与脱敏规则约束,见从智能体追踪中脱敏 PII。
下个迭代就做这几件。一:写出那份效果清单——压制的、允许的、已定价的——并且先把通知类工具打桩。二:镜像 5–10% 的流量,不要全量。三:除了分歧什么都不打分,盲裁,分三个桶。四:在你看到任何一个数字之前,先把晋级阈值写下来。如果这一页你只带走一句,就带走这句:一次实时并行的影子运行能告诉你一个候选不合格,却不能告诉你一个候选已经就绪。相关:晋级之后的事见智能体的在线实验,离线闭上反应回路见模拟用户,而当你以为被压制的某个效果其实没被压制时,见修复智能体已经做过的事。