Codex 审批策略拆解:三档字符串与五个细粒度开关怎么选

2026-08-09

Codex(OpenAI Codex)里最容易被配错的一个键就是 approval_policy。它在官方《Configuration Reference》里的类型写的是 string/table——一个键有两种完全不同的写法,一种是三档字符串,一种是带五个布尔开关的表。很多人只知道前者,于是遇到”我只想关掉某一类弹窗、别的还留着”这种需求时,就开始在三档之间反复横跳,怎么调都不对。

这篇把两种写法的边界、各自能做到什么、以及怎么验证当前真正生效的是哪一档,一次讲清楚。

先分清三件不同的事

在动 approval_policy 之前,得先承认它管的范围比你想的小。CLI 这边至少有三层是分开的:

键 / 选项管什么
沙箱边界sandbox_mode / -s, --sandbox能不能做(文件系统与网络的硬边界)
审批策略approval_policy / -a, --ask-for-approval做之前问不问你
权限档default_permissionspermissions.<name>.* / -P, --permission-profile更细的路径与域名级授权

三层是叠加关系,不是替代关系。把审批调松,边界并不会跟着松;把边界撤了,弹不弹窗也不会自动跟着变。这一条是后面所有判断的地基,先立住它,能省掉一大半来回试错。

三档字符串:官方释义与判断依据

三档取值是 untrusted / on-request / never,CLI 侧对应 -a, --ask-for-approval <APPROVAL_POLICY>。官方给的释义是:

  • untrusted:只有”受信任”的命令(如 ls、cat、sed)免审批;模型提出不在受信集合内的命令时,升级给用户。
  • on-request:由模型决定何时请求审批。
  • never:从不询问,执行失败直接回传给模型。

判断依据其实很直白,看你愿意为”少点几次同意”付出什么代价:

untrusted,适合你刚拉下来一个不熟的仓库、或者对方代码里有一堆你没读过的脚本。它的成本是打断多——受信集合之外的东西都会来问你一次。好处是那些”看起来只是跑个构建、实际上会动别的东西”的命令,你有机会拦住。

on-request,把”什么时候该问”的判断权交给模型。这是日常写代码时打断最少的一档,代价是你必须接受一个前提:判断权不在你手上。所以它更适合你已经把沙箱边界收好了的场景——边界收紧之后,即使模型判断失误没来问你,能造成的后果也被 sandbox_mode 兜着。

never,适合无人值守的批处理:codex exec 跑在脚本里、或者跑在计划任务里,本来也没人坐在终端前面点同意。它的关键行为是”执行失败直接回传给模型”,也就是失败不会挂住流程,而是变成模型的一条输入让它自己想办法。

never 不等于放开权限——最常见的误读

这是我见过最多人栽的地方:把 never 当成”给它全部权限”。

不是。never 改变的只有一件事——要不要问你。沙箱边界原封不动。真正撤掉边界的是另外两样东西:sandbox_mode = "danger-full-access"(官方原文写的是 “The agent runs without sandbox restrictions. This removes the filesystem and network boundaries…”),以及顶层选项 --dangerously-bypass-approvals-and-sandbox(官方原文 “EXTREMELY DANGEROUS. Intended solely for running in environments that are externally sandboxed”)。

反过来说也成立:你配了 never 之后如果发现一堆命令写文件失败,那多半不是审批的问题,是沙箱模式或者可写根没配对,该去看 sandbox_modesandbox_workspace_write.writable_roots,而不是继续在审批策略上折腾。

表形式:五个细粒度开关

字符串写法有个做不到的事:只放行某一类弹窗。想按类别控制,就得把 approval_policy 写成表。官方《Configuration Reference》里列出的是这五个布尔键:

官方说明
approval_policy.granular.sandbox_approval是否允许沙箱提权审批弹窗
approval_policy.granular.rules是否允许 execpolicy prompt 规则审批
approval_policy.granular.mcp_elicitationsMCP elicitation 弹窗允许还是自动拒绝
approval_policy.granular.request_permissions是否允许 request_permissions 工具弹窗
approval_policy.granular.skill_approval是否允许 skill 脚本审批弹窗

这五个开关分别对应五条不同的”打扰来源”:沙箱要提权、execpolicy 规则命中了 prompt、MCP 服务器发起 elicitation、模型调 request_permissions 工具、以及 skill 脚本要跑。它们平时混在一起弹,你只觉得”烦”,分不清是谁弹的;一旦分成五个开关,就可以按来源关。

一个容易踩的坑:关掉之后是拒绝还是放行

注意看上面这张表的措辞差别。mcp_elicitations 那一行,官方明确写了两种结果——“允许还是自动拒绝”,也就是说关掉它是自动拒绝,不是自动同意。而另外四个键,官方的说法都只是”是否允许……弹窗”,并没有写明关掉之后走的是拒绝还是放行

这个差别很要命:如果关掉等于自动拒绝,那你关掉 skill_approval 之后 skill 就直接跑不起来;如果关掉等于静默放行,含义正好相反。官方文档在这四个键上没给结论,我这边在 codex-cli 0.147.0(Windows 11)上只跑过只读命令,没有发起过任何模型对话请求,也就给不出实测结论,所以这里不替它补一个答案——你要关这四个中的任何一个,先在一个无关紧要的目录里小规模验证一次实际行为,别直接推到主力项目上。这是我能给的最诚实的建议。

写法示例

字符串形式,一行搞定:

approval_policy = "on-request"

表形式,按来源逐个开关:

[approval_policy.granular]
sandbox_approval = true
rules = true
mcp_elicitations = false
request_permissions = true
skill_approval = true

不想改文件、只想这一次生效,用顶层的 -c 覆盖。它接受点号路径表示嵌套,value 按 TOML 解析,解析失败则按字面字符串处理:

codex -c approval_policy.granular.mcp_elicitations=false

以上为按官方文档键位组合的示例,未逐项实测,以官方文档为准。

谁在替你点同意

除了 approval_policy,还有一组键决定”审批请求交给谁处理”:

  • approvals_reviewer:默认 user,可设 auto_review
  • auto_review.policy:自动评审用的本地 Markdown 策略;官方标注受管配置优先
  • guardian_policy_config:受管的 Markdown 评审策略,覆盖本地策略
  • CLI 侧还有 --approve-for-me:审批请求走自动复核,并使用 workspace-write 沙箱。

这里有个对企业环境用户特别重要的判断依据:如果你在受管的工作区里,本地怎么写都可能被 guardian_policy_config 盖掉。所以当你改完本地策略、行为却纹丝不动时,先别怀疑自己 TOML 写错了,先确认这台机器是不是在受管配置之下——本地策略与受管策略的优先级,官方已经写死了。

另外 --approve-for-me 是连带效果的:它不只改了”谁来批”,还同时把沙箱定在 workspace-write。如果你本来跑的是 read-only,加上这个选项之后边界是变了的,这一点在选它之前要想清楚。

审批开关不止 approval_policy 这一处

还有几组独立的审批相关键,散落在配置的别的段落里,名字都带 approval,很容易和 approval_policy.granular 搞混:

  • MCP 服务器:mcp_servers.<id>.default_tools_approval_modemcp_servers.<id>.tools.<tool>.approval_mode
  • 应用 / 连接器:apps.<id>.*apps._default.* 下的 default_tools_approval_mode,取值 auto / prompt / writes / approve
  • 插件自带的 MCP server:plugins.<plugin>.mcp_servers.<server>.* 下的启停与工具审批。

它们和 approval_policy.granular 是不同段落里的不同键,官方文档没有描述两者的交叉行为,所以我不下”谁覆盖谁”的结论。实操上的意义是:当你发现关了 granular 开关还在弹,先去看是不是某个 MCP server 或 app 自己的 approval_mode 在起作用,别一直盯着 approval_policy 改。

怎么确认当前真正生效的是哪一档

配置改完最怕的不是配错,是”改了但没生效,你还以为生效了”。这里有几条可执行的确认手段。

第一,跑 doctor 看 sandbox 行。 在 codex-cli 0.147.0(Windows 11)上执行 codex doctor --summary,Configuration 分组里的 sandbox 检查项本机输出为 restricted fs + restricted network · approval OnRequest。这一行同时给了沙箱状态和当前的审批档位,是最快的自查入口。要强调的是:这里显示的 OnRequest本机配置下的生效值,不代表这就是产品默认值——官方文档里明确标注了默认值的是沙箱模式(workspace-write 为默认模式),审批策略这边不要拿别人机器上的输出当默认。

第二,配置坏了 doctor 会直说。 在 codex-cli 0.147.0(Windows 11)上执行 codex -c 'features=[unclosed' doctor --summary,命令并没有崩溃退出,doctor 照常跑完,但 Notes 区多了一行:

✗ config       config could not be loaded - Fix the reported config error, then rerun codex doctor.

也就是说,config.toml 语法坏掉时,Codex 不会拦着你不让跑,它会带着没加载成功的配置继续工作。所以”我改了审批策略但完全没变化”的第一步永远是跑 doctor 看这一行有没有出现 ✗,而不是反复改键名。

第三,别指望 --strict-config 兜住所有拼写错误。 这个选项的说明是”config.toml 里出现本版本不认识的字段时直接报错退出”,但它有触发边界:在 codex-cli 0.147.0(Windows 11)上执行 codex -c model_reasoning_effortt=high --strict-config exec --help(注意键名故意多了一个 t),命令正常打印了 help,没有报未知字段错误。说明校验发生在真正加载配置去跑会话的时候,--help 这类不进入会话的路径不触发校验。你想用它来验证 approval_policy.granular 的键名有没有敲错,就不能靠打 help 来验。

第四,想留多套档位就用 profile。 顶层选项 -p, --profile <CONFIG_PROFILE_V2> 会把 $CODEX_HOME/<name>.config.toml 叠加到基础用户配置之上。比 -c 敲一长串更适合”日常一套、无人值守一套”这种固定组合。

三种处境的决策路径

处境一:本地日常写代码,人一直在终端前面。 先把 sandbox_mode 收到 workspace-write,再选 on-request。理由是打断最少,而判断失误的后果由沙箱边界兜着。五个细粒度开关一个都别动——你都坐在电脑前了,弹窗对你是信息不是噪音。

处境二:codex exec 跑在脚本或计划任务里,没人盯。never,失败直接回传给模型,流程不会挂在等人点同意上。这时候值得单独考虑 mcp_elicitations = false:官方明确写了它关掉是自动拒绝,无人值守场景下”自动拒绝”比”挂在那儿等”要好。另外记得 never 不放开边界,所以要一并把 sandbox_mode 和可写根配到位,否则你会得到一堆写入失败。

处境三:接手一个陌生仓库,或者要跑别人给的脚本。untrusted,接受打断多这个代价。这一档的价值就在于把”不在受信集合里的命令”全都摆到你面前,让你有机会看一眼再决定。

什么情况下别碰这些键

三种情况我建议直接放手:

一是你在受管工作区里。本地 auto_review.policy 会被 guardian_policy_config 覆盖,你花时间调本地策略可能是白费,先找管理员确认口径。

二是你想靠关审批来解决权限报错。前面说过,审批和边界是两层,权限报错该去看沙箱模式和可写根。

三是你打算把那四个语义未明的开关(sandbox_approvalrulesrequest_permissionsskill_approval)批量关掉图省事。官方没写关掉之后是拒绝还是放行,在你自己验证清楚之前,批量关等于把一组行为未知的开关同时拨了。

最后提一句文档本身的用法:learn.chatgpt.com 上任何一个文档页 URL 后面加 .md 后缀就能拿到 Markdown 版本,站点还提供 llms.txt(完整页面索引)和 llms-full.txt(合并全文)。审批与权限这块的键位更新得不慢,与其记住本文的表格,不如把配置参考页的 .md 存下来,每次升级之后 diff 一遍。

相关阅读


本文依据 Codex 官方文档(learn.chatgpt.com/docs/ 的《Configuration Reference》《Sandbox》页面)整理,核对日 2026-08-09;文中标注「本机实测」的部分基于 codex-cli 0.147.0 / Windows 11 环境下的只读命令输出。产品功能、模型与价格以官方最新说明为准。

想系统学会用 AI?报名体系课或加入会员,照着学、照着用。