
简介面向LangChain入门者的实践代码包适合刚接触大模型应用开发的Python开发者参考。资源以极简方式呈现了LangChain的基础用法与前端展示页压缩包仅5KB共3个文件包含inscode在线开发环境配置、HTML介绍页面以及gitignore规则文件结构清晰便于快速理解项目组织方式并直接运行体验。目前已有103人浏览学习。借助这份代码开发者可以了解LangChain模块化、可组合的核心设计理念结合描述中提到的LLM接口、提示词模板、链式操作、记忆功能与工具调用等概念对照代码片段建立直观认识为后续搭建问答系统、对话机器人等应用打下基础。整体轻量简洁适合作为第一份LangChain动手练手材料。 说实话LangChain 这个框架我一开始是有点排斥的。原因很简单抽象层太多封装太厚很多人用它写完一堆 chain却根本不知道底层在调什么。但你又不得不承认当项目里要同时接大模型、做检索、拆流程、加记忆、挂 Agent 的时候LangChain 确实能帮你省下大量重复的胶水代码。这篇文章把我自己在实际项目里用 LangChain 做过的内容从环境搭建到 RAG、Agent、记忆再到和 LangGraph 的选型对比完整拆一遍附带可运行的代码。适合刚接触 LangChain、想把它落到真实项目里的开发者也适合准备 LangChain 相关面试、需要把概念和实操串起来的人。全文不吹不黑只讲实际能用的东西。1. 项目整体设计与思路拆解1.1 LangChain 到底在解决什么问题先想清楚一个问题没有 LangChain我们能不能写大模型应用当然能。最简单的场景一段 prompt、一个 API 调用几行代码就完事。但你很快会发现真实业务根本不是单次调用能搞定的。举个例子你想做一个根据公司内部文档回答问题的工具。你首先要加载各种格式的文档做切分、向量化然后把用户的提问和检索到的内容拼成新的 prompt再调用模型生成答案最后还要把引用来源附上。这还没算多轮对话的记忆、模型偶尔抽风的重试、不同模型的切换。如果每个环节都自己手写能写但每个项目都重写一遍就是纯粹的重复劳动。LangChain 干的其实就是这件事把大模型应用里那些高频的、通用的环节抽象成标准组件。你需要文档处理它有 loader 和 splitter你需要向量检索它有 vectorstore 封装你需要让模型调用工具它有 agent 框架。你要做的是根据业务场景把这些组件串起来而不是从零搭轮子。1.2 项目里最常用的几个核心模块LangChain 调整过很多次版本模块边界也变过但核心概念一直没变。我自己用的版本是 0.3.x下面按实际使用频率排序模块作用常用组件Models统一封装各家大模型接口OpenAI、ChatOllama、HuggingFacePrompts管理 prompt 模板和结构化输出PromptTemplate、ChatPromptTemplateIndexes / Retriever处理文档、做语义检索TextLoader、RecursiveCharacterTextSplitter、FAISSChains把多个步骤串成一条流水线LCEL、create_retrieval_chainAgents让模型自主决定调用哪些工具create_tool_calling_agent、ToolMemory记录多轮对话的上下文ConversationBufferMemory、ConversationSummaryMemory这一版项目代码的设计思路是不追求花哨用最经典的组合做一个完整的聊天机器人带上 RAG 问答和 Agent 工具调用两个核心能力。每个模块单独拎出来都能讲组合在一起就是一个可运行的 demo。2. 环境搭建与模型接入实操2.1 安装依赖与版本选择LangChain 的版本坑比较多网上很多教程用的还是 0.1 甚至更老的 API直接抄代码经常报错。我这个项目用的是 0.3.x安装命令如下pip install langchain pip install langchain-openai pip install langchain-community pip install langchain-experimental pip install faiss-cpu pip install ollama说明一下每个包的定位langchain是核心框架langchain-openai是 OpenAI 兼容接口的适配层Ollama 本地模型也走这个包langchain-community放的是社区维护的集成组件faiss-cpu是向量检索库本地开发够用。版本不用刻意锁死但建议至少是 0.2 以上否则 API 差异太大。2.2 模型接入OpenAI 与本地 Ollama写代码之前要想清楚用哪个模型。OpenAI 的 GPT 系列效果稳定但涉及 API 费用和数据出境问题Ollama 可以本地跑 Llama 3、Qwen 这些开源模型免费、离线可用但效果和速度取决于机器配置。我这个项目做了两层适配方便随时切换。用 OpenAI 时配置环境变量export OPENAI_API_KEY你的keyfrom langchain_openai import ChatOpenAI llm ChatOpenAI( modelgpt-4o-mini, temperature0.7, )用本地 Ollama 时先确保已安装并启动 Ollama然后拉取一个模型比如ollama pull qwen2.5:7bfrom langchain_ollama import ChatOllama llm ChatOllama( modelqwen2.5:7b, temperature0.7, )两种方式接进来之后对象类型都是BaseChatModel后面的代码完全不用改。这就是 LangChain 统一抽象的好处。2.3 Prompt 模板与结构化输出prompt 模板是 LangChain 里最不起眼但最重要的部分。很多人喜欢在代码里直接拼接字符串一旦 prompt 复杂起来就乱成一锅粥。以本项目里的问答系统为例我定义了一个系统 promptfrom langchain_core.prompts import ChatPromptTemplate prompt ChatPromptTemplate.from_messages([ (system, 你是一个专业的技术助手。请基于给定的资料回答问题 如果资料中没有相关信息请直接说你不知道不要编造。), (human, 资料\n{context}\n\n问题{question}), ])这里有两个变量context是从向量库检索出来的相关资料question是用户输入。用模板的好处是prompt 的调整只需要改这里不需要动业务代码。另外如果你需要模型返回 JSON 格式的稳定结构光在 prompt 里写请返回 JSON是不够的。更好的做法是用with_structured_output绑定 Pydantic 模型from pydantic import BaseModel class Answer(BaseModel): content: str confidence: float structured_llm llm.with_structured_output(Answer) result structured_llm.invoke(你的问题)这样返回结果一定是结构化的后续代码处理起来特别舒服不用写一堆正则去解析。3. RAG 实战做一个带引用的文档问答系统3.1 RAG 的整体流程拆解RAGRetrieval-Augmented Generation检索增强生成是 LangChain 目前最常见的落地场景。核心思路是不直接让模型回答而是先从你的文档库里检索出相关内容再把资料问题一起交给模型。为什么需要这一步因为模型的知识有截止日期也不了解你内部的私有数据。你当然可以通过微调把知识塞进去但文档频繁更新的话微调成本太高了。RAG 则把知识外置到向量数据库里随时可以增删改回答还自带引用来源对用户来说也更有说服力。本项目里的 RAG 流程分五步加载文档用TextLoader或PyPDFLoader读取本地文件。文本切分长文档按固定大小切块避免超过模型上下文窗口。向量化把每个文本块转换成高维向量。语义检索用户提问时把问题向量化在库里找最相似的文本块。生成回答把检索到的文本块作为上下文和问题一起交给模型。3.2 关键参数与完整实现文本切分的参数直接影响回答质量这是 RAG 里最值得调的部分。我用的是RecursiveCharacterTextSplitterfrom langchain_text_splitters import RecursiveCharacterTextSplitter text_splitter RecursiveCharacterTextSplitter( chunk_size500, # 每个块的最大字符数 chunk_overlap100, # 相邻块之间的重叠字符数 separators[\n\n, \n, 。, , , , ], ) docs loader.load() splits text_splitter.split_documents(docs)chunk_size决定了每次喂给模型的资料粒度。设置太小单个块可能缺少完整语义设置太大既浪费 token 又影响检索精度。chunk_overlap是块与块之间的重叠目的是避免一个完整句子被拦腰切断。这两个参数没有绝对最优值我一般先按 500 和 100 起步再根据实际回答效果调。向量化本项目的做法是直接用 OpenAI 的 embedding 模型from langchain_openai import OpenAIEmbeddings from langchain_community.vectorstores import FAISS embeddings OpenAIEmbeddings(modeltext-embedding-3-small) vectorstore FAISS.from_documents(splits, embeddings)本地环境也可以切换到OllamaEmbeddings比如nomic-embed-text模型。FAISS 是向量检索库把向量存在本地文件重启不丢vectorstore.save_local(faiss_index) vectorstore FAISS.load_local(faiss_index, embeddings, allow_dangerous_deserializationTrue)检索部分有一个关键参数k表示取回几个相关块。这个值不是越大越好块太多会把不相关的内容也塞进 prompt干扰模型判断。本项目里设置k4retriever vectorstore.as_retriever(search_kwargs{k: 4})最后用 LangChain 0.3 推荐的 LCEL 语法把流程串起来。这里我用了一个经典的create_retrieval_chaincreate_stuff_documents_chain组合from langchain.chains import create_retrieval_chain from langchain.chains.combine_documents import create_stuff_documents_chain combine_docs_chain create_stuff_documents_chain(llm, prompt) rag_chain create_retrieval_chain(retriever, combine_docs_chain) response rag_chain.invoke({question: 什么是LangChain}) print(response[answer])create_stuff_documents_chain的意思是把检索到的文档全部塞进 prompt。如果文档很多也可以换成create_map_reduce_documents_chain做分块总结但日常场景 stuff 足够用。4. Agent 实战与记忆机制4.1 Agent 和 Chain 的本质区别Chain 是预设好的流水线每一步做什么完全确定。Agent 则不然它把决策权交给了模型模型根据用户的提问自己判断需要调用哪些工具按什么顺序调用甚至可以在失败后重试。这个区别用生活类比很好理解Chain 像是给外卖员规定好固定路线Agent 则给外卖员一张地图和几个工具电动车、电梯、电话让他自己规划怎么最快送到。本项目里做了一个能查天气、能算数学题的 Agent。为什么做这两个工具因为它们一个是外部信息获取一个是本地计算推理正好代表工具调用的两种典型形态。4.2 工具定义与执行流程在 LangChain 里定义工具很简单用tool装饰器包一个函数即可from langchain_core.tools import tool import requests tool def get_weather(city: str) - str: 查询指定城市的当前天气。城市名使用中文例如北京。 response requests.get(fhttps://wttr.in/{city}?format3) return response.text tool def calculate(expression: str) - str: 计算数学表达式例如2 3 * 4。 try: result eval(expression, {__builtins__: {}}, {}) return f计算结果: {result} except Exception as e: return f计算失败: {str(e)}这里有两个细节值得注意。第一函数的 docstring 非常重要它就是模型决定要不要调用这个工具的依据写清楚功能、参数格式效果会好很多。第二eval实际使用中要非常小心我这里仅为演示生产环境建议用更安全的解析方案。接下来创建 Agentfrom langgraph.prebuilt import create_react_agent from langchain_core.messages import SystemMessage tools [get_weather, calculate] agent create_react_agent(llm, tools, state_modifierSystemMessage( content你是智能助手需要工具时直接调用不需要的话直接回答。 )) result agent.invoke({messages: [(user, 北京今天天气怎么样)]})这里我用的是langgraph.prebuilt里的create_react_agent这是 LangChain 0.3 后推荐的 Agent 创建方式后面会专门讲它和 LangGraph 的关系。4.3 记忆机制怎么选Agent 和 RAG 链默认都没有记忆每次调用都是独立的。用户上一轮说了什么下一轮就忘了。这在多轮对话场景里是不能接受的。LangChain 里的记忆机制有好几种我常用的有三类记忆类型原理适用场景ConversationBufferMemory缓存全部历史消息对话轮次少ConversationBufferWindowMemory只保留最近 N 轮控制 token 消耗ConversationSummaryMemory用模型压缩对话摘要长对话、成本敏感但说实话直接在 LangChain 的 chain 上挂 Memory 类接口繁琐且效果局限。我更推荐在 Agent 层面直接维护消息列表把历史消息手动塞进去from langchain_core.messages import HumanMessage, AIMessage def ask_with_memory(question: str, history: list): messages [SystemMessage(content你是智能助手。)] history [HumanMessage(contentquestion)] response agent.invoke({messages: messages}) history.append(HumanMessage(contentquestion)) history.append(AIMessage(contentresponse[messages][-1].content)) return response[messages][-1].content history [] ask_with_memory(我的名字是张三, history) ask_with_memory(我叫什么名字, history)这种方式的好处是灵活、透明、可控而且符合最新版 LangChain 的设计方向。与其纠结该选哪种 memory 类不如直接用消息列表什么需求都能实现。5. LangChain 与 LangGraph 的选型对比5.1 两者到底是什么关系很多新手混淆 LangChain 和 LangGraph其实现在的关系已经很清楚LangChain 是组件库LangGraph 是编排框架后者越来越成为前者的底层引擎。从版本演进来看LangChain 早期的 Chain 设计比较死板分支和循环很难实现。后来官方把重心转向 LangGraph它把应用建模成一张图节点是处理步骤边是流转条件支持循环、分支、人机交互甚至持久化。现在 LangChain 里很多高级功能比如 Agent、记忆底层都跑在 LangGraph 上。我前面用的create_react_agent就是 LangGraph 提供的。5.2 什么场景必须上 LangGraph基于我自己的实践可以给出一个比较清晰的选型标准简单顺序流程用 LangChain 的 LCEL 链就够不用上 LangGraph。需要条件分支、循环、或者复杂状态管理直接用 LangGraph。Agent 应用直接上 LangGraph哪怕用 prebuilt 的 agent 也行。需要人工审批、断点续跑必须用 LangGraph它的interrupt机制是 LangChain 没有的。举个例子一个客服机器人需要判断用户意图然后走售后流程还是售前流程售前流程里又要根据商品类型调用不同工具。这种带分支和循环的场景用 Chain 写起来很别扭用 LangGraph 画一张图就清楚了from langgraph.graph import StateGraph, START, END def route_after_intent(state): if state[intent] after_sales: return after_sales_node return pre_sales_node graph StateGraph(...) graph.add_node(after_sales_node, after_sales_handler) graph.add_node(pre_sales_node, pre_sales_handler) graph.add_conditional_edges(intent_node, route_after_intent)所以我的建议是新项目如果预感到流程会变复杂直接上 LangGraph 没有坏处但如果只是简单问答硬上 LangGraph 只会增加理解成本。6. 常见问题与排查技巧实录6.1 高频问题速查这段时间帮同事和网友排查过不少 LangChain 报错整理成一张速查表问题现象可能原因解决办法AttributeError: ChatOpenAI has no attribute generate版本过旧链式调用依赖新 API升级到 langchain-openai 0.1结构化输出返回乱码模型不支持 JSON 模式或绑定失败换用支持 tool calling 的模型或加 Pydantic 校验检索结果与问题无关切分粒度过大或向量模型不匹配调小 chunk_size或更换 embedding 模型Token 超限报错上下文塞入过多历史改成窗口记忆或摘要记忆Agent 不调用工具docstring 写得不清楚重写 docstring说清参数格式FAISS 加载报安全警告反序列化防护机制确认文件可信后加 allow_dangerous_deserializationTrue6.2 几个实用的调试经验第一调试 LangChain 应用不要靠猜把中间变量打出来看。我习惯在关键环节加打印比如retrieved_docs retriever.invoke(你的问题) print(f检索到 {len(retrieved_docs)} 个文档块) print(retrieved_docs[0].page_content[:200])这样能快速定位是检索的问题还是生成的问题。等你确认逻辑没问题了再把打印去掉。第二不要把 prompt 写死在代码里。我见过太多人把一长段 prompt 塞在业务逻辑中后期改一版 prompt 就要动代码。建议把 prompt 放到单独的配置文件里或者至少用 LangSmith 之类的工具做版本管理不然上线后模型效果波动你连上次用的什么 prompt都不知道。第三注意环境一致性。同一个 LangChain 项目在本地跑通了换一台机器就报错八成是版本不一致。强烈建议用pip freeze requirements.txt锁住版本。我之前在项目里就吃过一次亏本地 0.3.1 正常测试环境自动装成 0.3.7结果内置 Agent 的行为变了排查了半天。按我个人的实操体会LangChain 这个框架最大的学习成本不是 API 本身而是理解它为什么要这么设计。你只要把组件化思维建立起来后面看文档的速度会快很多。这个项目的代码只是一个起点你可以基于它继续扩展换一个更合适的向量模型、接上自己的业务数据、把 LangGraph 的图逻辑再改复杂一点都是很好的练手方向。最后再分享一个小技巧学 LangChain 不要光看官方教程多去 GitHub 上翻一些真实项目的代码看看别人是怎么组织 prompt、怎么管理工具列表、怎么处理异常的。框架的 API 会过时但工程上的组织思路和经验不会。本文还有配套的精品资源点击获取