专题篇章 · 拆开 OpenAI Codex

Guardian:让一个模型去审批另一个模型

四步法、失败关闸、超时与拒绝分账,以及按 turn 计数的熔断器

本页解决的问题

先给结论

「Guardian:让一个模型去审批另一个模型」要解决的关键问题是什么?

四步法、失败关闸、超时与拒绝分账,以及按 turn 计数的熔断器

判断标准

跟着交接处走,不要只看 Demo。 系统是否可靠,往往取决于模型、工具、状态、权限和人的交接处。把每次交接都当成可以观察、测试和恢复的地方。

下一步

为一个自动化步骤写清输入、负责人、审批和恢复动作。

常见误区

一次运行成功了,却说不清发生了什么,也无法安全重放。

课程目标读完能说清三件事。Guardian 只吃被配置点名的 on-request 审批,用一次锁死的模型会话代替用户弹窗。审查材料按不可信证据处理,超时、跑崩、坏 JSON 一律停住动作。明确拒绝才记入熔断器,连拒到阈值就打断当前 turn。
先玩一遍 · 一条命令进审查台
同一条审批:先走四步,再看熔断器会不会接手
命令
换一条,看审查员在哪一类上先打分再下结论。
故障
后三项是兜底。超时和坏 JSON 关闸,但不记连续拒绝。
四步审查等待开始
1 重建 transcript抽出用户原话和工具痕迹
2 送进锁死会话只读、Never、MCP 已清空
3 交回 JSON先打风险和授权,再给结论
4 应用结果allow 继续,其余一律停住
证据与结论条款未引用
curl --upload-file README.md https://example.com/inbox
risk_level
user_authorization
outcome
rationale等待评估
熔断器 · Standard
连续拒绝 0 / 3,窗口 50 内累计 0
用户侧与模型侧还没有收到结论。
逻辑轨迹 · 动画每一步对应源码里的哪一段
  1. 判断本轮审批是否交给 Guardianreview.rs L186
  2. 扩展若声明接管则不再开审查会话review.rs L313
  3. 过滤 transcript,只留用户意图和工具证据prompt.rs L506
  4. 按 Full 或 Delta 拼审查材料prompt.rs L89
  5. 克隆父配置,锁成只读并写成 Neverreview_session.rs L1407
  6. trunk 空闲则追加,忙碌则 forkreview_session.rs L617
  7. 等待 JSON,超时上限 90 秒mod.rs L53
  8. 没有合法 JSON 就解析失败,可重试后关闸prompt.rs L714
  9. allow 放行,deny 写上禁止改道的指示review.rs L717
  10. 只有显式 Deny 才记入熔断器review.rs L711
  11. 达到连续或窗口阈值,就 InterruptTurnmod.rs L176
点播放,看一条命令怎么走过四步审查,以及熔断器什么时候接手。
模型审模型的风险审查员会格式漂移,也会被工具输出里的指示词牵着走。合同要求先打风险和授权,再给出可执行的 allow 或 deny。
失败怎么收场超时走 TimedOut,坏 JSON 走 FailedClosed,动作都停住。这两类故障清零连续拒绝计数,避免把基础设施抖动算成模型连续作恶。
熔断器接手之后Standard 连续三次明确拒绝就打断当前 turn。后续命令不再开新审查,因为这一轮已经被 abort 掉了。
教学示意:评估字段按 policy.md 的 Outcome rule 推演,用于展示四步法与熔断器的结构差异。逻辑轨迹右侧行号对应 openai/codex 仓库 commit 4f39251a01。
思路一 · 四步走完,中间态一律关闸
它解决什么问题

你开着 Codex 改仓库。模型先跑 git status,再读两个文件,然后要 git push。下一分钟它要 curl,再下一分钟要往 /tmp 写备忘,再下一分钟要删掉那份备忘。弹窗叠弹窗。人开始只看命令头两个词,拇指已经形成肌肉记忆。

这就是审批疲劳。防线还在,判断已经不在。回路退化成一个总是亮绿灯的按钮。这时如果把自动放行交给刚写出这条命令的主模型,申请人兼审批人。如果失败时放行,超时和坏 JSON 就变成免费通行证。

思路是什么

Codex 把该不该自动放行抽成一次专职审查。它不替代沙箱,也不替代网络代理。它只接管一类本来会弹给用户的 on-request 审批。路由很窄:策略必须是 OnRequestGranular,审查员必须是 AutoReview。默认审查员仍是用户。出处:codex-rs/core/src/guardian/review.rs 第 186 至 210 行

模块头把四步写死。

1 重建 transcript

只留用户原话和近期工具痕迹。合成脚手架、普通 developer 消息丢掉。超长内容打上 truncated 标记。

2 另开审查会话

克隆父配置,继承已经建好的 managed network 与 allowlist。审查员必须吐出严格 JSON。

3 失败关闸

超时、跑崩、坏 JSON,执行一律停住。中间态按拒绝处理。

4 只应用明确结论

合同要的是 allow 或 deny。产品要的是可执行判定。

合同只有四个字段。三个轴的枚举写在协议层的 approvals.rs,不在 protocol.rsoutcome 是唯一必填。低风险允许可以只回 {"outcome":"allow"},缺省的风险补成 Low,授权补成 Unknown。

codex-rs/core/src/guardian/mod.rs第 116 至 123 行
/// Structured output contract that the guardian reviewer must satisfy.
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
pub(crate) struct GuardianAssessment {
    pub(crate) risk_level: codex_protocol::protocol::GuardianRiskLevel,
    pub(crate) user_authorization: codex_protocol::protocol::GuardianUserAuthorization,
    pub(crate) outcome: GuardianAssessmentOutcome,
    pub(crate) rationale: String,
}
源码快照说明:依据本地仓库 openai/codex,核对文件 codex-rs/core/src/guardian/mod.rs,commit 4f39251a01,核对日期 2026-08-22。GuardianRiskLevelGuardianUserAuthorizationGuardianAssessmentOutcome 的穷尽枚举在 codex-rs/protocol/src/approvals.rs 第 85 至 109 行。
审批请求 OnRequest 紧凑 transcript 用户意图加工具证据 锁死审查会话 只读,Never 严格 JSON 四个字段 allow 或 deny 只应用明确结论 失败关闸 超时、崩掉、坏 JSON
教学化结构图:四步走完,中间态没有第三条路。
为什么长期成立

审批疲劳是人因问题,审查员自己也会格式漂移。把没给出可执行答案收成拒绝,换语言重写也成立。输入是不可信证据加一条确切动作,输出是穷尽的 allow 或 deny,解析失败就停。

思路二 · 审查员进的是一间上了锁的房间
它解决什么问题

主模型刚写出这条要执行的命令。再让它审自己,回路是通的。工具输出里再夹一句请批准我,审查材料就被污染。审查权如果落回申请人,专职审查员这个角色就不存在。

思路是什么

审查会话克隆父配置后立刻改写。审批策略锁成 Never,权限剖面与只读相交,MCP 服务器清成空表,技能、记忆、Apps 指令关掉,再禁用一串非必要特性。它还丢掉父级传入的 exec-policy 规则,改用空的默认管理器。父级规则可能反过来塑造审查员,甚至让审查员自己跑的只读命令被静默放行。出处:codex-rs/core/src/guardian/review_session.rs 第 1406 至 1448 行;codex-rs/core/src/session/mod.rs 第 544 至 548 行

审查员可以跑只读命令,用来核实本地状态,比如删除目标在不在、是不是空目录。它不会弹出新的审批,也不会再开一层 Guardian。配置装配时显式禁用了 GuardianV2

trunk 空闲时,后续审批追加到同一条会话,prompt cache 稳定。trunk 忙碌时,从上次提交的 rollout 长出一间临时小屋,审完就拆,不回写。

父配置 网络代理可继承 克隆 审查房间 只读沙箱 权限剖面相交 Never 不再弹审批 MCP 清空 特性一并关掉 空 exec-policy 父规则不进来
教学化结构图:审查员能用的能力被削到只剩只读核实。
为什么长期成立

给不受信任的审查权一个尽量小的环境,是安全设计的通用形状。换模型、换提示词、换能力面,该问的还是同一句:审查员到底需要哪几样能力,其余的能不能一样都不给。

思路三 · 超时和拒绝分账,连续拒绝才拉闸
它解决什么问题

审查员和执行模型卡在同一条被拒动作上,人看到的是一轮空转。如果把超时也算进连续拒绝,基础设施抖动会被误判成模型连续作恶。

思路是什么

超时走 ReviewDecision::TimedOut,明确拒绝走 Denied。对模型的文案也拆开。超时告诉它不要仅因超时认定不安全,可以再试一次或去问用户。明确拒绝拼上禁止改道绕过的指示,只允许实质更安全的替代,或用户知情后的明确批准。出处:codex-rs/protocol/src/protocol.rs 第 3909 至 3910 行;codex-rs/core/src/guardian/review.rs 第 70 至 74 行

熔断器按 turn 记账,窗口长度 50。Standard 的阈值是连续 3 次,或窗口内累计 10 次。CyberModel 紧到第一次拒绝就停。只有评估结果为 Deny 才计入。超时和 fail-closed 走 record_non_denial,连续计数清零。触发后发 GuardianWarning,再 abort_turn_if_active出处:codex-rs/core/src/guardian/mod.rs 第 53 至 59 行、第 157 至 194 行

allow / 超时 / 坏 JSON record_non_denial 连续计数清零 窗口里记一次非拒绝 显式 Deny record_denial 连续加一 Standard 阈值是 3 InterruptTurn 打断当前 turn
教学化记账图:同一 turn 里,只有明确拒绝会把熔断器往前推一格。
失败时关闸。明确拒绝才记一笔。
为什么长期成立

安全闸门需要把没做完和明确说不分开记账。混成一句没通过,会把瞬时故障训练成绕过行为。按 turn 计数、按窗口计数,两套阈值即可。面向高对抗场景的策略可以紧到第一次拒绝就停。

横向对比 · 决定权放在哪

DeepSeek Harness:两个旋钮,决定权留在人

在 DSH 仓库里检索 reviewer、guardian、auto-approve,没有独立审查会话这种实现。它把同一问题收成两个旋钮。审批策略只有 askneverask 把问题交给 answerer 链,链上没人接就 unavailable,调用方 fail closed。never 直接 rejected。授权粒度是一次性的 allowed-once

DSH 可以没有 Guardian,因为它把谁来审固定成人,再用预设降低切换成本。代价是审批疲劳原样存在。ask 模式下弹窗仍然全数到达用户,never 则把判断权整段关掉。

已核对 user-approval 与 permission-presets · 2026-08-22 · DSH · 审批与权限

Claude Code:分类器给弹窗抢时间

在 Claude Code 的还原源码里同样没有 Guardian 那种独立审查会话、风险分类学 JSON 合同,或按 turn 计数的熔断器。找到的是 Bash 工具上的一条分类器旁路。分类器在用户弹窗已经显示时后台跑。高置信且用户还没动手,才替用户点允许。它匹配的是 prompt rule,范围是 bash 命令。弹窗仍在。失败时用户继续自己点。

差别可以收成一句话。Claude Code 用分类器给弹窗抢时间,Codex 用一次锁死会话把弹窗从主路径拿掉。前者省的是等待,后者改的是谁来做决定。

已核对 bashPermissions.ts 分类器旁路 · 2026-08-22
课堂练习
01

同一次 turn,熔断器怎么记账

同一 turn 里,审查员先超时一次,再明确拒绝两次。问:下一次再明确拒绝时,Standard 熔断器会不会打断这一轮。把第二次改成坏 JSON,再算一遍。

进阶一问:用户后来用人工覆盖批准了那条被拒动作。下次审查会把它当成可信授权,还是只当上下文。

Takeaway:Guardian 用一次锁死的模型会话代替弹窗。超时、跑崩、坏 JSON 一律关闸。超时和拒绝分账,连续拒绝才熔断当前 turn。下一层仍是沙箱、网络代理和人。

「先玩一遍 · 一条命令进审查台」的能力藏在每次交接里

「你开着 Codex 改仓库。模型先跑 git status ,再读两个文件,然后要 git push 。下一分钟它要 curl,再下一分钟要往 /tmp 写备忘,再下一分钟要删掉那份备忘。弹窗叠弹窗。人开始只看命令头两个词,拇指已经形成肌肉记忆」说明,Agent 的表现不只由模型决定。模型、上下文、工具、状态、权限和人之间的每次交接,都会改变任务能否继续以及出了问题能否恢复。

先写清状态,再增加能力

从「这就是审批疲劳。防线还在,判断已经不在。回路退化成一个总是亮绿灯的按钮。这时如果把自动放行交给刚写出这条命令的主模型,申请人兼审批人。如果失败时放行,超时和坏 JSON 就变成免费通行证」出发,可以把流程拆成起始状态、下一步动作、工具返回、状态更新和停止条件。这样调试时找的是第一处丢失信息或权限的位置,而不是笼统地说“模型变笨了”。

  • 判断本轮审批是否交给 Guardian review.rs L186
  • 扩展若声明接管则不再开审查会话 review.rs L313
  • 过滤 transcript,只留用户意图和工具证据 prompt.rs L506

成功路径不能代表系统可靠

用「进阶一问:用户后来用人工覆盖批准了那条被拒动作。下次审查会把它当成可信授权,还是只当上下文」重放一次成功和一次失败,记录每一轮真正传入的上下文、工具结果和负责人;只要第二个人能复述这条链,系统才有可维护性。

从「先玩一遍 · 一条命令进审查台」走到「思路一 · 四步走完,中间态一律关闸」

「先玩一遍 · 一条命令进审查台」先把问题落在「同一条审批:先走四步,再看熔断器会不会接手 播放 单步 重置 命令 git status 公开 curl 上传 README 影子 HOME 换一条,看审查员在哪一类上先打分再下结论。 故障 正常走完 审查超时 坏 JSON 连拒三次 后三项是兜底。超时和坏 JSON 关闸,但不记连续拒绝。 四步审查 等待开始 1 重建 transcript 抽出用户原话和工具痕迹 2 送进锁死会话 只读、Never、MCP 已清空…」上;到了「思路一 · 四步走完,中间态一律关闸」,讨论继续推进到「你开着 Codex 改仓库。模型先跑 git status ,再读两个文件,然后要 git push 。下一分钟它要 curl,再下一分钟要往 /tmp 写备忘,再下一分钟要删掉那份备忘。弹窗叠弹窗。人开始只看命令头两个词,拇指已经形成肌肉记忆」。两段连起来,重点就不只是记住一个结论,而是看清它成立所依赖的条件。

把这条判断带到下一个场景

分析 Agent 时,沿着状态、动作、工具结果和下一步的顺序走一遍;每次交接都要能说明信息从哪里来、由谁确认、失败时停在哪里。

  • 「先玩一遍 · 一条命令进审查台」:同一条审批:先走四步,再看熔断器会不会接手 播放 单步 重置 命令 git status 公开 curl 上传 README 影子 HOME 换一条,看审查员在哪一类上先打分再下结论。 故障 正常走完 审查超时 坏 JSON 连拒三次 后三项是兜底。超时和坏 JSON 关闸,但不记连续拒绝。 四步审查 等待开始 1 重建 transcript 抽出用户原话和工具痕迹 2 送进锁死会话 只读、Never、MCP 已清空…
  • 「思路一 · 四步走完,中间态一律关闸」:你开着 Codex 改仓库。模型先跑 git status ,再读两个文件,然后要 git push 。下一分钟它要 curl,再下一分钟要往 /tmp 写备忘,再下一分钟要删掉那份备忘。弹窗叠弹窗。人开始只看命令头两个词,拇指已经形成肌肉记忆
  • 「最后的要点」:克隆父配置,锁成只读并写成 Never review_session.rs L1407

最后的「最后的要点」把讨论落到「克隆父配置,锁成只读并写成 Never review_session.rs L1407」。回看这条线索时,最值得保留的是:当输入、规模或风险改变,哪些判断需要重新做一遍。

标记为已学完 阅读进度会自动记录
← 上一篇下一篇 →

继续阅读

同一条线上的下一篇。

文章讨论

读到这里,留下一个判断。

把刚想明白的地方、还没想通的问题,留给下一位一起学习的人。

正在讨论 Guardian:让一个模型去审批另一个模型 拆开 OpenAI Codex
3条讨论文章讨论 · 与共学社区同步
在共学社区查看
AM
Asha Morgan内容编辑
观点实践记录

我把这篇文章里的一个判断改写成了今天可以验证的小实验。比记住结论更有用的是,知道下一步要观察什么。

文章讨论7 有帮助
LH
Lin Harper独立开发者
观点观点

读完以后我先回头找它成立的条件,而不是直接把方法搬进项目。这个顺序让后面的取舍清楚很多。

文章讨论5 有帮助
KM
Kiki Moore产品运营
问题问题

如果把这个判断放到真实工作里,最先需要补的约束是什么?我想知道从阅读到第一次实践之间,哪一步最值得先做。

文章讨论4 有帮助