LangChain v1.x四大组件拆解:LangGraph、core、Classic关系详解

发布时间:2026/9/10 19:11:14
LangChain v1.x四大组件拆解:LangGraph、core、Classic关系详解 老读者都知道我一直在跟进 LangChain 的各个大版本更新最近不少朋友来问同一个问题打开官方文档发现有的教程让你装langchain有的让你装langgraph还有地方冒出个langchain-core和Classic这四样东西到底是什么关系说真的v1.x 这次改动确实比以往任何一次都大它不光是加新功能而是把整个项目从架构上重新切了一遍。如果你还是拿 0.x 时代的思路去理解现在的 LangChain那确实容易一头雾水甚至会在装包、跑代码的时候直接被一段段ImportError打懵。我从 0.x 时代一路升级到 v1.x中间踩了不少坑也花了不少时间把新版的项目结构、依赖关系和运行机制理顺了。这篇文章我就用最直白的方式把 LangChain、LangGraph、langchain-core 和 Classic 四个概念之间的账算清楚再结合一个实际例子演示它们是怎么协作的。不管你是刚接触 LangChain 的新手还是准备从 0.x 迁移的老用户这篇文章应该能帮你把新版生态的地图彻底拼完整。1. v1.x 之前LangChain 0.x 时代埋下的两个老问题想要理解 v1.x 为什么要把项目拆成这么多个包得先回到 0.x 时代看看当时到底有什么痛点。我不是考古而是因为这些痛点直接决定了新架构的设计方向搞懂背景之后你再去看官方文档很多看起来“多此一举”的设计就都能说得通了。1.1 一体化仓库的尴尬所有东西都堆在一起在 0.x 时代整个 LangChain 生态是一个巨大的单体仓库。你安装一个langchain包里面既有基础的模型调用接口也有各类 Agent、Chain、Tool、Memory甚至还有一堆集成代码。听起来挺“全家桶”的实际上用起来问题很大。最直接的麻烦是依赖冲突。举个真实例子0.x 时代你想用某个 PDF 加载器它可能依赖pypdf你想用某个向量库它可能强制要求某个特定版本的numpy。但你的项目里可能已经在用另一个版本的numpy了于是 pip 开始疯狂解依赖冲突最后不得不靠--no-deps这种野路子强行装包装完又不一定跑得起来。我当时有个项目就是这样为了调用一个简单的文档加载器被迫在同一台机器上搞了三个虚拟环境。还有一个问题就是升级牵一发动全身。0.x 版本迭代非常快今天加入一个 Agent 类型的抽象明天调整某个 Chain 的接口签名加上 0.1、0.2、0.3 之间还来回折腾 API社区里大量教程代码过几个月就失效。这种超高速迭代对一个快速发展的开源项目来说是双刃剑——它让 LangChain 始终站在 LLM 应用开发的最前沿但同时也让版本兼容成了一个让人头大的话题。1.2 Agent 与 Chain 的边界越来越模糊除了依赖问题0.x 时代还有一个更深层的架构问题Agent 和 Chain 的边界太模糊了。你用 Chain 可以搭一条固定的处理流水线比如“先提取关键词再调用模型生成回答”Agent 则是让模型自己决定“下一步调用哪个工具”。在 0.x 的实现里两者大量复用同一套抽象和运行逻辑有时候你写出来的代码看起来是在用 Chain实际上内部已经跑起了 Agent 的决策循环。但这两者的运行模式本质上是不同的Chain 更像是工厂里的流水线工人模型按固定顺序干活Agent 更像一个项目经理它自己排计划、自己选工具、自己判断任务是否完成。把这两套东西强行塞进同一个框架里结果就是抽象层次混乱新用户学起来累维护者改起来也累。所以 LangChain 团队在升级到 v1.x 时做了一个很果断的决定——把“编排执行”这个最关键的能力单独拆成一个新包同时把最核心的抽象层也独立出来老代码则放进一个叫 Classic 的包里作为过渡。这就是整个 v1.x 架构重组的基本逻辑。2. 四个概念一张关系网LangChain、LangGraph、langchain-core 与 Classic 各自的定位到了 v1.x项目不再是你装一个包就能搞定的时代了。官方把原来的大仓库拆成了几个职责清晰的独立包每个包只干一件事。下面我把这四个概念逐个讲清楚我会尽量用生活化的类比避免一上来就堆术语。2.1 langchain-core整个生态的“地基与接口标准”langchain-core是整个 v1.x 生态最底层、最核心的公共抽象库。它里面定义的就是各种基类和接口标准BaseChatModel、BaseMessage、BaseTool、BaseRetriever、Runnable协议等等。换句话说它是所有其他包的“宪法”规定了大家该怎么定义模型、消息、工具、链式调用接口。这个包本身不提供任何具体的模型接入、工具实现或者向量库集成它只提供“接口契约”。你可以把它理解成一个公司里的岗位说明书——它定义了“产品经理”要做什么、“工程师”要承担什么职责但它不是某一个具体的员工也没有具体的执行能力。正因如此langchain-core的依赖非常轻不会给你引入一堆用不上的第三方库。在 v1.x 里无论你用的是标准langchain、langgraph还是未来出现的任何新包只要它遵循langchain-core定义的那套标准彼此之间就能无缝配合。这个设计的好处很明显各包之间解耦你的项目不再会因为装一个 PDF 加载器而被迫升级整个框架的底层依赖。我做多 agent 项目的时候最直观的感受就是升级包时心里踏实多了不再担心一个微小的手动依赖调整导致某个 API 悄然消失。2.2 langgraph真正执行编排任务的“大脑中枢”langgraph是 v1.x 里真正干活的编排引擎。它负责 Agent 的行为逻辑、状态管理、图结构执行、条件分支、循环控制等等。你如果写过稍微复杂一点的 Agent一定体会过那种“模型说要调工具调完工具还要把结果喂回去再让模型判断一次”的循环。在 0.x 时代这种逻辑要靠 AgentExecutor 这类高层抽象来包办但内部机制黑盒化比较严重你很难精细控制它什么时候该停、什么时候该调用哪个工具。langgraph把这套东西彻底改造成了程序员熟悉的“图”模型。你把 Agent 的执行流程定义成一张有向图节点Node负责执行具体的动作比如调用模型、调用工具、更新状态边Edge负责定义执行顺序和条件分支。状态对象 State 则在节点的每一步执行中被查询和更新整个运行过程你都可以施加精细控制比如“如果模型返回了工具调用请求就跳转到工具节点否则结束”。为什么会把 Agent 编排得这么细因为实际生产环境中Agent 的“不可控”是最大的痛点。你以为交给模型一个任务它就能自动规划好路径但真实运行中经常出现工具调用格式错误、循环不终止、上下文爆炸等问题。有了langgraph开发者就能像靠编程逻辑控制业务规则一样来控制 Agent 的行为不再是“跑了就听天由命”。另外langgraph是一个独立于 LangChain 的库表面上可以不依赖langchain主包来使用。但这个说法需要加个说明它内部的很多标准抽象比如消息模型、Runnable 协议依然遵循langchain-core的定义。所以在 v1.x 里langgraph和langchain-core的合作才是最常见的组合。2.3 langchain从“全家桶”变成了“集成层”那么问题来了都拆成这样了langchain这个主包还剩什么很多人以为 v1.x 的langchain包已经没用了实际上它变成了一个纯粹的“集成层”。在 v1.x 里langchain主要负责提供各种第三方集成的实现OpenAI、Anthropic、Google Gemini 等模型供应商的接入各种向量数据库的VectorStore实现文档加载器、输出解析器、文本拆分器等等。你可以把它理解成“即插即用的硬件驱动库”——langchain-core定义了 USB 接口的标准而langchain则提供了各种真实设备的驱动实现。所以如果你要用 LangChain 生态来构建一个实际的 LLM 应用那么比较常规的做法是langchain提供模型和工具的集成实现langgraph负责把这些组件编排成 Agent 或复杂工作流langchain-core则在背后保证它们之间的接口一致。三个包各司其职缺一不可。2.4 Classic老代码的“遗产仓库”不是系统组件而是迁移避风港最后聊Classic。这个名字很容易引起误会加上它和抓包工具 Fiddler Classic 撞名导致不少人搜索时还以为是同一个东西。在 LangChain 语境下Classic 指的就是 0.x 时代那些不会主动迁移到新架构的旧代码的合集包官方叫它langchain-classic。这个包干的事情非常明确把 0.x 的 AgentExecutor、各类旧 Chain、旧工具等继续保留并且提供兼容层。也就是说你如果有一个跑在 0.3.x 上的老项目暂时没时间迁移那可以把依赖切成langchainlangchain-classic很多旧 API 还能继续工作不至于升级 v1.x 之后全部瘫痪。但 Classic 的定位是“过渡方案”不是“长期方案”。LangChain 团队对它的维护力度和更新频率远低于langchain-core和langgraph如果未来 LLM 生态发生重大变化Classic 里的旧抽象将会是最先被抛弃的地方。所以我建议除非你维护的是存量老项目否则别在新代码里主动用 Classic。它的存在不是为了让你写新代码而是为了让你有充裕的时间完成迁移。3. 用一张实例图拆解四者协作从装包到跑通一个带工具的 Agent概念讲再多不落到代码上总觉得心虚。这一节我用一个非常常用的场景——构建一个能够查询本地 SQLite 数据库的 Agent把四个包的角色全部串起来演示一遍。这个例子不复杂但足够说明问题。3.1 按需装包如何正确选择要装的依赖v1.x 里第一件头疼的事就是装包。网上很多老教程会让你直接pip install langchain结果装完发现langgraph没有langchain-core版本也和预期不一致。我们先看一个比较合理的安装组合。pip install langchain1.0.0 pip install langgraph1.0.0 pip install langchain-openai pip install langchain-community我这里没有装langchain-classic因为新项目不需要。langchain-openai是 OpenAI 模型供应商的独立集成包它依赖langchain-core定义的标准接口同时被langchain主包统一管理。装完后你可以执行一条命令检查各包版本确保它们处在同一生态周期pip list | grep -i lang如果你是在已有项目上做迁移装包之前一定要先读一下官方发布的 Upgrade Guide。不同小版本之间可能有细微差异比如langchain-core里某些 Runnable 接口签名调整langgraph的 StateGraph 初始化参数变化等。软件包依赖这回事最忌二五眼想当然直接升级。3.2 四个包在代码里各自干些什么假定我们要做一个 SQL Agent它需要做到接收用户自然语言问题模型把它转换成 SQL 查询然后连接 SQLite 执行查询最后把结果组织成自然语言回答。用四个包的分工来解构它langchain-core在代码里的角色是各种基础类型。比如我们定义消息列表时会用到它的SystemMessage、HumanMessage定义工具时会继承它的BaseTool或者使用tool装饰器模型返回的结果也会被装进AIMessage等类型中。这些类型定义了整个运行过程中的数据结构标准。langchain主包的角色是具体的集成。比如创建 OpenAI 模型from langchain_openai import ChatOpenAI model ChatOpenAI(modelgpt-4o, temperature0)注意实际调用时这个类来自langchain_openai但它对外的接口遵循langchain-core里 ChatModel 的标准。你可能还会用到langchain_community里的 SQLite 工具封装或者自己写一个get_schema的函数作为工具。langgraph的角色是把上面这些能力组织成一个可执行的图。下面我写一个简化版的图from langgraph.graph import StateGraph, START, END from typing import TypedDict, List from langchain_core.messages import BaseMessage class AgentState(TypedDict): messages: List[BaseMessage] sql_query: str query_result: str def call_model(state: AgentState): response model.invoke(state[messages]) return {messages: [response]} def execute_sql(state: AgentState): # 从 AI 消息中解析出 SQL然后执行把结果放回 state ... return {query_result: result} def should_continue(state: AgentState): # 判断是继续调用工具还是直接结束 ... return end if finished else tool graph StateGraph(AgentState) graph.add_node(model, call_model) graph.add_node(sql, execute_sql) graph.add_edge(START, model) graph.add_conditional_edges(model, should_continue, {tool: sql, end: END}) graph.add_edge(sql, model) app graph.compile()在这个代码片段里StateGraph来自langgraph状态结构和消息类型来自langchain-core执行模型调用和 SQL 执行时使用的则是langchain主包提供的集成能力。四个包的协作关系清清楚楚。Classic在这样新的代码里完全不出现只有在旧项目里使用AgentExecutor、LLMChain等旧 API 时才会被 import。比如下面这段旧代码风格在新架构里只能靠langchain-classic才能跑通from langchain.chains import LLMChain from langchain.agents import AgentExecutor如果用新版langgraph你不会再写AgentExecutor而是自己定义带条件边的图。3.3 状态管理langgraph 最关键的设计别当成“代码编排花架子”我很早之前看langgraph示例代码时觉得这不就是把流程控制逻辑从代码搬进了图结构里吗好像也没省多少事。等我真去写一个多步推理 Agent 时才发现状态管理才是它最值钱的部分。langgraph的状态机制可以理解为一张“工作记忆白板”。图上每个节点执行完毕后都可以往白板上新增或修改一些信息下一个节点能读到这些信息并据此决定下一步动作。这个白板不是全局变量那么简单它支持在各种分支和循环中自动传递甚至还能通过 reducer 的方式对同一字段做增量合并。比如上面 SQL Agent 里model节点每次拿到的是最新的messages列表生成一条 SQL 后追加进去execute_sql节点读取这个sql_query字段执行完把结果写回query_result下一步model节点再把结果和之前的对话历史一起拿去生成最终回答。整个过程中状态的变化轨迹可以随时序列化、打印、人工审查。排查 Agent 跑偏问题的时候你不再需要到处打日志直接把状态快照拉出来看一眼就清楚了。如果你只在一两处流程里用「模型返回 - 工具执行 - 再模型返回」的循环也许确实用langgraph和用 0.x 时代AgentExecutor没有本质区别。但一旦你需要在流程中插入人工审批、子图并行、记忆持久化、时间旅行等高级能力时图编排的状态管理优势就完全体现出来了。我现在的经验是只要 Agent 可能要跑多个工具步骤就直接上langgraph别拿手写循环硬蹭。4. v1.x 各包选型与代码迁移别再拿 0.x 的经验硬套新版进入 v1.x 之后很多从 0.x 时代带来的“惯性思维”反而成了最大的坑。比如你习惯性用agent create_openai_functions_agent(...)然后AgentExecutor(agentagent, toolstools)这套旧模式在 v1.x 里已经被langgraph的create_agent或者直接构建状态图所取代。这一节我列一些我在迁移过程中总结出的选型与对应关系希望对准备升级的人有帮助。4.1 旧 API 到新 API 的大致映射参考我做了一张速查表方便你在迁移时快速定位该用哪个包的哪个类旧 0.x 用法v1.x 推荐方向主要归属包LLMChain(prompt..., llm...)直接用 promptmodelAgentExecutor用StateGraph自定义图或用create_agent快速创建langgraphBaseTool自定义工具继续用接口保持稳定langchain-coreConversationBufferMemory状态管理放到 State 中不要依赖 Memory 类langgraphPythonReplTool等内置工具从langchain_community.tools或langchain.tools导入langchain主包或独立包load_qa_chain等 Question-Answering Chain拆成检索、提示词、模型、输出解析等独立组件再用图或链组装langchain/langgraph这个表格不要求你背下来但建议在迁移时对照着走。很多旧代码并非全部要改特别是纯工具类、模型调用类的代码在 v1.x 里依然稳定真正大改的是高层编排层的部分。4.2 一个现实的平滑迁移步骤从 0.x 到 v1.x 我做了什么我做迁移时不是一股脑全重写而是按三层拆开处理效果很好。第一层先把模型调用、工具实现、基础链式调用这些“叶子组件”升级到 v1.x 的标准因为这部分改动最小。第二层把AgentExecutor相关的逻辑拆成赤裸裸的StateGraph节点和条件边这一步是整个迁移里最耗时的但也让我把以前“糊涂着用”的 Agent 行为彻底梳理清楚了。第三层处理状态和持久化。旧项目里如果用ConversationBufferMemory直接删掉把对话历史全部放到 State 里的messages字段维护如果要持久化可以考虑langgraph的 checkpointer 功能。我见过一种最容易踩坑的迁移方式把 0.x 代码装个langchain-classic就完事以为换个包名就安全了。实际上 Classic 里很多工具实现依赖的底层包已经不被新版官方容器正常带入你可能会遇到安装langchain-classic后拉进来一堆老版本依赖和langchain-core的新接口冲突。Classic 的正确用途是给你一个过渡缓冲期不是让你一劳永逸躲在新旧之间的夹缝里。4.3 langgraph 和 langchain 边界变更后的新习惯从 v1.x 开始要有意识地建立一个新的“心智模型”需要编排找 langgraph需要集成找 langchain需要标准接口找 langchain-core。这个心智模型一旦建立你再看官方文档就不会再问“为什么一会儿让我看 LangGraph 的文档一会儿让我看 LangChain 的文档”这种问题。以 Agent 开发为例最正统的 v1.x 路线是这样的先在langchain主包里选好模型集成、选好内置工具然后到langgraph里定义状态和节点把所有东西粘成一张图。如果你要处理复杂的并行执行比如同时调用多个检索工具后再汇总结果给模型那可以用langgraph的SendAPI 或者 Fan-out 分支实现。如果你想做带记忆的对话 Agent那就在编译图时传入checkpointer这样每次运行的中间状态就可以被保存和追溯还能实现类似人工接管、暂停恢复的效果。这些能力在 0.x 时代要么实现得很别扭要么根本没有。还有一点很实用在 v1.x 中官方对langgraph的重视程度已经明显高于传统的 Chain。假如你在写一个比较复杂的业务场景刚想用旧式 Chain 去拼接步骤我建议你停下来想一想是否可以直接画成一个StateGraph。很多原本用 Chain 实现的长流程任务比如说“生成摘要 - 提取关键词 - 查重 - 生成报告”在langgraph里就是四个节点加三条普通边的事情状态清晰中途想在任一步插个调用或加个分支都极其顺手。5. 常见问题速查表我收集到的 v1.x 高频困惑与避坑建议整合一下平时大家在评论区问得最多、也是我实际踩过的一些坑汇总成一张速查表。5.1 LangChain 和 LangGraph 到底有什么区别什么时候用哪个这是被问得最多的一个问题。最简单的回答是LangChain 是集成层LangGraph 是编排层。你的程序里如果需要调用 OpenAI 模型、加载文档、接入向量库这些都是 LangChain 或它的子集成包的工作如果你要写一个多步骤、带条件判断和循环的智能体应用用 LangGraph 来组织流程更合适。如果只是“模型聊几句”这种场景你可以不用 LangGraph直接model.invoke(messages)就够了。但只要是“模型决定调什么工具、把结果反馈给模型继续推理”这种带循环的过程我强烈建议至少用上 LangGraph。别等到代码越写越乱才想起来换到那时重构成本远高于一开始就用图把流程定下来。5.2 langchain-core 要不要单独安装它有什么用在一些环境中你安装langchain或者langgraph时它们会作为依赖自动带上langchain-core所以并不需要你手动单独安装它。但你要知道它是干什么的它是所有包共同遵循的接口标准。如果哪天你在代码里发现from langchain_core.messages import HumanMessage导入失败大概率是依赖没有装完整或者版本不兼容此时再手动检查安装langchain-core也不迟。有人说既然它是底层接口那我是不是直接用langchain-core开发更“轻量”能不能行得通取决于你干什么。如果你只是要纯手工调用模型并自行封装所有工具也许可以但实际开发中你很难绕开langchain提供的各种集成因为那是省时间的地方。不要为了追求轻量而舍本逐末。5.3 Classic 是不是必须装为什么我装了它反而出现一堆报错Classic 不是必须装的。新项目完全可以无视它。只有当你的旧项目暂时迁不过来需要过渡时它才有价值。安装它之后出现报错通常是因为你把 Classic 里的旧 API 和新版的模型、工具混用了。比如你从langchain.chains里 import 一个LLMChain但这个 Chain 内部用的是 0.x 的消息结构和langchain-core的BaseMessage不是完全兼容。这时候你要么把旧代码完全迁移到langgraph风格要么就老老实实把项目和新版隔离不要混着用。5.4 版本冲突死活装不上我常用的排查办法这个问题几乎不可避免尤其是在老项目上升级。我的建议是先创建一个干净的新虚拟环境再用 pip 安装你需要的包逐个验证 import。如果出现版本冲突先看报错信息里是哪些包互相要求冲突然后用 pip 的pip check来查依赖问题。不要盲目升级全部包尽量锁定 LangChain 官方各包之间的兼容版本区间。如果你用的是 poetry 或 uv让它们统一管理依赖解析会省心不少。另外一个小技巧是在升级前读一遍官方包的 changelog特别是langchain-core和langgraph的。这两个包的版本号变更往往暗示着接口层面的重大变化。很多看似莫名其妙的报错其实是某个方法签名悄悄变了。你花 10 分钟看更新日志远胜过在 Stack Overflow 上翻一晚上的旧答案。5.5 网上资料还停留在 0.x我该怎么辨别过时内容现在搜 LangChain 相关教程铺天盖地还是 0.x 时代的写法。很多教程让用户写from langchain.agents import initialize_agent、from langchain.memory import ConversationBufferMemory这些在 v1.x 里要么已经移到 Classic要么直接被移除。辨别方法非常简单如果一篇教程里频繁出现AgentExecutor、LLMChain、initialize_agent这类词大概率是 0.x 的遗老写法如果教程里在强调langgraph、StateGraph、langchain-core这个概念体系那基本可以放心参考。学习 v1.x 的最佳顺序我个人建议是先把langchain-core的几个核心概念看明白比如 Runnable、Message、Tool再上手langgraph写一个简单的反应式 Agent最后才去研究langchain主包里的各种集成工具。这个顺序能让你少走很多弯路不会一上来就被各种集成库淹没。写在最后的一点个人总结从 0.x 到 v1.x很多人把这看成一次普通的版本号升级但实际上这更像是一次“重新创业”。LangChain 团队没有选择在旧代码上打补丁而是大胆地把 Agent 编排拆给了 LangGraph把接口标准下沉到 langchain-core把旧代码扔进 Classic 作为缓冲。这套组合拳对整个生态的长远健康度来说是个好事——它意味着以后各个模块可以独立演进、独立发版不会再出现“改一个 Agent 逻辑就得带着整个全家桶重新升级”的尴尬局面。以我自己的项目经历来看最早我挺抗拒重写 Agent 执行器的觉得AgentExecutor用得好好的为什么非要去学什么图。等我咬牙把项目迁到langgraph之后我才真正意识到很多以前只能在社区帖子里看到的高级玩法——状态持久化、分支并行、嵌套子图、人工介入、断点恢复——其实才是专业做 LLM 应用该有的基本功。虽然学习曲线确实比 0.x 陡了一点但对长期维护和工程化落地来说这个代价是完全值得的。最后给还在犹豫要不要升级的朋友一个建议别急着把你手上所有的项目一次性迁移过来。你先从一个小模块、一个小 Agent 开始用 v1.x 的写法重新实现一遍对比看看调试体验和流程可控性到底差多少。我赌你试完之后大概率不会再想回到 0.x 时代。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询