Agent硬规则应落在工具执行代码里
系统提示词无法可靠强制执行退款上限等业务约束,关键规则需要在模型调用工具前由代码校验。文章提出输入、工具、输出及人工升级四层防护,强调将行为引导与权限执行分开。
AI 深度解读
把「退款超过 $500 必须经理批准」写进 system prompt,并不能保证 Agent 真会遵守。原文的核心主张是:提示词负责引导行为,代码里的护栏负责约束执行,尤其要在工具调用落地之前检查业务规则。
这篇短文的价值,是把 Agent 安全从「提示词怎么写」拉回「系统怎么设计」。不过,作者给的是示意代码和工程建议,没有攻击拦截率或误拦截率的实测数据,示例本身也有需要补齐的边界。
模型可以提议退款,执行权应该留在代码里
原文先给出一条常见的提示词规则:
IMPORTANT: Never issue refunds over $500. Always require manager approval.
它试图限制大额退款,并要求经理批准。要注意,Never 和 Always 只是文本里的措辞,并没有建立实际审批机制。
作者认为,提示注入、多轮对话和复杂边界情况,都可能让模型偏离这条要求。如果业务代码直接执行模型生成的工具调用,退款仍然可能发生。
模型生成了符合格式的调用,不等于这次操作获得了业务授权。
作者把护栏分成四个位置:输入端筛查提示注入、个人身份信息(PII)和偏离业务范围的滥用;工具端检查每次调用;输出端检查秘密、隐私和越权承诺;遇到不确定情况或触发规则时,转交人工处理。
其中,工具端最关键。输入筛查可能漏掉攻击,输出检查也可能发生得太晚。发送邮件、执行退款之前,才是阻止实际操作的关键关口。
工具调用前的检查,具体应该放在哪里
下面这段被作者称为「20 行」的示例,把退款和邮件规则集中起来,在执行工具之前逐条检查:
POLICIES = {
"issue_refund": [
lambda a, ctx: a["amount"] <= 500 or "Refund exceeds $500 limit",
lambda a, ctx: ctx.order_verified or "Order not verified",
],
"send_email": [
lambda a, ctx: a["to"] in ctx.customer_emails or "Recipient not on file",
],
}
def guarded_call(tool, args, ctx):
for rule in POLICIES.get(tool.name, []):
verdict = rule(args, ctx)
if verdict is not True:
log_policy_violation(tool.name, args, verdict)
return {"status": "blocked", "reason": verdict}
return tool.run(**args)
要重点看最后一行:tool.run(**args) 只有在前面的规则全部通过后才会执行。被拒绝的调用会记录原因,并返回 blocked。
这里检查了三件事:退款金额不超过 $500、订单已经核验、邮件收件人在客户地址列表中。即使模型坚持执行,也不能靠回复内容修改这些条件。
但示例并没有实现经理审批。超过 $500 的退款会直接被拒绝,没有「审批通过后放行」的路径。它也没有说明 ctx 中的订单状态和客户邮箱来自哪里;这些数据必须由可信的业务系统提供,才能成为有效的授权依据。
护栏要同时证明拦得住,也放得过
作者建议,用攻击测试验证护栏,再把每次发现的问题变成长期保留的回归检查。
检查不能只停留在第一次交互。原文特别问到:攻击发生在第 1 轮和第 6 轮,规则是否都成立?换了模型之后是否还有效?拦下违规操作时,有没有误伤正常用户?
这对应两个需要分别统计的指标:
- 攻击请求拦截率,目标应接近 100%。
- 合法请求拦截率,目标应接近 0%。
这两个数字是作者提出的目标,不是已经测出的成绩。只追求高拦截率,很容易做出一个谁都用不了的 Agent。
原文还介绍了 BotGauge,称它能把策略用于评估、监控和防护,并通过自适应对抗场景测试边界。但文章没有提供测试集、效果数据或产品对照,这部分应按产品介绍理解。
我的判断
我认同把业务约束放在执行入口。相比继续堆叠提示词,这种做法能直接检查金额、订单状态和收件人等具体条件,拒绝原因也更容易追踪。提示词仍然有用,可以帮助模型理解规则、减少无效调用,但不能承担最终授权。
不过,作者所说的「提示词无法改变 guarded_call 允许什么」有前提:所有工具执行都必须经过这个入口,而且策略和上下文不能被模型随意修改。
示例还有一个明显缺口:POLICIES.get(tool.name, []) 对未登记工具返回空列表,随后会直接执行。新增工具却忘记配置策略,就可能绕过检查。生产实现需要明确决定:未知工具是否一律拒绝,以及参数缺失、类型错误时如何处理。
这是一份值得采用的设计原则,还不是可以直接上线的完整安全方案。
文章没有给出对照实验,无法据此判断四层护栏各自的收益,也不能认定某个产品优于自建检查。
能拿来做什么
- 在 Node Agent 的工具执行层建立统一入口,把模型提出的调用先交给业务策略检查,并确保每个工具都经过该入口。
- 为退款、发邮件等操作配置明确的授权条件;需要人工审批时,补上审批状态校验和转交流程,不能只在提示词里写一句要求。
- 把第 1 轮、第 6 轮攻击和正常请求加入回归用例,更换模型后重新验证同一组业务边界。
- 给拒绝操作记录原因,并分别统计攻击拦截率和合法请求误拦截率,避免靠扩大拒绝范围制造安全感。