护栏要做在基础设施层
给 Agent 加护栏,最常见的做法是写进提示词:「不要执行删除操作」「重要操作前先询问用户」。
这不算护栏。提示词是建议,不是约束——模型这次遵守不代表下次遵守,而间接提示注入的存在意味着模型可能正在被攻击者的话术引导。OWASP 在 2026 版 LLM Top 10 里把 Excessive Agency 从第六位提到了第三位,根因就包括"把自主权交给了不该有的地方"。
真正的护栏有一条硬标准:Agent 在技术上无法绕过它。
1. Least Agency:先问要不要给自主权
最小权限原则(least privilege)说的是"能访问什么"。对 Agent 来说这不够,还要多一层:该不该让它自己决定(least agency)。
很多场景根本不需要自主。一个"查询订单然后生成回复"的流程,步骤是固定的,写成 workflow 即可——把它做成 Agent,等于凭空多出一个不可预测的执行路径,收益为零,风险不为零。这个判断标准在《Agent 和写死流程的差别》里讲过:步骤能不能提前枚举。
确定要给自主权之后,才谈下面这些。
2. 按动作分级,而不是按感觉
把 Agent 能做的动作按风险分档,每档对应一个固定的处理方式。这张表是静态配置,不是模型自己判断。
| 级别 | 例子 | 处理方式 |
|---|---|---|
| 只读 | 检索、查询、读取文件 | 自动执行 |
| 草稿 | 生成待发内容、创建草稿 | 自动执行,但结果可撤销 |
| 有副作用 | 提交表单、改状态、发内部消息 | 必须人工确认 |
| 不可逆 / 对外 | 付款、删除、对外发布、发邮件给外部 | 硬确认 + 延迟执行 + 完整审计 |
分级的三个判断维度:可逆性(能不能撤回)、影响范围(个人或系统级)、是否跨越组织边界(对外可见的动作一律从严)。
3. 确认要做在执行层
关键设计:检查点是基础设施层的门,不是提示词里的一句话。
实现上就是——危险动作的执行入口要求一个"已批准"的信号,这个信号不是模型能生成的:
const RISK = {
searchOrder: 'auto',
createDraft: 'auto',
submitOrder: 'confirm',
refund: 'confirm+delay',
}
async function runTool(name, args, ctx) {
const level = RISK[name] ?? 'confirm' // 未知工具一律从严
if (level === 'auto') return handlers[name](args)
const token = await approvals.issue({ name, args, userId: ctx.userId })
const ok = await approvals.waitFor(token, { timeout: 120_000 })
// 超时不执行——默认拒绝,不是默认放行
if (!ok) return { content: [{ type: 'text', text: '该操作未获批准,已取消' }] }
if (level === 'confirm+delay') await sleep(MANDATORY_DELAY)
return handlers[name](args)
}
几条要点:
未知工具默认从严。 白名单之外的工具一律需要确认,而不是默认放行。
超时等于拒绝。 这是默认值的方向问题:超时后不执行,比"没人反对就执行"安全得多。
批准要绑定具体参数。 批准的是"给张三退款 200 元",不是"批准退款操作"。参数变了,批准就失效——否则模型可以在批准后改参数。
4. 审批界面给什么
人在审批时看到的信息,决定了这次审批有没有意义。至少要给五样:
- 要执行的具体动作(不是摘要,是具体参数和对象)
- Agent 给的理由
- 本次会话里之前做过什么(上下文,否则无法判断这一步是否合理)
- 影响评估和可逆性(能不能撤回)
- 关键参数的明文确认(金额、对象、数量要单独列出让人确认)
有两条要防:
不要让 Agent 自己起草同意文本。 授权范围应该来自一份静态的能力清单,而不是 Agent 现场生成的描述——否则它可以把危险动作描述得很温和。
过滤掉 Agent 生成的紧迫性话术。 "情况紧急,请立即批准"这类表述不应该出现在审批界面上,它本质上是社交工程。
5. 审批疲劳是真实风险
人工审批有个已知失效模式:如果 95% 的审批请求都是正常的,人会开始无脑点通过。
对策是两条:
减少不必要的确认。 分级表要调准,别什么都问——这既是为了体验,也是为了保住那 5% 真需要看的确认的有效性。
监控审批行为。 会话级的审批速率限制;审批通过率显著高于历史基线时告警。Agent 不能批准自己的提权请求,这条要写死。
6. Rule of Two
有一条判断规则很好用,业界叫 Rule of Two(Meta 的 Agent 安全实践提出,思想源自 Simon Willison 的"致命三要素"):
- 会读到不可信内容(网页、邮件、用户上传的文档)
- 能接触敏感数据
- 能改变状态或对外通信
规则本体不是"三者齐全要确认",而是更严格的数量约束:一个会话在同一时刻至多具备其中两项,才可以无监督运行;一旦三项同时成立,就必须人在回路。
换成工程口径:如果这个 Agent 会读外部内容、又能碰到内部数据、还能发消息或写库,那它就不能自主跑——要么砍掉一项能力(比如把写操作拆到另一个不带读取权限的 Agent),要么每个动作都确认。三者齐全意味着一次成功的提示注入就能造成实际损害,而注入是拦不干净的,只能靠限制能力组合来兜底。
还有一个经常被漏掉的点:沙箱是最底层的护栏。审批弹窗可以被绕过(用户点了"总是允许"),提示词可以被说服,只有"这个进程根本读不到那个目录、连不上那个网段"是绕不过去的。能沙箱就沙箱,审批是第二道。
顺带一条容易被忽略的:写入 Agent 的记忆也是特权操作。因为记忆会影响后续所有决策,往记忆里塞一条假信息,比一次错误的工具调用更持久。这一点在《记忆不等于上下文》里还会提到。
7. 兜底:kill switch
无论前面做得多好,都要有一个能立刻停下的开关:
- 随时可用,不受 Agent 当前状态影响
- 触发后立即停止执行、撤销在途操作
- 日志防篡改,事后能复盘
以及一个设计原则:撤销能力要提前规划。执行前就想清楚这个动作怎么撤回;想不清楚的动作,就不该给 Agent 自主执行权。
8. 检查清单
- 危险动作的执行入口有没有一个模型无法伪造的批准信号
- 未知工具是不是默认从严
- 超时是拒绝还是放行
- 批准是否绑定了具体参数
- 审批界面有没有过滤 Agent 自己写的紧迫性话术
- 有没有 kill switch 和撤销路径
这几条里最容易漏的是最后一条。它没有出事时完全看不出价值,出事时是唯一的止损手段——和《给大模型链路装仪表》里"两分钟内拿到 trace"是同一类投入:平时是成本,出事时是底线。