急停开关

O8
运维 · 智能体运维:部署与运营

急停开关:能让一整支正在跑的智能体队伍停下来的那个按钮。

每个把智能体推到生产的团队,迟早都会想要一个能停下整支队伍的按钮。难点不在按钮本身——难在它真正得拦下的东西(飞行中调用、排队任务、计划重试、扇出出来的子代理),难在这个停止信号要比工作的扇入扩散得更快,还难在那场季度演练,让你在真正要用它的那一天之前就证明它有效。

STEP 1

"停下"到底要拦下什么。

按下急停开关听起来是一个动作;对智能体队伍其实是四个,任何一个漏掉都会让这个按钮变成摆设。一个真正的急停开关,最少要覆盖以下面:

  • 飞行中的 LLM 与工具调用——取消它们,不要等它们返回。开关按下后还要跑 60 秒的工具调用,就是 60 秒你亲手签字的流血。
  • 排队中的任务——"排空还是丢弃"这件事要事前定。排空意味着队列仍跑到完;丢弃意味着你接受半截任务的代价,换一次真正的停止。多数由安全驱动的事故倾向于丢弃,并依赖日志足以恢复。
  • 计划重试与定时器——切换前所有 at(future_time) 必须被取消,而非"晚点过期不会出事"。idempotency-and-retries 里的重试链,正是你以为已经停了之后十分钟最容易触发的部分。
  • 已派发的 webhook 与副作用——对智能体已经派给下游系统的动作,急停开关召不回它们;它能做的是精确记录什么已经触发(让一次补偿动作扫尾成为可能)并阻止派出任何新的。

底线:开关按下后,没有任何新的副作用从系统里出去。durable-state-and-resumability 里的日志告诉你,已经出去的是哪些。

STEP 2

四个范围,四个按钮。

一个全局总开关日常用太钝、真出事时又太慢够不着。这套分级阶梯与 incident-response-for-agents 里那条配对——每一级都需要它自己的按钮,并在循环内、每个副作用之前求值:

  • 能力——冻结单个工具(比如那个危险的写工具),同时读仍然流动;诊断继续,损害停下。
  • 运行——让单个 run_id 在下一拍循环上停机;最便宜的外科手术式停止。
  • 租户或特性——停下某个租户或某个特性开关下的所有运行;当某一群体异常而其他健康时正合适。
  • 全局——停下整个世界。你几乎永远不想用上的按钮,而它必须在你真用上的那一次有效。

每一级都是它自己的按钮,是因为值班在凌晨三点的活儿是挑最小够用的锤子,而不是辩论该升级到哪一级。给这些范围供电的标志本身就是 feature-flags-for-agents 的一个用例:按请求求值、fail-closed、可观测的切换日志。

STEP 3

扩散:停止必须跑赢扇入。

一支分布式智能体队伍的 worker 跨进程、跨机器、跨地区,全部从某处读取急停状态。隐患在于:停止信号到达一个 worker 时,另一个已经开始了下一次工具调用;扩散尾巴越长,你吃下的"切换后效应"就越多。让扩散诚实的两个性质:

  • 在循环内、每个副作用之前求值这个标志——不是运行开始时,也不是进程启动时。一个把急停状态在进程启动时就缓存住的 worker,就是一个会忽略你刚按下的开关的 worker。
  • 对标志存储 fail closed——当标志服务不可达时,worker 把开关当作开来对待,而非关。否则你会得到一个:恰好在你想伸手按它的那种故障里反而失效的急停开关。

对一个持久智能体而言,"重新部署一下"或"杀掉 Pod"不是急停——一个可恢复的运行会在下一个 worker 上回来,并精确地继续那个有害循环。停止必须是一次感知状态、恢复路径也会遵守的停机,否则你造的是一个能熬过自己被杀的失控。

STEP 4

桌面演练:未经测试的急停开关等于不存在。

你需要这个开关的那一天,不是发现以下事实的合适日子:标志存储已经一个月不可达;上个季度部署的 worker 池在读另一个配置命名空间;停止时丢弃这条路径在副作用账本里留下了孤儿行。把演练放在日历上,而不是事故里:

  • 每季度,在 staging 用接近生产形态的流量,在四个范围分别按一次拉杆。
  • 测量:每个 worker 的"停下时间"、切换后仍发出的副作用计数、T+0 与 T+60 秒时的队列状态、恢复后日志的一致性。
  • 把这次演练沉淀为一个永久回归测试——同样场景、可回放、纳入 CI——这样一次破坏扩散的重构会在它上线之前先卡在闸门上。
STEP 5

开关按下之后:系统处在什么状态,又怎么恢复。

急停开关是一次停机,不是一次拆机。恢复是这套纪律的下半场——而当你在按按钮之前就把"之后"的样子定好,恢复会容易得多:

  • 日志完整——每个落地的副作用都连同它的幂等键被记录;每个没落地的,都可从运行计划里恢复。一次干净的停止,给出"应做"与"已做"之间一份干净的 diff。
  • 补偿动作是显式的,不是凭直觉的——退款、撤回、客户通知,是从一张清单上下来的,不是从值班的直觉里下来的。副作用账本就是那张清单。
  • 恢复要求一个绿色的发布——若起因是一个坏的 rollout-and-versioning 三元组,先把它回滚再解除停机。在同一个破契约上恢复,等于按提示词把事故再走一遍。
  • 一个理由就够了——一次护栏指标回归或一次写速率异常,就是一次切换,不是一次辩论。先回到安全状态再去调查。

你在需要它之前就建好、按日历演练、把恢复路径写下来的那个急停开关,给你换来的是一次复盘而不是一份新闻稿。在你不可能再去建它的那一天之前,就把它建好。