智能体拒绝操作,未必是策略引擎生效
作者测试 agentpolicy 时发现,Claude Code 虽然拒绝危险操作,策略引擎的审计记录却为空,实际限制来自默认沙箱。文章围绕 PreToolUse 钩子接入,揭示安全策略未进入执行链路的验证盲点。
AI 深度解读
Claude Code 拒绝了危险命令,是否就能证明自建策略引擎生效?agentpolicy 作者差点据此交付:三次工具调用的表现都符合预期,审计日志却一条记录也没有。真正拦住操作的是 Claude Code 自带的沙箱,作者的策略根本没被调用。
这次 agentpolicy v0.1.0 实测最有价值的地方,是揭开了一个容易漏掉的验收问题:当平台和自建组件都能产生相似结果时,怎样证明结果确实来自你要验证的那一层?
拒绝操作,为什么还不能算测试通过
agentpolicy 是一个本地优先、基于 Cedar 的策略决策点,负责判断 AI Agent 的动作应该允许、拒绝、请求人工介入、限流还是脱敏,并提供预置规则包。它已发布到 PyPI,安装命令是 pip install agentsec-agentpolicy。
作者这次验证的是 Claude Code 集成。Claude Code 提供 PreToolUse hook:工具调用前,把工具输入以 JSON 传给指定脚本,再根据脚本的退出码决定放行、阻止或请求确认。
hook 脚本 scripts/fieldtest/t1_evaluate.py 包装了 agentpolicy evaluate,走的是已发布 CLI 使用的加载器和引擎,没有另写一套测试专用实现。策略文件 t1_policy.yaml 规定了三个场景:
- 读取 staging 目录可以放行。
- 写入 prod 需要人工介入。
- 对 prod 执行破坏性操作必须拒绝。
第一次运行,三次工具调用看起来都对:Claude Code 会请求权限,也拒绝执行 rm -rf。但作者打开 artifacts/audit.ndjson,发现文件是空的。
问题就在这里。Claude Code 自己也有危险命令防护,即使自建 hook 缺席,对话里仍可能出现类似的拒绝。用户看到的是最终表现,看不到背后的决策归属。
操作被拦住,只能证明某个机制生效,不能证明你的策略引擎参与了决策。
一个没有加载的配置,藏住了两处接线错误
根因很普通:作者把 hook 配置放进了工作目录的 .claude/settings.json,以为放在约定位置就会加载。
按作者报告,在未经交互式信任的新目录里,Claude Code 不会加载这份目录配置。测试采用无界面运行方式,目录又是新建的,于是配置文件虽然存在,却没有进入运行流程。
修复只需要显式传入 --settings <file>,并在每次调用时都带上。配置加载后,hook 开始执行,审计记录也出现了。
排查过程中还暴露出两处不同层面的错误。
一处在测试执行器。作者把原始 shell 断言交给了一个会经由 agentpolicy CLI 分发命令的辅助函数,结果 bash ... 被当成 agentpolicy 的子命令解析并拒绝。表面看是测试失败,实际是命令交给了错误入口。
另一处在决策词汇。agentpolicy 用 escalate 表示需要人工介入,Claude Code 的权限语义则叫 ask。作者在策略里写了 decision: ask,配置解析器直接拒绝,并指出行列位置。
这里的 fail-closed,指配置无法正确解释时停止加载,而不是猜测含义后继续运行。它确实抓住了错误,但也说明,两个系统描述同一件事时,字段值未必通用。
不能把产品说明里的自然语言能力,直接当成配置枚举值。
审计记录怎样证明策略真的进了调用链
作者后来改变了验收依据:不再检查对话里有没有拒绝,而是检查 audit.ndjson 是否包含读取对应的 allow、生产写入对应的 escalation,以及破坏性操作对应的 deny。
这个做法成立,有一个明确前提:引擎每次执行评估,都会写入决策记录。在这套测试里,日志为空就说明没有发生评估;对话中的拒绝文字则可能来自其他机制。
作者还先把组件拆开验证:策略先通过 evaluate 单独跑通,hook 再通过管道输入 JSON 单独测试,最后才接入真实 Agent 循环。这样,组合后新增的故障就更容易定位到连接层。
最终报告记录的环境是 Claude Code 2.1.187,连接本机模型。测试捕获了六组 LLM 请求与响应,生成三条审计记录:allow_low_risk、escalate_prod_write、deny_critical_op。破坏性命令被带有策略理由的拒绝拦住,Agent 随后重新规划。
六组模型交互和三条审计记录统计的是不同事件,不能混为一个调用次数。
测试工具位于 scripts/fieldtest/,证据位于 field-test/v0.1.0/results/s18-tier1/cases/FT-T1-CLAUDE/。原文称配置、策略及捕获材料都随运行结果提交了,但没有给出更多模型信息。
我的判断
我认同作者把验收从「表现正确」推进到「决策来源可核对」。对接 AI 编程工具时,平台默认权限、沙箱和自建规则可能同时存在,只看最终对话,确实容易把别人的拦截算成自己的功劳。
但这份报告证明的是三个既定场景下,策略成功接入了调用链。它没有证明所有工具输入都被正确识别,也没有覆盖全部绕过路径。作者没有提供与其他策略方案的对照数据,不能据此判断 agentpolicy 的安全性或性能更好。
审计也有前提:必须确认检查的是本次运行的日志,且写入机制正常。日志条数能验证组件是否参与,具体决策内容才能验证它是否做对。
显式传入配置路径,是这次无界面集成测试里很实用的修复;至于所有环境是否都应采用同一种配置加载方式,原文没有展开。可直接迁移的是验证方法,不是把单次环境结论推广成通用规则。
能拿来做什么
- 给日常 AI 编程流程增加权限 hook 时,先准备允许、人工介入、拒绝三个固定场景,并核对对应审计决策,别只保存聊天截图。
- 在前端或 Node 项目的无界面测试中,明确传入策略和 hook 配置路径,并检查配置确实加载,避免依赖新目录尚未建立的信任状态。
- 对接两个系统时,先列出决策值映射,尤其核对
escalate与ask这类含义接近、取值不同的字段,再运行完整 Agent 流程。 - 排查集成故障时,按策略评估、JSON hook 输入、真实工具调用的顺序逐层验证,让每一步都有可以核对的输出。