
工具结果被拦住了,为什么操作还是发生了?
一次工具调用,先留下一条 executed,随后又留下一条 blocked。如果界面只显示最后一个词,用户很容易以为这次操作根本没有发生。
在我们的隔离实验里,工具确实运行了一次。被拦住的是随后返回的内容。
这不是前后矛盾。它说明“阻断”需要一个宾语:阻断调用、阻断结果流出,还是阻断后续处理?如果把它们压成一个总状态,治理越细,用户反而越难判断现场。
一个允许调用的工具,仍可能返回不该流出的内容
AG2 是一个用于构建 Agent 应用的开源框架。#3240提出在工具执行后增加输出扫描:调用本身合法,也可能从文件、数据库或外部接口取回敏感信息。因此,输入检查不能替代返回值检查。
这个设计边界是合理的。输出扫描只有拿到结果后才能判断内容;但它没有倒转时间的能力,不能把已经发生的工具动作撤回。
我们固定了该 PR 的提交 bf363ef52853e7b918863dec2fe1e3902b811e6f,运行原中间件的工具执行入口。研究时 PR 尚未合并。实验使用公开测试中已有的合成敏感值,没有真实凭据。
先确认“拦住了什么”
第一组配置选择强制执行模式。工具返回一个密钥形状的字符串,中间件识别后把结果替换为治理错误。
我们设置的执行计数器增加到一。回执先记录执行发生,再记录输出被阻断。最终返回对象不含那段合成密钥。
这组观察支持两项事实:该分支完成了返回值阻断,工具调用也已经发生。它没有证明业务写入、网络请求或模型上下文,因为测试工具只是计数夹具,框架事件外壳也由研究脚本提供。
对真实业务的启示是推断:如果工具本身已经产生外部效果,结果扫描失败不能作为“重新调用不会重复动作”的依据。是否可以重试,需要由动作自己的幂等或查询合同回答。
八组对照:模式与返回容器都会改变边界
我们保留原策略、检测、改写与回执逻辑,替换 AG2 框架导入的事件外壳,经过原 on_tool_execution。两轮独立进程分别运行八组输入。
| 条件 | 工具运行 | 返回值中的合成敏感内容 | 回执序列 |
|---|---|---|---|
| 强制模式,成功文本含密钥 | 1 | 被阻断 | executed → blocked |
| 监测模式,同样文本 | 1 | 被脱敏 | executed → executed |
| 观察模式,同样文本 | 1 | 原样保留 | executed |
| 强制模式,错误对象含密钥 | 1 | 原样保留 | error |
| 标记策略,同样文本 | 1 | 保留,有检测记录 | executed → executed |
| 强制模式,密钥位于结构化值 | 1 | 被阻断 | executed → blocked |
| 强制模式,密钥位于结构化键 | 1 | 原样保留 | executed |
| 强制模式,SSN 位于结构化字符串值 | 1 | 被脱敏 | executed → executed |
图 1:依据本文已保存观测绘制的实验逻辑示意;箭头表示本图标明的处理关系,不是实际运行截图。来源:随文实验附件。
两轮结果一致。观察模式和标记策略本来就允许内容通过,不能称为安全绕过。监测模式下,原本要求阻断的命中会降为脱敏;因此也不能简单理解为“凡是不强制阻断就完全不处理”。
成功结果、错误对象和字典键,是不同的入口
原代码对成功结果中的文本部分和结构化字符串值进行扫描。错误对象直接返回;遍历字典时读取的是值,不是键。
所以,同一段合成内容从成功文本换到错误对象,检测结果就变了。把它放进字典键,也不会经过这条扫描路径。
这并不自动证明实际模型收到了秘密。真实框架可能在其他位置处理错误、转换数据或限制内容类型;本轮没有运行那一层。但它已经说明,讨论“输出是否经过治理”时,不能只测试正常的文本返回。
一张实用的覆盖表应列出文本、结构化值、键、错误和其他容器,再区分每种模式下是扫描、脱敏、阻断还是原样通过。只有先把合同列清,才能判断某个未处理分支是显式设计还是应修缺口。
回执也需要说明它描述哪一段
executed → blocked 可以精确表达“工具运行了,返回内容被扣留”。如果消费者把最后一条回执当成整次动作状态,这个精确信息就会丢失。
同样,executed → executed 也不一定代表运行了两次。在我们的监测和标记场景中,计数器仍然只有一,第二条回执来自输出治理的记录。
因此,回执数量不能直接等于工具次数。建议把调用身份、记录阶段、是否执行、内容是否允许流出分别展示;输出被扣留时,应让用户知道动作是否已发生,而不是只看见一个笼统的“失败,请重试”。
这是从实验提出的设计建议,不是已实现的统一回执合同。随文证据说明保存原模块哈希、八组观测与替代依赖;真实 Agent、消息序列化、模型上下文和外部效果未测。
工具入口回答“能不能做”。输出检查回答“做完以后,哪些信息能继续流动”。两者都重要,正因为它们不能替彼此回答。