中文资讯 掘金 AI Fri, 21 Aug 2026 正文 ok 973 words

两个 Agent 如何协作:Host-Worker 模式(第91篇-E77)

英文标题:两个 Agent 怎么协作:Host-Worker 模式(第91篇-E77)

本文对比了两种多 Agent 协作方式:Eino 的 Host MultiAgent 将 specialist Agent 注册为 tool,由 host LLM 通过 tool call 决定分派;DeepFlux 则将 subagent 作为 workflow 中可编排的步骤执行。Eino 支持单意图直接返回、多意图汇总以及 host 直接回答三条路径,并通过 HandOff 回调观测任务交接。DeepFlux 的 subagent 会接收图状态 JSON、调用外部 Agent,并将结果回写 workflow 状态,还支持在子 Agent 工具调用阶段进行 HITL 审批中断。对开发者而言,对话式任务更适合 Host MultiAgent,DAG 工作流编排更适合 DeepFlux subagent,而通用的 Agent 封装调用可使用 AgentTool。
打开原文相关 4 · 机会 2
media3.2 KB media589 B media5.4 KB

中文

Part 16 开篇。前面 15 个 Part 讲的是一个 Agent 怎么做安全、怎么加记忆、怎么接知识库——但单个 Agent 的注意力是有限的。一个 Agent 面对“帮我查北京天气、订机票、比价酒店”这种多维度任务,会在上下文里来回跳,工具一多就乱。这篇回答一个问题:两个 Agent 怎么协作——Host-Worker 模式,主 Agent 分派、子 Agent 执行,注意力该拆给谁。

两个问题串全篇:

  1. Eino 的 Host MultiAgent 怎么让 host LLM 把 specialist 当 tool 调?(分派机制)
  2. DeepFlux 的 subagent 步怎么把子 Agent 嵌入 workflow?(嵌入式调用)

(一)Eino Host MultiAgent:把 Agent 当 Tool 调

eino/flow/agent/multiagent/host/compose.go 核心只有 335 行。一句话概括:host LLM 把每个 specialist 看成一个 tool,tool 名就是 specialist 名,tool 描述就是 specialist 的职责声明。

先看怎么注册(compose.go:84-105):

agentTools := make([]*schema.ToolInfo, 0, len(config.Specialists))
for i := range config.Specialists {
    specialist := config.Specialists[i]
    agentTools = append(agentTools, &schema.ToolInfo{
        Name: specialist.Name,
        Desc: specialist.IntendedUse,
        ParamsOneOf: schema.NewParamsOneOfByParams(map[string]*schema.ParameterInfo{
            "reason": {Type: schema.String, Desc: "the reason to call this tool"},
        }),
    })
}

Name 和 IntendedUse 来自 AgentMeta(types.go:130-134):

type AgentMeta struct {
    Name        string
    IntendedUse string
}

这个设计很干净:IntendedUse 就是 specialist 的“简历”——host LLM 不需要知道 specialist 内部怎么实现,它只需要知道“这个 agent 能干什么”。和普通 tool 的区别是:普通 tool 是确定性函数(如查询天气 API),specialist 则是完整的 Agent(拥有自己的 LLM、工具链和推理循环)。

整个 Graph 的拓扑(compose.go:49-151,用节点名标注):

START → Host(ChatModel) → Branch(有 tool_call?)
                              ├─ 否 → END(直接回答)
                              └─ 是 → converter → MultiBranch(哪个 specialist?)
                                                    ├─ weather → collector → AfterBranch
                                                    ├─ flight  → collector → AfterBranch
                                                    │          单意图 → single_answer → END
                                                    │          多意图 → map2list → Summarizer → END
                                                    └─ hotel   → collector → AfterBranch

关键节点:

  • Host(addHostAgent, :187-203):就是带 tool list 的 ChatModel,system prompt 默认是 "decide which tool is best for the task and call only the best tool."
  • directAnswerBranch(:205-220):检查 host 输出中有没有 tool call;没有则直接进入 END——由 host 自己回答。
  • multiSpecialistsBranch(:222-244):读取 tool call 的 function name,匹配到对应的 specialist 节点;如果同时出现多个 tool call,则标记 isMultipleIntents=true。
  • specialist 节点(addSpecialistAgent, :154-185):每个 specialist 可以是一个 ChatModel,也可以是任意 Invokable/Streamable,例如 react.Agent。
  • multiIntentSummarizeNode(:286-335):多意图时汇总各 specialist 结果。如果配置了 Summarizer 则使用 LLM 汇总,否则直接拼接。

Demo(/tmp/e91demo,使用纯标准库复刻核心路由逻辑)通过三组 specialist 验证分派:

====== 场景 A:Host MultiAgent · 注册 tool 清单 ======
  tool: weather    desc: 查询天气信息,包括温度、湿度、降水概率
  tool: flight     desc: 查询航班信息,包括航班号、起降时间、延误情况
  tool: hotel      desc: 查询酒店信息,包括价格、房型、评分

====== 场景 B:单意图路由(只调天气)======
  host 决策: 调 weather
  specialist 结果: 北京今天晴,22°C,湿度 45%
  单意图=true 多意图=false 直接回答=false

====== 场景 C:多意图路由(同时调天气和航班)======
  host 决策: 调了 2 个 specialist
  [weather]: 北京今天晴,22°C,湿度 45%
  [flight]: CA1234 北京→上海 08:00-10:30 准点
  汇总结果: [weather]: 北京今天晴,22°C,湿度 45%
[flight]: CA1234 北京→上海 08:00-10:30 准点
  单意图=false 多意图=true 直接回答=false

====== 场景 D:无匹配 → host 直接回答 ======
  host 决策: 无匹配 specialist
  host 直接回答: host direct: 我无法处理这个请求
  单意图=false 多意图=false 直接回答=true

三种路径分别是:single intent(直接返回)、multi intent(汇总)和 direct answer(host 自己回答)。实际 Eino 中,host LLM 的 tool call 决策比 Demo 的关键词匹配复杂得多,但从骨架上看就是这三个分支。

HandOff 回调:观测“谁交给了谁”

callback.go 定义了 MultiAgentCallback.OnHandOff,每次 host 将任务交给 specialist 时都会触发:

type HandOffInfo struct {
    ToAgentName string
    Argument    string
}

这给观测层提供了一个干净的切面:不需要翻查 tool call 日志,直接查看 handoff 事件,就能知道“host 把什么任务交给了谁”。

(二)DeepFlux Subagent:把 Agent 嵌入 Workflow

Eino Host MultiAgent 是“Agent 之间的对话”——host 和 specialist 都是独立 Agent,通过 tool call 通信。DeepFlux 则走另一条路:subagent 是 workflow 中的一个步骤。

orchestration/domain/model/workflow.go:26-35 定义了六种步骤类型:

type StepKind string
const (
    StepKindTask     StepKind = "task"
    StepKindApproval StepKind = "approval"
    StepKindSubagent StepKind = "subagent"
    StepKindSleep    StepKind = "sleep"
    StepKindMap      StepKind = "map"
    StepKindForeach  StepKind = "foreach"
)

subagent 步的核心是 subagentLambda(einoexec/subagent.go:64-161),流程分为四步:

  1. 读取图状态:workflow 的图共享状态 → JSON,这就是子 Agent 的上下文。
  2. Agent First 指令:step.Input 有值时,将其作为 agent 指令并附加状态 JSON;为空时,则回落到纯状态 JSON,以兼容旧版 WorkflowDef。
  3. 通过 AgentInvoker 闭包调用:装配根注入的闭包,同步调用 agent BC 的 RunSubAgentHandler.RunSync。
  4. 将结果写回图状态:子 Agent 输出 → state.Data[step.Ref]。

Demo 的场景 E 验证了这个流程:

====== 场景 E:DeepFlux Subagent 步 · 图状态传递 ======
  step.Input: 根据用户查询,返回天气信息
  step.Ref: weather_agent
  子 agent 输出: [weather_agent 执行结果] 北京晴 22°C (收到上下文 142 字节)
  图状态[weather_agent]: [weather_agent 执行结果] 北京晴 22°C (收…

====== 场景 F:Agent First · step.Input 为空时回落纯状态 JSON ======
  step.Input 为空,回落纯状态 JSON
  子 agent 输出: [flight_agent 执行结果] 北京晴 22°C (收到上下文 178 字节)

场景 E 和 F 的区别在于:E 有 step.Input,子 Agent 收到的是 "根据用户查询,返回天气信息\n\n[上游状态]\n{...}";F 没有 step.Input,子 Agent 收到的是纯状态 JSON。输入大小差异(142 与 178 字节)反映了这一差异。

HITL 审批门:子 Agent 也能被叫停

subagent 步并不是简单地“调用完成即结束”。子 Agent 内部的 pre-tool hook 可以请求中断(subagent.go:129-144),触发 ErrSubagentInterrupt → Eino 中断 → Run 进入 SUSPENDED 状态。resume 时:

  • 批准 → per-tool 定向放行(V5):只放行已批准的那一次工具调用,已执行的调用不会重跑。
  • 拒绝 → 写入 denied 标签供下游 Branch 分流,run 不会被终止。

这个审批门与 approval 步复用同一套 suspend/resume 机制,但语义不同:approval 步是“整个步骤等待人工审批”,而 subagent 审批门是“子 Agent 的某一次工具调用等待人工审批”。

(三)两种模式,一张表

维度 Eino Host MultiAgent DeepFlux Subagent
通信方式 host LLM 产出 tool call → specialist 节点 图状态 JSON → AgentInvoker 闭包
specialist 是什么 图的节点(ChatModel 或 Agent) 外部 agent config(独立 session)
host 的角色 也是 LLM,自己做决策 workflow 引擎(编译器 + 图执行)
上下文传递 消息列表(messages) 图状态(map[string]string)→ JSON
多 specialist 并行调用 + summarizer 汇总 顺序步骤(DAG 编排)
中断/审批 无内置 HITL 子 agent 内 pre-tool hook 可中断
适用场景 对话式多 Agent 协作 工作流式多 Agent 编排

Host MultiAgent 适合“对话式”场景:用户说一句话,host 判断该找谁,找完之后返回结果。host 和 specialist 是平等的 Agent,只是职责不同。

DeepFlux subagent 适合“工作流式”场景:多个步骤按照 DAG 执行,subagent 只是其中一步;前面可能有 task 步进行数据预处理,后面可能有 approval 步等待人工审批。

(四)Eino ADK 的另外两种多 Agent 模式

除了 Host MultiAgent,Eino ADK 还提供两种多 Agent 模式,但文档均标注为 NOT RECOMMENDED。

Supervisor(adk/prebuilt/supervisor/supervisor.go)

该模式建立在 agent transfer 之上,supervisor 与 sub-agents 共享完整上下文。sub-agents 只能与 supervisor 通信,不能彼此直接通信。源码注释直言:

Supervisor is built on agent transfer with full context sharing, which has not proven to be more effective empirically. Consider using ChatModelAgent with AgentTool or DeepAgent instead.

AgentTool(adk/agent_tool.go)

该模式将任意 Agent 包装为一个 tool(NewAgentTool),使另一个 Agent 可以直接调用它。这是 ADK 推荐的替代方案:不使用 transfer 共享上下文,而是像调用普通 tool 一样调用子 Agent——子 Agent 拥有独立的 session 和 checkpoint。

AgentTool 的设计与 Host MultiAgent 中的 specialist 本质上是同一思路:Agent 就是 Tool。区别在于,AgentTool 更底层,可以作为任意 Agent 的 tool;Host MultiAgent 则是更高层的封装,自带 Graph 编排。

小结

问题 答案 关键源码
Host 怎么分派 specialist 注册为 tool(Name + IntendedUse → ToolInfo),host LLM 产出 tool call 匹配 host/compose.go:84-105
specialist 怎么执行 作为 Graph 节点,前置 handler 将消息注入 state,结果经 collector 汇聚 host/compose.go:154-185
单意图 vs 多意图 单意图直接返回,多意图标记后进入 summarizer 汇总 host/compose.go:222-335
DeepFlux subagent 怎么嵌入 作为 workflow 步类型,图状态 JSON → AgentInvoker 闭包 → 结果写回 einoexec/subagent.go:64-161
上下文怎么传 Host MultiAgent 使用消息列表,DeepFlux 使用图状态 JSON subagent.go:104-117
Agent First 是什么 step.Input 有值 → 作为 agent 指令并附加状态;为空 → 回落纯状态 JSON subagent.go:112-117
什么时候用哪个 对话式 → Host MultiAgent;工作流式 → DeepFlux subagent;通用 → AgentTool 三种模式对比

几条设计判断:

  • **Agent 就是 Tool。**Host MultiAgent 和 AgentTool 都在做同一件事:将 Agent 包装成可调用工具。区别在于,Host MultiAgent 自带 Graph 编排,AgentTool 则是留给调用方自行组装的裸 tool。
  • **IntendedUse 是 specialist 的“简历”。**host LLM 不需要知道 specialist 内部有什么工具、什么 prompt,只需要知道“这个 agent 能干什么”。这与人类团队分工相同——不需要知道同事如何完成工作,只需要知道应将任务交给谁。
  • **上下文传递方式决定耦合度。**消息列表(Host MultiAgent)是松耦合:host 和 specialist 各自维护自己的上下文。图状态 JSON(DeepFlux)则是紧耦合:subagent 能获得 workflow 的完整状态,但状态结构变化也会影响所有步骤。
  • **ADK 文档的诚实标注值得注意。**Supervisor 和 DeterministicTransfer 都标注了 NOT RECOMMENDED,并提供替代方案(AgentTool/DeepAgent)。这并非“功能不好用”,而是“经验证明这个方向不如另一种方案”——工程文档中很少见到这种坦诚表达。

下一篇(E92)将拆解 MultiAgent Host 源码,以及 ADK prebuilt 的 supervisor、planexecute、deep 三种预制模式——从“怎么用”深入到“内部怎么实现”。E93 将讲解 Agent 间的 Transfer 交接,即用户如何在不同 Agent 之间无缝切换。

English / 原文

Part 16 开篇。前面 15 个 Part 讲的是一个 Agent 怎么做安全、怎么加记忆、怎么接知识库——但单个 Agent 的注意力是有限的。一个 Agent 面对"帮我查北京天气、订机票、比价酒店"这种多维度任务,会在上下文里来回跳,工具一多就乱。 这篇回答一个问题:两个 Agent 怎么协作 ——Host-Worker 模式,主 Agent 分派、子 Agent 执行,注意力该拆给谁。

两个问题串全篇:

  1. Eino 的 Host MultiAgent 怎么让 host LLM 把 specialist 当 tool 调?(分派机制)
  2. DeepFlux 的 subagent 步怎么把子 Agent 嵌入 workflow?(嵌入式调用)

(一)Eino Host MultiAgent:把 Agent 当 Tool 调

eino/flow/agent/multiagent/host/compose.go 核心只有 335 行。一句话概括:host LLM 把每个 specialist 看成一个 tool,tool 名就是 specialist 名,tool 描述就是 specialist 的职责声明 。

先看怎么注册(compose.go:84-105):

agentTools := make([]*schema.ToolInfo, 0, len(config.Specialists))
for i := range config.Specialists {
    specialist := config.Specialists[i]
    agentTools = append(agentTools, &schema.ToolInfo{
        Name: specialist.Name,        
        Desc: specialist.IntendedUse, 
        ParamsOneOf: schema.NewParamsOneOfByParams(map[string]*schema.ParameterInfo{
            "reason": {Type: schema.String, Desc: "the reason to call this tool"},
        }),
    })
}

Name 和 IntendedUse 来自 AgentMeta(types.go:130-134):

type AgentMeta struct {
    Name        string 
    IntendedUse string 
}

这个设计很干净:IntendedUse 就是 specialist 的"简历" ——host LLM 不需要知道 specialist 内部怎么实现,它只需要知道"这个 agent 能干什么"。和普通 tool 的区别是:普通 tool 是确定性函数(查天气 API),specialist 是完整的 Agent(有自己的 LLM + 工具链 + 推理循环)。

整个 Graph 的拓扑(compose.go:49-151,用节点名标注):

START → Host(ChatModel) → Branch(有 tool_call?)
                              ├─ 否 → END(直接回答)
                              └─ 是 → converter → MultiBranch(哪个 specialist?)
                                                    ├─ weather → collector → AfterBranch
                                                    ├─ flight  → collector → AfterBranch
                                                    │          单意图 → single_answer → END
                                                    │          多意图 → map2list → Summarizer → END
                                                    └─ hotel   → collector → AfterBranch

关键节点:

  • Host (addHostAgent, :187-203):就是带 tool list 的 ChatModel,system prompt 默认 "decide which tool is best for the task and call only the best tool."
  • directAnswerBranch (:205-220):检查 host 输出有没有 tool call,没有就直接 END——host 自己回答了
  • multiSpecialistsBranch (:222-244):读 tool call 的 function name,匹配到对应的 specialist 节点;如果多个 tool call 同时出现,标记 isMultipleIntents=true
  • specialist 节点 (addSpecialistAgent, :154-185):每个 specialist 可以是一个 ChatModel,也可以是任意 Invokable/Streamable(如 react.Agent)
  • multiIntentSummarizeNode (:286-335):多意图时把各 specialist 结果汇总。有 Summarizer 配置就用 LLM 汇总,否则纯拼接

demo(/tmp/e91demo,纯标准库复刻核心路由逻辑)用三组 specialist 验证分派:

====== 场景 A:Host MultiAgent · 注册 tool 清单 ======
  tool: weather    desc: 查询天气信息,包括温度、湿度、降水概率
  tool: flight     desc: 查询航班信息,包括航班号、起降时间、延误情况
  tool: hotel      desc: 查询酒店信息,包括价格、房型、评分

====== 场景 B:单意图路由(只调天气)======
  host 决策: 调 weather
  specialist 结果: 北京今天晴,22°C,湿度 45%
  单意图=true 多意图=false 直接回答=false

====== 场景 C:多意图路由(同时调天气和航班)======
  host 决策: 调了 2 个 specialist
  [weather]: 北京今天晴,22°C,湿度 45%
  [flight]: CA1234 北京→上海 08:00-10:30 准点
  汇总结果: [weather]: 北京今天晴,22°C,湿度 45%
[flight]: CA1234 北京→上海 08:00-10:30 准点
  单意图=false 多意图=true 直接回答=false

====== 场景 D:无匹配 → host 直接回答 ======
  host 决策: 无匹配 specialist
  host 直接回答: host direct: 我无法处理这个请求
  单意图=false 多意图=false 直接回答=true

三种路径:single intent(直接返回)/ multi intent(汇总)/ direct answer(host 自己回答)。实际 Eino 中 host LLM 的 tool call 决策比 demo 的关键词匹配复杂得多,但骨架上就是这三个分支。

HandOff 回调:观测"谁交给了谁"

callback.go 定义了 MultiAgentCallback.OnHandOff,每次 host 把任务交给 specialist 时触发:

type HandOffInfo struct {
    ToAgentName string 
    Argument    string 
}

这给观测层提供了一个干净的切面:不用翻 tool call 日志,直接看 handoff 事件就知道"host 把什么任务交给了谁"。

(二)DeepFlux Subagent:把 Agent 嵌入 Workflow

Eino Host MultiAgent 是"Agent 之间的对话"——host 和 specialist 都是独立 Agent,通过 tool call 通信。DeepFlux 走的是另一条路:subagent 是 workflow 的一个步 。

orchestration/domain/model/workflow.go:26-35 定义了六种步类型:

type StepKind string
const (
    StepKindTask     StepKind = "task"      
    StepKindApproval StepKind = "approval"  
    StepKindSubagent StepKind = "subagent"  
    StepKindSleep    StepKind = "sleep"     
    StepKindMap      StepKind = "map"       
    StepKindForeach  StepKind = "foreach"   
)

subagent 步的核心是 subagentLambda(einoexec/subagent.go:64-161),流程四步:

  1. 读图状态 :workflow 的图共享状态 → JSON——这是子 agent 的上下文
  2. Agent First 指令 :step.Input 有值 → 作为 agent 指令,状态 JSON 附后;为空 → 回落纯状态 JSON(向后兼容旧 WorkflowDef)
  3. 经 AgentInvoker 闭包调用 :装配根注入的闭包,同步调用 agent BC 的 RunSubAgentHandler.RunSync
  4. 结果写回图状态 :子 agent 输出 → state.Data[step.Ref]

demo 场景 E 验证了这个流程:

====== 场景 E:DeepFlux Subagent 步 · 图状态传递 ======
  step.Input: 根据用户查询,返回天气信息
  step.Ref: weather_agent
  子 agent 输出: [weather_agent 执行结果] 北京晴 22°C (收到上下文 142 字节)
  图状态[weather_agent]: [weather_agent 执行结果] 北京晴 22°C (收…

====== 场景 F:Agent First · step.Input 为空时回落纯状态 JSON ======
  step.Input 为空,回落纯状态 JSON
  子 agent 输出: [flight_agent 执行结果] 北京晴 22°C (收到上下文 178 字节)

场景 E 和 F 的区别:E 有 step.Input,子 agent 收到的是 "根据用户查询,返回天气信息\n\n[上游状态]\n{...}";F 没有 step.Input,子 agent 收到的是纯状态 JSON。输入大小差异(142 vs 178 字节)反映了这个差异。

HITL 审批门:子 Agent 也能被叫停

subagent 步不是简单的"调完就完"。子 agent 内的 pre-tool hook 可以请求中断(subagent.go:129-144),触发 ErrSubagentInterrupt → Eino 中断 → Run→SUSPENDED。resume 时:

  • 批准 → per-tool 定向放行(V5):只放行被批准的那次工具调用,已执行的不重跑
  • 拒绝 → 写 denied 标签供下游 Branch 分流,run 不杀

这个审批门和 approval 步用的是同一套 suspend/resume 机制,但语义不同:approval 步是"整个步等人批",subagent 审批门是"子 agent 的某个工具调用等人批"。

(三)两种模式,一张表

维度 Eino Host MultiAgent DeepFlux Subagent
通信方式 host LLM 产出 tool call → specialist 节点 图状态 JSON → AgentInvoker 闭包
specialist 是什么 图的节点(ChatModel 或 Agent) 外部 agent config(独立 session)
host 的角色 也是 LLM,自己做决策 workflow 引擎(编译器 + 图执行)
上下文传递 消息列表(messages) 图状态(map[string]string)→ JSON
多 specialist 并行调用 + summarizer 汇总 顺序步(DAG 编排)
中断/审批 无内置 HITL 子 agent 内 pre-tool hook 可中断
适用场景 对话式多 Agent 协作 工作流式多 Agent 编排

Host MultiAgent 适合"对话式"场景 :用户一句话,host 判断该找谁,找完回来。host 和 specialist 是平等的 Agent,只是职责不同。

DeepFlux subagent 适合"工作流式"场景 :多个步骤按 DAG 执行,subagent 只是其中一步,前面可能有 task 步做数据预处理,后面可能有 approval 步等人审批。

(四)Eino ADK 的另外两种多 Agent 模式

除了 Host MultiAgent,Eino ADK 还提供了两种多 Agent 模式,但文档都标注了 NOT RECOMMENDED :

Supervisor(adk/prebuilt/supervisor/supervisor.go)

建立在 agent transfer 之上,supervisor 和 sub-agents 共享完整上下文。sub-agents 只能和 supervisor 通信(不能互相直接通信)。源码注释直言:

Supervisor is built on agent transfer with full context sharing, which has not proven to be more effective empirically. Consider using ChatModelAgent with AgentTool or DeepAgent instead.

AgentTool(adk/agent_tool.go)

把任意 Agent 包装成一个 tool(NewAgentTool),让另一个 Agent 可以直接调它。这是 ADK 推荐的替代方案:不用 transfer 共享上下文,而是像普通 tool 一样调用——子 Agent 有独立的 session 和 checkpoint。

AgentTool 的设计和 Host MultiAgent 的 specialist 本质上是一个思路:Agent 就是 Tool 。区别在于 AgentTool 更底层(可以作为任意 Agent 的 tool),Host MultiAgent 是更高层的封装(自带 Graph 编排)。

小结

问题 答案 关键源码
Host 怎么分派 specialist 注册为 tool(Name+IntendedUse→ToolInfo),host LLM 产出 tool call 匹配 host/compose.go:84-105
specialist 怎么执行 作为 Graph 节点,前置 handler 把消息注入 state,结果走 collector 汇聚 host/compose.go:154-185
单意图 vs 多意图 单意图直接返回,多意图标记后走 summarizer 汇总 host/compose.go:222-335
DeepFlux subagent 怎么嵌入 workflow 步类型,图状态 JSON→AgentInvoker 闭包→结果写回 einoexec/subagent.go:64-161
上下文怎么传 Host MultiAgent 用消息列表,DeepFlux 用图状态 JSON subagent.go:104-117
Agent First 是什么 step.Input 有值→作 agent 指令+状态附后;空→回落纯状态 JSON subagent.go:112-117
什么时候用哪个 对话式→Host MultiAgent;工作流式→DeepFlux subagent;通用→AgentTool 三种模式对比

几条设计判断:

  • Agent 就是 Tool。 Host MultiAgent 和 AgentTool 都在做同一件事:把 Agent 包装成可调用的工具。区别在于 Host MultiAgent 自带 Graph 编排,AgentTool 是裸 tool 留给调用方组装。
  • IntendedUse 是 specialist 的"简历"。 host LLM 不需要知道 specialist 内部有什么工具、什么 prompt,它只需要知道"这个 agent 能干什么"。这和人类团队分工一样——你不需要知道同事怎么做,只需要知道该把任务交给谁。
  • 上下文传递方式决定耦合度。 消息列表(Host MultiAgent)是松耦合——host 和 specialist 各自维护自己的上下文。图状态 JSON(DeepFlux)是紧耦合——subagent 能拿到 workflow 的完整状态,但也意味着状态结构变化会影响所有步。
  • ADK 文档的诚实标注值得注意。 Supervisor 和 DeterministicTransfer 都标注了 NOT RECOMMENDED,并给出了替代方案(AgentTool/DeepAgent)。这不是"功能不好用",而是"经验证明这个方向不如另一个方向"——工程文档里很少见到这种诚实。

下一篇(E92)拆 MultiAgent Host 源码 + ADK prebuilt 的 supervisor/planexecute/deep 三种预制模式——从"怎么用"到"里面怎么实现的"。E93 讲 Agent 间的 Transfer 交接——用户在不同 Agent 间无缝切换。