
1. 项目概述为什么是 LangChain 1.x如果你最近在折腾大语言模型应用大概率听过 LangChain 这个名字。它就像一个为 LLM 应用开发准备的“瑞士军刀”把调用模型、处理数据、管理对话流程这些繁琐的活儿都封装好了。但你可能也发现了LangChain 的版本迭代有点快社区里关于 0.x 和 1.x 的讨论也让人有点迷糊。今天咱们就抛开那些复杂的概念直接上手最新的 LangChain 1.x看看它到底怎么用以及为什么说现在从 1.x 开始学是更明智的选择。简单来说LangChain 1.x 不是一个简单的版本号升级它代表了一次重大的 API 重构和设计理念的进化。0.x 版本虽然功能强大但 API 设计上存在一些历史包袱模块间的耦合度较高对于新手来说学习曲线陡峭。而 1.x 版本的核心目标就是“简化”和“模块化”它提供了更清晰、更一致的接口让开发者能像搭积木一样构建应用。举个例子以前你可能需要写一堆胶水代码来连接不同的组件现在很多功能通过声明式的LCEL就能轻松搞定。所以无论你是刚接触 LLM 开发的新手还是从 0.x 迁移过来的老手直接切入 1.x 都是性价比最高的选择。它能让你更快地构建出稳定、可维护的应用而不是把时间浪费在理解和适配旧的、即将被淘汰的 API 上。2. 环境准备与核心概念扫盲2.1 搭建你的 Python 开发环境工欲善其事必先利其器。在开始写代码之前一个干净、隔离的 Python 环境是必须的。我强烈推荐使用conda或venv来管理你的项目依赖这能避免不同项目间的包版本冲突是专业开发的基本素养。对于大多数开发者我建议直接使用venv因为它是 Python 3.3 之后内置的无需额外安装。打开你的终端或命令行跟着以下步骤操作# 1. 为你的 LangChain 项目创建一个新目录并进入 mkdir my-langchain-project cd my-langchain-project # 2. 创建虚拟环境环境名通常叫 venv 或 .venv python -m venv venv # 3. 激活虚拟环境 # 在 Windows 上 venv\Scripts\activate # 在 macOS/Linux 上 source venv/bin/activate激活后你的命令行提示符前通常会显示(venv)这表明你已经在这个隔离的环境中工作了。接下来安装 LangChainpip install langchain但请注意仅仅安装langchain是不够的。LangChain 本身是一个框架它需要与具体的大模型“连接”才能工作。因此你通常还需要安装对应模型供应商的 SDK。例如如果你要使用 OpenAI 的模型就需要额外安装openai库pip install openai注意langchain包是一个“元包”它包含了许多核心接口和工具但一些特定的集成如与向量数据库、特定工具链的深度集成可能需要安装额外的子包如langchain-community、langchain-openai等。在 1.x 版本中这种模块化设计更加清晰。对于快速上手先安装langchain和对应的模型 SDK如openai就足够了。2.2 理解 LangChain 1.x 的核心构建块安装好环境后我们先不急着写代码花几分钟理解一下 LangChain 1.x 最核心的几个抽象概念。这能让你后续的代码编写事半功倍。1.x 版本的设计非常清晰主要围绕以下几个核心组件展开模型 I/O (Model I/O)这是与 LLM 交互的基础层。主要包括Prompt 模板用于构建和格式化发送给模型的指令。1.x 的模板更加强大和灵活。语言模型大模型本身如 OpenAI 的 GPT、Anthropic 的 Claude 等。在 LangChain 中它们被抽象成统一的BaseLanguageModel接口。输出解析器用于将模型返回的非结构化文本字符串解析成你程序里需要的结构化数据如 Python 对象、JSON 等。检索 (Retrieval)当你的问题需要基于特定知识库如公司文档、产品手册来回答时就需要用到检索。这通常涉及将文档“切割”成片段转换成“向量”存入数据库提问时再找出最相关的片段送给模型。这是构建 RAG 应用的核心。链 (Chains)链是将多个组件模型、提示词、工具等按特定顺序组合起来完成一个复杂任务的“配方”。例如“总结网页内容”这个任务可能就是一个“获取网页文本 - 提取关键信息 - 用模型总结”的链。在 1.x 中LCEL成为了构建链的首选和推荐方式它让链的创建和组合变得异常简单和直观。代理 (Agents)代理是 LangChain 中最具想象力的部分。一个代理内置了一个“大脑”通常是 LLM和一套“工具”如搜索网络、查询数据库、执行代码。大脑根据用户的目标自主决定调用哪个工具、按什么顺序调用直到完成任务。这实现了真正的“自主”AI 应用。我们后面会重点体验如何使用create_agent来快速构建一个代理。记忆 (Memory)为了让对话或交互具有连续性记忆组件负责存储和管理历史对话信息并在新的交互中将其提供给模型。理解这些组件后你会发现 LangChain 1.x 的应用开发本质上就是选择合适的“积木”组件并用“胶水”LCEL 或链把它们按照业务逻辑粘合起来的过程。3. 从零开始你的第一个 LangChain 应用理论说得再多不如动手跑一行代码。让我们从最简单的“模型调用”开始逐步增加复杂度。3.1 基础模型调用与对话首先你需要一个 LLM 的 API 密钥。这里我们以 OpenAI 为例其他模型如 Anthropic、智谱 AI 等操作类似。确保你已经在环境变量中设置了OPENAI_API_KEY。import os from langchain_openai import ChatOpenAI # 1. 初始化聊天模型 # 推荐使用 ChatOpenAI 而非旧版的 OpenAI它专为对话优化。 # model_name 指定模型如最新的 “gpt-4o” temperature 控制创造性0-1越高越随机。 llm ChatOpenAI(model_namegpt-4o, temperature0.7) # 2. 发起一次简单的对话 response llm.invoke(请用一句话介绍 LangChain。) print(response.content) # 输出可能类似于“LangChain 是一个用于开发由语言模型驱动的应用程序的框架。”这段代码完成了最核心的交互问模型一个问题得到回答。llm.invoke是 1.x 中同步调用的标准方法。你可能会问为什么不直接用 OpenAI 的官方 SDKLangChain 的价值在于当你明天想换用 Claude 或国产大模型时只需要将ChatOpenAI替换成ChatAnthropic或ChatZhipuAI后面的代码几乎不用改。这就是抽象层带来的可移植性优势。3.2 使用 Prompt 模板提升交互质量直接传递字符串给模型在简单场景下可行但在复杂应用中我们需要结构化、可复用的提示词。这就是 Prompt 模板的用武之地。from langchain_core.prompts import ChatPromptTemplate # 1. 定义一个提示词模板 # 使用 ChatPromptTemplate.from_messages这是 1.x 推荐的方式支持多角色对话。 prompt_template ChatPromptTemplate.from_messages([ (system, 你是一位专业的{domain}专家回答问题时需严谨且易于理解。), (human, 请解释一下什么是{concept}) ]) # 2. 格式化模板传入变量 formatted_prompt prompt_template.invoke({ domain: 软件开发, concept: 面向对象编程 }) print(formatted_prompt.to_string()) # 输出 # System: 你是一位专业的软件开发专家回答问题时需严谨且易于理解。 # Human: 请解释一下什么是面向对象编程 # 3. 将格式化后的提示词传给模型 llm ChatOpenAI(modelgpt-4o, temperature0.5) response llm.invoke(formatted_prompt) print(response.content)实操心得在 1.x 中ChatPromptTemplate比旧的PromptTemplate更强大因为它天然支持 System、Human、AI 等多种消息角色这对于构建复杂的多轮对话应用至关重要。invoke方法返回的是一个PromptValue对象可以直接传递给模型的invoke方法这种一致性让代码非常优雅。3.3 使用 LCEL 构建你的第一个链前面我们把模型和提示词分开操作现在用LCEL把它们“链”起来。LCEL 的语法非常直观使用管道符|。from langchain_core.prompts import ChatPromptTemplate from langchain_openai import ChatOpenAI from langchain_core.output_parsers import StrOutputParser # 1. 定义组件 prompt ChatPromptTemplate.from_template(请将以下文本翻译成{language}{text}) llm ChatOpenAI(modelgpt-4o) output_parser StrOutputParser() # 一个简单的将模型输出解析为字符串的解析器 # 2. 使用 LCEL 构建链 # 语法 prompt | llm | output_parser # 读作将输入传给 prompt 格式化再给 llm 处理最后用 output_parser 解析。 translation_chain prompt | llm | output_parser # 3. 调用链 result translation_chain.invoke({ language: 法语, text: 你好世界 }) print(result) # 输出 Bonjour le monde!看我们只用一行代码prompt | llm | output_parser就创建了一个功能完整的翻译链。LCEL 的魅力在于它的可组合性。如果你想在翻译前先总结一下原文只需要再组合一个总结链即可。这种声明式的编程风格让复杂的 AI 应用逻辑变得清晰易懂。4. 核心实战打造你的第一个智能代理代理是 LangChain 的“杀手级”功能。想象一下你告诉 AI “帮我查一下北京明天天气然后根据天气推荐一件合适的穿搭”AI 能够自己决定先去调用天气查询工具拿到结果后再调用一个穿衣推荐工具最后把整合的结果给你。这就是代理。在 1.x 中创建代理的标准方式是使用create_react_agent。ReAct是“推理行动”的框架是当前最主流的代理范式之一。4.1 为代理准备工具代理自己不会搜索网络或计算它需要“工具”。我们先定义两个简单的工具from langchain.agents import tool import datetime # 使用 tool 装饰器可以轻松地将一个函数转化为 LangChain 可识别的工具。 # description 至关重要代理的大脑LLM就是根据这个描述来决定何时使用这个工具。 tool def get_current_time(placeholder: str) - str: 当用户询问当前时间、日期或今天星期几时调用此工具。参数 placeholder 无实际用处仅为满足工具格式要求。 now datetime.datetime.now() return f当前时间是{now.strftime(%Y-%m-%d %H:%M:%S)}今天是星期{[一,二,三,四,五,六,日][now.weekday()]}。 tool def calculate_length(text: str) - str: 当用户询问一段文本的长度、字符数或字数时调用此工具。 char_count len(text) word_count len(text.split()) return f文本 {text[:20]}... 的字符数为 {char_count}单词数按空格分割约为 {word_count}。4.2 创建并运行代理有了工具我们就可以创建代理了。这里会用到create_react_agent函数。from langchain.agents import create_react_agent from langchain_openai import ChatOpenAI from langchain.agents import AgentExecutor # 1. 准备模型和工具列表 llm ChatOpenAI(modelgpt-4o, temperature0) tools [get_current_time, calculate_length] # 2. 创建 ReAct 代理 # 需要提供一个 prompt 参数LangChain 提供了预制的、针对 ReAct 框架优化的提示词模板。 from langchain.agents import load_tools # 注意create_react_agent 期望一个 BasePromptTemplate我们可以使用内置的助手提示。 from langchain_core.prompts import PromptTemplate # 这是一个简化的 ReAct 提示模板。在实际复杂应用中建议使用 LangChain Hub 上更完善的版本。 react_prompt PromptTemplate.from_template( 你是一个乐于助人的助手可以访问以下工具 {tools} 请严格遵循以下格式回答问题 问题用户提出的问题 思考你需要思考如何一步步解决问题。你可以使用工具。 行动要使用的工具名称必须是[{tool_names}]中的一个。 行动输入工具的输入必须是一个简单的字符串。 观察工具返回的结果 ... (这个“思考/行动/行动输入/观察”的循环可以重复多次) 思考我现在知道了最终答案 最终答案对用户问题的最终、完整的回答 开始 问题{input} 思考{agent_scratchpad} ) agent create_react_agent(llm, tools, react_prompt) # 3. 创建代理执行器 # AgentExecutor 是驱动代理运行的核心它负责处理代理的思考循环、工具调用和错误处理。 agent_executor AgentExecutor(agentagent, toolstools, verboseTrue, handle_parsing_errorsTrue) # 4. 运行代理 result agent_executor.invoke({ input: 请问现在几点了另外Hello, LangChain! 这句话有多长 }) print(result[output])当你运行这段代码并将verboseTrue时你会在控制台看到代理完整的思考过程 进入新的 AgentExecutor 链... 思考用户问了两个问题当前时间和文本长度。我有两个工具get_current_time 和 calculate_length。我应该先回答时间再计算文本长度。 行动get_current_time 行动输入现在 观察当前时间是2024-05-20 14:30:15今天是星期二。 思考我已经得到了当前时间。现在需要计算文本长度。 行动calculate_length 行动输入Hello, LangChain! 观察文本 Hello, LangChain!... 的字符数为 16单词数按空格分割约为 2。 思考我现在知道了最终答案 最终答案现在是 2024年5月20日 星期二 下午2点30分15秒。文本 “Hello, LangChain!” 的字符数是16包含大约2个单词。 链结束。这个过程清晰地展示了代理的“推理-行动”循环。它自己规划了步骤选择了正确的工具并整合了结果。4.3 代理开发中的关键技巧与避坑指南在实际开发中打造一个稳定可靠的代理需要注意以下几点工具描述是灵魂LLM 完全依赖工具的description来决定是否调用它。描述必须清晰、准确说明工具的用途、适用场景和输入格式。模糊的描述会导致代理错误调用或拒绝调用。处理复杂输入/输出工具的参数和返回值应尽量简单字符串、数字、字典。如果返回复杂对象代理可能无法理解。必要时在工具内部将复杂结果格式化成清晰的文本描述。控制成本与超时代理可能会陷入无效的思考循环。务必在AgentExecutor中设置max_iterations最大迭代次数默认15和max_execution_time最大执行时间来防止无限循环和意外的高额 API 费用。善用verbose模式在开发调试阶段一定要开启verboseTrue。这是你洞察代理“内心想法”的唯一窗口能帮你快速定位是提示词问题、工具描述问题还是逻辑问题。错误处理工具调用可能失败网络错误、API限制。设置handle_parsing_errorsTrue可以让执行器在代理输出格式错误时尝试修复而不是直接崩溃。5. 进阶整合构建一个简单的 RAG 问答系统代理让 AI 有了“手”和“脚”而 RAG 则给了 AI 一个“外部大脑”。我们结合之前学的快速构建一个基于本地文档的问答系统。这里我们用Chroma作为向量数据库OpenAIEmbeddings来生成向量。# 安装必要的包 pip install langchain-chroma langchain-openai tiktoken from langchain_chroma import Chroma from langchain_openai import OpenAIEmbeddings, ChatOpenAI from langchain_core.prompts import ChatPromptTemplate from langchain_core.output_parsers import StrOutputParser from langchain_core.runnables import RunnablePassthrough from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain_community.document_loaders import TextLoader # 步骤 1: 加载并处理文档 loader TextLoader(./my_document.txt) # 假设你有一个文本文件 documents loader.load() # 将长文档切分成适合嵌入的小块 text_splitter RecursiveCharacterTextSplitter(chunk_size500, chunk_overlap50) chunks text_splitter.split_documents(documents) # 步骤 2: 创建向量数据库 embeddings OpenAIEmbeddings(modeltext-embedding-3-small) # 使用小尺寸嵌入模型以节省成本 vectorstore Chroma.from_documents(documentschunks, embeddingembeddings, persist_directory./chroma_db) # persist_directory 会将向量数据库保存到本地下次无需重新生成 # 步骤 3: 创建检索器 retriever vectorstore.as_retriever(search_kwargs{k: 3}) # 检索最相关的3个片段 # 步骤 4: 定义提示词模板用于将检索到的上下文和问题组合起来 template 你是一个知识渊博的助手。请仅根据以下提供的上下文信息来回答问题。 如果你在上下文中找不到答案就诚实地回答你不知道。不要编造信息。 上下文 {context} 问题{question} 请根据上下文给出答案 prompt ChatPromptTemplate.from_template(template) # 步骤 5: 定义 LLM 和输出解析器 llm ChatOpenAI(modelgpt-4o, temperature0) output_parser StrOutputParser() # 步骤 6: 使用 LCEL 组装 RAG 链 # 这个链的流程输入问题 - 用检索器获取上下文 - 格式化提示词 - 调用 LLM - 解析输出 rag_chain ( {context: retriever, question: RunnablePassthrough()} | prompt | llm | output_parser ) # 步骤 7: 提问 question 根据文档LangChain 的主要优势是什么 answer rag_chain.invoke(question) print(f问题{question}) print(f答案{answer})这个流程是 RAG 应用的标准范式加载 - 分割 - 嵌入 - 存储 - 检索 - 生成。通过 LCEL我们用几行清晰的代码就把这个复杂流程串联了起来。RunnablePassthrough()是一个特殊的组件它负责将输入这里是question原封不动地传递到下游。6. 常见问题与实战调试技巧在实际使用 LangChain 1.x 的过程中你肯定会遇到各种问题。这里我总结了一些最常见的“坑”和解决方法。6.1 版本兼容性与导入错误问题代码报错ImportError: cannot import name ... from langchain或看到LangChainDeprecationWarning。原因LangChain 1.x 进行了大幅度的模块重构。许多在 0.x 版本中直接从langchain主包导入的类现在移到了子包中。解决方案查阅官方迁移指南这是最重要的步骤。LangChain 官方提供了详细的迁移说明。使用正确的导入路径from langchain_openai import ChatOpenAI, OpenAIEmbeddings(替代from langchain.llms import OpenAI)from langchain_community.chat_models import ChatAnthropic(社区维护的集成)from langchain_core.prompts import ChatPromptTemplate(核心提示词模板)当你不知道从哪导入时直接去 LangChain API 参考 搜索类名是最快的方法。安装正确的包确保你安装了所需的集成包例如pip install langchain-openai langchain-chroma langchain-community。6.2 代理陷入循环或行为异常问题代理不停地调用同一个工具或者给出与问题无关的奇怪回答。排查思路检查工具描述这是最常见的原因。确保tool装饰器里的description字段清晰、无歧义准确说明了工具的功能和输入格式。用verboseTrue模式观察代理的思考过程看它是否误解了工具描述。简化提示词一开始可以使用官方提供的、经过验证的提示词模板如从 LangChain Hub 加载。不要一开始就自定义复杂的提示词。调整模型温度将temperature设为 0 或一个较低的值如 0.1可以减少模型的随机性使代理行为更稳定、可预测。限制迭代次数在AgentExecutor中设置max_iterations5来强制退出可能出现的死循环。6.3 RAG 检索效果不佳问题问答系统给出的答案不准确或者经常回答“我不知道”即使文档里有相关内容。优化方向文本分割策略RecursiveCharacterTextSplitter的chunk_size和chunk_overlap是关键参数。块太大会包含无关信息干扰模型块太小可能丢失关键上下文。通常从 500-1000 字符的chunk_size和 50-100 字符的overlap开始尝试。检索数量retriever.search_kwargs{“k”: 3}表示返回前 3 个相关片段。对于复杂问题可以尝试增加到 4 或 5给模型更多上下文。嵌入模型不同的嵌入模型效果差异很大。OpenAI 的text-embedding-3-small在成本和效果上取得了很好的平衡。对于中文场景可能需要考虑专门优化的双语或中文嵌入模型。提示词工程在 RAG 提示词中明确指令“仅根据上下文回答”并设计好上下文和问题的拼接格式有助于模型更好地利用检索到的信息。6.4 性能与成本优化问题应用响应慢或者 API 调用费用过高。实战技巧缓存对频繁重复的查询如相同的用户问题使用缓存。LangChain 内置了InMemoryCache或SQLiteCache。from langchain.globals import set_llm_cache from langchain.cache import InMemoryCache set_llm_cache(InMemoryCache())批处理如果有大量文档需要嵌入使用嵌入模型的批处理接口而不是循环调用单条。选择合适模型在原型阶段或简单任务上使用gpt-3.5-turbo而非gpt-4可以大幅降低成本。对于嵌入text-embedding-3-small比ada-002更便宜且性能更好。异步调用对于高并发应用使用ainvoke、abatch等异步方法可以显著提升吞吐量。走到这里你已经完成了从环境搭建、基础调用到构建代理和 RAG 系统的完整旅程。LangChain 1.x 的核心思想就是“组合”用清晰、一致的接口LCEL将各种功能模块模型、提示词、工具、检索器像管道一样连接起来。我个人的体会是初期不要追求构建大而全的系统而是从一个具体的小功能点切入比如“用一个工具查询天气”把它跑通理解数据流。然后逐步添加新的工具、引入记忆、或者换成更复杂的代理逻辑。多利用verboseTrue来观察内部过程这是最好的调试和学习方式。最后保持关注官方文档和更新这个生态正在快速发展但 1.x 的稳定 API 设计已经为你打下了坚实的基础。