LangChain 1.3实战:从零构建具备工具调用与记忆的智能体

LangChain 1.3实战:从零构建具备工具调用与记忆的智能体 在实际项目中集成大语言模型时开发者常常面临一个核心矛盾一方面我们希望利用LLM强大的理解和生成能力另一方面我们又需要它能够稳定、可靠地调用外部工具、访问私有数据并执行复杂逻辑。直接调用模型API往往只能完成简单的对话而要实现一个能自主规划、使用工具、处理数据的智能体则需要大量的胶水代码来处理提示词工程、工具调用、状态管理和错误处理。LangChain正是为了解决这一工程化难题而生的框架。它不是一个单一的库而是一套用于构建由语言模型驱动的应用程序的完整工具链和抽象层。对于开发者而言LangChain的核心价值在于将与大模型交互的常见模式如问答、摘要、数据提取和复杂流程如多步推理、工具调用、记忆管理标准化、模块化从而让开发者能够专注于业务逻辑而非底层通信细节。本文将以LangChain 1.3版本为基础从零开始带你完成一个智能体Agent从模型初始化到构建完整工作流的全过程。我们将不仅关注如何让代码跑起来更会深入解释每一步的设计意图、关键参数的影响以及生产环境中可能遇到的坑。无论你是希望快速上手LangChain进行应用开发还是为相关技术面试做准备这篇文章都将提供一条清晰的实践路径。1. 理解LangChain的核心抽象组件与链在开始写代码之前必须理解LangChain的几个核心抽象。这些抽象是框架的骨架混淆它们会导致后续配置和调试异常困难。1.1 模型I/O与LLM对话的标准化接口模型I/O层是LangChain与各种大模型交互的桥梁。它主要包含三个部分模型Models、提示词Prompts和输出解析器Output Parsers。模型LLMs/ChatModels这是对底层大模型API的封装。LLM模型接收字符串并返回字符串如GPT-3的text-davinci-003而ChatModel则接收消息列表并返回消息如GPT-4、Claude等。LangChain通过统一的接口调用它们屏蔽了不同供应商API的差异。提示词Prompts直接拼接字符串构建提示词既脆弱又难以维护。LangChain的PromptTemplate允许你创建带有变量的模板例如请总结关于{topic}的内容。更高级的ChatPromptTemplate则用于构建结构化的消息序列如System、Human、AI消息。输出解析器Output ParsersLLM的输出是文本但程序需要结构化的数据。OutputParser负责将模型的文本输出解析成我们需要的格式比如JSON对象、Python列表或者一个自定义的Pydantic模型。这三者共同构成了一个可预测的输入输出管道提示词模板 变量 - 填充后的提示词 - 发送给模型 - 原始文本输出 - 解析为结构化数据。1.2 记忆Memory让对话拥有上下文普通的API调用是无状态的。Memory组件赋予了链或智能体记住历史交互的能力。常见的Memory类型包括ConversationBufferMemory: 简单地将所有对话历史保存在一个缓冲区中。ConversationBufferWindowMemory: 只保留最近K轮对话。ConversationSummaryMemory: 对历史对话进行摘要以节省Token并保留长期上下文。VectorStoreRetrieverMemory: 将历史信息存入向量数据库需要时通过检索召回。选择哪种Memory取决于你的应用场景。对于长文档问答BufferWindow可能就够了对于多轮、复杂的对话SummaryMemory或VectorStoreMemory更为合适。1.3 链Chains将组件组合成可执行序列Chain是LangChain中最核心的编排概念。它代表了对一个组件的调用或对多个组件的序列化调用。最简单的链是LLMChain它组合了一个PromptTemplate、一个LLM和一个可选的OutputParser。# 伪代码示例一个简单的LLMChain from langchain.chains import LLMChain from langchain.prompts import PromptTemplate from langchain_openai import ChatOpenAI prompt PromptTemplate.from_template(请用一句话介绍{product}。) llm ChatOpenAI(modelgpt-3.5-turbo) chain LLMChain(llmllm, promptprompt) # 运行链 result chain.invoke({product: LangChain}) print(result[text])但链的真正威力在于组合。你可以通过SimpleSequentialChain或SequentialChain将多个链串联起来前一个链的输出作为后一个链的输入。例如可以先有一个链总结文档再用另一个链根据总结回答问题。1.4 智能体Agents与工具Tools让LLM学会使用外部能力智能体是LangChain的“杀手级”特性。一个智能体由以下几部分组成LLM作为智能体的“大脑”负责规划和决策。工具Tools智能体可以调用的函数。一个工具通常是一个Python函数它执行特定的任务如搜索网络、查询数据库、执行计算或调用API。工具包Toolkits一组相关工具的集合。智能体执行器Agent Executor这是运行智能体的运行时环境。它负责调用LLM解析其关于使用哪个工具的决策执行工具将结果反馈给LLM并循环此过程直到LLM给出最终答案。智能体的工作流可以概括为问题 - LLM思考决定使用哪个工具及输入- 执行工具 - 观察结果 - 再次思考 - ... - 给出最终答案。这使LLM的能力突破了其训练数据的限制能够处理实时信息、私有数据和复杂计算。2. 环境准备与项目初始化在开始编码前我们需要一个干净、可复现的Python环境。强烈建议使用虚拟环境来管理依赖。2.1 创建虚拟环境与安装依赖首先创建一个新的项目目录并进入。mkdir langchain-agent-tutorial cd langchain-agent-tutorial使用venv创建虚拟环境Python 3.8。python -m venv venv激活虚拟环境Linux/macOS:source venv/bin/activateWindows:venv\Scripts\activate激活后命令行提示符前通常会显示(venv)。接下来安装核心依赖。LangChain 1.x 版本后许多集成如与OpenAI、向量数据库的集成被拆分到了独立的langchain-*包中。我们需要安装核心包和可能用到的社区包。# 安装LangChain核心包 pip install langchain # 安装LangChain社区包包含许多第三方工具和集成 pip install langchain-community # 安装OpenAI集成如果你使用OpenAI的模型 pip install langchain-openai # 安装用于解析HTML等网络内容的包 pip install beautifulsoup4 # 安装用于发起HTTP请求的包许多工具需要 pip install requests # 可选安装用于环境变量管理的包 pip install python-dotenv注意langchain-community包包含了大量由社区维护的工具、LLM集成和向量存储集成。对于生产环境建议只安装你确切需要的特定集成包如langchain-openai以减少依赖冲突和安全风险。这里为了演示方便安装了社区包。2.2 配置API密钥大多数LLM服务如OpenAI、Anthropic都需要API密钥。永远不要将密钥硬编码在代码中。推荐使用环境变量管理。在项目根目录创建一个名为.env的文件# .env 文件 OPENAI_API_KEYsk-your-openai-api-key-here # 其他API密钥如SERPAPI_KEY、TAVILY_API_KEY等可按需添加然后在你的Python代码开头使用dotenv加载这些变量from dotenv import load_dotenv import os load_dotenv() # 从 .env 文件加载环境变量 openai_api_key os.getenv(OPENAI_API_KEY)2.3 初始化LangSmith可选但强烈推荐LangSmith是LangChain官方提供的调试、测试和监控平台。它能可视化地追踪每次链或智能体的调用步骤、输入输出、Token消耗和延迟是开发和排查问题的利器。访问 LangSmith官网 并注册。在设置中创建API密钥。在.env文件中添加LANGCHAIN_TRACING_V2true LANGCHAIN_ENDPOINThttps://api.smith.langchain.com LANGCHAIN_API_KEYls-your-langsmith-api-key-here LANGCHAIN_PROJECTyour-project-name # 设置项目名便于归类配置完成后当你运行代码时调用轨迹会自动上传到LangSmith你可以在网页上查看详细的执行过程。3. 从零构建你的第一个智能体我们将构建一个能够回答实时问题的智能体它可以使用网络搜索工具来获取最新信息。3.1 步骤一初始化语言模型我们以OpenAI的Chat模型为例。确保你的.env文件中已正确设置OPENAI_API_KEY。# agent_demo.py from langchain_openai import ChatOpenAI # 初始化Chat模型 # temperature控制创造性0.0更确定1.0更随机。对于工具调用通常设低一些。 # model_name指定模型版本。 llm ChatOpenAI( modelgpt-3.5-turbo, temperature0, openai_api_keyos.getenv(OPENAI_API_KEY) )关键参数解释model: 指定使用的模型。对于工具调用gpt-3.5-turbo或gpt-4系列是常见选择因为它们对函数调用Function Calling有良好支持。temperature: 生成文本的随机性。在需要稳定、可重复工具调用的Agent场景通常设置为0或一个较低的值如0.1。openai_api_key: 从环境变量传入避免密钥泄露。max_tokens: 限制模型单次响应的最大Token数防止响应过长。streaming: 设置为True可以启用流式输出适合需要实时显示的场景。3.2 步骤二定义工具Tools工具是智能体的“手”和“脚”。LangChain社区提供了大量预定义工具我们也可以自定义工具。首先我们使用一个预定义的网络搜索工具。这里以TavilySearchResults为例它需要一个 Tavily 的API密钥免费注册有额度。你也可以使用SerpAPI或DuckDuckGoSearchRun等。# 先安装Tavily集成包 # pip install langchain-tavily-search from langchain_community.tools.tavily_search import TavilySearchResults # 初始化搜索工具 # Tavily是一个专为AI优化的搜索引擎API search_tool TavilySearchResults( tavily_api_keyos.getenv(TAVILY_API_KEY), # 需要在.env中配置 max_results3 # 每次搜索返回的结果数 )自定义工具示例假设我们还需要一个计算器工具。from langchain.tools import tool from math import sqrt, log10, sin, cos, tan, radians tool def calculator(expression: str) - str: 执行数学计算。输入应为一个可被Python eval()安全执行的数学表达式字符串仅支持基本算术、math模块中的sqrt, log10, sin, cos, tan角度需先转弧度。例如‘3 5 * 2’ ‘sqrt(16)’ ‘sin(radians(30))’。 # 安全警告在生产环境中直接使用eval是危险的可能造成代码注入。 # 这里仅为演示。实际应用应使用安全的表达式解析库如asteval或严格限制字符集。 allowed_names {sqrt: sqrt, log10: log10, sin: sin, cos: cos, tan: tan, radians: radians} try: # 使用一个限制性的环境来执行表达式 result eval(expression, {__builtins__: {}}, allowed_names) return str(result) except Exception as e: return f计算错误{e}tool装饰器会自动将函数转换为LangChain能识别的Tool对象。docstring非常重要LLM会根据它来决定何时以及如何使用这个工具。3.3 步骤三创建智能体执行器有了模型和工具我们需要将它们组装起来。LangChain提供了多种智能体类型如ZERO_SHOT_REACT_DESCRIPTION,OPENAI_FUNCTIONS,STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION它们使用不同的提示词模板和推理逻辑。对于支持函数调用的模型如OpenAI的gpt-3.5/4OPENAI_FUNCTIONS或STRUCTURED_CHAT是高效且可靠的选择。from langchain.agents import create_openai_functions_agent, AgentExecutor from langchain import hub # 从LangChain Hub拉取一个适合OpenAI函数调用的提示词 # 这是一个预定义的、优化过的系统提示词指导LLM如何使用工具。 prompt hub.pull(hwchase17/openai-functions-agent) # 定义工具列表 tools [search_tool, calculator] # 创建智能体 agent create_openai_functions_agent(llm, tools, prompt) # 创建智能体执行器它是实际运行智能体的循环控制器 agent_executor AgentExecutor( agentagent, toolstools, verboseTrue, # 开启详细日志会在控制台打印每一步的思考过程 handle_parsing_errorsTrue, # 当LLM输出无法解析为工具调用时尝试处理错误 max_iterations10, # 限制最大迭代次数防止无限循环 early_stopping_methodgenerate, # 当LLM生成最终答案时停止 )关键参数解释verboseTrue: 开发调试时必开可以清晰看到Agent的“思考-行动-观察”循环。handle_parsing_errorsTrue: 当LLM的输出不符合工具调用格式时尝试让LLM重新生成。这是一个重要的容错机制。max_iterations:必须设置。防止Agent陷入死循环不断调用工具却无法得出最终答案。early_stopping_method: 通常设为generate表示当LLM的响应是一个直接给用户的最终答案而非工具调用时停止循环。3.4 步骤四运行与测试现在让我们运行这个智能体问它一个需要结合实时信息和计算的问题。# 运行智能体 question 截至今天苹果公司AAPL的股价是多少美元如果我用5000美元购买大概能买多少股忽略交易费用 try: result agent_executor.invoke({input: question}) print(\n 最终答案 ) print(result[output]) except Exception as e: print(f执行过程中出错{e})当verboseTrue时你会在控制台看到类似下面的输出这清晰地展示了Agent的工作流 Entering new AgentExecutor chain... 我需要找到苹果公司当前的股价然后计算5000美元能买多少股。 Action: tavily_search_results_json Action Input: {query: Apple Inc AAPL stock price today} Observation: [{title: Apple Inc. (AAPL) Stock Price Today, Quote News - Google Finance, url: https://www.google.com/finance/quote/AAPL:NASDAQ, content: Apple Inc. (AAPL) stock price today is $182.63 ...}, ...] Thought: 根据搜索结果苹果股价大约是182.63美元。现在计算5000美元能买多少股。 Action: calculator Action Input: 5000 / 182.63 Observation: 27.37 Thought: 我得到了计算结果。现在可以给出最终答案。 Final Answer: 截至今天根据网络信息苹果公司AAPL的股价大约为182.63美元。用5000美元购买在不考虑交易费用的情况下大约可以购买27股。 Finished chain. 最终答案 截至今天根据网络信息苹果公司AAPL的股价大约为182.63美元。用5000美元购买在不考虑交易费用的情况下大约可以购买27股。4. 深入解析工具调用、记忆与复杂工作流4.1 工具调用的底层机制与性能影响LangChain工具调用与LLM原生Function Call的区别本质上它们是一回事。当使用create_openai_functions_agent时LangChain在后台利用的是OpenAI模型原生的“函数调用Function Calling”能力。LLM接收工具函数的schema名称、描述、参数并在认为需要时输出一个符合该schema的JSON对象而不是普通文本。LangChain的Agent Executor捕获这个JSON找到对应的工具函数并执行。工具调用的速度受什么影响LLM响应延迟模型生成包含工具调用的响应需要时间与模型本身和temperature参数有关。工具执行时间如果工具是慢速的如调用一个慢速API、执行复杂查询这会成为瓶颈。网络往返次数每次工具调用都意味着一次LLM API调用。一个需要N步工具调用的任务至少需要N1次LLM调用N次思考1次最终生成这会显著增加总耗时和成本。上下文长度随着对话历史记忆和工具结果的累积提示词会变长可能影响LLM的处理速度和Token消耗。优化建议为工具编写清晰、精确的description帮助LLM准确判断何时使用。对于耗时工具考虑异步执行或设置超时。使用max_iterations严格限制循环次数。对于复杂但固定的流程考虑使用Chain而非Agent因为Chain的执行路径是确定的更高效。4.2 为智能体添加记忆Memory要让智能体在多轮对话中记住上下文需要将Memory集成到AgentExecutor中。from langchain.memory import ConversationBufferMemory # 创建一个对话记忆缓冲区 memory ConversationBufferMemory(memory_keychat_history, return_messagesTrue) # 在创建AgentExecutor时传入memory agent_executor_with_memory AgentExecutor( agentagent, toolstools, memorymemory, verboseTrue, handle_parsing_errorsTrue, max_iterations10, ) # 现在进行多轮对话 result1 agent_executor_with_memory.invoke({input: 你好我叫小明。}) print(result1[output]) # 可能回复你好小明 result2 agent_executor_with_memory.invoke({input: 你还记得我的名字吗}) # 因为memory中保存了上一轮对话LLM能回答出“你叫小明”。 print(result2[output])记忆的内容会被自动添加到发送给LLM的提示词中使其具备上下文感知能力。4.3 构建顺序工作流LangChain与LangGraph的选择LangChain vs. LangGraph vs. LangSmithLangChain核心框架提供构建LLM应用的基础模块模型、提示词、链、智能体、记忆。LangGraph基于LangChain专注于构建有状态、多参与者、可循环的复杂工作流。它用图Graph来定义节点Node和边Edge非常适合需要严格流程控制、分支、循环、并行处理的应用。如果你的智能体需要更复杂的决策循环比如一个模拟游戏、一个有多步审批的流程LangGraph是更好的选择。LangSmith开发运维平台用于调试、测试、监控和部署LangChain/LangGraph应用。何时用Chain何时用Agent何时用LangGraph确定性流程用Chain如果任务的步骤和顺序是固定的、可预测的例如获取数据 - 清洗数据 - 总结数据使用SequentialChain。它更高效、稳定。不确定性决策用Agent如果任务需要根据输入内容动态决定下一步做什么、使用哪个工具例如回答一个可能涉及搜索、计算、查数据库的开放性问题使用Agent。复杂状态与循环用LangGraph如果工作流包含复杂的状态管理、多个“参与者”不同的LLM或工具、显式的循环或条件分支例如一个客服对话系统需要根据用户意图在不同子流程间跳转使用LangGraph。5. 生产环境注意事项与常见问题排查将LangChain应用部署到生产环境需要考虑更多因素。5.1 配置管理切勿将API密钥、数据库连接字符串等敏感信息硬编码。使用环境变量或专业的配置管理服务如HashiCorp Vault、AWS Secrets Manager。在代码中通过os.getenv()读取。# 生产环境配置示例 import os from langchain_openai import ChatOpenAI from langchain_community.vectorstores import Chroma from langchain_community.embeddings import OpenAIEmbeddings def get_llm(): api_key os.environ.get(OPENAI_API_KEY) if not api_key: raise ValueError(OPENAI_API_KEY 环境变量未设置) return ChatOpenAI( modelos.environ.get(OPENAI_MODEL, gpt-4), temperaturefloat(os.environ.get(LLM_TEMPERATURE, 0.1)), openai_api_keyapi_key, max_tokensint(os.environ.get(MAX_TOKENS, 2000)), timeout30, # 设置请求超时 max_retries2, # 设置重试次数 )5.2 错误处理与鲁棒性智能体可能因为多种原因失败工具调用异常、LLM输出无法解析、达到最大迭代次数等。必须进行完善的错误处理。from langchain.schema import AgentFinish, OutputParserException try: result agent_executor.invoke( {input: question}, config{callbacks: [your_callback_handler]} # 可配置回调 ) except OutputParserException as e: # 处理LLM输出解析失败 logging.error(f解析Agent输出失败: {e}) # 可以尝试让Agent重试或返回一个友好的用户消息 result {output: 抱歉我处理您的请求时遇到了理解上的困难请尝试换一种方式提问。} except Exception as e: # 处理其他未知错误 logging.exception(fAgent执行发生未知错误: {e}) result {output: 系统暂时开小差了请稍后再试。}在AgentExecutor中合理设置max_iterations、handle_parsing_errors和max_execution_time是防止失控的重要手段。5.3 性能与成本监控Token消耗监控每次调用的输入/输出Token数。使用OpenAICallbackHandler等回调可以自动收集这些数据。延迟记录每个步骤LLM调用、工具执行的耗时。成本估算根据Token使用量和模型定价估算成本。对于高频应用这至关重要。LangSmith将这些监控任务交给LangSmith是最省心的方式它提供了完整的可视化追踪。5.4 常见问题排查清单当你的智能体表现不如预期时可以按照以下清单排查问题现象可能原因检查点解决方案Agent不调用任何工具直接回答1. 工具描述不清晰。2. LLM的temperature过高导致输出不稳定。3. 提示词Prompt未正确引导使用工具。1. 检查工具的description是否准确描述了功能和使用场景。2. 将temperature设为0再测试。3. 查看LangSmith轨迹检查发送给LLM的完整提示词。1. 重写工具描述使其更精确。2. 使用更低的temperature。3. 尝试不同的Agent类型或自定义提示词。Agent陷入无限循环不断调用同一个工具1. 工具返回的结果无法让LLM得出最终结论。2.max_iterations设置过高或未设置。3. 工具功能有缺陷返回错误或无关信息。1. 查看每次工具调用的Observation内容。2. 检查AgentExecutor的max_iterations参数。3. 单独测试工具函数确保其返回正确结果。1. 优化工具使其返回更结构化、信息量更足的结果。2. **务必设置合理的max_iterations如10。3. 修复工具逻辑增加错误处理。报错KeyError: ‘xxx‘或解析错误1. LLM输出的工具调用参数格式错误与预期schema不匹配。2. 自定义工具的args_schema定义有误。1. 开启verboseTrue查看LLM输出的原始Action Input。2. 检查自定义工具的参数定义Pydantic模型。1. 确保handle_parsing_errorsTrue以增加容错。2. 简化工具参数或为LLM提供更清晰的示例。执行速度非常慢1. 工具本身是慢速操作如网络请求。2. 上下文过长导致LLM处理慢。3. 网络延迟高。1. 为工具调用添加超时设置。2. 检查memory是否积累了过多内容。3. 使用本地模型或更近的API端点。1. 异步执行工具或使用缓存。2. 使用ConversationSummaryMemory或ConversationBufferWindowMemory限制历史长度。3. 考虑对LLM调用进行批处理或优化提示词。在LangSmith中看不到轨迹1. 环境变量LANGCHAIN_TRACING_V2未设置或为false。2. API密钥或端点配置错误。3. 代码中未正确初始化回调。1. 确认.env文件已加载且变量值正确。2. 检查LangSmith网站上的API密钥和项目设置。1. 确保在代码最开头加载dotenv并设置环境变量。2. 可以尝试在代码中显式设置os.environ[“LANGCHAIN_TRACING_V2”] “true”。6. 扩展方向与学习建议掌握了基础智能体的构建后你可以向以下几个方向深入集成更多数据源学习使用Document Loaders加载PDF、Word、网页等文档结合Text Splitters、Embeddings和Vectorstores构建RAG检索增强生成系统让智能体能够基于你的私有数据回答问题。探索复杂工作流学习使用LangGraph来构建具有复杂状态和分支的工作流例如模拟一个多角色对话系统或一个自动化业务流程。自定义与优化深入研究Custom Agents和Custom Tools创建完全符合你业务逻辑的组件。优化提示词工程提升任务执行的准确率和效率。部署与运维研究如何将LangChain应用打包为API服务使用FastAPI、Flask并部署到云服务器或容器平台。建立完整的监控、日志和告警体系。探索多模态结合视觉模型如GPT-4V和多模态工具构建能理解和处理图像、音频的智能体。学习路径建议从官方文档和教程开始然后通过克隆和修改示例项目来实践。遇到问题时优先查看LangSmith的调用轨迹它能帮你精准定位问题发生在哪个环节是提示词问题、工具问题还是LLM输出问题。记住构建可靠的AI应用是一个迭代过程需要不断地测试、观察和调整。