
最近一段时间类似“一周吃透 LangChain”“从入门到企业级实战”的视频标题在B站和各类技术社区里反复出现。单看这条路径本身它并没有夸大LangChain、LangGraph、Agent、RAG确实是从入门到做真实项目绕不开的四块拼图。但很多同学跟着视频敲了半天代码依然会卡在同一个地方LangChain 的 API 版本改来改去LangGraph 把原先的链式调用逻辑整个重构了一遍Agent 和 RAG 的边界又说不清楚最后项目一跑就报错不知道该查框架文档还是该查自己的代码。这篇文章不是复述某个视频而是把这条学习路径拆成四关配合可运行的示例和工程判断帮你把“看起来懂了”变成“真正能落地”。读完你会得到三个东西一套不再混乱的概念坐标系一条从最简调用走到 Agent 工具箱的实操链路以及一组企业级项目里真正需要避开的坑。我的判断是LangChain 依然值得学但值得学的绝不再是背 API。1.x 时代之后它已经不是一个单纯的链式调用框架而是一套 AI 应用工程生态。谁能尽早分清 LangChain、LangGraph、Agent、RAG 各自的职责谁就能少走至少一半弯路。1. 这篇文章真正要解决的问题先说痛点。你大概率遇到过下面几种情况跟着视频装好了langchain结果from langchain.llms import OpenAI直接报错因为新版本把模型接入全部挪到了langchain-openai这类独立包里。学会了LCEL链式写法也跑通了 RAG但业务里一遇到“如果用户问 A 就走检索问 B 就调工具”这类分支需求链式代码开始失控。看了很多 Agent 文章仍然不明白 Agent 和普通 RAG 到底有什么区别不知道什么时候该上 LangGraph。做了个人 Demo但到企业级场景就露怯没有版本管理、没有可观测性、没有评测、没有成本控制。这些问题不是单一知识点造成的而是整条学习路径没有搭好。你需要先把四个概念的地图画对再讨论具体代码。这篇文章会从基础概念讲到四个递进式代码示例最后落到生产环境最佳实践。你不需要提前会 LangChain但需要有一点 Python 基础理解基本的大模型 API 调用。2. LangChain、LangGraph、Agent、RAG 四者的关系很多教程把这四个词并列讲实际上它们不是同一层的东西。用一句话概括RAG 是一种应用架构模式解决“模型如何访问外部知识”的问题。LangChain 是一个工具生态提供模型接入、提示词管理、文档加载、向量存储、输出解析等基础能力。LangGraph 是一个编排引擎解决“复杂流程如何被可靠地控制和执行”的问题。Agent 则是基于 LangGraph 这类编排能力构建的智能体范式核心特征是模型自己决定下一步调用什么工具。可以把 LangChain 理解成“工具箱”LangGraph 理解成“流水线控制中枢”Agent 是跑在流水线上的一种“决策者”RAG 是决策者经常会用到的“资料库”。这也是为什么LangChain 官方后来把架构拆成langchain-core、langchain、langchain-community、langchain-openai等独立包并让 LangGraph 独立发展。理解这个拆分你就不会再纠结“LangChain 和 LangGraph 到底谁替代谁”了。下面用表格做一个直观对比维度LangChainLangGraphAgentRAG本质开发工具包图编排框架应用范式架构模式核心能力模型统一接入、提示词管理、文档处理状态图、条件分支、循环、子图工具调用、自主决策检索、重排、注入上下文类比工具箱工厂流水线流水线上的调度员旁边的资料仓库何时使用几乎所有 AI 应用流程复杂、需要分支/循环/人工介入需要模型动态决策知识库问答、私有数据问答这个表格是一个“决策坐标系”。当你拿到一个需求先问有外部知识需求吗有考虑 RAG。流程会分叉吗会考虑 LangGraph。需要模型自己决定调用哪些工具吗需要加 Agent。至于 LangChain它提供了这些模块的底座不用刻意区分“哪一步属于 LangChain”。3. 环境准备与前置条件先准备环境再做后面的示例。以下配置在当前主流版本下通用具体小版本以官方文档为准。3.1 基础环境Python 版本建议 3.10 或更高。某些依赖在 3.9 上也能跑但新版本生态已经逐步提高最低版本要求。包管理器建议使用venv或conda创建独立虚拟环境避免和系统环境冲突。大模型 API需要准备可用的 OpenAI 兼容 API Key。如果没有 OpenAI Key也可以使用支持 OpenAI 协议的中转服务、本地模型服务如 Ollama、vLLM、FastChat 等。本文示例以 OpenAI 兼容接口为主。操作系统Windows / macOS / Linux 均可命令行操作相同但 Windows 下注意路径分隔符。3.2 安装依赖使用requirements.txt管理依赖有利于复现环境。建议新建项目目录并且把依赖写清楚。# 文件路径requirements.txt langchain0.3,2.0 langchain-openai0.2,1.0 langchain-community0.3 langgraph0.2 langchain-chroma0.1 chromadb0.5 pypdf4.0 python-dotenv1.0执行安装python -m venv .venv source .venv/bin/activate # Windows 下使用 .venv\Scripts\activate pip install -r requirements.txt安装完成后在项目根目录创建.env文件# 文件路径.env OPENAI_API_KEY你的API密钥 OPENAI_BASE_URLhttps://api.openai.com/v1注意.env文件不要提交到 Git 仓库。如果使用 git在.gitignore中加入.env。3.3 验证环境python -c import langchain, langgraph; print(langchain.__version__, langgraph.__version__)能正常打印版本号说明依赖安装成功。接下来进入第一关。4. 第一关用 LangChain 跑通一次 LLM 调用很多入门教程还在让你from langchain.llms import OpenAI这在当前版本下已经不推荐了。正确的做法是按厂商接入独立包。4.1 最小调用示例# 文件路径examples/01_llm_call.py import os from dotenv import load_dotenv from langchain_openai import ChatOpenAI load_dotenv() model ChatOpenAI( modelgpt-4o-mini, temperature0, ) response model.invoke(用一句话解释什么是 RAG。) print(response.content)这段代码做了三件事加载.env、创建聊天模型实例、调用invoke拿到模型回复。注意ChatOpenAI返回的是一个AIMessage对象不是字符串所以要打印response.content。4.2 为什么要用 ChatOpenAI 而不是 OpenAI在 LangChain 当前生态中传统OpenAILLM 类更多面向文本补全而ChatOpenAI面向聊天补全。绝大多数真实应用都应该用聊天模型因为提示词和工具调用都基于 chat 格式。如果你在旧教程里看到from langchain.llms import OpenAI直接替换为ChatOpenAI会更符合当前最佳实践。一个小验证运行下面代码看看系统提示词和用户问题是如何参与生成的。# 文件路径examples/02_prompt_call.py from dotenv import load_dotenv from langchain_openai import ChatOpenAI from langchain_core.prompts import ChatPromptTemplate load_dotenv() prompt ChatPromptTemplate.from_messages([ (system, 你是一名擅长讲解技术概念的助手。), (human, 请用三句话解释{topic}), ]) chain prompt | model | StrOutputParser() result chain.invoke({topic: Agent 和 RAG 的区别}) print(result)第一关到这里就够了。这里真正容易踩坑的地方是StrOutputParser没有导入from langchain_core.output_parsers import StrOutputParser。很多人写链式调用报错一半都是导入路径的问题。这个环节的目标是让你感受 LangChain 的基本抽象模型、提示词、输出解析器以及它们之间通过|运算符串联的能力。5. 第二关RAG 知识库最小闭环RAG 的核心思路是不把问题直接抛给模型而是先从你的资料库中检索出相关内容再把“问题 检索内容”一起交给模型回答。这样做的好处是模型不需要“记住”私有知识只需要“阅读”检索结果。一个最小 RAG 闭环包含四步文档加载、文本切分、向量化存储、检索问答。5.1 加载文档并切分# 文件路径examples/03_rag_build.py from dotenv import load_dotenv from langchain_community.document_loaders import PyPDFLoader from langchain_text_splitters import RecursiveCharacterTextSplitter from langchain_openai import OpenAIEmbeddings from langchain_chroma import Chroma load_dotenv() loader PyPDFLoader(docs/manual.pdf) pages loader.load() # 注意PDF 可能很大建议先切分再做向量化 splitter RecursiveCharacterTextSplitter( chunk_size500, chunk_overlap80, ) chunks splitter.split_documents(pages) print(f切分后共 {len(chunks)} 个文本块) embeddings OpenAIEmbeddings(modeltext-embedding-3-small) vectorstore Chroma.from_documents( documentschunks, embeddingembeddings, persist_directory./chroma_db, ) print(向量库构建完成)这段代码把 PDF 加载为多个Document对象然后按 500 字符左右切块相邻块之间保留 80 字符重叠目的是避免一句完整语义被硬切到两块里。切分完的文本块向量化后写入本地 Chroma 数据库。chunk_size不是一个越大越好的参数。太长检索召回内容可能包含大量无关信息太短语义不完整。中文场景建议从 300 到 600 开始调配合chunk_overlap在 50 到 100 之间观察效果。5.2 用检索结果回答问题# 文件路径examples/04_rag_query.py from dotenv import load_dotenv from langchain_openai import ChatOpenAI, OpenAIEmbeddings from langchain_chroma import Chroma from langchain_core.prompts import ChatPromptTemplate from langchain_core.output_parsers import StrOutputParser from langchain_core.runnables import RunnablePassthrough load_dotenv() embeddings OpenAIEmbeddings(modeltext-embedding-3-small) vectorstore Chroma( persist_directory./chroma_db, embedding_functionembeddings, ) retriever vectorstore.as_retriever(search_kwargs{k: 4}) prompt ChatPromptTemplate.from_messages([ (system, 你是一个企业知识库助手。请只根据以下资料回答不要编造\n\n{context}), (human, {question}), ]) def format_docs(docs): return \n\n.join([d.page_content for d in docs]) chain ( {context: retriever | format_docs, question: RunnablePassthrough()} | prompt | ChatOpenAI(modelgpt-4o-mini, temperature0) | StrOutputParser() ) answer chain.invoke(这份手册里关于部署的步骤是什么) print(answer)这段代码的关键在于{context: retriever | format_docs, question: RunnablePassthrough()}它同时把检索结果经过格式化后写入context字段把用户原始问题传给question字段。后面的提示词明确要求模型“只根据资料回答”这是 RAG 应用中控制幻觉的关键。这一步就是rag实战里最常见的“检索问答”链路。如果你希望做成 API只需要用 FastAPI 包一层chain.invoke即可核心逻辑没有变化。6. 第三关用 LangGraph 替代链式思维RAG 的最小链路用 LCEL 已经够用。但真实业务里流程通常不是一条直线。比如先判断用户问题是否需要检索如果需要就查知识库不需要就查工具查完还要判断结果是否可信不可信就改写问题重新检索。这种“分支 循环 状态传递”的需求LCEL 会越写越痛苦而 LangGraph 是为这种图式流程设计的。6.1 LangGraph 核心概念LangGraph 最重要的抽象是StateGraph。你可以把整套流程想成一张有向图State所有节点共享的数据结构类似“数据库里的一张表”每个节点读取并更新它。Node图中的一个处理单元接收当前状态返回状态更新。Edge节点之间的连接。Conditional Edge根据当前状态动态决定下一个节点这是条件路由的核心。很多初学者第一次看 LangGraph 文档会晕原因是他们还在用“if else 顺序调用”的思维理解图。实际上你只需要记住写节点函数时输入是一个状态字典输出也是一个字典LangGraph 会用返回值去更新状态。6.2 最小状态图示例# 文件路径examples/05_langgraph_basic.py from typing import TypedDict from langgraph.graph import StateGraph, START, END class State(TypedDict): question: str need_rag: bool answer: str def judge_node(state: State): # 这里用最简单的方式模拟“判断是否走检索” q state[question] need_rag 手册 in q or 流程 in q return {need_rag: need_rag} def rag_node(state: State): # 真实场景中会调用第 5 章的检索问答链 return {answer: f已检索知识库回答{state[question]} 的答案} def direct_node(state: State): return {answer: f直接回答{state[question]} 的基础信息} def route_by_need_rag(state: State): return rag if state[need_rag] else direct builder StateGraph(State) builder.add_node(judge, judge_node) builder.add_node(rag, rag_node) builder.add_node(direct, direct_node) builder.add_edge(START, judge) builder.add_conditional_edges( judge, route_by_need_rag, {rag: rag, direct: direct}, ) builder.add_edge(rag, END) builder.add_edge(direct, END) graph builder.compile() result graph.invoke({question: 请说明手册中的部署流程}) print(result[answer])这个例子展示了 LangGraph 最典型的用法先有一个判断节点然后通过add_conditional_edges决定走 RAG 还是走直接回答。运行时状态字典会在节点之间传递judge_node写入的need_rag字段会被route_by_need_rag读取。如果你运行后看到ValueError: node ... is not a valid state key之类的报错通常是你返回了状态字典里没有定义的字段。LangGraph 对类型管理比较严格后续排查会讲。6.3 循环与子图LangGraph 的另一个优势是原生支持循环。以后你要做“检索结果不满意重新改写问题再检索一次”的功能只需要加一条回边。此外当多个团队各自维护一套流程时可以用子图做复用而不是复制代码。企业级实现建议先把业务流程图画出来再转换成节点和边。直接写代码往往会在分支变多以后失控。7. 第四关让 Agent 真正会“使用工具”Agent 和普通链式调用的核心区别是链式调用的流程由开发者提前写死Agent 流程中模型自己决定下一步调用什么工具、调几次、什么时候结束。LangGraph 提供的ToolNode和tools_condition能大幅度降低 Agent 的开发成本。下面是一个有搜索本地知识库和获取当前时间两个工具的 Agent 示例。7.1 工具定义# 文件路径examples/06_agent_tools.py from datetime import datetime from langchain_core.tools import tool from langchain_openai import ChatOpenAI from langgraph.prebuilt import ToolNode, tools_condition from langgraph.graph import StateGraph, START, END from langgraph.graph.message import add_messages from typing import Annotated, TypedDict from langchain_core.messages import AnyMessage tool def get_current_time(): 返回当前日期和时间适合问“现在几点”时使用。 return datetime.now().strftime(%Y-%m-%d %H:%M:%S) tool def search_manual(query: str): 查询产品手册中的内容。输入为问题。 # 实际项目中这里可以调用第 5 章的检索链路 return f针对「{query}」的检索结果部署时请先安装依赖并配置 .env。 class AgentState(TypedDict): messages: Annotated[list[AnyMessage], add_messages] tools [get_current_time, search_manual] model ChatOpenAI(modelgpt-4o-mini, temperature0) model_with_tools model.bind_tools(tools)7.2 Agent 图组装def chatbot(state: AgentState): return {messages: [model_with_tools.invoke(state[messages])]} builder StateGraph(AgentState) builder.add_node(chatbot, chatbot) builder.add_node(tools, ToolNode(tools)) builder.add_edge(START, chatbot) # 关键模型如果决定调用工具就进入 tools 节点 builder.add_conditional_edges(chatbot, tools_condition) builder.add_edge(tools, chatbot) builder.add_edge(chatbot, END) agent builder.compile() result agent.invoke({ messages: [{role: user, content: 现在几点了顺便查一下手册里的部署步骤。}] }) for msg in result[messages]: print(f{msg.type.upper()}: {msg.content})这段代码里最值得关注的是tools_condition。它是一个内置的条件函数如果模型返回了工具调用请求就路由到tools节点否则直接结束。tools节点执行完工具后又会把工具结果作为新消息塞回状态让chatbot再次看到完整对话。这就是agent开发的核心循环模型思考 - 调用工具 - 观察结果 - 继续思考。你不再需要手写 while 循环来模拟这个行为LangGraph 已经把循环做成了图结构。需要提醒的是agent.invoke的返回结果是完整消息列表包含多轮工具调用记录。你在做 Web 应用时不要直接把整段消息历史直接返回给用户而是要解析最终那一轮 AI 消息。8. 常见问题与排查思路四关跑通之后你大概率会遇到下面这些问题。按表格排查会快很多。问题现象可能原因排查方式解决方案ModuleNotFoundError: langchain_openai未安装langchain-openai包执行pip list | grep langchainpip install langchain-openaiAPI 调用返回认证错误.env未加载或 Key 错误在代码开头加print(os.getenv(OPENAI_API_KEY))检查.env路径和变量名输出里出现大量无关内容文本切分参数不合理打印切分块的前后文调小chunk_size增加chunk_overlapLangGraph 报某个 key 不在状态里节点返回了未定义的字段检查TypedDict定义和节点返回值补全字段或使用额外运行时 key 配置Agent 不调用工具模型太小或提示词没有说明工具用途打印model.kwargs中的 tools 绑定信息换更强模型或优化工具名称和描述中文检索效果差使用了通用英文 embedding 模型或切分破坏语义抽样检索结果查看命中的文本块内容换中文适配 embedding 模型调整切分策略代码相同但不同环境结果不一致依赖版本不统一检查requirements.txt是否完整锁定版本用pip freeze requirements-dev.txt固化版本一个比较隐蔽的问题The agent execution provider did not respond in time。这个现象通常不是 LangGraph 本身问题而是底层模型响应超时尤其在使用较慢的本地模型或公开 API 时容易出现。排查方向是模型服务响应时间而不是去调 LangGraph 的超时参数。如果本地模型太慢建议先用小模型做链路验证再切到高性能模型。9. 企业级工程化最佳实践个人 Demo 跑通只是起点。进入真实项目后你需要考虑的不再是“能不能跑”而是“能不能长期稳定地跑”。9.1 版本管理要严格LangChain 生态迭代快跨版本 API 变化很大。建议锁定大版本并在 CI 中固定测试环境。requirements.txt里不要用裸包名至少要指定主版本范围。发布前用pip freeze生成一份完整锁定版本文件。9.2 提示词也要版本化很多团队改了一段 prompt线上效果突然变化却无法回滚。建议把提示词当作代码管理写入 Git提交信息写清楚改动原因必要时做 AB 对比。你可以把 prompt 模板放在外部文件或配置中心运行时加载。9.3 RAG 必须做评测RAG 不是“接上向量库就完事”。你需要有一套评测集比如 50 到 100 个有标准答案的问题定期跑一遍观察检索命中率和最终答案正确率。如果发现某类问题回答变差优先检查切分方式和 embedding 模型再考虑换重排模型。9.4 Agent 要设安全边界不要让 Agent 无限重试工具调用。生产环境应对单次任务设置最大循环次数对工具调用做白名单并对高风险工具加人工确认机制。工具返回的内容也要视为不可信输入不能直接拼接进上下文后滥用。9.5 可观测性要提前设计至少记录以下信息每次调用的模型、token 数、延迟、工具调用列表、检索命中的文档 ID、最终判定结果。这样线上出问题时你才能快速定位是模型问题、检索问题还是工具问题。9.6 成本控制与限流Agent 多次工具循环会显著增加 token 消耗尤其当模型反复调工具失败时。建议在状态中维护一个step_count超过阈值直接返回“需要人工介入”。另外对用户请求做访问限流避免单用户大量调用拖垮成本。9.7 选择合适的模型不要一上来就用最大的模型。链路调试阶段用便宜的小模型因为错误信息更直接、排查更快上线前再针对关键任务用更强模型做评测。选择合适的模型本质上是一个工程决策不是“越强越好”的营销口号。10. 落地学习路径与后续方向回到开头的那个标题。为什么很多视频课会让人觉得“看懂了但不会做”因为视频内容通常是一条“平滑”的演示路径而真实开发是在“报错 - 排查 - 调整 - 再报错”中前进。如果你想在有限时间内真正吃透这条链路建议按下面这个顺序推进第 1 到 2 天跑通 LangChain 基础调用重点理解模型、提示词、输出解析器三个核心抽象。不要急着学高级特性。第 3 到 4 天做一个小型 RAG 项目建议用自己的文档不要用官方示例 PDF。自己动手切分、检索、对比不同chunk_size的效果。第 5 到 6 天用 LangGraph 重写 RAG 流程加入条件路由和简单循环感受它与 LCEL 的差异。第 7 天做一个带工具的 Agent至少让它能够调用两个工具并且完整观察中间消息链路。之后值得深入的方向包括结构化和函数调用、MCP 工具接入、重排算法、RAG 评测、Agent 记忆、多 Agent 协作、可观测性平台建设。这些内容每一条展开都能写一篇长文但前提是前四关要稳扎稳打。很多人失败不是因为某个知识点太难而是过早跳到“高级用法”却没有建立起最基础的概念坐标系。先把本文的四个代码示例跑通再往外扩展你会发现 LangChain 生态其实并没有传言中那么乱只是它把“约定”和“职责”藏在了新架构里需要你用工程化的视角去看懂它。建议把本文收藏备用下一篇再聊更深入的 LangGraph 条件路由和复杂状态管理。