Skip to main content

护栏要做在基础设施层

给 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 的"致命三要素"):

  1. 会读到不可信内容(网页、邮件、用户上传的文档)
  2. 能接触敏感数据
  3. 能改变状态或对外通信

规则本体不是"三者齐全要确认",而是更严格的数量约束:一个会话在同一时刻至多具备其中两项,才可以无监督运行;一旦三项同时成立,就必须人在回路。

换成工程口径:如果这个 Agent 会读外部内容、又能碰到内部数据、还能发消息或写库,那它就不能自主跑——要么砍掉一项能力(比如把写操作拆到另一个不带读取权限的 Agent),要么每个动作都确认。三者齐全意味着一次成功的提示注入就能造成实际损害,而注入是拦不干净的,只能靠限制能力组合来兜底。

还有一个经常被漏掉的点:沙箱是最底层的护栏。审批弹窗可以被绕过(用户点了"总是允许"),提示词可以被说服,只有"这个进程根本读不到那个目录、连不上那个网段"是绕不过去的。能沙箱就沙箱,审批是第二道。

顺带一条容易被忽略的:写入 Agent 的记忆也是特权操作。因为记忆会影响后续所有决策,往记忆里塞一条假信息,比一次错误的工具调用更持久。这一点在《记忆不等于上下文》里还会提到。

7. 兜底:kill switch​

无论前面做得多好,都要有一个能立刻停下的开关:

  • 随时可用,不受 Agent 当前状态影响
  • 触发后立即停止执行、撤销在途操作
  • 日志防篡改,事后能复盘

以及一个设计原则:撤销能力要提前规划。执行前就想清楚这个动作怎么撤回;想不清楚的动作,就不该给 Agent 自主执行权。

8. 检查清单​

  • 危险动作的执行入口有没有一个模型无法伪造的批准信号
  • 未知工具是不是默认从严
  • 超时是拒绝还是放行
  • 批准是否绑定了具体参数
  • 审批界面有没有过滤 Agent 自己写的紧迫性话术
  • 有没有 kill switch 和撤销路径

这几条里最容易漏的是最后一条。它没有出事时完全看不出价值,出事时是唯一的止损手段——和《给大模型链路装仪表》里"两分钟内拿到 trace"是同一类投入:平时是成本,出事时是底线。