故障关闭(Fail-Closed)
故障关闭指的是:系统在自身出错、被停用或被篡改时,默认拒绝服务而不是默认放行。放到 Agent 场景里,它意味着「权限服务挂了就没有 token」——代价是全集群一起停,收益是失控任务不可能趁故障跑完。与之相对的是绝大多数系统默认的 fail-open。
发布 2026-11-11更新 2026-11-11核实 2026-11-11什么是故障关闭
故障关闭(fail-closed)是一种失效时的默认行为约定:当系统组件出错、被停用、被篡改或无法判断时,它进入「拒绝」状态,而不是「放行」状态。
放到权限系统里,这句话可以写得很具体:没有许可,就没有服务。鉴权服务活着,请求按规则走;鉴权服务死了,所有请求一律拒。
它有一个天然的对立面——fail-open,也就是失效时默认放行。绝大多数互联网系统默认是 fail-open,因为可用性优先:缓存挂了直接回源、鉴权超时就先放过、配置中心不可用就用本地副本。这个取舍在「拒绝的代价远大于放行的风险」时完全合理。
判断该选哪一侧,只需要问一个问题:放行造成的后果可不可逆?
| 场景 | 放行后果 | 合理默认 |
|---|---|---|
| 商品详情页缓存失效 | 回源慢一点 | fail-open |
| 推荐服务的实验配置读取失败 | 用默认推荐位 | fail-open |
| 支付风控服务超时 | 可能放过欺诈交易 | fail-closed |
| Agent 的推理鉴权服务不可用 | 失控任务继续生成 token、继续发外部请求 | fail-closed |
| 数据库行级权限服务抖动 | 可能越权读数据 | fail-closed |
为什么 2026 年这个词突然重要
三年以前,「能不能停下模型」还是一个原则性问题——模型是一次请求一次输出,停掉请求就停了。现在不同了:Agent 会连续运行几小时到几天,中途自己调工具、发网络请求、写文件、花钱。风险面从「一次输出」变成了「一整段自主运行」。
这个变化带来两个直接后果:
第一,「停止」从瞬时动作变成了工程问题。任务可能同时跑在多个引擎、多个模型上,你发出停止指令时,它手上可能还有几百个在途请求。停得多快、停得多干净,需要专门的机制来保证。OpenAI 公布的 Control Room 把这件事量化了:从决策到任务完全拿不到 token,上限 35 秒,而这个延迟来自推理授权前的缓存层。
第二,业务代码不可信。这不是说工程师不老实,而是训练脚本、评估脚本、数据管道由各个团队自己写、变更频繁、散落在几十个仓库里,没法保证每一份都执行「我是否已被停止」的检查。所以强制点必须放在变更少、路径窄的地方。推理层正好符合——只有少数几条代码路径,集中部署,改一次全覆盖。
工作原理
以 Control Room 公开的架构为例,fail-closed 的落地通常包含三层。
1. 任务层:领票进场
每个任务启动时向中央服务申请一个 job_id,并且必须绑定一份已批准的安全案例(一份说明「这件事为什么可以跑」的文档)。
task.start()
→ job_id = control_room.request_job(safety_case="rl-run-20261110-03")
→ 之后每次采样:engine.sample(job_id, prompt)
job_id 是这条链上唯一的身份凭证。没有它,请求不被受理。
2. 推理层:每次请求都要许可
推理引擎在生成任何 token 之前,拿 job_id 去问中央服务:这个任务还能不能跑?
engine.sample(job_id, prompt)
→ control_room.check(job_id)
├─ allowed → 生成 token
└─ stopped → 返回拒绝,不产生任何 token
关键点在于检查发生在服务端,不在任务端。任务进程可以继续跑、继续 make 请求,但拿回来的永远是拒绝。爆炸半径被限制在这一个任务内,其他授权任务照常服务。
3. 决策层:人和监控都能拉闸
停止指令由两类主体发出:人(值班、研究员、安全团队)和监控模型。监控模型不属于「可选项」——它盯着被训练模型在做什么,按风险等级发告警,够严重就直接把 job_id 送进熔断层,跳过人工确认这一步。
4. 服务自身:坏了就全停
这是 fail-closed 的核心。中央服务被配置成:一旦它自己出错、被停用或被篡改,所有推理请求默认被拒绝,直到服务恢复。
if control_room.unavailable():
deny_all() # 不是 allow_all()
这条约定的含义值得重复一遍:敲掉闸门不会让任务获得自由,而是让整个集群一起停。 攻击者想要的是「绕过检查继续跑」,而 fail-closed 让「绕过检查」等于「全部停摆」——这让攻击变得没有收益。
三种主流落地形态
| 形态 | 机制 | 优点 | 代价 |
|---|---|---|---|
| 准入式(Control Room 型) | 每次请求向中央服务换许可,中央服务不可用即全拒 | 粒度细(任务级)、可解释、能审计 | 引入一次网络往返;授权缓存造成延迟(35 秒) |
| 令牌式(短期凭证) | 任务持短期 token,过期必须续签,续签服务挂了自然全拒 | 无需每请求检查,性能好 | 窗口期内仍可运行,停止不是即时 |
| 断路器式(circuit breaker) | 检测到异常行为(如异常外联)时熔断该任务或整个集群 | 反应快、不需要侵入业务代码 | 判定依赖启发式规则,误报会误伤 |
三者不互斥。成熟的做法是叠起来:令牌式做常态、准入式做高危动作、断路器做兜底。
常见的坑
坑一:把 fail-closed 当成全部安全。 35 秒不是安全,是上限。半分钟足够一个 Agent 发出成百上千次外部请求。真正的边界在任务本身能碰到什么——沙箱、网络白名单、文件系统权限,这些比熔断更底层。熔断是最后一道闸,不是第一道。
坑二:在业务代码里做检查。 「我在每个训练脚本开头加一行 if stopped: exit()」看起来省事,实际上不可维护:脚本会新增、会被人复制、会有人注释掉调试。检查必须在收敛的少数路径上做。
坑三:默认值写反了却没人发现。 这类 bug 不会在正常路径暴露,只会在故障时暴露——而那正是最不该出错的时刻。建议在故障演练里专门测一次「把鉴权服务杀掉,系统表现是否符合预期」。
坑四:只考虑技术故障,不考虑人为停用。 「被停用」和「被篡改」必须和「出错」同等对待。运维为了排障临时关掉鉴权服务,是最常见的绕过路径。
坑五:没有区分「拒绝」与「降级」。 拒绝是明确的失败信号,客户端应该重试或报错;降级是返回次优结果。把 fail-closed 实现成「返回空结果」会让上游误以为任务完成,比直接报错更危险。
怎么配:三步落地
第一步,给每个任务一个身份。
# 环境变量注入,任务侧无法伪造
export AGENT_JOB_ID="$(control-room issue --safety-case ./safety.yaml)"
第二步,把鉴权收口到一个中间层。 所有对模型、对外部工具的调用都经过同一处,在这一处检查许可。不要指望每个调用点自己检查。
第三步,把默认值写成拒绝,并演练它。
def authorize(job_id: str) -> bool:
try:
return control_room.check(job_id) == "allowed"
except Exception:
# 宁可全停,不可放行
log.error("control_room unreachable, failing closed")
return False
写完这段代码,做一次演练:手动把 control_room 指向一个不存在的地址,确认所有任务真的停下来,而不是悄悄继续跑。
哪些工具和系统用到了它
- OpenAI Agents API:Agents SDK 0.24 引入的 RunBudget(根请求准入与用量上限)本质上就是准入式控制——预算耗尽即拒绝新请求,而不是事后告警。
- Claude Code:权限与 deny 规则在沙箱层生效,v2.1.321 修复的三处问题(MCP OAuth 重定向泄露凭证、只读 Bash 命令逃出沙箱、deny 规则未覆盖
cp/mv写入目标)都属于「检查没覆盖到实际动作」这一类缺口。 - Codex CLI:Windows 原生沙箱与审批模式,本质是把「允许什么」变成默认拒绝、逐项批准。
- Dify / n8n 这类编排平台:靠节点级权限与人工审核节点实现弱化版的 fail-closed。
与几个近义概念的区别
| 概念 | 关注点 | 与 fail-closed 的关系 |
|---|---|---|
| Agent 沙箱 | 任务能碰到什么(文件、网络、系统调用) | 更底层。沙箱限制爆炸半径,fail-closed 保证检查不被绕过 |
| Agent 结果核验 | 产物对不对 | 事后。fail-closed 是事中,两者互补 |
| Reward Hacking | 模型取巧拿高分 | fail-closed 是防取巧的工程手段之一 |
| 提示词注入 | 输入侧的攻击 | 注入成功后的止损依赖 fail-closed |
| 断路器(circuit breaker) | 故障时切断流量 | fail-closed 的一种实现形态 |
| 熔断(kill switch) | 主动停止 | fail-closed 定义「停不下来时怎么办」 |
一句话记住
fail-open 赌的是「不会出事」,fail-closed 赌的是「出事也停得住」。 当你的系统开始自主行动、开始花钱、开始改别人的数据,第二个赌注更划算。
延伸阅读
- 案例:OpenAI 给自家研究集群装了总闸:Control Room
- 概念:Agent 沙箱 · Agent 结果核验 · Agent Harness · Reward Hacking · 提示词注入 · 每任务成本 · Agent 编排 · 上下文压缩 · MCP · 函数调用 · Agent Hooks
- 工具:OpenAI Agents API · Claude Code · Codex CLI · Dify · n8n
- 模型:GPT-6 Astra · Claude Opus 5.5
来源
- ⭐ Control Room: A central system to track and stop model workloads across our research infrastructure(OpenAI 官方工程博客,一手)
- OpenAI's Control Room Halts Model Jobs in 35 Seconds(含 job_id 流程与 9 月 DNS 事故复盘)
- OpenAI 部署 AI「控制室」:最长 35 秒阻断模型输出(凤凰网科技,2026-11-10)
- Claude Code v2.1.321 Release Notes(沙箱逃逸与 deny 规则缺口修复,一手)
常见问题
fail-closed 和 fail-safe 是一回事吗?
常被混用,但严格说不是。fail-safe 指故障时进入「安全状态」,这个安全状态可能是关闭也可能是保持运行(如飞机起落架故障时放下轮子仍然安全);fail-closed 是 fail-safe 的一种具体实现——安全状态就是拒绝。在权限与鉴权语境下,两者通常同义。
为什么大多数系统默认是 fail-open?
因为可用性优先。鉴权服务、缓存、配置中心挂掉时,先放行能让业务继续跑,用户无感;拒绝会让整个系统停摆。这个取舍在「拒绝的代价 > 放行的风险」时成立,在「放行可能导致不可逆后果」时不成立。
Agent 系统为什么更适合 fail-closed?
因为 Agent 的越界行为常常不可逆:对外发请求、改生产数据、写文件、产生费用。这些动作一旦发生无法回滚,而「暂停几分钟」通常只是延迟。代价不对称时,默认拒绝是对的。
fail-closed 会不会导致误伤?
会。鉴权服务抖动一次,可能让整个集群的合法任务一起失败。缓解手段是让拒绝逻辑足够简单可靠(少依赖、无状态、独立部署)、缩短故障窗口、并给出明确的重试语义,而不是把默认值改回放行。
有真实的生产案例吗?
OpenAI 2026-11 公布的 Control Room 是目前公开细节最完整的案例:任务领 job_id、推理引擎向中央服务请求许可、服务不可用时一律拒绝。详见本站资讯《OpenAI 给自家研究集群装了总闸》。
相关工具
Aider vs Claude Code:终端 AI 编程双雄怎么选
Aider vs Claude Code 2026 选型对比:开源 BYOK 多模型 vs Anthropic 订阅长任务 Agent,从编程能力、多模型支持、价格、Git 集成、国内可用性和适合人群判断,帮你选对终端 AI 编程工具。
Claude Code vs Cline:CLI AI Agent 怎么选?2026 对比
Claude Code vs Cline 2026 选型对比:Anthropic 官方闭源 CLI Agent vs Apache-2.0 开源 VS Code 插件。从模型绑定、工作流、MCP 支持、价格、隐私和适合人群 6 个维度帮你选对 CLI AI 编程工具。
Claude Code vs Codex CLI:终端 AI Agent 双雄对比
Claude Code vs Codex CLI 2026 选型对比:Anthropic 与 OpenAI 两大官方终端 Agent 的模型、长任务、MCP 生态、Windows 支持、订阅打包价格和国内可用性全方位对比,帮你判断该用哪个终端 AI Agent,以及能不能两个一起用。
Claude Code vs Crush:Anthropic 官方 vs 多模型 TUI(2026 实测选型)
Claude Code vs Crush 怎么选:Anthropic 官方 CLI(长任务最稳),对上 Charmbracelet 开源 TUI(多模型切换 + LSP)。按模型、长任务、价格对比。
Cursor vs Claude Code:什么时候用哪个?(2026 实测选型)
Cursor 和 Claude Code 到底怎么选?一句话结论 + 决策树 + 价格实测 + 国内可用性对比。GUI 派选 Cursor,终端长任务派选 Claude Code,最优解其实是共存。
Devin vs Claude Code:AI 编程 Agent 怎么选?异步自主 vs 终端同步对比
Devin vs Claude Code 2026 选型对比:Cognition 异步自主 Cloud Agent vs Anthropic 终端同步 CLI Agent,从形态、工作模式、长任务能力、并发、价格、中文支持和适合人群 8 个维度判断,帮你选对 AI 编程 Agent。