
简介这是一份面向初学者的LangChain入门与实践项目代码包。LangChain是当前流行的基于Python的开源框架通过模块化设计将大语言模型与外部数据、工具及记忆能力连接能有效解决信息滞后、无法执行外部操作、记忆有限等痛点并支持OpenAI、Hugging Face等多种主流模型。这份代码包聚焦其核心模块涵盖提示词模板、链式调用、记忆功能与工具集成等关键内容附有智能运维、问答系统、对话机器人等场景的示范代码可帮助开发者直观理解提示词工程与链式应用的组织方式。资源共3个文件以HTML说明文档为主体配合代码工程配置与版本管理文件整体仅5KB轻量易读适合在本地快速浏览并对照核心概念。已有103人学习下载对于希望低成本了解LangChain整体架构、快速上手构建LLM应用的开发者而言是一份简洁高效的入门素材。 前阵子有个做后端的朋友问我LangChain是不是已经被吹过头了我反问他最近你写AI应用是不是还得自己封装多轮对话、管理上下文、处理工具调用的结构化输出他不说话了。LangChain的定位就是这样——它不是最优雅的框架却是把LLM应用的公共组件沉淀得最全的一套抽象体系。这篇内容我结合自己从入门到上生产环境的完整项目代码把整个技术链路捋一遍从最基础的Chain到RAG再到Agent最后是工程化落地的坑希望能给正在入门LangChain的朋友一份能直接抄作业的参考。1. 先搞清楚LangChain到底解决了什么问题1.1 它不只是封装API的SDK很多人第一次接触LangChain以为它就是帮你调OpenAI接口的封装库然后对比一下直接requests.post()觉得多此一举。这个判断只对了一半。LangChain真正解决的是多组件协作时的胶水问题一个完整的AI应用通常需要提示词管理、模型切换、记忆保持、文档检索、工具调用、输出结构化这些组件单独写都不难难的是把它们拼在一起还能灵活替换。我自己的项目演进最能说明这一点。最早我用原生OpenAI SDK写了一个客服问答脚本prompt写死在代码里换模型要改六七处加个知识库检索直接重构。后来切到LangChainprompt变成了可配置模板模型可以按环境切换检索、记忆、工具全部变成可插拔的组件一次重构省下后面大半年的维护成本。1.2 最小可运行示例跑通一遍理解LangChain最快的方式是写一个最小链路。下面这段代码就是LangChain最经典的三段式模板、模型、解析器用管道符串联。from langchain_openai import ChatOpenAI from langchain_core.prompts import ChatPromptTemplate from langchain_core.output_parsers import StrOutputParser llm ChatOpenAI(modelgpt-4o-mini, temperature0.7) prompt ChatPromptTemplate.from_messages([ (system, 你是一个资深的{domain}领域专家请用通俗易懂的语言回答用户的问题。), (human, {question}) ]) parser StrOutputParser() chain prompt | llm | parser result chain.invoke({domain: 法律, question: 合同里违约金一般怎么约定}) print(result)prompt | llm | parser这一行是整个LangChain的精华管道符把提示词模板、模型调用、输出解析三个环节串联成一个Runnable对象。chain.invoke()接收一个字典里面的key对应模板里的{domain}和{question}。这种设计的好处是每个环节都可以独立替换比如把StrOutputParser换成JsonOutputParser接口完全不变。1.3 生态全景一张地图看清LangChain各模块LangChain的生态分成几块langchain-core是核心抽象Runnable、Message、Toollangchain-community是社区集成各种文档加载器、向量库、第三方模型langchain本身是Chain、Agent等高层逻辑还有langgraph负责有状态的工作流编排langsmith做链路追踪。市面上说的LangChain通常指这整个体系。入门时最容易犯的错是不知道接口该从哪个包import。比如ChatOpenAI在langchain_openai里PyPDFLoader在langchain_community.document_loaders里FAISS在langchain_community.vectorstores里。记住一个粗略原则模型相关看langchain_*的独立包通用工具和集成类看langchain_community新项目里langchain主包主要负责组装。2. 核心抽象逐个拆Prompt、Chain、Memory、Tool2.1 Prompt模板把提示词当成代码来维护提示词的工程化是LangChain给我带来最大收益的部分。用原生代码写AI应用prompt经常是字符串拼接等需求变了几轮之后整个文件又脏又乱。用ChatPromptTemplate之后提示词从业务代码里剥离出来变成了带变量的模板甚至可以做成配置文件。from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder prompt ChatPromptTemplate.from_messages([ (system, 你是{bot_name}性格{personality}。), MessagesPlaceholder(variable_namehistory), (human, {input}) ])注意MessagesPlaceholder这个组件它在模板里占了一个位置运行时填入多轮对话历史。这是做聊天应用的关键也是新手最容易漏的地方——没有历史占位符模型永远记不住上下文。2.2 Chain组合管道式编程的边界在哪里LangChain 0.2之后的写法基本统一成了Runnable管道。除了最基础的prompt | llm | parser还可以用RunnableParallel做并行用RunnableLambda包任意Python函数。from langchain_core.runnables import RunnableParallel, RunnableLambda def format_result(data): return f答案{data[answer]}\n参考资料数{data[source_count]} parallel RunnableParallel( answerchain, source_countllm2 ) full_chain parallel | RunnableLambda(format_result)管道式编程的优点是用声明式方式描述数据流一眼就能看清整个处理链路。但它的边界也很明显没有内置的循环和条件分支一旦业务逻辑需要根据上一步结果决定下一步走哪条路就不是Chain能优雅解决的了那正是LangGraph的地盘。所以别迷信Chain它适合固定管线不适合动态决策。2.3 Memory记忆看着简单坑不少给聊天机器人加记忆是LangChain里最容易被低估的模块。早期版本里大家习惯用ConversationBufferMemory它会直接把所有历史消息塞给模型很快就把上下文窗口挤爆。from langchain.memory import ConversationBufferWindowMemory memory ConversationBufferWindowMemory(k5, return_messagesTrue)k5代表只保留最近5轮对话。这只是初级方案实际项目中更好的做法是把长期记忆落库比如用户偏好把短期记忆用窗口控制而复杂业务状态直接交给LangGraph去管不要在prompt层硬凑。我在复盘项目时发现记忆出问题通常会先看两件事——历史消息有没有悄悄把system消息挤掉以及token计算和实际用量是否一致。2.4 Tool自定义扩展大模型能力的最短路径大模型本身只会生成文本想让模型查数据库、算价格、发请求就得给它工具。LangChain里定义一个工具只需两步写普通Python函数再装饰一下。from langchain_core.tools import tool tool def get_weather(city: str) - str: 查询指定城市的实时天气。 import requests # 这里替换成真实天气API return f{city} 当前晴气温 24℃函数名、docstring、参数类型注解这三样东西会被LangChain自动解析成模型的工具描述。所以docstring要写清楚工具是干什么的、什么时候用模型看到描述才会在合适的场景调用它。另一个常见坑工具里不要做太重的事比如长时间同步请求模型调工具是有超时等待的生产环境里工具最好做成轻量封装内部再异步处理。3. RAG实战用项目代码跑通一个知识库问答3.1 完整链路加载、切分、向量化、检索、生成RAG检索增强生成是LangChain目前落地场景最广的能力先用项目代码把完整链路串起来。from langchain_community.document_loaders import PyPDFLoader from langchain_text_splitters import RecursiveCharacterTextSplitter from langchain_openai import OpenAIEmbeddings from langchain_community.vectorstores import FAISS # 1. 加载 loader PyPDFLoader(docs/产品手册.pdf) documents loader.load() # 2. 切分 splitter RecursiveCharacterTextSplitter( chunk_size500, chunk_overlap80, separators[\n\n, \n, 。, , , , ] ) chunks splitter.split_documents(documents) # 3. 向量化并入库 embeddings OpenAIEmbeddings(modeltext-embedding-3-small) vectorstore FAISS.from_documents(chunks, embeddings) vectorstore.save_local(data/vectorstore) # 4. 检索 retriever vectorstore.as_retriever(search_kwargs{k: 4}) # 5. 生成 from langchain_core.prompts import ChatPromptTemplate rag_prompt ChatPromptTemplate.from_messages([ (system, 你是客服助手。仅根据以下资料回答问题若资料中没有答案请直接说不知道。), (human, 资料{context}\n\n问题{question}) ]) def format_docs(docs): return \n\n.join(doc.page_content for doc in docs) rag_chain ( {context: retriever | format_docs, question: lambda x: x[question]} | rag_prompt | llm | parser ) print(rag_chain.invoke({question: 产品支持哪些连接方式}))这段代码里的retriever | format_docs是LangChain里很巧妙的嵌套管道检索器的输出是文档列表经过format_docs转成纯文本再作为context变量传给prompt。这样整个RAG流程依然保持管道式结构可读性很强。3.2 切分策略和检索质量直接决定体验RAG项目中模型本身反而不是瓶颈检索质量才是。我自己踩过的坑有两个最典型。第一个是切分粒度和格式。默认的RecursiveCharacterTextSplitter按字符数硬切如果文档是表格密集型的很容易把语义完整的表格从中间切开检索出来的片段残缺不全。后来我改成优先按段落、再按句子切同时控制chunk_overlap在80到150之间让相邻块之间保留一部分重复内容这才解决了答案断半截的问题。第二个是embedding模型的选择。中文场景直接用OpenAI的text-embedding-3-small质量可以但中文颗粒度一般对私域文档我后来换成BGE或M3E这类中文embedding模型配合Ollama本地部署效果提升明显。选embedding之前建议拿你自己的文档跑一组对比测试找一个检索命中率最高的组合。3.3 模型来源切换OpenAI、Ollama、vLLM统一接口LangChain最方便的一点是模型层抽象得非常干净。ChatOpenAI不只是接OpenAI只要接口兼容就能统一接入。from langchain_openai import ChatOpenAI # 方式一直连OpenAI llm ChatOpenAI(modelgpt-4o-mini, api_keysk-xxx) # 方式二本地Ollama llm ChatOpenAI( modelqwen2.5:7b, base_urlhttp://localhost:11434/v1, api_keyollama ) # 方式三vLLM部署的私有模型 llm ChatOpenAI( modelqwen2.5-14b-instruct, base_urlhttp://192.168.1.10:8000/v1, api_keyvllm )关键在base_urlOllama和vLLM都提供了OpenAI兼容接口所以在LangChain里都当ChatOpenAI用。这就意味着你可以先用OpenAI跑通逻辑再无缝切到本地模型做私有化部署业务代码一行都不用改。生产环境中我建议把模型配置全部放进环境变量或配置中心连model名都别写死在代码里。4. Agent实战从Chain升级到LangGraph4.1 让模型自己决定下一步ReAct模式怎么跑Chain和RAG都是固定管线但真实的业务需求往往是需要根据问题动态决定调哪个工具、查哪份资料。这就是Agent的用武之地。最经典的实现是ReAct模式模型在思考和行动之间循环直到得出最终答案。from langchain.agents import create_tool_calling_agent, AgentExecutor from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder from langchain_core.tools import tool tool def query_stock(code: str) - str: 查询股票代码的实时行情输入为6位股票代码。 # 替换为真实行情接口 return f{code} 最新价 12.50 元涨跌幅 1.2% tool def calculator(expression: str) - str: 计算数学表达式输入如 (12.5*1000)/3。 return str(eval(expression)) tools [query_stock, calculator] prompt ChatPromptTemplate.from_messages([ (system, 你是股票助手。使用工具回答用户问题所有数字结果保留两位小数。), MessagesPlaceholder(variable_namechat_history), (human, {input}), MessagesPlaceholder(variable_nameagent_scratchpad), ]) agent create_tool_calling_agent(llm, tools, prompt) executor AgentExecutor(agentagent, toolstools, verboseTrue) result executor.invoke({ input: 我买了1000股000001帮我算一下现在市值多少, chat_history: [] }) print(result[output])注意prompt里那个agent_scratchpad占位符它专门用来放Agent的中间推理过程是工具调用型Agent的标配。create_tool_calling_agent是0.2之后的新写法走的模型原生Function Calling能力效率和稳定性都比老版本的ReAct Agent好新项目建议直接用这个。4.2 LangChain和LangGraph到底怎么选这个问题的答案我在项目进入第二个版本时才彻底想明白。LangChain的Agent是一个黑盒调度器你给它工具和提示词它在内部循环调用模型但你不能精细控制中间的每一步LangGraph是把Agent拆成一张显式的状态图节点Node就是一步操作边Edge就是状态转移条件整个Agent的路径完全透明可控。from langgraph.graph import StateGraph, START, END from typing import TypedDict class AgentState(TypedDict): question: str intermediate_steps: list def call_model(state): # 第一步让模型决定调用哪个工具 return {intermediate_steps: [thinking...]} def call_tool(state): # 第二步执行工具 return {intermediate_steps: [tool result...]} graph StateGraph(AgentState) graph.add_node(model, call_model) graph.add_node(tool, call_tool) graph.add_edge(START, model) graph.add_conditional_edges(model, router, {continue: tool, finish: END})一句话总结简单的工具调用用LangChain Agent就够了涉及多步流程、人工审批、需要断点恢复、想精细控制每一步的业务直接上LangGraph。我的教训是从Chain直接跳到LangGraph中间在Agent上硬扛了两个星期最后发现该用的还是图编排。4.3 Agent跑偏的排查记录Agent上线后最常见的故障是模型不按预期调用工具。我遇到过三类情况排查链路值得分享第一类工具描述写得像说明书模型看不懂。排查方法是用LangSmith或直接打印Agent的中间步骤看模型每一步在想什么。后面我习惯先给每个工具说一句人话总结再给使用场景示例调用准确率立刻上来。第二类模型反复调用同一个工具停不下来。这通常是工具返回结果不明确导致的比如查询成功但返回空串。后来我在工具返回里统一加状态前缀比如查询成功...、未找到...模型收到明确反馈后就能正常终止。第三类上下文越跑越长Agent中途失效。Agent的中间推理会不停累积token进入死循环后上下文直接爆炸。解决办法是限制最大迭代次数并定期清理agent_scratchpad里的中间过程或者直接改用LangGraph做更可控的循环。5. 生产级项目代码怎么组织5.1 目录结构别把所有代码堆在main.py里LangChain项目随随便便就会膨胀如果不从一开始就做好代码组织后面改一个prompt都要在几百行里找。这是我目前比较顺手的结构llm-app/ ├── app/ │ ├── main.py # 入口FastAPI服务 │ ├── config.py # 配置加载 │ ├── chains/ # 各种RAG、基础问答链 │ │ ├── chat_chain.py │ │ └── rag_chain.py │ ├── agents/ # Agent定义 │ ├── tools/ # 自定义工具 │ ├── rag/ │ │ ├── loader.py # 文档加载 │ │ └── splitter.py # 切分策略 │ └── memory/ # 记忆管理 ├── config/ │ └── settings.yaml ├── data/ # 原始文档、向量库 ├── tests/ └── requirements.txt核心原则就一条每个组件一个文件文件之间只通过明确的接口通信。比如tools/里的函数只负责做一件事chains/里的chain只负责组装不要把检索逻辑、prompt、业务判断混在一起。5.2 配置和密钥管理从写死到外置密钥和模型配置是项目最容易出事故的位置。我在代码评审时见过不少把api_key写死在代码里提交到仓库的这非常危险。正确的做法是统一走环境变量或配置文件# .env 示例 OPENAI_API_KEYsk-xxxx OPENAI_BASE_URLhttps://api.openai.com/v1 LLM_MODELgpt-4o-mini EMBEDDING_MODELtext-embedding-3-small FAISS_INDEX_PATHdata/vectorstore代码里加一个config.py统一读取import os from dotenv import load_dotenv load_dotenv() OPENAI_API_KEY os.getenv(OPENAI_API_KEY) OPENAI_BASE_URL os.getenv(OPENAI_BASE_URL) LLM_MODEL os.getenv(LLM_MODEL).env文件加进.gitignore仓库里只保留.env.example模板。项目代码如果能推到公司私库记得先检查历史提交里有没有泄露出密钥必要时用工具清理历史记录。5.3 调试技巧与常见报错最后分享几个实测很管用的调试技巧。第一个是开verboseAgentExecutor(verboseTrue)或者chain.invoke()时打印中间步骤能看到每个环节的输入输出排查问题快得多。第二个是用好LangSmith它能把链条上每一步的token、耗时、prompt内容都记录下来我把它当成LangChain的日志系统。常见报错也列几个报错信息原因处理方式ModuleNotFoundError: langchain_community缺少集成包pip install langchain-communityOpenAIError: connection errorbase_url配置错误或网络不通检查base_url是否指向正确的vLLM/Ollama端口OutputParserException模型输出无法被解析器解析换更强的模型或改用JsonOutputParser并给例ValueError: too many values to unpack老版本Agent与新版API混用统一升级到0.2版本用create_tool_calling_agent最后一个建议LangChain版本更新很快不同大版本之间的API破坏性改动不少项目里最好锁定版本号比如langchain0.2.x升版本前先看变更日志。我自己吃过的亏就是langchain整体从0.1升到0.2时大量import路径变了几十个文件逐个改才缓过来。如果你刚开始上手LangChain建议先照着本文第一段最小示例跑通再逐步把RAG和Agent加进去。这个框架的抽象方式已经成为AI应用开发的事实标准掌握它之后无论底层模型怎么换、业务怎么复杂化你手上的技术栈都能接得住。本文还有配套的精品资源点击获取