[控场AI]
· 5 分钟阅读· 2,850 字

多Agent工具护栏:审批门与PII脱敏实战

多Agent工具护栏:审批门与PII脱敏实战

生产级工具调用Agent需三层护栏:默认拒绝策略、持久化审批门、验证式PII脱敏。

本文拆解了工具调用型Agent在生产环境中的三层安全护栏。首先,工具策略必须默认拒绝并与工具解耦,权限存在于工具和提示词之外,避免提示词注入扩大权限。其次,审批门应作为独立图节点,利用状态快照和恢复机制,确保暂停在进程重启后存活且不重复执行昂贵操作。第三,PII脱敏需通过Luhn和mod-97等算法验证匹配,并使用稳定占位符保留模型推理能力,同时承认其防护局限性。最后,通过确定性Mock LLM在CI中运行黄金用例测试,确保护栏不被意外绕过。

多Agent系统的演示往往在最有意思的部分戛然而止:主管Agent完成路由,工作Agent调用工具,然后工具就……做了点什么。在演示里,它是lookup_order;但在生产环境里,它可能是send_email或issue_refund。这时问题就变成了:谁有权按下那个按钮?谁又能在过程中看到客户数据?

本文基于一篇来自rss的技术文章,深入拆解工具调用型Agent应有的三层护栏:默认拒绝的工具策略、暂停并持久化的审批门、以及不破坏数据的PII脱敏。我们还会讨论如何在没有API Key的情况下测试这些机制。

多Agent工具护栏示意图

策略层:默认拒绝,且与工具解耦

第一原则是权限必须存在于工具和提示词之外。一个有bug或被注入的提示词,绝不能扩大自己的访问权限。原文给出的ToolPolicy类清晰地体现了这一点:evaluate方法接收租户和工具名,先检查工具是否在注册表中,再检查是否在租户的白名单里。

这里的关键设计是默认拒绝。一个空的allowed_tools意味着什么都不能调用。白名单忘记填充会安全失败(fail-safe),而黑名单忘记扩展则会危险地敞开(fail-open)。审批则是两个来源的逻辑或:工具作者可以将有副作用的工具标记为requires_approval=True,租户也可以在自己的approval_tools中添加更多工具。

注册一个带审批的工具只需一个装饰器:@registry.tool(description="Send an email.", requires_approval=True)。这种声明式的方式让安全策略成为代码的一部分,而不是散落在提示词或外部配置中。

审批门:暂停、持久化、恢复

“询问人类”听起来简单,直到你意识到运行必须停止、在进程重启后存活、并从正确的位置继续。原文指出了两个关键设计决策。

将审批门作为独立的图节点。 中断式暂停在恢复时会从第一行重新执行被中断的节点。如果暂停逻辑放在工作节点内部,你就会为工作节点的LLM调用付两次费。一个专用的tool_gate节点意味着唯一被重放的是廉价的策略检查。原文给出的图结构清晰地展示了worker与tool_gate之间的循环关系。

状态保持为纯JSON,并在每个节点后快照。 运行时内置了一个纯Python执行器,遵循与LangGraph相同的interrupt()契约:遇到需要审批的工具时,它抛出暂停,将{"state", "next", "interrupt"}写入检查点器,并返回审批请求。恢复时加载快照,带着人类的决定重新进入该节点。LangGraph是可选依赖,默认安装使用内置执行器加SQLite。

从调用方视角看,流程是:启动运行、获取暂停事件、检查待审批数据,然后调用resume(tenant, run_id, approved=True)。通过HTTP则是POST /v1/runs/{id}/approval,携带{"approved": true}。暂停载荷包含运行ID、工具名、参数和原因,让审批者确切看到自己在批准什么。

LangGraph 的 interrupt() 契约指的是:在节点函数中调用 interrupt() 会立即暂停图执行,并将当前状态保存到检查点;恢复时,图会从该节点重新开始执行,而不是从下一行继续。因此,被中断的节点必须能安全重放,且应尽量轻量。这正是原文强调审批门要独立成节点的原因——如果暂停逻辑放在工作节点内部,恢复时就会重新执行整个工作节点(包括昂贵的 LLM 调用),造成重复计费和副作用。LangGraph 通过检查点器(checkpointer)持久化状态,支持在进程重启后从断点恢复。

PII脱敏:别把订单号也吃掉

最天真的做法是用正则匹配“13到19位数字”来抓卡号。它也会把订单ID、时间戳和物流单号一并脱敏,你的Agent就废了。原文的解决方案是验证匹配:银行卡号必须通过Luhn算法,IBAN必须通过mod-97校验。

第二个技巧是稳定占位符。同一个值在单次运行中总是映射到同一个令牌,这样模型仍然能对其推理。例如,jane.doe@example.com会被替换为[EMAIL_1],映射表保留原始值。恢复操作只应在你的信任边界内进行。映射表本身是敏感数据,因为它包含原始值,必须作为静态数据对待。

原文也坦诚地指出:基于正则的检测器会漏掉一些东西(比如姓名和街道地址),所以脱敏是一层防护,而不是合规声明。

Luhn 算法(模10算法)是一种简单的校验和公式,用于验证银行卡号等标识符的有效性。它从最右侧数字开始,对偶数位数字加倍(若结果大于9则减9),然后将所有数字求和,若总和能被10整除则通过校验。IBAN 的 mod-97 校验则基于 ISO 7064 标准:将国家代码和校验位移至末尾,把字母转换为数字(A=10, B=11, …, Z=35),然后计算整个数字串对97取模,结果应为1。这两种校验能有效区分随机数字串和真实金融标识符,避免误伤订单号、时间戳等业务数据。

用黄金用例测试护栏

没有测试,这一切都不可信。原文建议声明用例并断言运行最终状态和输出。YAML格式的黄金用例覆盖了多种场景:需要审批的邮件发送(期望状态awaiting_approval)、工具查找被拒绝(期望状态completed且输出不包含shipped)、注入被阻断(期望状态blocked:prompt_injection_blocked)、PII不被回显(输出不包含原始邮箱)、以及预算强制执行(期望状态failed:budget_exceeded)。

因为运行时接受确定性的Mock LLM,这些用例可以在CI中运行,无需网络或密钥。一个悄悄让未审批邮件通过的提示词改动,会让构建变红,而不是让客户愤怒。

打包版本与核心启示

所有这些都实现在Agent Forge Core中:一个用于构建工具型Agent的Python运行时,包含主管/工作编排、内置执行器加可选的LangGraph和CrewAI适配器、默认SQLite加可选Postgres、FastAPI服务、护栏(PII、注入检测、预算、工具策略)、成本追踪和黄金用例评估运行器。它采用MIT许可供自用,禁止转售,并提供30天退款保证。

无论你基于什么构建,值得保留的操作顺序是:默认拒绝、副作用前暂停、模型看到之前脱敏、在事故之前写好测试。

#多Agent工具护栏#Human-in-the-loop审批#PII脱敏#工具调用安全#默认拒绝策略#Agent运行时#黄金用例测试
分享:

相关推荐