LangChain智能体实战:从ReAct框架到多工具协作构建AI助手

发布时间:2026/8/8 5:24:01
LangChain智能体实战:从ReAct框架到多工具协作构建AI助手
1. 项目概述从工具链到智能体实战如果你已经跟着上篇教程把LangChain的基本链条Chain和检索增强生成RAG系统跑通了那么恭喜你你已经拿到了进入大模型应用开发世界的入场券。但真正的魔法或者说让应用真正“活”起来的关键在于“智能体Agent”。上篇我们搭建的系统更像是一个流程固定的自动化流水线用户问系统查模型答。而智能体的核心思想是赋予系统“思考”和“使用工具”的能力让它能根据目标自主规划步骤、调用工具、处理复杂任务。这就像从一台自动售货机升级为一位拥有工具箱、能帮你解决各种问题的全能助手。本教程的下半部分我们将深入LangChain的智能体世界。我不会再重复安装环境和基础概念而是直接切入实战带你构建一个能理解复杂指令、自主调用搜索、计算、代码执行等工具并最终给出可靠答案的智能体。我们会重点剖析ReActReasoning Acting这一核心框架并对比不同的Agent类型如OpenAI Functions, ReAct, Self-ask with search等在实战中的表现差异。同时我会分享在开发过程中遇到的典型“坑”比如工具描述不清导致的幻觉、长上下文下的规划失效等问题并提供经过实测的解决方案。无论你是想开发一个能自动分析数据的AI分析师还是一个能联网查询最新信息的智能客服这篇实战指南都将为你提供清晰的路径和可复现的代码。2. 智能体的核心架构与设计思路在直接写代码之前我们必须先理解智能体系统是如何运转的。一个典型的LangChain智能体由几个核心部分组成理解它们之间的关系是设计高效智能体的前提。2.1 智能体系统的核心组件一个智能体系统不是单一模型而是一个精巧的协作体系。我们可以把它想象成一个项目团队大语言模型LLM是团队的“大脑”和“项目经理”它负责理解任务、制定计划、做出决策工具Tools是团队里的“专家成员”各自擅长特定领域如搜索、计算、数据库查询智能体Agent本身则是团队的“协作规则”和“执行流程”它定义了大脑如何指挥专家们工作。具体到LangChain的实现主要包括工具Tool 一个封装了特定功能的可调用对象。每个工具必须有清晰的name、description和args_schema参数模式。description至关重要它是LLM决定是否以及如何调用该工具的“说明书”。一个模糊的描述会导致LLM错误调用或直接忽略。工具包Toolkit 一组相关工具的集合方便管理。例如一个SQL工具包可能包含sql_db_query、sql_db_schema等工具。智能体执行器AgentExecutor 这是智能体的运行时引擎。它负责循环执行以下步骤将当前任务和观察结果上一步工具的输出传递给LLM - LLM思考并决定下一步行动调用某个工具或给出最终答案- 执行器调用对应的工具 - 将工具返回的结果作为新的“观察”输入下一轮循环。它还会处理错误、管理对话历史长度防止超出上下文窗口并决定何时停止。智能体类型AgentType 这决定了LLM的“思考模式”。不同的类型预设了不同的提示词模板和输出解析逻辑。例如ZERO_SHOT_REACT_DESCRIPTION适用于通用场景OPENAI_FUNCTIONS则专门为适配OpenAI的Function Calling能力而优化。2.2 ReAct框架让智能体学会“思考-行动”ReActReasoning Acting是目前最主流的智能体推理框架也是LangChain中多数Agent类型的理论基础。它的工作流程完美模拟了人类解决问题的方式思考Thought LLM分析当前状况用户问题、已有信息、可用工具并推理出下一步应该做什么。例如“用户想知道北京今天的天气。我需要使用搜索工具来获取实时信息。”行动Action 根据思考LLM格式化地输出要调用的工具名称和输入参数。例如Action: Search, Action Input: “北京今日天气”。观察Observation 执行器调用工具并将返回的结果如搜索到的天气信息反馈给LLM。循环 LLM接收到观察结果再次进入“思考”阶段评估信息是否足够回答用户问题。如果不够继续规划新的行动如果足够则输出最终答案Final Answer。这种显式的“思考-行动-观察”循环不仅让智能体的决策过程变得可解释、可调试也极大地提高了任务完成的可靠性。在代码中你会看到LLM的输出被严格解析为包含thoughtactionaction_input等字段的结构。2.3 工具设计的艺术清晰、精确、可靠工具是智能体的手脚设计好坏直接决定智能体的能力上限。这里有几个关键原则描述Description务必精准 避免使用“查询信息”这样模糊的描述。应该明确说明工具的功能、输入格式和输出内容。例如一个搜索工具的描述应该是“一个通用的搜索引擎工具用于获取关于当前事件或事实性问题的信息。输入应该是一个具体的搜索查询词。”参数模式Args Schema要严格定义 使用Pydantic模型明确定义工具所需的参数名称、类型和描述。这能帮助LLM更准确地生成调用参数。例如一个计算器的工具其args_schema应明确定义expression字段为字符串类型并描述为“一个数学表达式如’(35)*2’”。工具应保持原子性和可靠性 每个工具最好只做一件事并做好错误处理。一个总是抛出异常的工具会严重干扰智能体的决策循环。确保工具在无效输入时有友好的错误返回例如返回“错误无法解析表达式”而不是直接让Python异常冒泡。实操心得 在早期开发中我经常遇到智能体“幻觉”出不存在工具的情况。后来发现根本原因是工具描述和名称不够独特。比如有两个工具都叫“search”或者描述都是“用于查找资料”LLM就会混淆。给你的工具起一个具有区分度的名字并撰写差异化的详细描述能立刻提升智能体的工具调用准确率。3. 构建你的第一个多功能智能体从零到一理论说得再多不如一行代码。让我们开始构建一个能同时处理信息检索、数学计算和代码执行的智能体。我们将使用OpenAI的GPT-4作为“大脑”因为它具有优秀的推理和函数调用能力。3.1 环境准备与工具定义首先确保你已安装必要库并设置好API密钥。我们将使用langchain-openai新版LangChain的OpenAI集成和langchain的核心组件。# 安装必要库 (如果未安装) # pip install langchain langchain-openai langchain-community duckduckgo-search wikipedia import os from langchain_openai import ChatOpenAI from langchain.agents import AgentExecutor, create_openai_tools_agent from langchain.tools import Tool, DuckDuckGoSearchRun, WikipediaQueryRun from langchain_community.utilities import WikipediaAPIWrapper from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder from langchain.chains import LLMMathChain from langchain.agents import load_tools # 设置你的OpenAI API Key os.environ[OPENAI_API_KEY] your-api-key-here # 初始化LLM使用gpt-4-turbo以获得更好的推理能力 llm ChatOpenAI(modelgpt-4-turbo-preview, temperature0)接下来定义我们的工具集。我们将创建三个核心工具搜索工具 使用DuckDuckGo获取实时网络信息。维基百科工具 获取相对结构化的百科知识。计算工具 使用LangChain内置的LLMMathChain来处理数学计算。# 1. 初始化搜索和维基百科工具 search DuckDuckGoSearchRun() wiki WikipediaQueryRun(api_wrapperWikipediaAPIWrapper(top_k_results2, doc_content_chars_max1000)) # 2. 创建计算工具。LLMMathChain本身是一个Chain需要包装成Tool。 math_chain LLMMathChain.from_llm(llmllm, verboseFalse) math_tool Tool( nameCalculator, funcmath_chain.run, description专门用于解答数学计算问题。输入必须是一个明确的数学表达式或文字描述的计算问题。 例如计算圆的面积半径为5或直接输入(12 15) * 3 / 2。 ) # 3. 将搜索和维基百科也包装成Tool并赋予清晰的描述。 tools [ Tool( nameWeb_Search, funcsearch.run, description一个强大的互联网搜索引擎。当你需要获取最新的、实时的信息或者查询当前事件、新闻、天气、股价等动态数据时使用此工具。 输入应该是一个简洁、明确的关键词或查询语句。例如2024年巴黎奥运会最新消息。 ), Tool( nameWikipedia, funcwiki.run, description查询维基百科百科全书。当你需要了解某个概念、人物、历史事件、科学理论等相对稳定和结构化的知识时使用此工具。 输入应该是你想要查询的主题名称。例如人工智能爱因斯坦。 ), math_tool # 直接加入计算工具 ]3.2 构建智能体与执行器在LangChain的最新版本中推荐使用create_openai_tools_agent来构建适配OpenAI函数调用格式的智能体。我们需要定义一个提示模板来指导LLM的行为。# 定义智能体的提示词模板。这是一个非常关键的部分它设定了智能体的角色和行为准则。 prompt ChatPromptTemplate.from_messages([ (system, 你是一个强大且精准的AI助手。你可以使用工具来获取信息或进行计算。 请遵循以下规则 1. 仔细思考用户的问题判断是否需要使用工具以及使用哪个工具。 2. 如果使用工具请严格按照工具描述的要求来格式化你的输入。 3. 每次只执行一个操作调用一个工具。 4. 根据工具返回的结果进行下一步思考。如果结果足以回答问题请给出最终答案如果不够则继续使用合适的工具。 5. 你的最终答案应该基于工具返回的事实并清晰、完整地呈现给用户。如果信息不确定请说明。 ), MessagesPlaceholder(variable_namechat_history), # 预留位置用于多轮对话 (human, {input}), MessagesPlaceholder(variable_nameagent_scratchpad), # 这里是执行器自动填充思考-行动-观察记录的地方 ]) # 创建智能体 agent create_openai_tools_agent(llm, tools, prompt) # 创建智能体执行器它是真正运行循环的组件 agent_executor AgentExecutor( agentagent, toolstools, verboseTrue, # 设为True可以看到详细的思考过程调试时非常有用 handle_parsing_errorsTrue, # 自动处理LLM输出格式解析错误 max_iterations10, # 防止智能体陷入无限循环设置最大迭代次数 early_stopping_methodgenerate, # 当LLM连续两次输出“Final Answer”时停止 )3.3 运行测试看智能体如何工作现在让我们用一个复杂问题来测试我们的智能体。将verboseTrue可以看到完整的ReAct过程。# 测试一个需要多步推理和工具调用的问题 result agent_executor.invoke({ input: 请先搜索一下OpenAI公司最新的CEO是谁然后计算一下他的年龄如果已知出生年份与2024年的差值。 }) print(\n *50) print(最终答案) print(result[output])当你运行这段代码时在控制台会看到类似以下的输出verbose模式 Entering new AgentExecutor chain... 思考用户的问题分为两部分。首先我需要找到OpenAI公司最新的CEO是谁。这是一个关于当前公司领导层的事实性问题应该使用网络搜索工具来获取最新信息。 行动调用Web_Search工具输入“OpenAI CEO 最新”。 观察[搜索引擎返回的结果例如“OpenAI现任CEO为Sam Altman...”] 思考我得到了信息OpenAI的CEO是Sam Altman。接下来需要计算他的年龄。我需要知道他的出生年份。让我再搜索一下Sam Altman的出生信息。 行动调用Web_Search工具输入“Sam Altman 出生年份”。 观察[搜索结果“Sam Altman出生于1985年4月22日...”] 思考现在我知道了Sam Altman出生于1985年。用户要求计算他的年龄与2024年的差值也就是2024 - 1985。这是一个数学计算问题应该使用计算器工具。 行动调用Calculator工具输入“2024 - 1985”。 观察39 思考我已经完成了所有步骤。我找到了OpenAI的最新CEO是Sam Altman并计算出他在2024年是39岁假设计算时是2024年。现在可以给出最终答案。 最终答案根据搜索到的信息OpenAI公司最新的CEO是Sam Altman。他出生于1985年因此在2024年他的年龄是39岁。 Finished chain. 最终答案 根据搜索到的信息OpenAI公司最新的CEO是Sam Altman。他出生于1985年因此在2024年他的年龄是39岁。这个过程清晰地展示了ReAct框架的威力智能体自主规划了“搜索CEO - 搜索出生年份 - 计算年龄”的步骤链并正确选择了对应的工具。4. 高级话题智能体类型对比与长上下文管理构建出基础智能体后我们会面临更多实际挑战哪种Agent类型更适合我的场景当任务步骤非常多对话历史很长时智能体会“忘记”最初的目标吗4.1 主流智能体类型深度解析LangChain提供了多种预设的AgentType它们主要区别在于提示词模板和输出解析器。了解其差异能帮你做出更好选择。ZERO_SHOT_REACT_DESCRIPTION 这是最通用、最常用的类型。它使用标准的ReAct格式要求LLM输出Thought:Action:Action Input:。它对工具的描述依赖度很高适用于大多数通用LLM。优点是兼容性好缺点是输出格式需要严格解析有时LLM会不按格式输出导致错误。OPENAI_FUNCTIONS/OPENAI_MULTI_FUNCTIONS 这是为OpenAI模型量身定做的类型。它利用OpenAI原生的“函数调用Function Calling”功能。你不需要复杂的输出解析LLM会直接返回一个结构化的JSON指明要调用的函数工具及其参数。优点是极其稳定、可靠与OpenAI模型集成度最高格式错误极少缺点是只能用于支持函数调用的OpenAI模型如gpt-3.5-turbo, gpt-4。STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION 这个类型要求为工具定义严格的args_schema使用Pydantic。LLM会基于这个模式来生成结构化的动作输入。它比ZERO_SHOT更精确尤其适合参数复杂的工具。优点是参数生成更准确缺点是提示词更复杂可能消耗更多tokens。CONVERSATIONAL_REACT_DESCRIPTION 在ZERO_SHOT的基础上专门为多轮对话场景优化。它能更好地维护和管理对话历史上下文。选择建议 如果你主要使用OpenAI的模型无脑选择OPENAI_FUNCTIONS它的稳定性和易用性是最好的。如果你使用其他模型如Anthropic Claude、本地部署的LLaMA等那么ZERO_SHOT_REACT_DESCRIPTION或STRUCTURED_CHAT是更通用的选择。在我们的示例中由于使用了ChatOpenAI和create_openai_tools_agent底层默认就采用了OPENAI_FUNCTIONS的范式。4.2 处理复杂任务与长上下文挑战当智能体需要执行一个包含非常多步骤的复杂任务时例如分析一份长文档然后进行多轮搜索和计算所有的“思考”、“行动”、“观察”文本都会累积在对话历史中很容易触及LLM的上下文长度限制如GPT-4 Turbo的128K tokens。一旦超出最早的关键信息比如用户最初的问题可能会被“遗忘”导致智能体跑偏。LangChain的AgentExecutor提供了一些机制来应对max_iterations 硬性限制循环次数防止无限循环或步骤过多。根据任务复杂度合理设置一般10-20步对于大多数任务已足够。early_stopping_method 设置提前停止条件。“generate”模式比较常用当LLM连续两次输出“Final Answer”时停止这可以应对一些输出抖动。对话历史摘要Memory 这是解决长上下文问题的核心策略。不是把所有原始历史都传给LLM而是使用一个“记忆”组件来维护一个精炼的摘要。from langchain.memory import ConversationSummaryBufferMemory from langchain.chains import ConversationChain # 创建一个具有摘要功能的记忆体 memory ConversationSummaryBufferMemory( llmllm, # 需要一个LLM来生成摘要 max_token_limit2000, # 记忆体的最大token限制 return_messagesTrue # 返回消息格式适用于ChatModel ) # 我们需要将记忆体集成到智能体中。一种方法是将记忆作为输入变量的一部分。 # 注意create_openai_tools_agent的prompt中我们已经预留了chat_history的Placeholder。 # 我们需要在调用执行器时将memory中的历史传递进去。 # 首先让我们重写一个支持记忆的调用流程 prompt_with_memory ChatPromptTemplate.from_messages([ (system, 你是一个强大且精准的AI助手。你可以使用工具来获取信息或进行计算。 以下是之前的对话摘要{summary} 请基于摘要和当前问题继续协助用户。), # 将系统提示改为包含摘要 MessagesPlaceholder(variable_namechat_history), (human, {input}), MessagesPlaceholder(variable_nameagent_scratchpad), ]) # 重新创建智能体和执行器这里为了演示简化流程。实际应用可能需要更复杂的封装 agent_with_memory create_openai_tools_agent(llm, tools, prompt_with_memory) agent_executor_with_memory AgentExecutor( agentagent_with_memory, toolstools, verboseTrue, memorymemory, # 将memory对象传给执行器 max_iterations15, ) # 使用示例 result1 agent_executor_with_memory.invoke({input: 特斯拉的股票代码是什么}) print(result1[output]) # 假设回答了“TSLA” # 在后续问题中记忆体中的摘要会帮助LLM记住上下文 result2 agent_executor_with_memory.invoke({input: 它今天的股价是多少}) # LLM在思考时会知道“它”指的是特斯拉并可能直接调用搜索工具查询“TSLA stock price today”ConversationSummaryBufferMemory的工作原理是当对话历史超过max_token_limit时它会使用LLM将早期的对话内容压缩成一个简短的摘要然后将这个摘要和最近的对话历史一起作为新的上下文。这样既保留了关键信息又节省了token。避坑指南 记忆管理是个精细活。摘要虽然节省空间但不可避免地会丢失细节。对于需要精确引用之前长篇内容的场景如基于长文档问答更好的方案是使用RAG来管理文档知识而用记忆来管理对话流程本身。将长文档存入向量数据库让智能体学会在需要时去检索而不是依赖有限的对话上下文。5. 实战进阶构建专属工具与处理复杂输出当内置工具无法满足需求时你需要创建自定义工具。同时智能体调用的工具可能返回复杂结构如JSON、列表我们需要教会LLM如何理解和利用这些结果。5.1 创建自定义工具以天气查询为例假设我们需要一个查询指定城市天气的工具。我们可以封装一个调用公开天气API的函数。import requests from pydantic import BaseModel, Field from typing import Type # 首先定义工具的输入参数模型 class WeatherInput(BaseModel): location: str Field(description城市名称例如北京 New York。最好使用英文城市名以提高API兼容性。) units: str Field(description温度单位metric表示摄氏度imperial表示华氏度。默认为metric。, defaultmetric) # 然后编写工具函数 def get_current_weather(location: str, units: str metric) - str: 获取指定城市的当前天气情况。 这是一个模拟函数实际应用中你需要替换为真实的天气API如OpenWeatherMap。 # 这里使用OpenWeatherMap API作为示例你需要注册并获取API KEY api_key YOUR_OPENWEATHERMAP_API_KEY if api_key YOUR_OPENWEATHERMAP_API_KEY: # 模拟返回用于演示 return f当前模拟天气数据{location}的天气为晴朗温度25摄氏度。 base_url http://api.openweathermap.org/data/2.5/weather params { q: location, appid: api_key, units: units } try: response requests.get(base_url, paramsparams, timeout10) data response.json() if response.status_code 200: city data[name] temp data[main][temp] desc data[weather][0][description] return f{city}的当前天气{desc}温度{temp}°{C if unitsmetric else F}。 else: return f错误无法获取{location}的天气API返回{data.get(message, 未知错误)} except Exception as e: return f请求天气API时发生异常{str(e)} # 最后使用LangChain的tool装饰器或Tool类创建工具 from langchain.tools import tool tool(args_schemaWeatherInput) def weather_tool(location: str, units: str metric) - str: 获取指定城市的当前天气情况。输入需要城市名。 return get_current_weather(location, units) # 或者使用Tool类创建 weather_tool_alt Tool.from_function( funcget_current_weather, nameGet_Weather, description查询指定城市的实时天气。输入参数为城市名字符串和可选单位metric或imperial。, args_schemaWeatherInput ) # 将自定义工具加入到工具列表中 tools.append(weather_tool_alt)现在你的智能体就拥有了查询天气的能力。当用户问“上海天气怎么样”时LLM会根据工具描述识别出需要调用Get_Weather工具并自动将“上海”作为location参数传入。5.2 处理结构化工具输出与多工具协作有时工具返回的不是简单文本而是JSON等结构化数据。智能体需要理解这些数据以进行下一步决策。例如一个数据库查询工具可能返回一个包含多条记录的列表。关键在于工具的描述和返回格式。你可以在工具描述中明确说明返回的数据结构并让工具函数返回一个易于LLM理解的字符串化摘要。import json def query_user_database(query: str) - str: 模拟一个用户数据库查询工具。 返回一个用户列表的JSON字符串摘要。 # 模拟数据库查询结果 mock_data [ {id: 1, name: 张三, department: 技术部, salary: 15000}, {id: 2, name: 李四, department: 市场部, salary: 12000}, {id: 3, name: 王五, department: 技术部, salary: 18000}, ] # 简单过滤逻辑仅用于演示 filtered_data [user for user in mock_data if query.lower() in user[department].lower() or query.lower() in user[name].lower()] if not filtered_data: return 未找到匹配的用户。 # 将结果格式化为清晰的文本便于LLM阅读 result_str 找到以下用户\n for user in filtered_data: result_str f- 姓名{user[name]}部门{user[department]}薪资{user[salary]}元\n return result_str db_tool Tool.from_function( funcquery_user_database, nameQuery_User_DB, description查询用户数据库。输入是一个查询字符串可以包含部门名称或用户姓名的一部分。 工具将返回匹配用户的清晰列表包含姓名、部门和薪资信息。 ) # 测试多工具协作先查数据库再计算平均薪资 agent_executor.tools.append(db_tool) # 临时加入工具 complex_result agent_executor.invoke({ input: 请先查询技术部有哪些员工然后计算他们的平均薪资。 })在这个例子中智能体会先调用Query_User_DB工具获得“技术部有张三和王五薪资分别为15000和18000”的文本结果。然后LLM会理解这个结果并规划下一步行动调用Calculator工具输入(15000 18000) / 2来计算平均薪资。核心技巧 让工具返回对LLM“友好”的文本至关重要。避免直接返回原始的、复杂的JSON或HTML。在工具函数内部做好数据的清洗、筛选和格式化用自然语言或简洁的列表形式呈现关键信息能极大提升智能体后续推理的准确性和效率。6. 调试、优化与生产化部署建议开发智能体的过程很少一帆风顺。你会遇到LLM不按格式输出、工具调用循环、返回结果无法理解等问题。以下是一些实战中总结的调试和优化经验。6.1 常见问题与排查技巧实录问题1智能体陷入无限循环或重复调用同一工具现象 控制台不断输出相似的Thought和Action始终无法输出Final Answer。可能原因工具描述不清 LLM无法从工具结果中提取所需信息认为任务未完成于是反复调用。工具返回错误或无关信息 工具本身API出错或返回的内容无法解答问题。最大迭代次数设置过高 即使有问题也一直循环。解决方案检查工具描述 确保描述准确说明了工具的功能和输出。例如计算器工具的描述应强调“用于数学计算”而不是“用于解决问题”。增强工具鲁棒性 在工具函数内添加更完善的错误处理和结果验证。对于搜索类工具如果返回“未找到结果”可以明确返回“未搜索到相关信息”而不是空字符串或错误页面HTML。启用verboseTrue 这是最重要的调试手段。仔细观察每一轮Thought的内容。如果LLM的思考逻辑出现偏差例如它一直在纠结一个错误的前提问题可能出在之前的某次Observation上。降低max_iterations 先设为一个较小的值如5快速失败便于定位问题。问题2LLM输出格式错误导致AgentExecutor解析失败现象 抛出OutputParserException之类的异常。可能原因 主要发生在使用ZERO_SHOT_REACT_DESCRIPTION等非OpenAI函数调用的Agent类型时。LLM有时不会严格遵守Thought:Action:Action Input:的格式。解决方案使用handle_parsing_errorsTrue参数AgentExecutor会尝试自动修复一些小的格式错误。优化提示词System Prompt 在系统提示中更加强调输出格式。例如明确写上“你必须严格按照以下格式输出\nThought: [你的思考]\nAction: [工具名]\nAction Input: [工具输入]”。切换到OPENAI_FUNCTIONS类型 这是最根本的解决方案。OpenAI的函数调用功能几乎完全避免了格式错误问题。问题3智能体在复杂多步任务中“迷失方向”现象 任务执行到一半智能体似乎忘记了最终目标开始进行无关的操作。可能原因 上下文过长早期目标被挤出上下文窗口或者中间步骤的观察结果引入了大量无关细节干扰了LLM。解决方案使用ConversationSummaryBufferMemory 如前所述对历史进行摘要。精简工具返回 确保每个工具返回的都是最精炼、最相关的信息去掉无关的HTML标签、广告文本等。在系统提示中强化目标 在提示词开头反复强调用户的最初问题。例如“你的最终目标是{用户问题}。请所有思考都围绕这个最终目标进行。”6.2 性能优化与生产化考量当你准备将智能体投入生产环境时需要考虑以下方面成本控制 智能体的每次Thought和工具调用后的重新推理都会消耗LLM的token。一个复杂的多步任务成本可能很高。策略 设定严格的max_iterations。对工具返回内容进行长度限制例如只截取搜索结果的摘要。对于常见问题可以结合简单的RAG或规则系统先行过滤避免所有请求都走昂贵的智能体流程。延迟 串行的“思考-行动-观察”循环会导致总耗时等于各步骤之和。如果工具调用涉及网络请求如搜索、API调用延迟会叠加。策略 尽可能选择响应速度快的工具。对于可以并行调用的工具例如同时查询多个不相关的数据源目前的LangChain标准AgentExecutor不支持但更高级的框架如LangGraph支持这种“规划-并行执行”的模式。稳定性与监控错误处理 确保AgentExecutor配置了完善的错误处理handle_parsing_errors,max_iterations。日志记录 记录每一次完整的交互链包括所有Thought, Action, Observation这对于调试和优化至关重要。看门狗Watchdog 对于长时间运行的任务可以考虑外部超时控制防止因某个工具挂起而导致整个智能体进程卡住。评估与测试 建立一套测试用例覆盖常见问题、边界情况和复杂多步任务。定期运行测试评估智能体的成功率、平均步骤数和成本作为迭代优化的依据。构建一个成熟可用的智能体系统是一个持续迭代和优化的过程。从最简单的工具链开始逐步增加工具复杂度仔细设计提示词和工具描述并通过大量的测试和调试来打磨其可靠性和智能性。LangChain提供了强大的基础设施但最终智能体的“智慧”程度取决于你对领域问题的理解、对工具的设计以及对LLM能力的巧妙引导。