基于LangChain与ReAct机制:从零构建能调用工具的AI智能体
这次我们来看一个能让你亲手搭建AI Agent的项目。如果你对市面上各种AI助手背后的原理感到好奇想知道它们是如何“思考”和“行动”的那么这篇文章就是为你准备的。我们将聚焦于LangChain框架和ReAct机制通过一个完整的代码示例带你从零开始构建一个能调用外部工具的智能体。整个过程不涉及复杂的硬件部署核心是理解其工作机制并动手实践。LangChain是一个强大的开源框架它简化了基于大语言模型LLM的应用开发流程。而ReActReasoning Acting则是一种让LLM能够进行推理并执行行动如调用工具的范式。结合两者你就能打造一个具备基础“自主”能力的AI Agent。本文的重点不是复现一个商业级产品而是让你快速理解核心概念并跑通一个可工作的原型。无论你是想为现有项目添加智能交互还是为面试积累实战经验这篇文章都能提供直接的帮助。1. 核心能力速览在深入代码之前我们先快速了解基于LangChain和ReAct构建的AI Agent具备哪些核心能力以及你需要准备什么。能力项说明项目类型AI Agent开发框架与机制实践核心组件LangChain (框架)、ReAct (机制)、大语言模型 (如GPT-3.5/4)主要功能1. 理解用户意图并进行推理。2. 根据推理结果自动选择并调用预定义的工具如计算、搜索。3. 处理多轮对话具备记忆能力。4. 将复杂任务拆解为“推理-行动-观察”的循环步骤。硬件/环境门槛无特殊GPU要求。本项目主要依赖外部LLM API如OpenAI因此对本地算力要求极低普通CPU电脑即可运行。关键是需要能访问相应的模型API。启动与运行方式通过Python脚本启动本质是一个本地运行的Agent执行器通过代码调用。是否支持API本文示例为核心机制演示未封装成独立HTTP API服务但你可以基于此代码轻松集成到FastAPI等Web框架中。是否支持批量任务Agent本身是单次调用但可以通过循环或队列管理轻松实现批量任务处理。适合场景1. 学习AI Agent与ReAct机制原理。2. 快速原型验证为产品添加智能工具调用能力。3. 自动化工作流中的决策与执行环节。2. 适用场景与使用边界在动手之前明确它能做什么、不能做什么以及需要注意什么至关重要。它适合谁开发者/学习者希望深入理解AI Agent工作原理而不仅仅是调用现成API。项目原型构建者需要快速验证一个“能使用工具”的AI想法。自动化脚本升级者希望将固定的脚本升级为能根据情况自主选择工具的智能流程。它能解决什么问题动态工具选择用户提问“今天天气如何”Agent能自动推理出需要调用“天气查询工具”而不是让用户手动指定。复杂任务拆解用户提出“帮我分析上个月销售额下降的原因”Agent可以规划出先“获取数据”再“执行分析”最后“生成报告”的步骤。弥补LLM短板让LLM专注于其擅长的语言理解和推理而将精确计算、实时信息获取等任务交给专业工具。它的局限性是什么依赖LLM能力Agent的推理质量高度依赖于底层LLM如GPT的能力。工具定义需准确工具的描述description必须清晰否则LLM可能无法正确调用。非生产就绪本文示例为教学目的缺乏错误处理、权限管理、成本控制等生产级考量。存在幻觉风险LLM可能产生错误推理导致调用错误的工具或参数。安全与合规边界API密钥管理本文示例将API密钥硬编码在代码中这在实际项目中是极不安全的。务必使用环境变量或密钥管理服务。工具调用权限你定义的工具如删除文件、发送邮件可能具有破坏性。必须在工具实现内部做好权限校验和确认机制。内容合规LLM生成的内容需符合法律法规工具调用产生的结果如网络搜索也需进行内容审核。成本控制频繁调用LLM API和外部工具API可能产生费用需设置用量监控和限制。3. 环境准备与前置条件我们的目标是快速搭建一个可运行的环境。以下是详细的准备清单。3.1 基础软件环境操作系统Windows 10/11, macOS, 或 Linux (如Ubuntu 20.04)均可。Python版本推荐使用 Python 3.8 至 3.11 版本。避免使用过新或过旧的版本以免出现库依赖冲突。包管理工具使用pip进行包安装。建议先升级pippip install --upgrade pip。3.2 核心Python库安装我们将使用langchain和langchain-openai库。打开你的终端或命令提示符执行以下命令创建并激活虚拟环境强烈推荐以隔离项目依赖# 创建项目目录并进入 mkdir my_ai_agent cd my_ai_agent # 创建虚拟环境Windows python -m venv venv venv\Scripts\activate # Windows激活 # 创建虚拟环境macOS/Linux python3 -m venv venv source venv/bin/activate # macOS/Linux激活 # 安装核心依赖 pip install langchain langchain-openai解释langchain是核心框架langchain-openai提供了对OpenAI模型的便捷集成。3.3 获取LLM API访问权限本项目需要一个能够访问的大语言模型。我们将以OpenAI的GPT系列为例。访问 OpenAI平台 注册并登录。在API Keys页面点击Create new secret key创建一个新的API密钥。妥善保存此密钥我们将在代码中使用。你也可以使用其他兼容OpenAI API的模型服务只需在代码中更改base_url。3.4 代码编辑器选择你熟悉的即可如 VS Code、PyCharm 或 Sublime Text。4. 项目搭建与代码解析环境准备好后我们直接进入核心代码部分。我们将创建一个Python文件并逐部分解析其工作原理。4.1 创建项目文件在my_ai_agent目录下创建一个名为react_agent_demo.py的文件。4.2 完整代码与逐行解析将以下代码复制到文件中请将your_openai_api_key_here替换为你自己的API密钥。# react_agent_demo.py from langchain import hub from langchain.agents import create_structured_chat_agent, AgentExecutor from langchain.memory import ConversationBufferMemory from langchain.tools import BaseTool from langchain_openai import ChatOpenAI # 第一部分初始化大语言模型 (LLM) # 使用ChatOpenAI类来连接GPT模型。这里以GPT-3.5-turbo为例成本较低适合实验。 # 将‘your_openai_api_key_here’替换成你的真实API密钥。 # 如果你使用其他兼容OpenAI API的服务如Azure OpenAI、某些国内代理服务需要修改openai_api_base。 llm ChatOpenAI( modelgpt-3.5-turbo, openai_api_keyyour_openai_api_key_here, # 重要请勿将真实密钥提交到代码仓库 temperature0, # 温度设为0使输出更确定减少随机性 openai_api_basehttps://api.openai.com/v1 # 默认OpenAI端点若用其他服务需修改 ) # 第二部分定义自定义工具Tool # 工具是Agent可以调用的“手”和“脚”。这里我们创建一个加法计算工具。 # 必须继承BaseTool类并实现_run方法。 class CalculatorTool(BaseTool): # name和description至关重要LLM根据description来决定是否以及何时调用此工具。 name calculator description 当需要执行精确的数学计算特别是加法时使用此工具。输入应为两个数字。 # _run方法是工具的核心逻辑。这里我们实现一个简单的加法。 # 注意实际项目中这里可以连接数据库、调用外部API、执行系统命令等。 def _run(self, a: float, b: float) - float: 执行加法运算。 result a b print(f[工具日志] 计算 {a} {b} {result}) # 打印日志便于观察 return result # 可选如果工具需要异步支持可以实现_arun方法。 # async def _arun(self, a: float, b: float) - float: # return self._run(a, b) # 创建工具列表。一个Agent可以拥有多个工具如搜索工具、时间工具、文件读写工具等。 tools [CalculatorTool()] # 第三部分构建Agent提示词Prompt # ReAct机制需要特定的提示词来引导LLM进行“思考-行动-观察”的循环。 # LangChain Hub上预置了许多优秀的Agent提示词模板我们直接拉取一个适用于结构化聊天的。 # 这避免了我们从零开始编写复杂的提示词。 prompt hub.pull(hwchase17/structured-chat-agent) # 第四部分创建Agent和Agent执行器Executor # create_structured_chat_agent函数将LLM、工具和提示词组合成一个Agent。 agent create_structured_chat_agent(llmllm, toolstools, promptprompt) # ConversationBufferMemory为Agent添加记忆功能使其能记住对话历史。 memory ConversationBufferMemory(memory_keychat_history, return_messagesTrue) # AgentExecutor是驱动Agent运行的“发动机”。它负责解析LLM的输出调用工具处理观察结果并循环直到任务完成。 agent_executor AgentExecutor.from_agent_and_tools( agentagent, toolstools, memorymemory, verboseTrue, # 设置为True将在控制台输出详细的执行步骤便于调试和理解。 handle_parsing_errorsTrue # 优雅地处理LLM输出解析错误 ) # 第五部分运行测试 if __name__ __main__: print( 测试1需要调用工具的计算问题 ) # 这是一个需要精确计算的问题期望Agent自动调用CalculatorTool。 result1 agent_executor.invoke({input: 请帮我计算一下3.1415926加上2.7182818等于多少}) print(f最终答案: {result1[output]}\n) print( 测试2无需调用工具的纯文本问题 ) # 这是一个文本处理问题不涉及计算期望Agent直接利用LLM能力回答而不调用工具。 result2 agent_executor.invoke({input: 将这句话翻译成英文今天天气真好我们一起学习AI吧。}) print(f最终答案: {result2[output]}\n) print( 测试3基于历史记忆的连续对话 ) # 由于启用了memoryAgent能记住之前的对话。 result3 agent_executor.invoke({input: 我们刚才计算的第一个结果是多少}) print(f最终答案: {result3[output]})5. 功能测试与效果验证现在让我们运行这个脚本并观察ReAct机制是如何工作的。5.1 执行测试在终端中确保位于项目目录且虚拟环境已激活运行命令python react_agent_demo.py5.2 预期输出与过程解析如果一切正常你将在控制台看到类似以下的详细输出verboseTrue的作用 测试1需要调用工具的计算问题 Entering new AgentExecutor chain... Action:{ action: calculator, action_input: {a: 3.1415926, b: 2.7182818} }[工具日志] 计算 3.1415926 2.7182818 5.8598744 Observation: 5.8598744 Thought: 我已经通过计算工具得到了两个数字相加的结果。 Final Answer: 3.1415926 加上 2.7182818 等于 5.8598744。 Finished chain. 最终答案: 3.1415926 加上 2.7182818 等于 5.8598744。过程拆解ReAct循环推理 (Reasoning)LLM分析用户输入“计算3.14159262.7182818”判断这是一个数学计算问题。行动 (Action)LLM根据推理决定调用名为calculator的工具并生成正确的调用参数{a: 3.1415926, b: 2.7182818}。观察 (Observation)AgentExecutor执行工具调用CalculatorTool._run方法被执行返回结果5.8598744。这个结果被作为“观察”反馈给LLM。最终回答LLM接收到观察结果后进行最终推理组织成自然语言回答给用户。 测试2无需调用工具的纯文本问题 Entering new AgentExecutor chain... Thought: 这是一个翻译任务不需要使用计算器工具。 Final Answer: The weather is really nice today, lets study AI together. Finished chain. 最终答案: The weather is really nice today, lets study AI together.过程解析LLM推理后认为这是一个纯语言任务无需调用任何工具直接利用自身知识生成答案。这展示了Agent的智能决策能力——只在必要时才使用工具。 测试3基于历史记忆的连续对话 Entering new AgentExecutor chain... Thought: 用户问的是之前计算的结果。我需要查看聊天历史来找到它。 Final Answer: 我们之前计算的第一个结果是 3.1415926 加上 2.7182818 等于 5.8598744。 Finished chain. 最终答案: 我们之前计算的第一个结果是 3.1415926 加上 2.7182818 等于 5.8598744。过程解析ConversationBufferMemory发挥了作用。Agent在推理时能够访问到chat_history中存储的先前对话从而正确回答了基于历史的问题。5.3 判断成功的标准测试1成功Agent自动识别出计算需求正确调用了calculator工具并返回了精确的数值结果。测试2成功Agent正确判断无需使用工具直接给出了翻译结果。测试3成功Agent能够引用对话历史中的信息进行回答。控制台输出清晰verboseTrue模式下能清晰看到Thought、Action、Observation的步骤这正是ReAct机制的可视化体现。6. 扩展实践添加更多工具与复杂工作流一个只会加法的Agent显然不够看。我们来扩展它让它更强大。6.1 添加一个网络搜索工具模拟由于直接调用真实搜索引擎API需要密钥我们这里模拟一个工具。在实际项目中你可以集成SerpAPI、Tavily或DuckDuckGo等搜索工具。# 在定义CalculatorTool的代码块后添加以下工具类 import random class WebSearchTool(BaseTool): name web_search description 当需要获取最新的、模型训练数据之外的信息时使用此工具。例如查询新闻、天气、股价等。 def _run(self, query: str) - str: 模拟网络搜索返回模拟结果。实际应调用真实搜索API。 print(f[工具日志] 正在搜索: {query}) # 模拟不同的搜索结果 mock_results { 天气: 北京晴15-25°C上海多云18-28°C。, 股价: AAPL: $172.34 (1.2%)MSFT: $415.86 (0.8%)。, 新闻: 【模拟新闻】AI领域最新突破某团队发布新模型性能提升显著。 } # 简单匹配关键词实际应用中应更智能 for key in mock_results: if key in query: return mock_results[key] return f已为您搜索到关于{query}的相关信息此为模拟数据。 # 更新工具列表包含计算器和搜索工具 tools [CalculatorTool(), WebSearchTool()] # 注意创建agent和agent_executor时也要使用更新后的tools列表6.2 测试复杂查询更新代码后运行一个新的测试print( 测试4复杂任务需要组合推理 ) # 这个问题可能涉及搜索获取信息和计算 result4 agent_executor.invoke({input: 苹果公司今天的股价是多少如果我有100股总价值多少美元}) print(f最终答案: {result4[output]})预期行为Agent可能会先调用web_search工具获取股价然后调用calculator工具计算总价值100 * 股价。这展示了Agent处理多步骤任务的能力。7. 资源占用与性能观察与依赖本地大模型的AI应用不同本项目的主要资源消耗和性能瓶颈在于网络API调用。7.1 资源占用分析CPU/GPU本地运行代码本身消耗极低普通笔记本电脑即可流畅运行。主要计算发生在远程的LLM服务端。内存Python进程内存占用很小主要取决于对话历史memory的长度。对于一般对话内存占用可忽略不计。网络带宽需要稳定的网络连接以调用OpenAI API。每次Agent的“思考”和“回答”都可能产生一次或多次API调用。7.2 性能影响因素与优化LLM响应速度取决于你使用的API服务如OpenAI的延迟和速率限制。工具执行时间如果你的工具需要调用慢速的外部服务如查询大型数据库会拖慢整个Agent的响应。ReAct循环次数复杂问题可能导致多轮“思考-行动-观察”循环每次循环都是一次LLM API调用增加总耗时和成本。verbose模式在生产环境中应将verboseFalse以减少日志输出开销。优化建议设置超时和重试在调用外部API的工具中务必设置超时和重试逻辑。限制最大迭代次数AgentExecutor可以设置max_iterations参数防止Agent陷入无限循环。使用更高效的提示词从LangChain Hub选择或精心设计更高效的提示词可以减少不必要的思考步骤。缓存对频繁且结果不变的查询如某些计算可以在工具层添加缓存。8. 接口API封装与批量任务处理虽然我们的示例是脚本形式但将其改造成服务或用于批量处理非常容易。8.1 封装为FastAPI服务以下是一个简单的示例将Agent包装成HTTP API# agent_api.py from fastapi import FastAPI, HTTPException from pydantic import BaseModel from .react_agent_demo import agent_executor # 假设核心代码在react_agent_demo模块中 app FastAPI(titleAI Agent API) class QueryRequest(BaseModel): question: str app.post(/ask) async def ask_agent(request: QueryRequest): try: # 注意在生产环境中应考虑异步执行和任务队列避免阻塞。 result agent_executor.invoke({input: request.question}) return {answer: result[output]} except Exception as e: raise HTTPException(status_code500, detailstr(e)) if __name__ __main__: import uvicorn uvicorn.run(app, host0.0.0.0, port8000)启动服务后就可以通过POST /ask接口进行查询。8.2 处理批量任务对于需要处理文件内多个问题的场景可以编写一个简单的批处理脚本# batch_process.py import json from react_agent_demo import agent_executor # 导入你的agent def process_batch(input_file: str, output_file: str): with open(input_file, r, encodingutf-8) as f: questions [line.strip() for line in f if line.strip()] results [] for q in questions: print(f处理中: {q}) try: answer agent_executor.invoke({input: q}) results.append({question: q, answer: answer[output]}) except Exception as e: results.append({question: q, answer: f处理出错: {e}}) with open(output_file, w, encodingutf-8) as f: json.dump(results, f, ensure_asciiFalse, indent2) print(f批量处理完成结果已保存至 {output_file}) if __name__ __main__: # 假设 questions.txt 每行是一个问题 process_batch(questions.txt, answers.json)9. 常见问题与排查方法在开发过程中你可能会遇到以下问题问题现象可能原因排查方式解决方案ModuleNotFoundError: No module named ‘langchain’依赖未安装或不在当前Python环境。在终端执行 pip listgrep langchain。openai.AuthenticationErrorAPI密钥错误、过期或额度不足。检查代码中的openai_api_key是否正确。登录OpenAI平台检查额度。更新正确的API密钥。检查账单和用量。Agent陷入循环不输出最终答案提示词引导不佳或工具描述不清导致LLM无法做出最终决策。查看verboseTrue的日志观察Agent在重复什么动作。1. 检查工具description是否准确清晰。2. 在AgentExecutor中设置max_iterations10等限制。3. 尝试使用不同的提示词模板。LLM无法正确解析工具参数LLM生成的action_input格式与工具_run方法定义的参数不匹配。查看错误日志对比LLM输出的JSON和工具方法签名。1. 确保工具description中说明了输入格式。2. 使用StructuredTool或Tool的args_schema来明确定义参数JSON Schema。handle_parsing_errorsTrue仍报错LLM的输出完全不符合任何可解析的格式。查看完整的LLM输出内容。1. 降低LLM的temperature如设为0。2. 使用更强大的模型如GPT-4。3. 在提示词中更严格地规定输出格式。工具调用失败如网络超时工具内部依赖的外部服务不可用。在工具的_run方法内部添加更详细的异常捕获和日志。实现重试机制、设置超时时间、提供降级策略如返回缓存数据。10. 最佳实践与使用建议基于以上实践总结出以下几点建议帮助你更好地使用和扩展这个AI Agent。从简单开始逐步复杂化先实现一个能稳定运行的单工具Agent再逐步添加更多工具和复杂逻辑。不要一开始就设计过于复杂的工作流。精心设计工具描述Description这是LLM决定是否及如何调用工具的最重要依据。描述应简洁、准确说明工具的用途、输入和输出。例如“当需要获取某地当前天气时使用此工具。输入应为城市名称字符串。”实施严格的输入验证与清理在工具的_run方法内部务必对输入参数进行验证和清理防止注入攻击或非法操作尤其是当工具能执行文件、数据库或系统命令时。成本与性能监控记录每一次LLM调用和工具调用的耗时及成本如果涉及。这有助于优化提示词、工具选择和发现性能瓶颈。为生产环境做好准备密钥管理永远不要将API密钥硬编码在代码中。使用环境变量或专业的密钥管理服务。错误处理为整个Agent执行流程添加全局异常捕获和友好的错误信息返回。限流与降级如果作为API服务需要实施限流策略。当核心工具如搜索失败时应有降级方案如返回静态提示。深入理解ReAct的局限性ReAct依赖于LLM的推理能力对于逻辑极其复杂或需要超长规划步骤的任务它可能会“迷失”。对于确定性的复杂流程传统的编程工作流可能更可靠。通过这个从零开始的实战项目你已经掌握了使用LangChain和ReAct机制构建AI Agent的核心流程。关键在于理解“推理-行动-观察”这一循环如何赋予LLM使用工具的能力。接下来你可以尝试集成更实用的工具如数据库查询、邮件发送、内容生成或者探索LangChain提供的其他强大组件如索引、检索链来打造更智能、更专属的AI助手。