深入学LangChain官方文档-Router与Handoffs:多智能体如何路由和交接控制权
本篇对应的官方文档
- Multi-agent:说明多智能体的上下文管理与模式边界。
- Router:定义一次性分类、单跳
Command与并行Send。- Handoffs:说明状态驱动的跨轮控制权交接、
ToolMessage配对和两种实现方式。本篇讲解范围
本篇区分一次请求的分发和连续对话中的控制权转移,说明状态与消息怎样保持完整;主 Agent 如何委派子任务、按需加载 Skill 或构建自定义工作流,留给下一篇。
第 17 篇让系统能从企业资料中取回证据,但用户的问题不一定都该由同一个 Agent 处理。制度问答、退款办理和人工审批,需要的工具、提示词与权限都不同。
把全部能力堆进一个 Agent,模型会在过长的上下文和过多工具之间犹豫;过早拆成一群 Agent,又会制造无意义的跳转。先判断一件事:这次是一次性把问题分给专家,还是要让专家在后续对话中持续接手?
多智能体最常见的价值是控制上下文:每个专业 Agent 只看完成当前职责需要的知识和工具。它也可以让不同团队独立维护能力,或并行处理多个资料源。但如果一个 Agent 加上动态工具和明确提示词已经稳定,继续拆分只会增加状态同步和排错成本。
Router:把一次请求送到合适的处理者
Router 先分类输入,再把它送给一个或多个专业 Agent,最后把结果合成。它适合“问题类型清楚、这次请求可以独立结束”的场景,例如用户同时询问知识库政策和订单状态,系统可以并行查询两个领域后汇总。
Router 本身通常不承担多轮编排。无状态 Router 把每次请求都重新分类;需要保留对话历史时,可以让分类器读取状态,但它仍然是一个前置分发步骤。不要把“Router 会调用多个 Agent”误解为“它天然适合持续客服对话”。
单跳和并行扇出分别对应不同问题
当一次请求只属于一个领域,Command(goto=active_agent)表达单跳路由最直接;当同一个问题需要多个独立证据源,Send可以并行扇出,再由汇总节点合并结果。并行不意味着一定更快:它仍受外部服务延迟、限流和结果合成质量影响。
下面两段分别把“只去一个专家”和“同时请求多个专家”的下一跳写成返回值;它们不负责生成答案。
fromlanggraph.typesimportCommand,Senddefroute_one(state)->Command:active_agent=classify_query(state["query"])returnCommand(goto=active_agent)defroute_many(state):classifications=classify_many(state["query"])return[Send(item["agent"],{"query":item["query"]})foriteminclassifications]
这段代码的结果不是最终回答,而是下一步的执行位置。active_agent必须来自可审计的分类逻辑;若分类错误,后续专家再擅长也只会在错误的领域里工作。对高风险路由,可把规则、置信度阈值或人工确认放在路由前,而不是把“猜对类别”交给结果阶段补救。
Handoff:状态改变后,后续对话也换人
退款不是一次问答就能结束:用户先问规则,随后提供订单号、补充原因、确认金额,最后可能进入人工审批。这种跨轮次、按阶段解锁能力的流程需要 Handoff。
它的核心是一个持久状态字段,例如active_agent或current_step。工具更新字段后,下一轮模型调用读取新状态,换用对应的提示词、工具或独立 Agent。
Handoff 的“交接”既可以发生在多个 Agent 之间,也可以发生在一个 Agent 的不同配置之间。重点不在对象数量,而在用户是否需要持续和当前处理者直接对话、状态是否必须跨轮保存、能力是否只能在前置条件满足后才开放。
改状态时,消息链也必须完整
工具调用不是只改一个字段。模型发出transfer_to_refund后,消息历史还期待一个与tool_call_id对应的ToolMessage。
若只写active_agent="refund"而没有工具结果,下一轮的消息序列会缺少请求—响应配对,模型或运行时无法可靠解释刚才发生了什么。
这个工具同时写回消息和状态:前者收完整个 tool call,后者才把后续对话切到退款处理阶段。
fromlangchain.messagesimportToolMessagefromlangchain.toolsimporttoolfromlanggraph.typesimportCommand@tooldeftransfer_to_refund(runtime)->Command:returnCommand(update={"messages":[ToolMessage(content="已转交退款专员。",tool_call_id=runtime.tool_call_id,)],"active_agent":"refund",})
这里ToolMessage的职责是完成本次工具调用,active_agent的职责是决定后续行为,两者不能互相替代。若退款专家还需要订单号,就应在新状态里直接向用户追问;不要让总控 Agent 假装仍在处理,再把每一句话隐式转发给专家。
两种实现,按能力差异选
第一种做法是一个 Agent 加 Middleware:每次模型调用前,Middleware 根据active_agent动态更换系统提示词和可用工具。它适合角色差异主要是流程阶段和工具集合不同的情况,部署和共享状态都较简单。
第二种做法是多个 Agent 子图。每个专家是独立节点,拥有自己的工具、提示词和可测试边界,状态机负责下一跳。它适合领域上下文、权限模型或维护团队确实不同的场景。无论选哪种,messages、用户身份和审批状态都需要明确哪些共享、哪些隔离。
不要把四种模式混成一个概念
Router 解决“这次请求去哪里”;Handoff 解决“后续对话现在由谁继续”。
Subagent 是主 Agent 在持续任务中按需委派;Custom Workflow 则把确定性步骤和 Agent 行为显式编排。它们可以组合,但每个模式应先回答自己的控制权问题。
工程上可按一个简单顺序决策:输入类别明确、一次回答即可完成时,用 Router;需要用户跨轮与不同阶段直接交互时,用 Handoff;主 Agent 要反复分解和汇总复杂工作时,才进入 Subagent;需要可预测的流程节点、重试和分支时,再下探 Custom Workflow。任何模式都不能越过权限、审批和业务系统的权威边界。
结论:分发与交接的区别在“下一轮”
Router 把本次请求分类、分发并合成结果;Handoff 通过持久化状态把后续消息也交给新的处理者。前者追求清晰和轻量,后者解决连续对话中的控制权、能力解锁和消息完整性。
做到这一步,多智能体就不再只是“多个提示词”,而是有明确状态与责任边界的协作系统。下一篇会继续讨论:总控 Agent 需要委派长任务、按需装载知识或组合自定义流程时,怎样避免主上下文再次膨胀。