跳到主要内容

多 agent 组合:Handoff 与 Workflow

BeeAI 提供两种把多个 agent 拼起来的方式,对应两种控制哲学:让模型决定(Handoff)还是让开发者决定(Workflow)。

5.1 HandoffTool:把一个 agent 包成工具

HandoffTool(tools/handoff.py:26)的核心想法极简:一个 agent 就是一个 Runnable,而工具也是被 run 的东西,所以可以把整个 agent 包装成一个工具。主 agent 调这个工具,等于把任务委派给被包的专家 agent。

# 示意,基于 README 的多 agent 例子
from beeai_framework.tools.handoff import HandoffTool
main_agent = RequirementAgent(
llm=...,
tools=[HandoffTool(knowledge_agent), HandoffTool(weather_agent)],
# 主 agent 在运行时自己决定把任务交给哪个专家
)

委派时它做的事(handoff.py:69-98):

  • 从上下文里取出主 agent 的记忆(context.context["state"]["memory"],handoff.py:70-75)——这正是 01 章 里 runner 调工具时塞进 context 的 state;
  • 把记忆里的非系统消息复制给目标 agent(若目标可 clone 就先克隆一份,避免污染,handoff.py:78);
  • 把本次委派的 task 作为新的用户消息,跑目标 agent,取它最后一条消息的文本当工具输出。

直觉: Handoff 是「运行时、由模型驱动」的协作——主 agent 像项目经理,看着任务临场决定派给谁。委派关系不写死在代码里,而是模型每一步的选择。

5.2 Workflow:显式状态图

Workflow(workflows/workflow.py:32)走另一条路:开发者显式声明一组步骤(step),每个 step 是一个处理函数,返回「下一步去哪」。这是「编译期、由开发者驱动」的编排。

# 示意,演示 Workflow 的最小形态
workflow = Workflow(schema=MyState, name="research")
workflow.add_step("plan", plan_step) # 每个 step 是 state -> 下一步名
workflow.add_step("search", search_step)
workflow.add_step("write", write_step)
workflow.set_start("plan")
result = await workflow.run(MyState(...))

执行循环在 workflow.py:115-188:从起始 step 开始,每个 step 拿到深拷贝的状态跑,返回值决定下一步——可以是具体 step 名,也可以是保留字 Workflow.NEXT / PREV / SELF / START / END(workflow.py:33-37)来表达「下一个 / 上一个 / 重跑自己 / 回开头 / 结束」。每步前后都发 start / success 事件,出错发 error

step 的返回路由逻辑(workflow.py:143-155):

# 示意,浓缩自 workflows/workflow.py:143-155
if step_next == Workflow.START: next = run.steps[0].name # 回到最初
elif step_next == Workflow.PREV: next = ...prev or END # 上一步
elif step_next == Workflow.SELF: next = ...current # 重跑自己
elif step_next in (None, NEXT): next = ...next or END # 顺着往下
else: next = step_next # 显式跳某步

因为 step 的处理函数可以是任意 Runnable(包括 agent),Workflow 天然能把多个 agent 串成有条件分支、有循环的流程。它和 Handoff 的区别在于:流转图是你写死的,模型只在每个 step 内部自由发挥。

5.3 两条路线怎么选

HandoffToolWorkflow
谁决定流转模型(运行时)开发者(声明式)
形态agent → 工具step 状态图
适合开放式委派、专家路由固定流程、可控分支与循环
可预测性低(看模型)高(图写死)

两者并不互斥:常见做法是用 Workflow 搭确定性骨架,在某些 step 里放带 Handoff 工具的 RequirementAgent,把「灵活」收进可控的边界里。


最后一章:巧妙之处、边界与代码地图。→ 05-cleverness-boundaries-map.md