Skip to content

AgentTool 子调用工具泄露问题分析 #2219

Description

@Flash-LHR

现象

主 agent 注册了若干外部工具,子 agent 只注册了一个普通工具。

主 agent 通过 AgentTool 调子 agent 时,子 agent 明明只配置了自己的工具,却在模型请求上下文里看到了主 agent 的外部工具。

根因

AgentTool 创建子 invocation 时使用了:

parentInv.Clone(...)

Invocation.Clone 会复制父 invocation 的:

RunOptions

父 run 中由 AG-UI 注入的外部工具会进入:

RunOptions.ExternalTools

子 invocation 继承后,LLM flow 又会把这些外部工具追加到子 agent 的模型请求里:

AG-UI input.Tools
  -> RunOptions.ExternalTools
  -> AgentTool parentInv.Clone(...)
  -> child invocation.RunOptions.ExternalTools
  -> LLM flow append tools
  -> 子 agent 看到外部工具

影响范围

父 agent 静态注册工具不受影响,子 invocation 切到子 agent 后,基础工具面来自子 agent 自己的 Tools()。问题范围集中在父 invocation RunOptions 继承下来的工具字段。

受影响字段如下。

字段 影响
ExternalTools 外部工具会进入子 invocation,是本次问题的主链路
AdditionalTools run 级别追加的外部工具也会进入子 invocation
ExternalToolNames 外部工具的派生状态会进入子 invocation
ToolFilter 父工具过滤器会进入子 invocation,并在子流程工具过滤阶段被使用

源码确认的路径如下。

路径 行为
普通 AgentTool 会继承父 RunOptions,当前没有清理外部工具字段,是本次问题触发点
DynamicTool 会通过 Clone 派生子 invocation,随后清理 AdditionalToolsExternalToolsExternalToolNamesToolFilter
Explorer 会继承父 invocation,随后清理 ExternalToolsExternalToolNamesToolFilter,保留 AdditionalTools
Graph AgentNode 会继承父 ExternalTools,测试明确要求 parent external tools 先于 node-scoped external tools 出现在子 invocation
Team 会通过 Clone 派生成员 invocation,继承父 RunOptions
ChainAgent / CycleAgent / ParallelAgent 会通过 Clone 派生子 agent invocation,继承父 RunOptions
transfer_to_agent 会通过 Clone 派生目标 agent invocation,继承父 RunOptions

结论

普通 AgentTool 子调用 clone 了父 invocation 的 RunOptions,但没有清理外部工具面,导致父 run 注入的外部工具暴露给子 agent。

修复建议

方案一 修改默认行为

普通 AgentTool 创建子 invocation 时默认清理父 invocation 继承下来的外部工具字段。

RunOptions.AdditionalTools = nil
RunOptions.ExternalTools = nil
RunOptions.ExternalToolNames = nil
RunOptions.ToolFilter = nil

这个方案可以直接修复所有普通 AgentTool 调用场景,更符合语义直觉。语义上把子 agent 作为独立工具边界,子 agent 默认只看到自己定义的工具。

方案二 新增 option

保持当前默认行为,新增一个 AgentTool option 显式控制外部工具隔离,形式类似已有的 WithPinModel(true)

示例命名如下。

WithPinExternalTools(true)

开启后清理父 invocation 继承下来的外部工具字段。

RunOptions.AdditionalTools = nil
RunOptions.ExternalTools = nil
RunOptions.ExternalToolNames = nil
RunOptions.ToolFilter = nil

这个方案兼容性更稳,调用方可以逐个 AgentTool 启用隔离。

回归测试

至少补三类测试:

  1. 父 invocation 有 ExternalTools,子 agent 模型请求不应看到。
  2. 父 invocation 有 AdditionalTools,子 agent 模型请求不应看到。
  3. 父 invocation 有 ToolFilter,不应误过滤子 agent 自身工具。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions