
1. 从零搭建 LangChain 开发环境为什么版本管理比装包本身更重要很多人第一次接触 LangChain第一反应是打开终端敲pip install langchain然后跑一个官方示例看到输出就觉得自己入门了。但真正开始写项目时各种报错接踵而至ImportError、ModuleNotFoundError、API 调用返回 401、模型名称不识别……这些问题九成以上不是 LangChain 本身的 bug而是环境没搭对。我见过太多初学者在这一步卡住然后开始怀疑自己是不是不适合学 AI 开发。其实问题很简单LangChain 的生态迭代速度极快不同版本之间的 API 差异巨大而 Python 环境如果管理混乱装出来的包版本互相冲突后面写什么都是白搭。1.1 Python 版本选择与虚拟环境的必要性LangChain 目前对 Python 版本的要求是 3.9 及以上但我实测下来推荐直接用 Python 3.11。原因有三第一3.11 在性能上比 3.9 有明显提升尤其是涉及大量字符串处理和异步调用时第二3.11 对类型注解的支持更完善LangChain 的很多新特性依赖这些第三主流云平台和容器镜像对 3.11 的支持已经非常成熟。安装 Python 本身没什么好说的官网下载安装包一路下一步即可。Windows 用户注意勾选“Add Python to PATH”否则后面在命令行里调用python会提示找不到命令。Mac 用户如果用的是 M 系列芯片建议直接去官网下载 arm64 版本的安装包不要用系统自带的 Python。虚拟环境这一步绝对不能省。我不管你之前写 Python 是不是一直全局装包做 LangChain 开发必须用虚拟环境。原因很简单LangChain 依赖的包非常多包括pydantic、openai、langchain-core、langchain-community等等这些包各自又有自己的依赖链。如果你全局装很可能和你之前某个项目的依赖版本冲突到时候排查起来非常痛苦。创建虚拟环境的命令python -m venv langchain-envWindows 激活langchain-env\Scripts\activateMac/Linux 激活source langchain-env/bin/activate激活后你的命令行前面会出现(langchain-env)的标识说明当前处于虚拟环境中。之后所有pip install操作都只影响这个环境不会污染全局。1.2 LangChain 包结构的变化与正确安装方式这里要重点讲一个很多人踩过的坑。LangChain 在 0.1 版本之后做了大规模重构把原来一个大包拆成了多个子包包名作用langchain-core核心抽象层定义 Runnable、Prompt、OutputParser 等基础接口langchain-community社区贡献的第三方集成包括各种模型、向量库、工具langchain-openaiOpenAI 官方集成包langchain-google-genaiGoogle Gemini 集成包langchain高层封装包含 Chain、Agent 等如果你只装langchain很多集成功能是用不了的。正确的安装方式是按需安装pip install langchain langchain-core langchain-community langchain-openai langchain-google-genai另外强烈建议装python-dotenv用来管理 API Keypip install python-dotenv注意不要一次性装太多包。我建议先装核心的几个跑通一个最小示例后再根据需求逐步添加。这样出问题时容易定位是哪个包引起的。1.3 API Key 的安全管理别把密钥写死在代码里初学者最容易犯的错误就是把 API Key 直接写在代码里# 错误示范 openai_api_key sk-xxxxxxxxxxxx这样做的问题第一如果你把代码传到 GitHub密钥就泄露了别人可以拿去刷你的额度第二切换不同项目时要改代码容易出错第三团队协作时每个人都要改代码非常混乱。正确做法是用.env文件管理OPENAI_API_KEYsk-xxxxxxxxxxxx GOOGLE_API_KEYxxxxxxxxxxxx然后在代码里这样读取from dotenv import load_dotenv import os load_dotenv() openai_key os.getenv(OPENAI_API_KEY)记得把.env加入.gitignore避免误提交。这个习惯看起来简单但养成之后能省掉很多麻烦。2. 用 LangChain 调用大模型从最简示例到多模型切换环境搭好之后下一步就是让代码真正跑起来。LangChain 最大的价值之一就是提供了一套统一的接口让你可以用几乎相同的方式调用不同厂商的模型。这意味着你写好的业务逻辑换一个模型只需要改几行代码。2.1 最小可运行示例三行代码调用 OpenAI先来看最基础的调用方式from langchain_openai import ChatOpenAI llm ChatOpenAI(modelgpt-4o-mini) response llm.invoke(用一句话解释什么是大语言模型) print(response.content)这三行代码背后发生的事情ChatOpenAI初始化时读取环境变量中的 API Key创建一个客户端对象invoke方法把输入文本包装成消息格式发送到 OpenAI 的接口返回的response是一个AIMessage对象content属性才是真正的文本内容。很多人第一次跑的时候会忘记设置环境变量然后报 401 错误。如果你确认.env文件写对了但还是报错检查一下load_dotenv()是否在创建模型对象之前调用。2.2 切换到 Gemini接口统一带来的便利现在假设你想换成 Google 的 Gemini 模型代码改动非常小from langchain_google_genai import ChatGoogleGenerativeAI llm ChatGoogleGenerativeAI(modelgemini-1.5-flash) response llm.invoke(用一句话解释什么是大语言模型) print(response.content)注意这里的关键点两个模型类的invoke方法签名完全一致。这就是 LangChain 抽象层的价值。你的业务代码不需要关心底层是哪个模型只需要面向invoke这个接口编程。我个人的经验是在项目初期可以同时配置多个模型通过一个配置项来切换。比如import os from dotenv import load_dotenv from langchain_openai import ChatOpenAI from langchain_google_genai import ChatGoogleGenerativeAI load_dotenv() def get_llm(provideropenai): if provider openai: return ChatOpenAI(modelgpt-4o-mini) elif provider gemini: return ChatGoogleGenerativeAI(modelgemini-1.5-flash) else: raise ValueError(f不支持的模型提供商: {provider}) llm get_llm(gemini) print(llm.invoke(你好).content)这样做的好处是当某个模型服务出现波动时你可以快速切换而不需要改业务逻辑。2.3 消息角色与多轮对话的实现大语言模型的对话本质上是一系列消息的序列。LangChain 定义了三种消息类型SystemMessage系统提示用来设定模型的行为和角色HumanMessage用户输入AIMessage模型回复一个典型的多轮对话是这样的from langchain_core.messages import SystemMessage, HumanMessage, AIMessage messages [ SystemMessage(content你是一个 Python 编程助手回答要简洁准确。), HumanMessage(content什么是列表推导式), AIMessage(content列表推导式是一种简洁创建列表的语法。), HumanMessage(content给我一个例子) ] response llm.invoke(messages) print(response.content)这里的关键在于你需要手动维护messages列表每次对话后把新的用户输入和模型回复追加进去。LangChain 提供了ChatMessageHistory来简化这个过程但理解底层原理很重要因为后面做 Agent 和复杂 Chain 时消息管理是核心。提示SystemMessage的内容会显著影响模型的表现。我建议在系统提示里明确说明输出格式、语言、角色定位这样能减少很多后续处理的工作。3. Prompt 模板与输出解析让模型输出可控可解析直接调用模型返回的是自然语言文本但实际项目中我们往往需要结构化的数据。比如从一段文本中提取姓名、电话、地址或者让模型按照固定格式输出 JSON。这就需要 Prompt 模板和输出解析器配合使用。3.1 PromptTemplate 的基本用法Prompt 模板的核心思想是把可变部分抽出来固定部分复用。最简单的例子from langchain_core.prompts import ChatPromptTemplate prompt ChatPromptTemplate.from_messages([ (system, 你是一个专业的翻译助手将用户输入翻译成{target_language}。), (human, {text}) ]) formatted prompt.format_messages(target_language英文, text今天天气真好) response llm.invoke(formatted) print(response.content)ChatPromptTemplate的from_messages方法接受一个消息列表其中用{}包裹的是变量占位符。调用format_messages时传入具体值就会生成完整的消息列表。这种写法的好处是Prompt 和代码逻辑分离。你可以把 Prompt 单独放在一个文件里方便调整和版本管理。3.2 用 PydanticOutputParser 强制模型输出结构化数据假设你需要从用户评论中提取情感倾向和关键词希望输出 JSON 格式。手动写 Prompt 让模型输出 JSON 经常不稳定模型可能会加一些额外的解释文字。用PydanticOutputParser可以解决这个问题from langchain_core.output_parsers import PydanticOutputParser from pydantic import BaseModel, Field class ReviewAnalysis(BaseModel): sentiment: str Field(description情感倾向只能是 positive、negative 或 neutral) keywords: list[str] Field(description评论中的关键词列表) parser PydanticOutputParser(pydantic_objectReviewAnalysis) prompt ChatPromptTemplate.from_messages([ (system, 分析用户评论提取情感倾向和关键词。\n{format_instructions}), (human, {review}) ]) chain prompt | llm | parser result chain.invoke({ review: 这个产品质量很好物流也快非常满意, format_instructions: parser.get_format_instructions() }) print(result.sentiment) print(result.keywords)这里用到了 LangChain 的管道操作符|把 Prompt、模型、解析器串成一条链。get_format_instructions()会自动生成格式说明告诉模型应该输出什么样的 JSON。实测下来这种方式比手动写“请输出 JSON”要稳定得多。因为解析器会在模型输出不符合格式时抛出明确的错误方便你定位问题。3.3 处理解析失败的常见情况即使有了解析器模型偶尔还是会输出不符合格式的内容。常见原因有两个一是模型能力不够二是 Prompt 里的格式说明不够清晰。我的处理经验是在系统提示里明确说“只输出 JSON不要有任何其他文字”使用OutputFixingParser做兜底当解析失败时自动让模型修复对于关键业务加一层 try-except解析失败时记录日志并降级处理from langchain.output_parsers import OutputFixingParser fixing_parser OutputFixingParser.from_llm(parserparser, llmllm) chain prompt | llm | fixing_parserOutputFixingParser的原理是当原始解析器失败时把错误信息和原始输出一起发给模型让模型重新输出正确格式。这会多消耗一次 API 调用但对于稳定性要求高的场景是值得的。4. 构建 Chain 与 Agent从固定流程到自主决策前面讲的都是单次调用实际项目往往需要多步骤处理。LangChain 提供了两种主要的编排方式Chain 和 Agent。理解它们的区别和适用场景是进阶的关键。4.1 LCEL 表达式语言用管道符串联处理步骤LCELLangChain Expression Language是 LangChain 0.1 之后主推的编排方式核心就是|操作符。它的设计灵感来自 Unix 管道前一步的输出作为后一步的输入。一个典型的多步骤 Chainfrom langchain_core.prompts import ChatPromptTemplate from langchain_core.output_parsers import StrOutputParser # 第一步生成产品描述 desc_prompt ChatPromptTemplate.from_template(为以下产品写一段吸引人的描述{product}) # 第二步根据描述生成广告语 slogan_prompt ChatPromptTemplate.from_template(根据以下描述写一句简短的广告语{description}) chain ( desc_prompt | llm | StrOutputParser() | (lambda x: {description: x}) | slogan_prompt | llm | StrOutputParser() ) result chain.invoke({product: 一款便携式咖啡机}) print(result)这里用了一个 lambda 函数来转换数据格式因为第二步的 Prompt 需要的是description字段而第一步输出的是纯字符串。这种数据格式转换在 Chain 中非常常见。LCEL 的优势在于支持流式输出、支持异步调用、支持批量处理而且代码可读性强。我建议新项目优先用 LCEL除非有特殊需求。4.2 Agent 的工作机制让模型自己决定调用什么工具Chain 是固定流程Agent 则是动态决策。Agent 的核心思路是给模型一组工具函数让模型根据用户问题自己决定调用哪个工具、传什么参数。先定义工具from langchain_core.tools import tool tool def get_weather(city: str) - str: 查询指定城市的天气 # 实际项目中这里会调用天气 API return f{city}今天晴气温 25 度 tool def calculate(expression: str) - str: 计算数学表达式 return str(eval(expression))然后创建 Agentfrom langchain.agents import create_tool_calling_agent, AgentExecutor from langchain_core.prompts import ChatPromptTemplate prompt ChatPromptTemplate.from_messages([ (system, 你是一个有用的助手可以查询天气和进行计算。), (human, {input}), (placeholder, {agent_scratchpad}) ]) agent create_tool_calling_agent(llm, [get_weather, calculate], prompt) executor AgentExecutor(agentagent, tools[get_weather, calculate], verboseTrue) result executor.invoke({input: 北京今天天气怎么样顺便帮我算一下 23 乘以 47}) print(result[output])verboseTrue会打印出 Agent 的思考过程方便调试。你会看到模型先决定调用get_weather拿到结果后再决定调用calculate最后综合两个结果给出回答。注意Agent 的稳定性高度依赖模型的能力。我用下来GPT-4 级别的模型在工具调用上明显比小模型可靠。如果预算有限建议先用 Chain 实现固定流程等模型能力提升或预算充足时再上 Agent。4.3 Chain 与 Agent 的选型建议维度ChainAgent流程固定预先定义动态模型决定可控性高中灵活性低高调试难度低高适用场景流程明确的业务需要多工具协作的复杂任务我的建议是能用 Chain 解决的不要用 Agent。Agent 看起来酷但调试成本高而且模型偶尔会做出意料之外的决策。只有在流程确实无法预先确定时才考虑 Agent。5. 实战中的坑与经验那些文档里不会写的东西这一部分是我在实际项目中踩过的坑和总结的经验官方文档里通常不会提到但对初学者来说非常有用。5.1 模型名称写错导致的报错LangChain 本身不校验模型名称它只是把名称透传给 API。所以如果你写错了模型名报错信息来自 API 提供商而不是 LangChain。比如 OpenAI 会返回model_not_foundGemini 会返回not found。我的做法是在配置里维护一个模型名称列表启动时校验。另外不同提供商的模型命名规则不同OpenAI 用gpt-4o-miniGemini 用gemini-1.5-flash不要混用。5.2 超时与重试网络波动时的必备配置调用远程 API 时网络波动是常态。LangChain 的模型类支持timeout和max_retries参数llm ChatOpenAI( modelgpt-4o-mini, timeout30, max_retries3 )timeout是单次请求的超时时间max_retries是失败后的重试次数。我建议 timeout 设 30 秒max_retries 设 2 到 3 次。设太大反而不好因为如果 API 真的挂了重试再多次也没用只会浪费时间。5.3 Token 消耗的监控与优化大模型 API 是按 Token 计费的初学者很容易在不知不觉中消耗大量额度。几个实用的优化技巧精简 SystemMessage去掉不必要的说明对于长文本先做摘要再传给模型使用tiktoken库预估 Token 数量在开发阶段用便宜的小模型上线前再切换import tiktoken encoding tiktoken.encoding_for_model(gpt-4o-mini) tokens encoding.encode(你的文本内容) print(fToken 数量: {len(tokens)})养成监控 Token 的习惯能帮你避免月底看到账单时的心痛。5.4 异步调用提升吞吐量如果你的应用需要同时处理多个请求同步调用会成为瓶颈。LangChain 支持异步调用import asyncio async def main(): result await llm.ainvoke(你好) print(result.content) asyncio.run(main())对于批量处理场景可以用abatchasync def batch_process(): results await llm.abatch([问题1, 问题2, 问题3]) for r in results: print(r.content) asyncio.run(batch_process())异步调用的吞吐量比同步高很多尤其是在等待 API 响应的时间里可以并发处理其他请求。5.5 日志与调试verbose 模式的使用开发阶段建议开启 verbose 模式能看到 LangChain 内部的执行细节import langchain langchain.verbose True或者针对单个 Chainexecutor AgentExecutor(agentagent, toolstools, verboseTrue)verbose 模式会打印每一步的输入输出对于理解 Chain 和 Agent 的工作机制非常有帮助。但上线时要关掉否则日志量太大。6. 从示例到项目一个完整的 LangChain 应用骨架学到这里你已经掌握了 LangChain 的核心概念。最后给一个完整的项目骨架把前面讲的内容串起来。6.1 项目目录结构my-langchain-app/ ├── .env ├── .gitignore ├── requirements.txt ├── config.py ├── llm_factory.py ├── chains/ │ ├── __init__.py │ └── analysis_chain.py ├── tools/ │ ├── __init__.py │ └── custom_tools.py └── main.py这个结构的好处是职责分离配置、模型创建、Chain 定义、工具定义各自独立方便维护和测试。6.2 核心模块代码config.pyimport os from dotenv import load_dotenv load_dotenv() OPENAI_API_KEY os.getenv(OPENAI_API_KEY) GOOGLE_API_KEY os.getenv(GOOGLE_API_KEY) DEFAULT_MODEL os.getenv(DEFAULT_MODEL, gpt-4o-mini)llm_factory.pyfrom langchain_openai import ChatOpenAI from langchain_google_genai import ChatGoogleGenerativeAI from config import DEFAULT_MODEL def create_llm(provideropenai, **kwargs): if provider openai: return ChatOpenAI(modelDEFAULT_MODEL, timeout30, max_retries3, **kwargs) elif provider gemini: return ChatGoogleGenerativeAI(modelgemini-1.5-flash, **kwargs) raise ValueError(f未知提供商: {provider})main.pyfrom llm_factory import create_llm from chains.analysis_chain import build_analysis_chain def main(): llm create_llm(openai) chain build_analysis_chain(llm) result chain.invoke({text: 这个产品非常好用推荐购买}) print(result) if __name__ __main__: main()6.3 依赖管理requirements.txt 的正确写法langchain0.2.0 langchain-core0.2.0 langchain-community0.2.0 langchain-openai0.1.0 langchain-google-genai1.0.0 python-dotenv1.0.0 pydantic2.7.0建议锁定版本号避免不同环境装出不同版本导致行为不一致。升级时手动改版本号测试通过后再提交。6.4 测试与迭代的建议写 LangChain 应用测试非常重要。我的做法是对每个 Chain 写单元测试用 mock 替换真实 API 调用对 Prompt 做 A/B 测试比较不同写法的效果记录每次调用的输入输出方便回溯问题from unittest.mock import patch patch(llm_factory.ChatOpenAI) def test_analysis_chain(mock_llm): mock_llm.return_value.invoke.return_value.content {sentiment: positive} # 测试逻辑这样可以在不消耗 API 额度的情况下验证代码逻辑。7. 关于学习路径的一点个人体会回头看LangChain 的学习曲线其实不算陡但容易迷失在大量的概念和包里面。我的建议是不要试图一次学完所有东西。先把“调用模型”和“Prompt 模板”这两件事搞透能写出一个简单的问答应用然后再逐步扩展到 Chain、Agent、RAG。另外不要过度依赖框架。LangChain 封装了很多东西但底层还是 HTTP 请求和 JSON 解析。理解底层原理遇到问题时才能快速定位。我见过有人 LangChain 用得很熟但连 API 请求长什么样都不知道一旦框架出问题就完全懵了。最后多动手。看十篇教程不如自己写一个能跑起来的小项目。从最简单的开始逐步加功能遇到问题就查文档、看源码、做实验。这个过程本身就是最好的学习。