一句话结论 把编码 Agent 的"能做什么"和"被允许改什么"分开:前者靠 prompt 与上下文,后者必须落到可在 Git 里被评审、可在测试...
一句话结论
把编码 Agent 的"能做什么"和"被允许改什么"分开:前者靠 prompt 与上下文,后者必须落到可在 Git 里被评审、可在测试里被验证、可在事故里被回放的边界契约。只给提示词、不给权限边界,Agent 越能干,出错的代价越大。
一、问题不是"它会不会写错",而是"它被允许改什么"
2026 年 8 月 29 日,EngineeringSpec 在其官方博客发表了一篇名为《Give Coding Agents Permission, Not Just Prompts》的文章,开篇就抛出一个具体的故障场景:一段被精确提示的编码 Agent,任务是"刷新鉴权会话,但不要打断在线用户",它在仓库里读到正确的抽象、写出了能跑通的代码、通过了所有测试。与此同时,它顺手改了共享鉴权中间件、迁移了一张数据库表、还动了部署脚本。
代码技术上是正确的,测试是绿的,但变更范围超出了任何人批过的边界。作者把这种事故归纳为一个被业界长期忽略的盲区:更好的 prompt 能表达意图,更多的上下文能让 Agent 理解系统,更强的验证能判断结果是否成立——但这三件事单独来看,没有一件回答"Agent 被允许改什么"。
同一周,工程师 Saleem Mirza 在自己的博客上发表了《When deny doesn't win: least-privilege permissions for Claude Code》一文,从一个更工程化的视角补上了同一件事的另一面:即便权限规则写得正确,Claude Code 的原生权限系统以固定优先级(deny > ask > allow)解析规则,工程师为了读 AWS 资源写的"宽 deny + 窄 allow"会被宽 deny 一票否决,工程师要么放掉 deny、要么手工审批 700 多次工具调用(原文链接到一个 GitHub issue,记录了一次真实的 700+ 次审批事故)。
把这两件事放在同一张地图上看,它们其实是同一类问题的两个切面:Agent 在企业里被部署得越深,它能"看到"的代码、配置、生产环境就越多;而组织真正想约束的,从来不是它"会不会做错",而是它"被允许做什么"。
二、把 Agent 的"控制"拆成三件独立的事
EngineeringSpec 把 Agent 周围的控制机制拆成三类,这三类不是替代关系,是互补关系:
- Context(上下文):Agent 知道什么。这是 prompt、检索、仓库索引、文档加载解决的问题。上下文多,Agent 写得准。
- Validation(验证):Agent 改完之后,这次改动是否成立。这是测试、CI、Code Review、端到端校验解决的问题。验证强,改动出错的概率低。
- Authority(权限边界):Agent 被允许改什么。这是 Git 里被评审过的契约、可在事故里被回放的变更范围、明确写到策略里的路径白名单解决的问题。权限边界清晰,事故发生时能定位"谁批过这件事"。
这三件事常被混在一起讨论,但它们的失效模式完全不同。一个 prompt 写得再准,也不构成审批记录;一次仓库只读访问,也不构成写权限;一次成功的测试或分析,也不扩大边界。如果用 prompt 的强度去回答权限问题,得到的答案永远是"Agent 表现得很好,所以它有权做这件事"——这是一个危险的反向推理。
三、把权限边界落到 Git 里的可评审契约
EngineeringSpec 的做法是把一次工程变更表示为仓库里一份版本化的契约,契约里写清楚:本次变更的目标文件、路径策略、技术义务、验证人身份、停止条件。契约作为一次普通的 Git 变更走评审流程,实现 Agent 只消费评审后、被锁定在受信任基线里的那份契约,而不是消费 prompt 或者工作区里临时存在的文档。
这种做法的核心收益是把权限的来源从"prompt + 模型判断"转移到"Git 历史里被评审过的事实"。一个 Agent 可以为了正确性而广泛读取仓库,但它能写入的范围被锁死在契约授权的路径集合里。如果实施过程中发现契约批得太窄,正确的反应不是 Agent 自行扩大解释权,而是停下来,把新的决策显式提到评审流,让人类决定要不要扩边界。
对应到企业里常见的"Agent 写库前是否要人工确认"这件事,这条路径给出了一个清晰的答案:权限边界不是 Agent 在运行时临时判定的,而是在变更发生前就已经写在某个可评审、可回放、可追溯的地方。如果这份契约不存在,Agent 就应该停下来问,而不是猜。
四、当"宽 deny + 窄 allow"被一票否决时,谁来兜底
Saleem Mirza 的工作正是这一原则的工程化补丁。Claude Code 的原生权限规则以固定优先级解析,一个工程师想表达"允许读取 AWS 资源、但拒绝所有修改类操作"时,必须写"deny: Bash(aws:*)"加"allow: Bash(aws * describe-*)"。问题是这两个规则都匹配"aws ec2 describe-instances",Claude Code 会先看到 deny、再看到 allow,allow 被 deny 一票否决。
原生规则里没有表达"宽 deny + 窄 allow"的能力,要么去掉 deny 让破坏性操作畅通,要么保留 deny 然后手工审批每一次只读调用。Saleem 写的 permcheck 工具是给 Claude Code 加一层策略引擎,只要窄规则在语义上"被包含"在宽 deny 之内,allow 可以覆盖 deny,并把"包含性"作为可测试的属性——任何窄规则都能在 CI 里跑出确定性结果,而不是依赖 prompt 的判断。
许可列表和拒绝列表的"包含性"是 2026 年下半年企业 Agent 治理里反复出现的关键词。它本质上是把权限从"自然语言描述"翻译成"形式化、可验证的规则"。一旦规则可验证,组织就可以把它当作代码评审的一部分,而不只是 Agent 启动时的一次性配置。
五、五种控制机制各管一段,不要混用
合并两篇文章里的控制矩阵,企业落地 Agent 时常用的"权限"手段其实在管不同的事:
- 原生权限规则(如 Claude Code 的 settings.json):厂商强制执行的 allow、ask、deny 列表。优势是确定性,不消耗 token;局限是宽 deny + 窄 allow 的表达力不够,容易被一票否决。
- Auto 模式:用分类器判断当前调用是否符合请求与上下文。能识别规则作者没写到的边界,代价是每一次判断都是一个模型调用,延迟与成本不可忽略。
- 策略引擎 + 版本化规则(如 permcheck):把权限规则当作代码管理,在 CI 里跑回归测试。优势是可审计、可回滚;局限是只对规则里写到的命令生效,运行时拼出来的命令或未被枚举的工具不在覆盖范围内。
- 执行沙箱:操作系统层与网络层的隔离。优势是命令一旦通过沙箱也兜得住;局限是配置依赖操作系统能力,且对"未声明"的工具默认不阻断。
- 二次确认 / HITL:关键操作前的人工审批。优势是处理"未在规则里写明、但语义上有风险"的场景;局限是工程师疲劳——Saleem 引用的事故就是 700 次审批的真实例子。
这五件事不是替代关系。一家企业落地编码 Agent 时,通常要四件或四件以上一起用:写库类高破坏性操作走原生 deny + 沙箱双轨,只读类广覆盖操作走策略引擎允许 + 审计日志,真正未知的边界靠 Auto 模式分类器 + 必要时的人工兜底。单独押注任何一种,都对应着一种典型的事故模式。
六、企业落地常见的五种踩坑模式
- 把 prompt 当审批记录:Agent 写完一段代码,通过测试,就把"模型认为这是对的"当成"人类批过这件事"。任何事故复盘里,这句话都会被反向追问"谁批过"——答不上来就是权限设计的盲区。
- 把仓库读权限当写权限:Agent 能看到 .env、AWS 密钥、生产数据库连接串,不代表它有权改这些。把读权限与写权限明确分轨,而不是默认"能读到就能改"。
- 把"测试通过"当成"权限扩大":测试通过说明这次变更在工作范围内成立,不说明 Agent 改的范围就是被允许的范围。一次测试通过不能反推一次权限授予。
- 把策略写在 Prompt 里:Prompt 会因为模型升级、上下文长度截断、用户改写而漂移;写在 settings.json 或独立策略文件里的规则是确定性的,可以测试。同一策略在两处维护,迟早会不一致。
- 把人工审批当兜底机制:700 次审批的真实事故说明,当策略不充分时把所有压力推到工程师,结果就是审批疲劳 + 实际生效的"全 Allow"。HITL 应是异常路径,不是日常路径。
七、给正在落地编码 Agent 的团队的五条具体建议
- 把权限边界作为 Git 里的可评审契约来维护:不在 prompt、不在工作区文档里写"Agent 不能改什么",而是在仓库里维护一份版本化的契约,跟代码走同样的评审流程。契约字段至少包含目标文件、路径策略、验证人、停止条件。
- 原生 deny 与 allow 分轨管理:破坏性操作(写库、删表、改部署)走 deny-by-default 列表,放在厂商原生配置里、不可被 Agent 运行时覆盖;只读操作走策略引擎的 allow 列表,可以更精细,但要在 CI 里跑回归测试。
- 关键操作走人工确认,且只在策略未覆盖时触发:把人工确认设计成异常路径,而不是日常路径。如果一个团队的人工确认调用超过每天十次,意味着策略不够细,需要回头扩规则,而不是继续让工程师点。
- 把权限策略当作代码做回归测试:每条"宽 deny + 窄 allow"都跑一遍"包含性"测试,确认窄规则确实被宽 deny 涵盖;每条新增 allow 配一段端到端调用,跑出预期结果。把策略测试接到 CI,跟单元测试同等地位。
- 执行边界交给操作系统与网络层:策略引擎只判断"调用是否符合规则",不替代沙箱。所有写库类高破坏性操作,默认走容器或虚拟机的文件系统隔离 + 网络 egress 白名单,允许 deny 漏判时,执行层兜得住。
写在最后
把这两篇相隔十天、来自不同作者、不同视角的文章放在一起,得到的是一个共同的判断:2026 年下半年,编码 Agent 在企业里的主要风险不是"它写得不够好",而是"它被允许改的范围比人类意识到的更大"。给编码 Agent 权限边界,而不是只给提示词,这不是一个工具选择问题,是一个治理结构问题。EngineeringSpec 的原文结尾写道,授权的来源是被评审过的 Git 历史,而不是 prompt 或者工作区里临时存在的文档;Saleem Mirza 的原文结尾写道,真正的边界永远是操作系统与网络层提供的可强制执行边界,权限检查只能降低风险,不能替代执行边界。
这两句话放在一起,就是当下企业落地编码 Agent 的底层规则:Agent 能写多准是一回事,Agent 被允许改什么,必须由人类事先在可评审的地方写清楚。对于正在把编码 Agent 嵌入生产链路的企业来说,先回答"谁在什么文件里写过这次变更被允许做什么",再去谈"Agent 写得准不准",是更稳定的工程顺序。
本文基于以下两篇 30 天内英文一手素材合并改写:
1. EngineeringSpec,《Give Coding Agents Permission, Not Just Prompts》,2026-08-29,https://engineeringspec.org/blog/give-coding-agents-permission-not-just-prompts/
2. Saleem Mirza,《When deny doesn't win: least-privilege permissions for Claude Code》,2026-08-28,https://blogs.zethian.com/when-deny-doesnt-win.html
所有事实性表述可追溯到上述原文;具体案例为通用化描述,不指向特定企业。