AI Agent意图路由实战:从原理到LangChain实现多技能智能助手 1. 从“意图识别”到“路由分发”Agent应用的核心枢纽如果你在2024年或2025年就开始接触AI Agent开发大概率会经历过一个阶段你精心设计了一个Agent给它装备了各种强大的工具Tool比如搜索、计算、写代码但当你问它一个稍微复杂点的问题时它要么“卡壳”在一个工具里出不来要么像个无头苍蝇一样在几个工具间来回切换就是给不出你想要的答案。问题的根源往往不在于大模型LLM不够聪明也不在于工具不够强大而在于缺少一个关键的“调度中枢”——意图路由。简单来说意图路由就是Agent的“大脑皮层决策层”。它负责理解用户的真实意图然后根据这个意图将任务精准地分发给最合适的子模块去执行。这个子模块可能是一个单一的工具Tool也可能是一个更复杂的、由多个步骤组成的子工作流Workflow甚至可能是另一个专门的Agent。没有有效的意图路由你的Agent就像一个拥有豪华厨房和顶级食材却不知道客人想点中餐还是西餐的餐厅空有一身本领无处施展。到了2026年随着大模型能力的进一步渗透和多模态交互的常态化Agent的应用场景会从简单的“问答机器人”演变为复杂的“数字员工”或“业务协作者”。这时意图路由的重要性会愈发凸显。它不再是“锦上添花”的可选项而是构建可靠、高效、可扩展Agent应用的基石。本文将抛开理论空谈直接切入实战用一个完整的、可运行的Python项目带你一步步搭建一个具备意图路由能力的Agent系统。我们将使用LangChain作为基础框架但重点会放在路由逻辑的设计与实现上让你不仅“跑通代码”更能掌握其背后的设计思想。2. 项目蓝图构建一个多技能AI助手为了让我们的实战更有针对性我们先来定义这个Agent要做什么。假设我们要开发一个“个人效率助手”它需要处理以下几类常见的用户请求信息查询例如“上海今天的天气怎么样”、“特斯拉最新的股价是多少”内容生成例如“帮我写一封感谢客户的邮件语气要专业且亲切。”、“为我的新产品‘智能水杯’想五个宣传口号。”代码辅助例如“用Python写一个函数计算斐波那契数列。”、“帮我看看这段JavaScript代码有什么潜在的内存泄漏风险”复杂任务规划例如“我想策划一个周末的短途旅行预算2000元从北京出发。”、“我需要为下周三的团队会议准备一份议程和材料清单。”显然用一个“万能”的LLM调用加上一堆工具列表Toolkit让模型自己选在处理简单任务时或许可行但面对“策划旅行”这类复杂任务时效果会很不稳定。模型可能会陷入细节或者错误地选择工具顺序。因此我们需要一个路由层先对用户的输入进行意图分类然后根据分类结果激活不同的处理流水线。我们的系统架构将分为三层路由层Router核心组件负责解析用户输入判断意图类别。执行层Executors对应不同意图的专门处理模块。每个执行器本身可以是一个简单的工具调用也可以是一个封装好的子Agent或工作流。协调层Orchestrator负责接收路由结果调用对应的执行器并整理最终输出返回给用户。下面我们就开始用代码将这份蓝图变为现实。2.1 环境准备与依赖安装首先确保你的Python环境在3.9以上。我们将主要使用langchain和langchain-openai同时为了演示不同的执行器也会引入一些其他工具库。建议使用虚拟环境。# 创建并激活虚拟环境可选 python -m venv venv source venv/bin/activate # Linux/Mac # venv\Scripts\activate # Windows # 安装核心依赖 pip install langchain langchain-openai langchain-community # 安装一些可能用到的工具库示例 pip install requests # 用于天气、股价查询的HTTP请求 pip install duckduckgo-search # 用于网络搜索 # 注意openai库已通过langchain-openai集成通常无需单独安装接下来你需要准备一个LLM的API密钥。本文以OpenAI的GPT-4系列模型为例因为它目前在Function Calling函数调用和指令遵循方面表现稳定非常适合构建路由逻辑。你可以在OpenAI官网获取API Key。# 在代码开头或环境变量中设置你的API Key import os os.environ[OPENAI_API_KEY] your-openai-api-key-here注意将API Key直接写在代码中是不安全的做法在生产环境中务必使用环境变量或密钥管理服务。例如在终端中执行export OPENAI_API_KEYyour-key然后在代码中使用os.environ.get(“OPENAI_API_KEY”)来读取。2.2 定义意图类别与路由逻辑这是整个项目的核心。我们需要先明确有哪些意图类别并为每个类别设计一个“路由提示词”Router Prompt和对应的“目的地”Destination。在LangChain中我们可以使用LLMRouterChain或更灵活的MultiRouteChain的思路。但为了更清晰地理解原理我们先从底层构建一个路由函数。from langchain_openai import ChatOpenAI from langchain.prompts import ChatPromptTemplate from langchain.schema.output_parser import StrOutputParser from langchain.schema.runnable import RunnableBranch, RunnableLambda # 初始化路由专用的大模型。可以选用更快速、成本更低的模型如 gpt-3.5-turbo router_llm ChatOpenAI(modelgpt-4-turbo-preview, temperature0) # temperature设为0使路由决策更稳定 # 定义我们的意图类别 INTENT_CATEGORIES { “query”: “信息查询用户想要获取实时或事实性信息如天气、股价、新闻、定义等。”, “generate”: “内容生成用户需要创作或生成新的文本内容如写邮件、写文案、头脑风暴、翻译等。”, “code”: “代码辅助用户需要编写、分析、解释或调试代码。”, “plan”: “复杂任务规划用户需要完成一个多步骤的复杂任务涉及规划、决策、信息整合等。” } # 构建路由提示词模板 ROUTER_PROMPT_TEMPLATE ChatPromptTemplate.from_messages([ (“system”, “””你是一个精准的意图分类器。你的任务是根据用户的输入判断其属于以下哪个类别。 请只输出类别名称不要输出任何其他解释或文字。 可用的类别及其描述 {categories} 用户输入{input} 意图类别”””), ]) # 创建路由链 router_chain ROUTER_PROMPT_TEMPLATE | router_llm | StrOutputParser() # 测试路由函数 def route_intent(user_input: str) - str: “””根据用户输入返回意图类别””” categories_str “\n”.join([f”{k}: {v}” for k, v in INTENT_CATEGORIES.items()]) result router_chain.invoke({“categories”: categories_str, “input”: user_input}) # 清理输出确保返回的是我们定义的key之一 result result.strip().lower() for intent in INTENT_CATEGORIES.keys(): if intent in result: return intent # 如果无法匹配返回一个默认类别比如 ‘query’ return “query” # 进行测试 test_inputs [ “北京明天会下雨吗”, “写一首关于春天的五言绝句。”, “用Python实现快速排序算法。”, “帮我规划一下十一黄金周去西安的旅游行程。” ] for inp in test_inputs: intent route_intent(inp) print(f”输入{inp} - 路由结果{intent}”)运行这段代码你应该能看到类似以下的输出输入‘北京明天会下雨吗’ - 路由结果query 输入‘写一首关于春天的五言绝句。’ - 路由结果generate 输入‘用Python实现快速排序算法。’ - 路由结果code 输入‘帮我规划一下十一黄金周去西安的旅游行程。’ - 路由结果plan这证明我们的路由层已经可以工作了。但这里有一个关键点我们让LLM直接输出类别名称这种方式简单但可能会因为模型输出格式的微小差异比如多一个句号导致匹配失败。更健壮的做法是使用LangChain的PydanticOutputParser或利用LLM的Function Calling能力强制其返回结构化的JSON数据。2.3 升级路由使用Function Calling实现结构化输出使用Function Calling可以让路由决策更加稳定和结构化。我们定义一个“路由函数”让模型调用这个函数并传入判断好的类别。from langchain_core.pydantic_v1 import BaseModel, Field from typing import Literal # 使用Pydantic模型定义路由输出结构 class RouteDecision(BaseModel): “””路由决策结果””” intent: Literal[“query”, “generate”, “code”, “plan”] Field(description”用户输入的意图类别”) confidence: float Field(description”对此判断的置信度0到1之间”, ge0, le1) reasoning: str Field(description”做出此判断的简要理由”, max_length200) # 创建支持结构化输出的LLM structured_llm router_llm.with_structured_output(RouteDecision) # 构建新的路由提示词可以更简洁因为输出结构已定义 STRUCTURED_ROUTER_PROMPT ChatPromptTemplate.from_messages([ (“system”, “你是一个精准的意图分类器。请分析用户输入判断其意图类别。”), (“human”, “用户输入{input}”), ]) # 创建结构化路由链 structured_router_chain STRUCTURED_ROUTER_PROMPT | structured_llm def route_intent_structured(user_input: str) - RouteDecision: “””返回结构化的路由决策””” return structured_router_chain.invoke({“input”: user_input}) # 测试 for inp in test_inputs: decision route_intent_structured(inp) print(f”输入{inp}”) print(f” 意图{decision.intent}, 置信度{decision.confidence:.2f}”) print(f” 理由{decision.reasoning}\n”)现在路由层不仅返回类别还给出了置信度和理由这为后续的决策比如低置信度时请求用户澄清提供了更多信息系统也更加健壮。3. 构建各意图执行器让专业的人做专业的事路由完成后我们需要为每个意图类别构建对应的“执行器”。每个执行器都是一个独立的处理单元。为了演示我们将实现其中几个。3.1 信息查询执行器这个执行器负责处理事实性查询。我们可以集成一个搜索工具如DuckDuckGo和一个LLM来总结答案。from langchain_community.tools import DuckDuckGoSearchRun from langchain.prompts import PromptTemplate from langchain.schema.runnable import RunnablePassthrough # 初始化搜索工具 search_tool DuckDuckGoSearchRun() # 定义查询处理的提示词模板 QUERY_PROMPT PromptTemplate.from_template(“”” 你是一个信息助手。请根据提供的网络搜索信息回答用户的问题。 如果搜索信息不足以回答问题请如实告知不要编造。 用户问题{question} 搜索信息{search_results} 请给出清晰、准确的回答 “””) # 创建查询处理链 query_llm ChatOpenAI(model“gpt-4-turbo-preview”, temperature0.2) query_chain ( {“question”: RunnablePassthrough(), “search_results”: search_tool} | QUERY_PROMPT | query_llm | StrOutputParser() ) def execute_query(question: str) - str: “””执行信息查询””” return query_chain.invoke(question) # 测试 print(execute_query(“2026年奥运会将在哪里举行”))3.2 内容生成执行器这个执行器相对直接主要依靠LLM的生成能力但我们可以通过系统提示词来定制风格。GENERATE_PROMPT ChatPromptTemplate.from_messages([ (“system”, “你是一位专业的文案写手和内容创作者。请根据用户的要求生成高质量、流畅、符合语境的内容。”), (“human”, “{instruction}”), ]) generate_llm ChatOpenAI(model“gpt-4”, temperature0.7) # 温度稍高更有创造性 generate_chain GENERATE_PROMPT | generate_llm | StrOutputParser() def execute_generate(instruction: str) - str: “””执行内容生成””” return generate_chain.invoke({“instruction”: instruction}) # 测试 print(execute_generate(“为公司的新年晚会写一段主持人开场白要求活泼有趣。”))3.3 代码辅助执行器这个执行器需要理解编程问题并能生成或分析代码。我们可以利用Code Interpreter的思路或者让LLM生成代码后再通过一个安全沙箱如exec的受限环境或Docker容器进行简单验证注意生产环境需极其谨慎。CODE_PROMPT ChatPromptTemplate.from_messages([ (“system”, “””你是一个资深的编程助手。请用清晰、高效、符合最佳实践的代码回应用户的请求。 如果用户要求分析代码请指出问题、优化建议或潜在风险。 生成的代码请包含必要的注释。 语言优先使用用户指定的语言若未指定则根据问题上下文推断如无特别说明默认使用Python。 “””), (“human”, “{request}”), ]) code_llm ChatOpenAI(model“gpt-4-turbo-preview”, temperature0.1) # 温度低代码更稳定 code_chain CODE_PROMPT | code_llm | StrOutputParser() def execute_code_assist(request: str) - str: “””执行代码辅助””” return code_chain.invoke({“request”: request}) # 测试 print(execute_code_assist(“写一个Python函数判断一个字符串是不是回文。”))3.4 复杂任务规划执行器这是最复杂的部分。它本身可能就是一个子Agent需要拆解任务、制定步骤、并可能调用其他工具如查询、生成来逐步完成。这里我们展示一个简化版让LLM生成一个详细的规划大纲。PLANNING_PROMPT ChatPromptTemplate.from_messages([ (“system”, “””你是一个卓越的项目经理和规划师。请将用户复杂的请求分解为一个清晰、可执行、分步骤的行动计划。 计划应包括总体目标、关键步骤每一步应具体、可操作、所需资源或信息、以及潜在的风险或注意事项。 请以Markdown列表的形式输出。 “””), (“human”, “复杂任务{task}”), ]) planning_llm ChatOpenAI(model“gpt-4-turbo-preview”, temperature0.3) planning_chain PLANNING_PROMPT | planning_llm | StrOutputParser() def execute_planning(task: str) - str: “””执行任务规划””” return planning_chain.invoke({“task”: task}) # 测试 print(execute_planning(“我想在三个月内学习机器学习基础知识并完成一个预测房价的小项目。请帮我制定学习计划。”))4. 组装协调层构建完整的意图路由Agent现在我们有了一流的“调度员”路由层和多个专业的“工人”执行器。最后一步是创建“协调层”将两者连接起来形成一个完整的Agent。我们将使用LangChain的RunnableBranch它可以根据条件将输入路由到不同的处理链非常适合我们的场景。from langchain.schema.runnable import RunnableBranch, RunnableLambda # 1. 定义路由分支 # 每个分支是一个 (condition, runnable) 对。condition是一个返回布尔值的函数。 # 我们根据结构化路由决策的 intent 字段来路由。 def route_based_on_decision(decision: RouteDecision) - str: “””一个简单的路由函数返回意图字符串””” return decision.intent # 2. 将各个执行器封装成RunnableLambda或RunnableSequence # 注意执行器函数接收的是原始用户输入而不是路由决策对象。 query_executor RunnableLambda(execute_query) generate_executor RunnableLambda(execute_generate) code_executor RunnableLambda(execute_code_assist) plan_executor RunnableLambda(execute_planning) # 3. 创建分支 branches RunnableBranch( (lambda x: x “query”, query_executor), (lambda x: x “generate”, generate_executor), (lambda x: x “code”, code_executor), (lambda x: x “plan”, plan_executor), ) # 4. 构建完整的Agent工作流 # 工作流用户输入 - 结构化路由 - 提取意图 - 分支执行 - 结果 full_agent_chain ( structured_router_chain # 输入: {“input”: user_input}, 输出: RouteDecision对象 | RunnableLambda(lambda d: d.intent) # 从RouteDecision中提取intent字段 | branches # 根据intent路由到对应的执行器 ) # 为了方便调用我们包装一个函数它接收字符串返回字符串 def run_agent(user_input: str) - str: “””运行完整的意图路由Agent””” try: # 分支链需要意图字符串作为输入但我们需要先获取路由决策 decision structured_router_chain.invoke({“input”: user_input}) # 根据意图选择执行器 intent decision.intent if intent “query”: return execute_query(user_input) elif intent “generate”: return execute_generate(user_input) elif intent “code”: return execute_code_assist(user_input) elif intent “plan”: return execute_planning(user_input) else: return f“无法处理此意图{intent}” except Exception as e: return f“处理请求时出现错误{str(e)}” # 5. 进行端到端测试 complex_questions [ “马斯克最近有什么新闻”, “为我们的环保科技公司想一句slogan。”, “用React写一个简单的计数器组件。”, “我打算开始健身增肌请为我制定一个为期两个月的初级训练和饮食计划。” ] print(“ 完整Agent测试 \n”) for q in complex_questions: print(f”用户{q}”) print(f”助手{run_agent(q)}”) print(“-” * 50)运行这个完整的测试你将看到同一个run_agent函数能够根据不同的用户问题自动选择最合适的处理路径并给出相应的回答。这就是意图路由的魅力所在。5. 实战进阶意图路由的优化与挑战一个能跑通的Demo只是起点。要让意图路由在实际应用中可靠、高效还需要考虑以下几个关键问题5.1 处理模糊意图与低置信度我们的路由决策包含了confidence字段。当置信度低于某个阈值例如0.7时说明模型对意图的判断不确定。这时更好的策略不是强行路由而是向用户发起澄清。def run_agent_with_clarification(user_input: str, confidence_threshold: float 0.7) - str: “””带澄清的低置信度处理””” decision structured_router_chain.invoke({“input”: user_input}) if decision.confidence confidence_threshold: # 生成澄清问题 clarification_prompt ChatPromptTemplate.from_messages([ (“system”, “你正在尝试理解用户的意图但不太确定。请生成一个简洁的问题帮助用户澄清他们的需求。”), (“human”, f”用户原话‘{user_input}’。你判断的意图是‘{decision.intent}’但置信度较低{decision.confidence:.2f}。”), ]) clarify_chain clarification_prompt | ChatOpenAI(model“gpt-4-turbo-preview”, temperature0) | StrOutputParser() clarification clarify_chain.invoke({}) return f“[需要澄清] {clarification}” # 高置信度正常处理 return run_agent(user_input) # 复用之前的逻辑5.2 执行器的组合与嵌套“复杂任务规划”执行器本身可能就是一个“元Agent”。它生成的计划其中的某些步骤如“查询当地美食”、“生成预算表格”可以再次被路由到query或generate执行器。这就形成了嵌套路由是构建复杂、强大Agent的关键。实现这一点需要将协调层设计成可递归调用的或者使用LangGraph等专门用于构建有状态、多步骤工作流的框架。5.3 性能与成本考量路由模型选择路由不一定需要用最强大、最贵的模型。像gpt-3.5-turbo这类模型在分类任务上通常已经足够准确且响应更快、成本更低。可以进行A/B测试在准确率和成本间找到平衡。缓存对于常见的、重复的用户意图可以缓存路由结果避免每次都对相同或相似的输入调用LLM。异步处理如果执行器涉及网络请求如搜索或长时间运行的任务应使用异步调用避免阻塞主线程。5.4 评估与迭代如何知道你的路由系统工作得好不好你需要建立评估机制。收集测试集整理一批真实的用户输入并人工标注正确的意图类别。计算指标运行路由器计算准确率、召回率、F1分数等。分析错误仔细查看分错的案例。是类别定义模糊还是提示词需要优化或者是模型能力不足迭代优化根据分析结果调整意图类别定义、优化路由提示词、或引入更细粒度的分类例如将query进一步分为weather_query,stock_query,general_knowledge_query。6. 从LangChain到LangGraph构建有状态的智能体工作流在我们当前的实现中协调层是线性的、无状态的输入 - 路由 - 执行 - 输出。但对于真正的“复杂任务规划”这远远不够。规划往往是一个循环往复的过程制定计划 - 执行步骤 - 检查结果 - 调整计划 - 继续执行。这就是LangGraph发挥作用的地方。LangGraph基于LangChain构建专门用于创建有状态、可循环、多参与者的图工作流。它非常适合实现我们上面提到的“嵌套路由”和“动态规划执行”。想象一下我们的“旅行规划”Agent在LangGraph中的工作流可能如下节点意图路由。接收用户请求“规划西安旅行”路由到plan意图。节点计划生成。调用LLM生成一个初步计划大纲如确定日期、查询天气、预订机票、查找酒店、安排行程。节点步骤执行器。这是一个子图或循环。它遍历计划中的每个步骤对于“查询天气”它会将任务路由回主图的query执行器或一个专门的天气查询工具。对于“查找酒店”它可能调用一个酒店预订API工具。每个步骤执行后将结果收集到共享的“状态”中。条件边。检查所有步骤是否完成。如果完成进入下一个节点如果某个步骤失败或需要人工确认则进入“人工干预”节点或重新调整计划。节点结果汇总。将所有步骤的结果整合成一份完整的旅行计划报告。使用LangGraph你可以用代码清晰地定义这些节点和它们之间的流转关系包括条件分支和循环。这比用单纯的函数调用链来实现要清晰和强大得多。对于2026年想要构建复杂商业级Agent的开发者来说掌握LangGraph这类框架将是必备技能。我个人的体会是意图路由是Agent智能的“开关”和“导航”。一个设计良好的路由系统能让你的Agent从“一个有点聪明但时常犯晕的聊天机器人”升级为“一个目标明确、分工有序的智能团队”。在实战中不要追求一步到位设计出完美的路由分类而是应该从核心的、差异最明显的几个意图开始通过不断收集用户反馈和错误案例逐步迭代和细化你的路由策略。同时务必关注系统的可观测性记录下每一次路由的决策、置信度和最终结果这些数据是你优化系统最宝贵的资产。