ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

LangChain vs LangGraph:从链到图的LLM应用架构选型

LangChain vs LangGraph:从链到图的LLM应用架构选型 # LangChain vs LangGraph从链到图的LLM应用架构选型## 一、问题的起点线性链什么时候会撞墙2023 年 LangChain 0.0.x 刚发布时它解决的问题很具体把「Prompt → LLM → 解析」这条链路标准化。开发者不用再手写字符串拼接、不用为每个模型单独写调用代码。LCELLangChain Expression Language在 0.1 版本引入后| 组合子配合 invoke / batch / stream / astream 四套统一接口确实让 RAG 管道和聊天机器人的开发成本大幅下降。但生产环境很快暴露出边界。一个典型的客服 Agent 需要先判断意图命中知识库就走检索检索置信度低就改写 query 重试循环涉及退款要走人工审批中断审批通过后调用工单 API外部副作用失败要回滚重来。这些需求里有三个词——**循环、中断、状态回滚**——线性 DAG 一个都给不了。LangGraph 就是为这个边界设计的。2025 年 10 月 LangChain 1.0 与 LangGraph 1.0 同期发布后两者的关系已经不是「二选一」LangChain 1.0 的 create_agent 直接构建在 LangGraph 运行时之上。理解它们的分层关系比记住功能对比表更有价值。## 二、执行模型差异DAG 与状态图**LangChain 的执行模型是单向数据流。** 一个 Runnable 序列编译成有向无环图数据从入口流到出口每个节点只拿到上游的输出不感知全局状态。分支只能靠 RunnableBranch 或 route 预先声明运行时无法根据中间结果动态改变拓扑。**LangGraph 的执行模型是 Pregel 风格的超步super-step。** 它把流程建模为 StateGraph节点是普通 Python 函数边是状态转移支持条件边、并行扇出Send API和**反向边**。反向边就是循环——这恰恰是 Agent 的核心。一次工具调用失败图可以退回 agent 节点重新推理这在 LangChain 里只能靠外部 while 循环硬编码。python# langgraph 1.0.xfrom langgraph.graph import StateGraph, START, ENDbuilder StateGraph(State)builder.add_node(agent, call_model)builder.add_node(tools, tool_node)builder.add_edge(START, agent)builder.add_conditional_edges(agent, should_continue, {tools: tools, end: END})builder.add_edge(tools, agent) # 反向边构成 ReAct 循环这段代码的价值不在于「写法更花哨」而在于**循环被声明为图的拓扑结构**而不是散落在控制流里。调试时你看到的是一张可序列化的图而不是一堆嵌套的 if/for。## 三、状态管理隐式上下文 vs 显式 reducer这是两者最深层的分野也是最容易被低估的一点。LangChain 通过 memory 模块后迁移到 LangGraph 的 checkpoint自动传递上下文本质是「把历史消息塞进 prompt」。开发者对「哪些字段被保留、如何合并、何时截断」几乎没有控制权。多轮对话里想同时维护 messages、user_profile、retrieved_docs、retry_count 四类状态就得自己写容器类。LangGraph 把这个过程显式化了。状态用一个 TypedDict 声明每个字段通过 Annotated[..., reducer] 指定合并策略python# langgraph 1.0.xfrom typing import Annotatedfrom typing_extensions import TypedDictfrom langgraph.graph.message import add_messagesclass State(TypedDict):messages: Annotated[list, add_messages] # 追加而非覆盖retry_count: int # 默认覆盖plan: list[str]add_messages 会按 message id 去重并追加这正是多轮对话需要的语义。而 retry_count 走默认的覆盖策略节点只返回增量 {retry_count: 1}框架负责合并。**状态更新变成了一等公民可观测、可测试、可持久化。**配合 checkpointer每个超步结束后状态快照落盘。MemorySaver 用于开发SqliteSaver 用于单机langgraph-checkpoint-postgres 2.x 用于生产。有了快照就有时间旅行传入历史 checkpoint_id 就能回放任意一步这对排查「Agent 为什么第三次调用工具时走错了分支」这类问题几乎是刚需。## 四、代码对比同一个 RAG 任务两种写法**LangChain 1.0LCEL**python# langchain-core 1.0.x, langchain-openai 1.0.xfrom langchain_openai import ChatOpenAI, OpenAIEmbeddingsfrom langchain_core.prompts import ChatPromptTemplatefrom langchain_core.output_parsers import StrOutputParserfrom langchain_core.runnables import RunnablePassthroughretriever vectorstore.as_retriever(search_kwargs{k: 4})prompt ChatPromptTemplate.from_template(仅依据上下文回答无法回答时回复不知道。\n上下文{context}\n问题{question})chain ({context: retriever, question: RunnablePassthrough()}| prompt| ChatOpenAI(modelgpt-4o-mini, temperature0)| StrOutputParser())chain.invoke(LangGraph 的 checkpointer 解决什么问题)大约 15 行覆盖 80% 的 RAG 场景。这是 LangChain 依然是原型首选的原因——学习曲线低stream 和 batch 免费获得。**LangGraph 1.0带人工审批的 Agent**python# langgraph 1.0.x, langgraph-checkpoint-sqlite 2.xfrom langgraph.graph import StateGraph, START, ENDfrom langgraph.checkpoint.sqlite import SqliteSaverfrom langgraph.types import interrupt, Commanddef human_approval(state: State):decision interrupt({tool_calls: state[messages][-1].tool_calls})if decision ! approve:return {messages: [reject_message(state)]}return tool_node(state)builder StateGraph(State)builder.add_node(agent, call_model)builder.add_node(approval, human_approval)builder.add_node(tools, tool_node)builder.add_edge(START, agent)builder.add_conditional_edges(agent, should_continue,{approval: approval, tools: tools, end: END})builder.add_edge(tools, agent)graph builder.compile(checkpointerSqliteSaver.from_conn_string(agent.sqlite))config {configurable: {thread_id: user-42}}graph.invoke({messages: [(user, 把这周日志汇总成周报并发送)]}, config)# 图在 interrupt 处挂起进程可以退出graph.invoke(Command(resumeapprove), config) # 数小时后从断点继续interrupt() 是 LangGraph 相对 LangChain 最实用的能力。LangChain 时代做人机协同标准做法是把整个状态 dump 到 Redis等审批回调再重新组装上下文——脆弱且难测。LangGraph 把「挂起—恢复」做进了运行时Command(resume...) 从最后一个 checkpoint 继续执行中间不需要保持进程存活。## 五、LangChain 与 LangGraph 能力对照| 维度 | LangChain 1.0 | LangGraph 1.0 || --- | --- | --- || 架构 | 线性工作流组件串联 | 图结构节点边支持环与分支 || 流程形态 | 逐步顺序执行 | 迭代、循环、可重访 || 状态管理 | 隐式靠 memory/context 模块传递 | 显式 TypedDict reducer || 学习曲线 | 低半天可上手 | 陡需要图编程思维 || 人工介入 | 需手写脚本定制 | interrupt() 原生支持 || 复杂度承载 | 简单管道分支靠 workaround | 原生分支、并行、循环 || 适用场景 | 原型、RAG、文档处理、聊天机器人 | 生产级多 Agent、长时状态化应用 |注意表中「隐式 vs 显式」这一行。它不是程度差异而是**能力边界差异**状态不可见就无法在任意点暂停、恢复和回放不能暂停恢复就做不了需要人类审批或跨天运行的业务。## 六、选型决策判断标准可以收敛成三个问题**流程里有没有循环** 有 query 改写重试、工具调用失败重试、自我反思迭代选 LangGraph。纯一次性的检索问答LangChain 足够。**单次会话是否需要跨进程存活** 需要等待人工审批、需要断点续跑、需要用户次日回来接着聊选 LangGraph Postgres checkpointer。**是否需要多个 Agent 分工** 规划者、执行者、审查者各司其职并可能并行探索再汇总只有 LangGraph 的 Send API 和子图能自然表达。反过来如果需求是「上传 PDF → 切片 → 向量化 → 问答」硬上 LangGraph 只会增加维护成本。图的表达能力有代价状态 schema、reducer 冲突、checkpoint 序列化、超步调优都是额外工作量。两者也能混用。LangGraph 的节点内部完全可以是一段 LCEL 链——把 chain.invoke 包进节点函数即可。实践中常见的分层是**LangGraph 管流程与状态LangChain 管单步内的模型调用与检索**。LangChain 1.0 的 create_agent 就是这个思路的官方实现。## 七、收敛趋势LangChain 1.0 把 agent 抽象收敛到 LangGraph 运行时之上同时把 langchain-core 稳定为 1.0.x 接口层langchain-community 中的集成逐步迁往独立包langchain-openai、langchain-anthropic 等均按 1.0.x 节奏发版。这个动作说明维护者自己也承认**线性链是入口状态图才是终点。**对团队而言现实建议是原型阶段用 LangChain 快速验证 prompt 与检索质量一旦需求出现「重试」「审批」「多轮规划」中的任意一个词就该迁移到 LangGraph。迁移成本主要在状态 schema 的重新设计而不是代码重写——把现有的 LCEL 链原样塞进节点先跑通再逐步把散落在函数闭包里的状态提取到 State 中。选框架的本质是选状态模型。状态越复杂、生命周期越长就越需要一张显式的图。
返回列表