当前位置: 首页 > news >正文

Agent Transfer:让 AI 把任务交给更合适的 AI

系列「企业级 AI Agent 实现拆解」E19 篇。上一篇 E18 讲了 ADK 的基础用法:ChatModelAgent、Runner、Interrupt/Resume。这篇聚焦 Multi-Agent 协作的核心问题——一个 Agent 怎么把任务交给另一个 Agent。ADK 提供了三种机制,但只有一种被官方推荐,另外两种留有明确的"NOT RECOMMENDED"注释。

读完这篇你会知道

  • 为什么需要 Agent Transfer:单 Agent 处理不了哪些场景
  • 三种协作机制:AgentTool(推荐)、SetSubAgents(不推荐)、Supervisor(不推荐)
  • AgentTool 的边界隔离:子 Agent 的 Exit/Transfer 动作为什么不传出来
  • Transfer 模式下对话历史怎么迁移:IsolatedSession 的设计
  • 确定性移交:DeterministicTransfer 的用法
  • 三种机制的实测对比

一、为什么一个 Agent 不够

单 Agent 处理任何问题有一个根本限制:上下文会越来越长

当你要求同一个 Agent 既搜索资料、又写代码、又做数学计算,历史消息越积越多,模型要在所有历史里找线索,注意力被稀释。而且,同一个系统 Prompt 很难同时把三个角色都交代清楚——“你是搜索员,也是程序员,也是数学家”——通常意味着什么都不精。

多 Agent 的核心价值就在这里:每个 Agent 只看自己需要的上下文,专注自己的职责


二、方案一(推荐):把 Agent 包装成工具

Eino 源码注释里明确写着(agent_tool.go:69):

// NewAgentTool creates a tool that wraps an agent for invocation.

用法:把一个子 Agent 包装成工具,父 Agent 通过普通的工具调用来"雇用"它。这是 ADK 官方唯一推荐的 Multi-Agent 模式

// 创建子 AgentresearchAgent,_:=adk.NewChatModelAgent(ctx,&adk.ChatModelAgentConfig{Name:"research_agent",Description:"the agent responsible to search the internet for info",Instruction:"You are a research agent...",Model:m,ToolsConfig:adk.ToolsConfig{...},})// 把子 Agent 变成一个工具researchTool:=adk.NewAgentTool(ctx,researchAgent)// 父 Agent 把这个"工具"加到自己的工具列表parentAgent,_:=adk.NewChatModelAgent(ctx,&adk.ChatModelAgentConfig{Name:"project_manager",Model:m,ToolsConfig:adk.ToolsConfig{ToolsNodeConfig:compose.ToolsNodeConfig{Tools:[]tool.BaseTool{researchTool,codeTool,reviewTool},},},})

从外部看,父 Agent 还是正常的 ReAct 循环,只是"工具"恰好是另一个 Agent。父 Agent 不关心子 Agent 内部怎么工作——它只是调用了一个名叫research_agent的工具,传入{"request": "find 2024 US GDP"}, 等待返回结果。

关键特性:动作边界隔离

子 Agent 内部可能触发 Exit、Transfer、BreakLoop 等动作,但这些动作不会传到父 Agent(源码agent_tool.go:90-93):

// Action Scoping: // - Interrupted: Propagated via CompositeInterrupt (interrupt/resume works across boundaries) // - Exit, TransferToAgent, BreakLoop: Ignored outside the agent tool

白话:子 Agent 想"结束任务",对它自己来说任务确实结束了,但父 Agent 只看到"这个工具调用完成了,返回了结果"。子 Agent 不能意外终止父 Agent 的执行流。唯一的例外是Interrupted(中断等待人工确认),这个会通过CompositeInterrupt传递出去,让整个系统都知道需要暂停等待用户。

Supervisor 预制模式

supervisor.New是 AgentTool 之上的一个预制封装(源码在adk/prebuilt/supervisor):

// eino-examples/adk/multiagent/supervisor/agent.go:192supervisorAgent,err:=supervisor.New(ctx,&supervisor.Config{Supervisor:sv,// 主控 AgentSubAgents:[]adk.Agent{searchAgent,mathAgent},// 子 Agent 列表})

supervisor.New自动把每个子 Agent 包装成AgentTool,注入到主控 Agent 的工具列表里。你只需要定义主控 Agent 的 Instruction(“你是项目经理,有两个下属……”),其余的工具调用由 ReAct 循环自动处理。


三、方案二(不推荐):LLM 驱动的 Agent 切换

这是另一套机制——让模型自己决定"我要交给哪个 Agent"。

// eino-examples/adk/intro/transfer/transfer.go:35a,err:=adk.SetSubAgents(ctx,routerAgent,[]adk.Agent{chatAgent,weatherAgent})

SetSubAgents做了两件事:

  1. 把子 Agent 的名字和描述告诉 Router Agent(注入到系统 Prompt)
  2. 给 Router Agent 加一个内置工具transfer_to_agent(参数:agent_name

执行时,RouterAgent 的模型看到用户问题,自己判断该交给谁,然后调用transfer_to_agent("WeatherAgent")——相当于给自己的下一步指路。

用户:"北京今天天气?" RouterAgent → 判断:这是天气相关 → 调用 transfer_to_agent(agent_name="WeatherAgent") WeatherAgent → 调用 get_weather(city="Beijing") → 返回结果

这个模式看起来自然,但 Eino 官方在源码里明确标注(utils.go:92-95):

// NOT RECOMMENDED: Agent transfer with full context sharing between agents has not // proven to be more effective empirically. Consider using ChatModelAgent with AgentTool // or DeepAgent instead for most multi-agent scenarios.

核心问题:全上下文共享。当 RouterAgent 的会话历史传给 WeatherAgent 时,WeatherAgent 要处理一堆它不需要的上下文(RouterAgent 的历史消息),既浪费 Token,又可能干扰判断。

上下文隔离机制

ADK 在实现 Transfer 时做了一个折中(deterministic_transfer.go:166)——创建IsolatedSession

isolatedSession:=&runSession{Values:parentSession.Values,// 共享 session values(键值对)valuesMtx:parentSession.valuesMtx,// Events: 不继承(默认为空)}

子 Agent 有独立的事件历史(不继承父 Agent 的全部消息),但共享session.Values(通过AddSessionValue/GetSessionValues存取的键值对)。这样可以在两个 Agent 间传递少量结构化状态,同时避免把全部对话历史扔过去。


四、方案三(不推荐):确定性移交

有时候移交目标不需要 AI 判断,就是固定的。AgentWithDeterministicTransferTo用于这个场景:

// 执行完 agentA,固定移交给 agentBwrappedA:=adk.AgentWithDeterministicTransferTo(ctx,&adk.DeterministicTransferConfig{Agent:agentA,ToAgentNames:[]string{"agentB"},})

执行完agentA的全部逻辑后,框架自动追加两条消息(assistant 说"我要移交给 agentB" + tool 确认消息),然后触发TransferToAgent动作,Session 流转到 agentB。

白话:这是硬编码的流水线——A 完事了一定交给 B,不经过任何 AI 决策。适合固定流程(“报告总结完毕,一定发给审阅 Agent”),不适合根据内容动态路由。

同样标注了 NOT RECOMMENDED,原因相同:全上下文共享。


五、三种方案一张表

AgentTool(推荐)SetSubAgentsDeterministicTransfer
路由决策者父 Agent 的 LLM(工具调用)Router Agent 的 LLM代码硬编码
上下文共享隔离(只传 request 字符串)全部共享(IsolatedSession 折中)全部共享
子 Agent 动作边界Exit/Transfer 不传出全部传出全部传出
适合场景绝大多数场景特定路由式场景固定流水线
官方立场✅ 推荐⚠️ 不推荐⚠️ 不推荐

六、完整示例:Supervisor 模式(AgentTool 推荐路径)

// eino-examples/adk/multiagent/supervisor/agent.go(精简)funcbuildSupervisor(ctx context.Context)(adk.Agent,error){sv,_:=adk.NewChatModelAgent(ctx,&adk.ChatModelAgentConfig{Name:"supervisor",Instruction:`You are a supervisor managing two agents: - a research agent: assign research-related tasks - a math agent: assign math-related tasks Do not do any work yourself.`,Model:m,Exit:&adk.ExitTool{},// 主控完成后用 exit 工具退出})searchAgent,_:=buildSearchAgent(ctx)// 有 search 工具的 AgentmathAgent,_:=buildMathAgent(ctx)// 有 add/multiply/divide 工具的 Agent// supervisor.New 内部自动 NewAgentTool 包装每个子 Agentreturnsupervisor.New(ctx,&supervisor.Config{Supervisor:sv,SubAgents:[]adk.Agent{searchAgent,mathAgent},})}

运行时发生的事:

用户:"Find US and NY GDP in 2024. What % of US GDP was NY?" 1. Supervisor 收到问题 2. Supervisor 决定:先搜索 → 调用 research_agent 工具,传入问题 3. research_agent 内部:搜索工具 → 返回 "US $29.18T, NY $2.297T" 4. Supervisor 收到搜索结果 5. Supervisor 决定:再计算 → 调用 math_agent 工具,传入数字 6. math_agent 内部:divide(2.297, 29.18) → 0.0787 7. Supervisor 汇总结果,调用 exit 工具,结束

主控 Agent 从未自己搜索或计算,只做"任务分配 + 汇总"。每个子 Agent 只看自己的 request,不知道其他 Agent 的存在。


七、对话历史怎么处理:一个实际问题

当子 Agent(AgentTool 模式)完成任务后,父 Agent 的对话历史里只有:

  • Tool 调用请求:{"tool": "research_agent", "input": {"request": "..."}}
  • Tool 返回结果:{"result": "US GDP was $29.18T..."}

子 Agent 内部的全部过程(搜索了哪些网页、中间想了什么)不进入父 Agent 的上下文。这是 AgentTool 的设计意图:结果传递,过程隔离

如果父 Agent 需要子 Agent 的中间事件(比如流式展示子 Agent 的思考过程),可以开启EmitInternalEvents

adk.ToolsConfig{EmitInternalEvents:true,// 子 Agent 的事件实时推送给 Runner 的消费者...}

注意:这些内部事件只推给外部消费者(UI 显示),不记录在父 Agent 的 runSession 里——父 Agent 的历史依然只有工具调用和结果,不会因此膨胀。


小结

AgentTool 是唯一被官方推荐的 Multi-Agent 模式,原因很简单:上下文隔离,边界清晰。父 Agent 通过 ReAct 工具调用驱动子 Agent,子 Agent 只看到自己的输入,不背负无关历史。supervisor.New是在 AgentTool 之上的预制封装,适合"主控 + 多专家"的常见结构。SetSubAgentsDeterministicTransfer虽然存在且功能可用,但源码里的 NOT RECOMMENDED 注释来自团队实测——在绝大多数场景下,AgentTool 效果更好,不要忽视这个提示。

下篇继续。


代码来源:cloudwego/eino · cloudwego/eino-examples

http://www.cnnetsun.cn/news/3018813.html

相关文章:

  • DSP56F826/827中断处理与SDK驱动开发实战指南
  • 【课程设计/毕业设计】基于 SpringBoot 的教学工作量台账管理统计系统的设计与实现 智能化教师教学工作量采集统计分析系统【附源码、数据库、万字文档】
  • LoRa转4G Cat1网关设计:低成本物联网数据传输方案
  • 基于DSP56F827的DTMF信号生成与检测嵌入式实践
  • CAT1 RTU工业物联网方案:双协议支持与硬件设计解析
  • Kimi LeetCode 3382. 用点构造面积最大的矩形 II Rust实现
  • 大模型幻觉防控四步法:从提示工程到人机协同实战指南
  • YOLO 部署到边缘设备:从 .pt 到 ONNX/TensorRT 全链路实战
  • GTA5线上小助手:3步轻松解锁终极游戏体验的完整指南
  • 黑色星期五折扣汇总:一个帮你省钱的开源项目
  • 从单核到多核异构:解析高性能嵌入式处理器架构与P5系列开发实战
  • 基于DPAA的USDPAA IPSecfwd:嵌入式Linux高性能IPSec转发实践
  • 终极解决方案:3步搞定Zotero中文文献识别难题的完整指南
  • 图的正负p-能量:从谱理论到3-能量下界证明
  • 终极指南:3步轻松安装HS2-HF Patch,打造完美HoneySelect2游戏体验
  • JenNet-IP协议栈:从6LoWPAN到MIB管理的物联网IP化通信实践
  • 2-伴随:连接高阶范畴与序结构的表示理论桥梁
  • 深度剖析Krita AI Diffusion:开源数字绘画与AI生成的无缝融合架构
  • 昆明市安宁市私人保镖在哪找比较靠谱
  • vSphere迁移史诗级避雷清单(含vMotion失败率TOP5原因):金融级生产环境验证的17项预检Checklist
  • 凸优化加速算法:原始对偶平均方法与精度证书的工程实践
  • AI智能体分类及其应用解析(3)
  • 半导体巨头ESG实践:从芯片设计到绿色制造的可持续竞争力
  • RDP Wrapper:让Windows桌面版变身多用户服务器的魔法工具
  • 四维流形连通和上的Weyl能量极小化与Bach平坦度量研究
  • 嵌入式系统PLL时钟配置:从原理到56852实战避坑指南
  • 【限时解锁】ESXi 8.0U2安装秘钥包:含ESXi-Boot-ISO定制工具、RAID驱动注入教程及HPE Gen10+固件补丁集
  • MCU硬件断点与实时追踪:S08DBGV3调试模块实战解析
  • ThinkPHP where方法SQL注入漏洞分析与复现:从表达式查询到exp利用
  • CSDN绕过multiPlatform发布