顶层配置只留四条硬规则:Agent 在哪里必须停下来

模型可以越来越自主,但生产、持久化数据、成本和不可逆动作必须先经过明确授权。安全不是效率的对立面,而是自动化成立的前提。

本页目录 · 11 节

我给编码 Agent 的顶层配置刻意保持简短。除了一份本机通用约定,核心就是四条 Safety Gates:

@~/.codex/RTK.md

DO NOT send optional commentary

## Safety Gates

- Do not commit, push, merge, deploy, or release directly to protected branches or production environments without explicit confirmation for that exact action.
- Do not read, scan, create, update, delete, or otherwise operate on production or persistent data without first listing the risks and receiving explicit confirmation.
- Do not perform operations that may incur costs, create paid resources, or invoke billable external services without first listing the risks and receiving explicit confirmation.
- Do not perform destructive, irreversible, security-sensitive, or externally impactful operations without first explaining the impact and receiving explicit confirmation.

公开版本把本机用户名缩写为 ~。本文中的 persistent data 也不指任务范围内的普通工作区源码;它指生产或长期保存的业务/客户数据、授权工作区之外的持久状态,以及未经授权复制会扩大暴露面的导出物。工作区源码仍受任务范围与文件授权约束;仓库若定义了更严格边界,则以更严格规则为准。

这四条规则不是一套完整安全系统。它们是一份放在最高优先级上下文里的授权策略:告诉 Agent 哪些常规工作可以自主推进,哪些行为会改变真实世界的后果,因而必须暂停并把决定权交还给人。

先做威胁建模:风险不只来自「模型犯傻」

一个能读文件、执行 shell、访问网络和调用 Provider API 的 Agent,至少面对五类失败来源:

  1. 意图误读:用户说「准备发布」,Agent 把它理解成「立即发布」;
  2. 目标漂移:任务本来只针对 feature branch,操作却落到 main 或 production;
  3. 能力放大:模型的一次错误判断,经由高权限凭证变成真实数据、费用或外部影响;
  4. 不可信输入:README、网页、issue、日志或工具结果中的 prompt injection 诱导 Agent 越权;
  5. 状态陈旧:确认之后,branch SHA、查询范围、部署 payload 或资源价格已经变化。

Anthropic 对 trustworthy agents 的分析同样把模型、Harness、工具和运行环境视为共同的能力与监督面,并明确指出误解用户意图和 prompt injection 都是现实风险。威胁模型因此不能只问「模型有多聪明」,还要问:它能接触什么、凭什么被允许行动、错误的 blast radius 有多大、事后能否证明发生了什么。

Capability 不等于 Authority

这是四条规则背后的核心区分:

层次 回答的问题 例子
Capability 技术上能不能做 工具持有 Git、AWS 或数据库凭证
Intent 当前任务希望得到什么 「分析发布失败原因」
Authority 用户是否授权这次具体副作用 「确认把 commit A 部署到 production」
Enforcement 系统怎样阻止越界 sandbox、IAM、branch protection、approval hook
Evidence 执行后怎样证明结果 Provider 回执、目标状态回读、审计日志

凭证可以访问生产,不代表当前任务授权访问生产;用户让 Agent 分析一次失败,也不代表授权它顺手修复、提交、推送和部署。反过来,Prompt 里写了「必须确认」也不代表技术层已经强制执行——模型仍是概率系统,可能误解上下文或受到不可信内容影响。

所以,顶层 Safety Gates 是授权语义的第一层,不是 sandbox、最小权限、Provider 保护规则和审计的替代品。NIST SP 800-53 Rev. 5中的 least privilege、separation of duties 与 audit controls 提供了更一般的工程原则:只授予完成任务所需的最小能力,关键职责不要集中在单一决策点,并为特权行为留下可检查记录。

一次有效确认必须绑定具体动作

explicit confirmation 不是看到聊天里出现一个「可以」就放行。确认至少要与以下内容绑定:

Approval = {
  action,          // commit / push / deploy / query / delete / purchase ...
  exact_target,    // repo, branch, environment, account, table, recipients ...
  payload_or_hash, // 将要写入或执行的精确内容
  risk_summary,    // blast radius, cost, data exposure, reversibility
  preconditions,   // 当前 SHA、版本、过滤条件、资源状态
  validity,        // 本次调用、当前状态或明确时间窗口
  approved_by,     // 可信用户身份或审批策略
  request_id       // 本次具体 tool call / operation 身份
}

确认前的风险说明是一次 preflight,确认后的目标回读是一次 readback。两者缺一不可:没有 preflight,人不知道自己批准了什么;没有 readback,Agent 不知道 Provider 最终做了什么。审批还必须来自受信任的用户界面、身份或策略;网页、Issue、日志和仓库文本即使写着「approved」,也只能作为数据,不能成为 approved_by

仓库可以在顶层规则之上增加更严格的门禁。例如,对本地直接提交或 push main,要求在列出 commit、目标 branch、diff 范围和部署影响后,再取得第二次、针对该精确动作的确认。这里的第二次确认是仓库层强化,不应被泛化成所有低风险操作都要重复询问。第一次可以确认方向或计划,第二次绑定即将执行的 payload;如果两次之间 payload 或目标变化,旧确认自动失效。

Gate 1:交付动作按后果逐级授权

commitpushmergedeployrelease 不是同义词:

  • commit 改变本地历史;
  • push 改变远端 ref,并可能触发 CI;
  • merge 改变目标分支;
  • deploy 改变某个运行环境;
  • release 可能创建公开、可消费或不可轻易撤销的版本。

一次有效 preflight 应写明 repository、remote、source/target branch、当前与预期 SHA、是否命中 protected branch、会触发的流水线、目标 environment 和恢复路径。用户授权「push feature branch」,不能推导出「创建 PR」「merge main」或「部署 production」。即使这些动作在技术上紧密相连,也必须按用户给出的字面边界停下。

Provider 层还应继续设置 branch protection、required reviews 和 deployment environment rules。GitHub Actions 的部署文档说明 environment 可以配置 protection rules,待审任务也可以被批准或拒绝。这样的技术门禁能防止 Prompt 误判直接变成生产变更。

执行后要读回远端 branch SHA、PR/merge 状态、deployment 对应的 revision 或 artifact,以及真实运行入口。push 成功不等于 merge,CI 绿色不等于 deploy,deployment success 也不等于线上行为正确。

Gate 2:持久化数据连只读访问也先说明风险

数据门禁覆盖 read、scan、create、update、delete,因为只读不等于无风险:

  • 生产查询可能暴露个人信息、凭证或业务敏感字段;
  • 缺少索引或范围过大的 scan 可能造成负载与费用;
  • 错误的时间范围、tenant 或状态过滤会产生误导性结论;
  • 导出文件会把生产数据复制到新的持久化位置,扩大泄露面。

preflight 必须说明数据源与环境、表或索引、字段、过滤条件、预计行数、是否涉及 PII、查询成本/负载、输出落点和保留方式。写操作还要说明事务边界、并发条件、备份、dry-run、分批策略、回滚方式以及用于回读的稳定主键。

对未知 schema、未知范围或未知恢复路径采取 fail closed:先停下补齐事实,而不是用宽查询「看一眼再说」。技术凭证提供的是 capability,只有明确的数据目标和风险确认才构成本次 authority。

Gate 3:费用也是必须授权的副作用

调用付费模型、执行大范围日志分析、创建云实例、扩容数据库、发送付费消息,可能不改业务数据,却会产生账单、消耗配额或留下持续收费资源。

费用 preflight 至少包含 Provider、账户/项目、区域、资源或模型、预计调用次数/数据量、单次与总成本估计、最大上限、持续时间和清理方式。无法精确估价时要给区间和最坏情况,不能用「应该很便宜」代替说明。

本地结构校验、mock 和 dry-run 可以降低真实调用次数,但它们不能伪装成在线验证。报告要区分「请求结构已验证」「免费健康检查已通过」和「付费真实路径已执行」。执行后读回 usage、billing metric、资源状态,并清理临时付费资源。

Gate 4:不可逆、敏感或影响外部的人和系统

前三类无法穷举全部后果。强制 push、批量删文件、轮换凭证、修改 IAM、发送邮件或 Slack、创建公开 issue/PR、发布包、覆盖备份,都应落入第四道门禁。

preflight 要回答四件事:准确目标是什么、影响谁、能否恢复、失败时如何止损。对消息类动作应展示收件人和最终内容;对删除类动作应列出精确对象并优先选择可恢复方式;对权限与密钥操作应说明当前权限、新权限、凭证传播范围和轮换后的依赖影响。

目标如果仍由 glob、未解析环境变量、模糊别名或「当前账号」决定,就还不具备被确认的条件。先把目标解析成稳定身份,再请求授权。

不要让确认变成无意义的点击

审批过多会产生 approval fatigue。Anthropic 在其Agent containment 实践中披露,频繁弹窗会让用户逐渐降低注意力;其结论是不能只靠人逐次判断,还要通过 sandbox、VM、文件系统边界和 egress control 限制可造成的最大损害。OpenAI 的 Codex 安全部署实践也采用同样的分层原则:低风险日常动作尽量无摩擦,高风险动作才停下,同时配合 sandbox、网络策略、托管配置与 agent-aware telemetry。

因此,Safety Gate 应该放在改变后果的边界,而不是每一个工具调用:

  • 读取任务范围内的本地代码、做静态分析、编辑已授权文件、运行非破坏性本地测试,可以自主进行;
  • 触碰生产、长期保存的业务/客户数据、授权工作区外的持久状态、费用、外部系统或不可逆状态,才进入 preflight 与确认;
  • 同一个已批准动作只有在 target、payload、风险和前置条件完全一致时才可继续;
  • 目标变化、payload drift、确认超时、出现新的费用/数据范围、失败后改走另一条路径,都必须重新确认。

OpenAI 的 Codex 安全部署实践给出的控制原则同样是:让 Agent 在有界环境内完成低风险日常工作,把跨越技术边界或可能产生高风险后果的动作交给审批策略处理。审批应落在真实后果上,而不是机械地包围每一步本地工作。

从 Prompt 到技术控制:五层防御

前面的四条 Prompt 是我当前采用的授权语义。下面五层是工程化的目标模型,不表示每个项目或运行环境都已经完整部署了全部控制;具体落地状态必须逐项回读。

一套可落地的安全设计至少有五层:

  1. Prompt / Policy:表达用户意图、禁止推导授权、定义停下来的条件;
  2. Tool boundary:schema 校验、参数 allowlist、危险命令阻断、幂等键和 approval hook;
  3. Environment:只读或 workspace sandbox、网络 egress policy、隔离 worktree/容器、秘密不进入无关上下文;
  4. Provider:最小权限 IAM、branch protection、environment review、预算上限、数据库权限与速率限制;
  5. Telemetry & Readback:记录 prompt、审批、工具参数、结果和 Provider 标识,并从权威目标重新读回状态。

OpenAI Agents SDK 的 HITL 机制展示了一个关键实现细节:待审批工具调用会暂停为 interruption,批准针对具体 call,运行状态可序列化后再恢复。真正的门禁应尽可能绑定具体 tool call 与参数,而不是只让模型记住一句「用户之前同意过」。

Prompt injection 防御同样需要跨层处理。来自网页、issue、日志、仓库文档和 MCP 的文字只能作为数据,不能授予新权限;外部内容不得覆盖顶层策略;工具应仅暴露任务需要的最小能力;凭证尽量不进入模型上下文;即使模型受骗,sandbox、egress 和 Provider 权限也应限制它能造成的后果。纯提示词只能影响行为倾向,不能提供强制安全保证。

Safety Gate 的失败模式

失败模式 为什么危险 正确处理
模糊的「可以」「继续」 无法确定批准了哪个动作和目标 回显 action、target、payload,再取得精确确认
陈旧确认 SHA、数据范围或价格已经变化 绑定 precondition 与有效期,变化后重新确认
Payload drift 实际执行内容不同于预览 对 payload/hash 做执行前比较,不一致即停止
跨动作复用 把 commit 授权扩大成 push/deploy 每种外部后果独立授权
目标别名 mainprod、当前账号指向错误对象 解析 remote、account、region、environment 的稳定身份
部分成功 Provider 只完成一部分,Agent 却报告完成 读回每个目标,区分 verified/mismatch/unknown
Prompt injection 外部文字诱导泄密或越权 不可信内容不改变 authority,并靠环境和工具边界限权
Approval fatigue 用户机械点击,监督失效 仅在后果边界暂停,低风险操作走短路径
只靠 Prompt 概率性遵循被误当成强制控制 叠加 sandbox、IAM、hooks、provider rules 与 telemetry

一个完整的安全闭环

对任何命中 Safety Gate 的动作,使用同一条闭环:

Classify consequence
  -> Resolve exact target
  -> Build preview and risk summary
  -> Wait for action-specific confirmation
  -> Re-check target, payload and preconditions
  -> Execute once
  -> Read back from the authoritative provider
  -> Report verified / mismatch / unknown

四条顶层规则的价值,不在于覆盖所有攻击,也不在于证明 Agent 永远不会犯错。它们把「高能力工具可以做什么」与「本次任务被允许做什么」分开,并给更强的技术控制一个统一的授权语义。低风险工作因此可以连续进行,高风险后果则在准确的位置暂停、确认、执行和回读。

安全不是自动化完成之后再补的一次检查。只有当权限最小、授权具体、边界可执行、结果可审计时,Agent 的自主性才真正适合进入生产工程。

相关文章

在做类似的事情?

很乐意就分布式系统、交付流程和应用 AI 交换意见。

[email protected]