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

[智能体设计模式]第2章-路由(Route)

本系列内容知识来源于《智能体设计模式》一书,仅做知识分享。

目录

路由模式概述

路由模式的核心组件

路由机制的应用阶段

实践与应用场景

1. 人机交互场景(虚拟助手、AI教师等)

2. 自动化数据与文档处理流程

3. 多工具/多智能体协同系统

实战代码示例(LangChain)

前置准备

完整代码

代码说明

详细说明

先明确核心角色

1. 第一步:创建“接线员”——coordinator_router_chain

2. 第二步:创建“专业部门”——branches字典

3. 第三步:创建“调度员”——delegation_branch

4. 第四步:组装整个“服务中心”——coordinator_agent

第一步:并行准备数据(左边的字典)

第二步:调度员处理(| delegation_branch)

第三步:提取最终结果(| (lambda x: x['output']))


路由模式概述

虽然通过提示链实现的顺序处理是利用语言模型执行确定性、线性工作流的基础技术,但在需要自适应响应的场景下,其适用性有限。现实中的智能体系统通常需要根据环境状态、用户输入或前序操作结果等因素,在多个潜在动作之间进行仲裁。

这种动态决策能力——即根据特定条件将控制流导向不同的专用函数、工具或子流程——就是通过 “路由”机制 实现的。

示例:一个用于客户咨询的智能体在具备路由功能后,可以首先对用户查询进行分类以判断意图。根据分类结果,查询可以被导向专门的问答智能体、用于账户信息检索的数据库工具,或用于复杂问题升级的流程,而不是始终采用单一、预设的响应路径。

路由模式的核心组件

路由模式的核心是执行评估并引导流程的机制,其实现方式包括以下4类:

实现方式

核心逻辑与特点

基于LLM的路由

通过提示语言模型分析输入,输出指示下一步的标识符/指令(如分类标签)。
示例提示:“分析以下用户查询,仅输出类别:‘订单状态'、‘产品信息'、‘技术支持'或‘其他'”

基于嵌入的路由

将输入查询转为向量嵌入,与不同路由/能力的嵌入比对,路由到最相似路径。
适用于语义路由(基于输入含义而非关键词)

基于规则的路由

使用预定义规则(if-else、switch-case),根据关键词、模式或结构化数据路由。
特点:更快、更确定,但灵活性低

基于机器学习模型的路由

用分类器等判别模型(小规模标注数据训练)实现路由。
特点:监督微调,路由逻辑编码在权重中,不依赖实时LLM推理

路由机制的应用阶段

路由可在智能体操作周期的多个阶段实现:

  • 初始任务分类(如用户查询意图识别)
  • 处理链中间决策(如选择下一步工具)
  • 子流程内路径选择(如适配不同格式的数据处理)

实践与应用场景

路由模式的核心价值是实现“动态分流”,适用于需要自适应决策的复杂系统,常见场景如下:

1. 人机交互场景(虚拟助手、AI教师等)

  • 核心作用:解析用户意图,动态调整响应策略
  • 应用示例:
    • 虚拟助手:根据查询意图调用信息检索工具、升级人工坐席,或跳转服务流程
    • AI教师:根据学生答题表现选择下一个课程模块,实现个性化学习路径

2. 自动化数据与文档处理流程

  • 核心作用:分类与分发,适配不同类型的处理需求
  • 应用示例:
    • 邮件/工单处理:根据内容优先级、主题分类,导向销售线索导入、紧急问题升级等工作流
    • 数据格式适配:根据API返回数据格式(JSON/CSV),路由到对应的数据转换流程

3. 多工具/多智能体协同系统

  • 核心作用:充当高级调度器,分配任务给专用组件
  • 应用示例:
    • 研究系统:由检索、摘要、分析等智能体组成,路由器根据当前目标分配任务
    • AI编程助手:先识别编程语言和用户意图(调试、解释、翻译),再将代码片段交给对应工具处理

实战代码示例(LangChain)

本示例通过 LangChain 构建一个简单的多智能体系统:设置“协调者”组件,根据用户请求意图(预订、信息查询、不明确),将请求路由到对应的“子智能体”处理器,模拟多智能体架构中的委托模式。

前置准备

  1. 安装所需库:
pip install langchain langgraph google-cloud-aiplatform langchain-google-genai google-adk deprecated pydantic
  1. 配置API密钥:
  • 确保环境变量中已设置 GOOGLE_API_KEY(用于调用 Gemini 模型)

完整代码

# 导入LangChain相关库:
# 1. 谷歌Gemini模型的LangChain封装(用于调用大模型)
from langchain_google_genai import ChatGoogleGenerativeAI
# 2. 聊天型提示模板(支持system/user/assistant多角色对话格式)
from langchain_core.prompts import ChatPromptTemplate
# 3. 字符串输出解析器(将大模型输出的原始响应转为字符串)
from langchain_core.output_parsers import StrOutputParser
# 4. 核心流程组件:
#    - RunnablePassthrough:透传数据(不修改输入,直接传递给下一个组件)
#    - RunnableBranch:分支路由(根据条件将数据导向不同处理流程)
from langchain_core.runnables import RunnablePassthrough, RunnableBranch# --- 配置大模型(核心依赖)---
# 确保环境变量中已设置GOOGLE_API_KEY(谷歌云平台的API密钥,用于调用Gemini)
try:# 初始化谷歌Gemini模型:# - temperature:温度参数(0=输出完全确定,无随机性;值越大越随机)llm = ChatGoogleGenerativeAI(model="gemini-2.5-flash", temperature=0)print(f"语言模型初始化成功:{llm.model}")
except Exception as e:print(f"语言模型初始化失败:{e}")llm = None# --- 定义模拟子智能体处理器(业务逻辑核心)---
# 这些函数是实际处理不同类型请求的"工人",此处为模拟逻辑(实际项目中可替换为真实业务代码)def booking_handler(request: str) -> str:"""模拟"预订智能体":处理机票/酒店预订类请求"""print("\n--- 委托给预订处理器 ---")  # 日志:标记当前路由到哪个处理器return f"预订处理器已处理请求:'{request}'。结果:模拟预订动作。"def info_handler(request: str) -> str:"""模拟"信息智能体":处理一般信息查询类请求(如常识、咨询等)"""print("\n--- 委托给信息处理器 ---")return f"信息处理器已处理请求:'{request}'。结果:模拟信息检索。"def unclear_handler(request: str) -> str:"""兜底处理器:处理无法明确分类的请求"""print("\n--- 处理不明确请求 ---")return f"协调者无法委托请求:'{request}'。请补充说明。"# --- 定义协调者路由链(核心:判断请求该交给哪个处理器)---
# ChatPromptTemplate.from_messages():创建多角色聊天提示模板
# 输入是一个列表,每个元素是(角色名, 提示内容)的元组
coordinator_router_prompt = ChatPromptTemplate.from_messages([# 1. system角色:给大模型设定"协调者"身份和判断规则(核心指令)("system", """分析用户请求,判断应由哪个专属处理器处理。- 若请求涉及预订机票或酒店,输出'booker'。- 其他一般信息问题,输出'info'。- 若请求不明确或不属于上述类别,输出'unclear'。只输出一个词:'booker'、'info'或'unclear'。"""),  # 强制大模型输出固定关键词,方便后续判断# 2. user角色:占位符{request},后续会被用户的真实请求替换("user", "{request}")
])# 只有大模型初始化成功后,才构建后续流程
if llm:# 构建"路由决策链":提示模板 → 大模型 → 输出解析器# LangChain的"|"是"链式调用"语法,数据从左到右传递:# 1. 先将用户请求注入coordinator_router_prompt,生成完整提示# 2. 把完整提示传给llm(大模型),得到原始响应# 3. 用StrOutputParser把原始响应转为字符串(去除多余格式)coordinator_router_chain = coordinator_router_prompt | llm | StrOutputParser()# --- 定义委托逻辑(将请求路由到对应处理器)---# branches字典:key是大模型输出的决策关键词,value是对应的处理流程branches = {# 当决策是"booker"时:调用booking_handler处理"booker": RunnablePassthrough.assign(# assign():给数据字典添加新字段(这里添加"output"字段存储处理结果)# lambda x: 匿名函数,x是当前数据字典(包含"request"和"decision"等字段))output=lambda x: booking_handler(x['user_input']['request'])),# 当决策是"info"时:调用info_handler处理"info": RunnablePassthrough.assign(output=lambda x: info_handler(x['user_input']['request'])),# 当决策是"unclear"时:调用unclear_handler处理"unclear": RunnablePassthrough.assign(output=lambda x: unclear_handler(x['user_input']['request'])),}# 构建"分支路由器":根据决策结果选择对应的处理分支# RunnableBranch的参数是:(条件1, 分支1), (条件2, 分支2), ..., 默认分支delegation_branch = RunnableBranch(# 条件1:如果决策结果是"booker",走booker分支(lambda x: x['decision'].strip() == 'booker', branches["booker"]),# 条件2:如果决策结果是"info",走info分支(lambda x: x['decision'].strip() == 'info', branches["info"]),# 默认分支:以上条件都不满足时,走unclear分支(兜底)branches["unclear"])# --- 构建最终的"协调者智能体" ---# 整体流程:数据准备 → 分支路由 → 结果提取coordinator_agent = {# 第一步:并行处理两个任务,生成数据字典的两个字段:# 1. "decision"字段:通过coordinator_router_chain得到决策结果# 2. "user_input"字段:通过RunnablePassthrough透传原始请求(不修改)"decision": coordinator_router_chain,"user_input": RunnablePassthrough()} | delegation_branch | (lambda x: x['output'])# 第二步:把数据字典传给delegation_branch,根据"decision"路由到对应分支# 第三步:用lambda x: x['output']提取处理结果(只返回最终输出,隐藏中间数据)# --- 示例用法(测试不同类型请求)---
def main():# 先判断大模型是否初始化成功if not llm:print("\n因LLM初始化失败,跳过执行。")return# 测试1:预订类请求(预期路由到booker分支)print("--- 预订请求示例 ---")request_a = "帮我预订飞往伦敦的机票。"# invoke():触发智能体执行,参数是输入数据字典result_a = coordinator_agent.invoke({"user_input": request_a})print(f"最终结果A: {result_a}")# 测试2:信息查询类请求(预期路由到info分支)print("\n--- 信息请求示例 ---")request_b = "意大利的首都是哪里?"result_b = coordinator_agent.invoke({"user_input": request_b})print(f"最终结果B: {result_b}")# 测试3:不明确请求(预期路由到unclear分支)print("\n--- 不明确请求示例 ---")request_c = "讲讲量子物理。"result_c = coordinator_agent.invoke({"user_input": request_c})print(f"最终结果C: {result_c}")# 程序入口:当脚本直接运行时,执行main函数
if __name__ == "__main__":main()

代码说明

  1. 核心组件
    • 子智能体处理器:booking_handler(预订)、info_handler(信息查询)、unclear_handler(不明确请求)
    • 协调者路由链:coordinator_router_chain,通过提示让LLM对请求分类(输出booker/info/unclear
    • 委托逻辑:delegation_branch,基于分类结果将请求路由到对应处理器
  1. 工作流程
    1. 用户输入请求 → 协调者路由链判断意图 → 输出分类标签
    2. 根据标签将请求委托给对应子智能体
    3. 子智能体处理后返回结果,协调者输出最终响应
  1. 错误处理
    • 包含LLM初始化失败的捕获逻辑,确保系统鲁棒性

详细说明

要搞懂这段代码,核心是抓住 LangChain的“工作流组装”思想——把大模型、工具、逻辑判断像“乐高积木”一样拼起来,最终实现“用户请求 → 自动判断类型 → 交给对应处理器处理”的完整流程。

我们拆成 3个核心部分+1个整体流程 来讲,用通俗的例子类比,避免复杂概念:

先明确核心角色

把这段代码想象成一个 公司的“客户服务中心”

  • coordinator_agent:整个服务中心(对外接收用户请求,最终返回结果)
  • coordinator_router_chain:中心的“接线员”(判断用户请求类型)
  • branches:3个专业部门(处理不同类型请求)
  • delegation_branch:中心的“调度员”(根据接线员判断,把用户转给对应部门)
  • booking_handler/info_handler/unclear_handler:部门里的“具体办事员”(执行实际处理逻辑)

1. 第一步:创建“接线员”——coordinator_router_chain

coordinator_router_chain = coordinator_router_prompt | llm | StrOutputParser()

这行是创建一个 “请求类型判断工具”,作用是:接收用户请求,输出一个“决策关键词”(只能是 booker/info/unclear 三者之一)。

拆解每个部分:

  • coordinator_router_prompt:给大模型的“指令模板”(比如写着:“用户的请求是预约类(输出booker)、咨询类(输出info)、都不是(输出unclear),只返回关键词,别多写”)
  • llm:大模型本身(根据上面的模板,分析用户请求)
  • StrOutputParser():“结果格式化器”(只提取大模型输出的文本字符串,去掉多余格式)

👉 举个例子:
用户说“我想预约明天的会议室” → 这个链会输出 booker
用户说“你们公司几点下班” → 输出 info
用户说“阿巴阿巴” → 输出 unclear

2. 第二步:创建“专业部门”——branches字典

branches = {"booker": RunnablePassthrough.assign(output=lambda x: booking_handler(x['user_input']['request'])),"info": RunnablePassthrough.assign(output=lambda x: info_handler(x['user_input']['request'])),"unclear": RunnablePassthrough.assign(output=lambda x: unclear_handler(x['user_input']['request'])),
}

这是一个“部门清单”,key是“接线员”输出的决策关键词,value是“这个部门怎么处理请求”。

重点拆解 RunnablePassthrough.assign(...)

  • RunnablePassthrough():“透传器”——把前面传来的所有数据(比如用户原始请求、决策结果)原封不动地传下去,不修改。
  • .assign(output=...):给“透传的数据”新增一个叫 output 的字段,字段值是“办事员处理后的结果”。
  • lambda x: ...:匿名函数,接收“透传的数据x”,从中提取用户原始请求(x['user_input']['request']),传给对应的“办事员”(比如 booking_handler)。

👉 通俗理解:
如果决策是 booker → 调用 booking_handler 处理用户的预约请求,把结果存到 output 字段;
如果决策是 info → 调用 info_handler 处理咨询请求,结果存到 output
如果是 unclear → 调用 unclear_handler (比如返回“我没看懂你的请求”),结果存到 output

3. 第三步:创建“调度员”——delegation_branch

delegation_branch = RunnableBranch((lambda x: x['decision'].strip() == 'booker', branches["booker"]),(lambda x: x['decision'].strip() == 'info', branches["info"]),branches["unclear"]  # 默认分支
)

这是“调度逻辑”:根据“接线员”的决策(x['decision']),把请求转给 branches 里对应的“部门”。

拆解:

  • RunnableBranch:LangChain的“分支选择器”,接收多个(条件+分支)对,再加上一个默认分支。
  • 第一个参数 (lambda x: x['decision'].strip() == 'booker', branches["booker"]):如果“决策结果”是 booker,就走 branches["booker"] 这个部门。
  • 第二个参数同理:决策是 info 就走 info 部门。
  • 最后一个 branches["unclear"]:兜底方案——如果决策既不是 booker 也不是 info(比如大模型输出错了),就走“无法理解”部门。

👉 举个例子:
“接线员”输出 booker → 调度员把请求转给 booking_handler
“接线员”输出 abc(乱码) → 调度员直接走默认的 unclear 部门。

4. 第四步:组装整个“服务中心”——coordinator_agent

coordinator_agent = {"decision": coordinator_router_chain,"user_input": RunnablePassthrough()
} | delegation_branch | (lambda x: x['output'])

这是最终的“完整工作流”,把前面的“接线员、调度员、部门”串起来,形成一个可直接调用的“智能体”。

按执行顺序拆解(| 是LangChain的“管道符”,数据从左到右流动):

第一步:并行准备数据(左边的字典)

这个字典的作用是“一次性生成两个关键数据”,传给后面的调度员:

  • decision:值是 coordinator_router_chain → 运行“接线员”,得到决策关键词(booker/info/unclear)。
  • user_input:值是 RunnablePassthrough() → 透传用户的原始请求(比如“我想预约会议室”),不让请求丢失。

👉 此时,字典会生成一个类似这样的数据:

{"decision": "booker",  # 接线员的判断结果"user_input": {"request": "我想预约明天的会议室"}  # 用户原始请求
}
第二步:调度员处理(| delegation_branch

把上面的字典传给“调度员”,调度员根据 decision 字段,调用对应的“部门”处理,最终返回一个包含 output 字段的数据:

{"decision": "booker","user_input": {"request": "我想预约明天的会议室"},"output": "预约成功!明天10点会议室A已为你预留"  # booking_handler的处理结果
}
第三步:提取最终结果(| (lambda x: x['output'])

最后用一个简单的匿名函数,从上面的数据中只提取 output 字段的值,作为整个智能体的最终返回结果。

👉 最终给用户的响应就是:"预约成功!明天10点会议室A已为你预留"

http://www.dtcms.com/a/600744.html

相关文章:

  • [智能体设计模式] 第五章 :函数调用
  • PixPin(截图工具) v2.2.0.0
  • 2023年混沌学堂JAVA课程(1-7期)+专题课
  • 备战算法专家--要点 1
  • 湖南服装网站建设东方财富网官方网站首页
  • 物业网站建设方案开发一个直播app
  • 设计模式实战篇(一):彻底搞懂 Singleton 单例模式
  • 什么是电子商务网站建设网站建设的一些背景图片
  • 一个有 IP 的服务端监听了某个端口,那么他的 TCP 最大链接数是多少
  • K8s常用排障调试工具 入侵排查 kubectl debug 命令详解
  • yield(放弃优先权)
  • 基于MATLAB的噪声图像处理方案
  • 做动态logo网站做网站有底薪吗
  • C语言编译器最新版 | 全面提升性能与兼容性
  • 厦门网站建设建设公司免费动漫软件app下载大全
  • 开源模型应用落地-FastAPI-助力模型交互-进阶篇-中间件(四)
  • springBoot (springCloud2025)集成redisCluster 集群
  • Redis在Windows上测试运行Memurai
  • windows ubuntu双系统下卸载ubuntu
  • 零基础入门C语言之C语言实现数据结构之双向链表
  • 初次接触 LoRA 技术
  • 西安哪家网站公司做的比较好做网页制作的价格
  • 【OpenCV + VS 】图像通道分离与合并
  • 【超分辨率专题】HYPIR:扩散模型先验与 GAN 对抗训练相结合的新型图像复原框架
  • 【ZeroRange WebRTC】kvsWebrtcClientMaster 获取 ICE 服务器配置解析
  • 手机网站建设liednswordpress改模板教程视频
  • Chrome V3 插件开发:监听并转发 API 请求
  • OpenCV 图像处理与键盘交互
  • 长沙理工《人工智能基础A》实验(上机)报告实验三 电商数据可视化/图像处理
  • Elasticsearch 的结构化文档配置 - 递归分块实践