Skip to main content

概述

路由器模式是一种多智能体架构,其中路由步骤对输入进行分类并将其定向到专门的智能体,然后将结果合成为组合响应。当您组织的知识分布在不同的垂直领域(每个领域都需要自己的智能体,配备专门的工具和提示)时,这种模式非常有效。 在本教程中,您将构建一个多源知识库路由器,通过一个真实的企业场景来展示这些优势。该系统将协调三个专家:
  • 一个GitHub 智能体,用于搜索代码、议题和拉取请求。
  • 一个Notion 智能体,用于搜索内部文档和维基。
  • 一个Slack 智能体,用于搜索相关讨论串和对话。
当用户询问“如何对 API 请求进行身份验证?”时,路由器会将查询分解为特定于来源的子问题,并行路由到相关智能体,并将结果合成为连贯的答案。

为什么使用路由器?

路由器模式提供了几个优势:
  • 并行执行:同时查询多个来源,与顺序方法相比降低了延迟。
  • 专门的智能体:每个垂直领域都有针对其领域优化的专注工具和提示。
  • 选择性路由:并非每个查询都需要每个来源——路由器智能地选择相关的垂直领域。
  • 针对性的子问题:每个智能体收到一个针对其领域定制的问题,从而提高结果质量。
  • 清晰的合成:来自多个来源的结果被组合成一个连贯的响应。

概念

我们将涵盖以下概念:
路由器 vs. 子智能体子智能体模式也可以路由到多个智能体。当您需要专门的预处理、自定义路由逻辑或希望显式控制并行执行时,请使用路由器模式。当您希望 LLM 动态决定调用哪些智能体时,请使用子智能体模式。

设置

安装

本教程需要 langchainlanggraph 包:
更多详情,请参阅我们的安装指南

LangSmith

设置 LangSmith 以检查智能体内部发生的情况。然后设置以下环境变量:

选择 LLM

从 LangChain 的集成套件中选择一个聊天模型:
👉 阅读 OpenAI 聊天模型集成文档

1. 定义状态

首先,定义状态模式。我们使用三种类型:
  • AgentInput:传递给每个子智能体的简单状态(仅包含查询)
  • AgentOutput:每个子智能体返回的结果(来源名称 + 结果)
  • RouterState:跟踪查询、分类、结果和最终答案的主工作流状态
results 字段使用归约器(Python 中的 operator.add,JS 中的 concat 函数)将并行智能体执行的输出收集到单个列表中。

2. 为每个垂直领域定义工具

为每个知识领域创建工具。在生产系统中,这些工具会调用实际的 API。在本教程中,我们使用返回模拟数据的存根实现。我们在 3 个垂直领域定义了 7 个工具:GitHub(搜索代码、议题、PR)、Notion(搜索文档、获取页面)和 Slack(搜索消息、获取讨论串)。

3. 创建专门的智能体

为每个垂直领域创建一个智能体。每个智能体都有特定领域的工具和针对其知识来源优化的提示。所有三个都遵循相同的模式——只有工具和系统提示不同。

4. 构建路由器工作流

现在使用 StateGraph 构建路由器工作流。该工作流有四个主要步骤:
  1. 分类:分析查询并确定要调用哪些智能体以及使用什么子问题
  2. 路由:使用 Send 并行分发到选定的智能体
  3. 查询智能体:每个智能体接收一个简单的 AgentInput 并返回一个 AgentOutput
  4. 合成:将收集到的结果组合成连贯的响应

5. 编译工作流

现在通过用边连接节点来组装工作流。关键是使用 add_conditional_edges 和路由函数来启用并行执行:
add_conditional_edges 调用通过 route_to_agents 函数将分类节点连接到智能体节点。当 route_to_agents 返回多个 Send 对象时,这些节点将并行执行。

6. 使用路由器

使用跨越多个知识领域的查询测试您的路由器:
预期输出:
路由器分析了查询,将其分类以确定要调用哪些智能体(GitHub 和 Notion,但此技术问题不涉及 Slack),并行查询了两个智能体,并将结果合成为连贯的答案。

7. 理解架构

路由器工作流遵循清晰的模式:

分类阶段

classify_query 函数使用结构化输出来分析用户的查询并确定要调用哪些智能体。这是路由智能所在之处:
  • 使用 Pydantic 模型(Python)或 Zod 模式(JS)确保有效输出
  • 返回一个 Classification 对象列表,每个对象包含一个 source 和目标 query
  • 仅包含相关的来源——不相关的来源会被简单地省略
这种结构化方法比自由形式的 JSON 解析更可靠,并使路由逻辑显式化。

使用 Send 进行并行执行

route_to_agents 函数将分类映射到 Send 对象。每个 Send 指定目标节点和要传递的状态:
每个智能体节点接收一个简单的 AgentInput,其中仅包含一个 query 字段——而不是完整的路由器状态。这使得接口清晰且显式。

使用归约器收集结果

智能体结果通过归约器流回主状态。每个智能体返回:
归约器(Python 中的 operator.add)连接这些列表,将所有并行结果收集到 state["results"] 中。

合成阶段

所有智能体完成后,synthesize_results 函数遍历收集到的结果:
  • 等待所有并行分支完成(LangGraph 自动处理)
  • 引用原始查询以确保答案解决用户所问的问题
  • 组合来自所有来源的信息,避免冗余
部分结果:在本教程中,所有选定的智能体必须在合成之前完成。

8. 完整的工作示例

以下是组合在一起的可运行脚本:

9. 高级:有状态路由器

到目前为止,我们构建的路由器是无状态的(每个请求独立处理,调用之间没有记忆)。对于多轮对话,您需要一种有状态的方法。

工具包装器方法

添加对话记忆最简单的方法是将无状态路由器包装为一个工具,供对话智能体调用:
这种方法保持路由器无状态,而对话智能体处理记忆和上下文。用户可以进行多轮对话,智能体将根据需要调用路由器工具。
工具包装器方法推荐用于大多数用例。它提供了清晰的分离:路由器处理多源查询,而对话智能体处理上下文和记忆。

完全持久化方法

如果您需要路由器本身维护状态——例如,在路由决策中使用先前的搜索结果——请使用持久化在路由器级别存储消息历史记录。
有状态路由器会增加复杂性。 当在不同轮次中路由到不同的智能体时,如果智能体具有不同的语气或提示,对话可能会感觉不一致。请考虑使用交接模式子智能体模式——两者都为与不同智能体的多轮对话提供了更清晰的语义。

10. 关键要点

路由器模式在以下情况下表现出色:
  • 不同的垂直领域:各自需要专门工具和提示的独立知识领域
  • 并行查询需求:受益于同时查询多个来源的问题
  • 合成需求:来自多个来源的结果需要组合成连贯的响应
该模式有三个阶段:分解(分析查询并生成有针对性的子问题)、路由(并行执行查询)和合成(组合结果)。
何时使用路由器模式当您有多个独立的知识来源、需要低延迟的并行查询,并希望显式控制路由逻辑时,请使用路由器模式。对于需要动态工具选择的更简单情况,请考虑子智能体模式。对于智能体需要按顺序与用户对话的工作流,请考虑交接

后续步骤