LangChain 与 LangGraph:从「链」到「图」,一次讲清它们是什么、什么关系

很多人对 LangChain 的理解停在「把节点串成一条链」,对 LangGraph 的理解停在「把线变成图」。 这两个理解都不算错,但都只摸到了表面。 这篇文章从「是什么 → 解决什么问题 → 两者什么关系」三个角度,把它们讲透。


一、先说结论

  • LangChain 是上层框架,提供可组合的「能力积木」:模型、提示词、工具、检索。
  • LangGraph 是底层编排运行时,提供「骨架」:状态、节点、边、持久化。
  • 两者的关系一句话:LangChain 决定「每一步里放什么」,LangGraph 决定「几步、怎么走」。

二、LangChain:它不是「链」,而是「积木」

2.1 名字的由来

「Chain(链)」这个名字确实来自最早的用法------把几步串起来:

python 复制代码
chain = prompt | model | parser

| 把上一步的输出接到下一步的输入,这就是「链」的字面含义。

所以如果你脑子里是「一条线」,那不算错,只是那是最小、最早的一种形态。

2.2 但今天它是什么

官方现在的定义是:LangChain 是构建智能体(agent)的框架。

它给你的不是一条线,而是一盒可以自由拼装的积木:

  • 模型(Model)
  • 提示词(Prompt)
  • 工具(Tool)
  • 检索(Retriever)
  • 输出解析(Parser)
  • 中间件(Middleware)

这些积木本身互不认识、也不会自己连起来。怎么连,是你的事。

2.3 它解决的真实问题

大模型本身只会「文本进、文本出」。但真实应用需要:

  • 接数据库、调外部 API
  • 记住上下文
  • 把输出变成结构化数据
  • 在不同模型厂商之间切换

这些每个项目都自己写一遍太重复,LangChain 把它们做成了标准抽象。

核心价值是「标准化」和「可组合」,不是提升模型能力。

2.4 它其实是一整套栈

LangChain 不是单个库,而是一套栈,从下到上分三层,外加一个横跨全程的平台:

层 名字 作用
上 Deep Agents 现成脚手架,自带规划、记忆、子代理
中 LangChain 框架积木,模型、工具、中间件
下 LangGraph 底层运行时,可循环的图 + 持久化
贯穿 LangSmith 追踪、评估、监控、部署
flowchart TD DA["Deep Agents --- 现成脚手架"] LC["LangChain --- 框架积木"] LG["LangGraph --- 底层运行时"] LS["LangSmith --- 观测与部署"] DA --> LC LC --> LG LS -.-> DA LS -.-> LC LS -.-> LG

越往上越省事,越往下越可控。可以按需选择,也可以随时在层之间移动。


三、LangGraph:不只是「图」,而是「有状态的运行时」

3.1 对它的三层理解

第一层:线性链

一条线走到底,没有回头路。这是最早的形态。

第二层:图(分支 + 循环)

节点之间可以有分支,也可以有回头。这是大多数人对 LangGraph 的理解------正确,但不够。

第三层:有状态的图运行时

这才是 LangGraph 真正的核心。图的重点不是「能画分支」,而是:

每一步共享一份状态,并且这份状态能被保存、恢复、暂停。

flowchart LR S((开始)) --> M[模型节点] M -->|有工具请求| T[工具节点] T --> M M -->|已完成| E((结束))

3.2 四个核心概念

概念 是什么 类比
State(状态) 贯穿全流程的共享数据,所有节点读写它 一块公共白板
Node(节点) 一个执行单元,接收 state、返回更新 白板上做一步的人
Edge(边) 节点之间的连线,决定下一步去哪 流程箭头
Conditional Edge(条件边) 由函数决定走哪条分支 路口的指路牌

关键点:节点不直接调用下一个节点,而是「更新状态 → 由边决定下一步」。

这正是它能循环的原因------只要边指回前面的节点,就构成了环。

3.3 三个真正拉开差距的能力

很多人会问:分支和循环,我用 if / while 也能硬写啊?

LangGraph 不可替代的地方在下面三点:

1. 持久化(Checkpointer)

每一步执行完都存一个检查点。任务跑到一半崩了、进程重启了,可以从断点继续,而不是从头再来。

2. Human-in-the-loop(人工介入)

因为状态被保存了,图可以中途暂停,等人类审核后再继续------比如转账前等人确认。

3. 流式输出

实时吐出每一步的中间结果,而不是等整条流程跑完。


四、两者的关系:零件与骨架

把两者合起来看,最好的心智模型是:

LangChain 提供「零件」,LangGraph 提供「骨架」。 零件决定「能做什么」,骨架决定「怎么流转」。

一次真实的 Agent 运行,分工是这样的:

css 复制代码
① LangChain:能力积木(决定「能做什么」)
   [模型]  [提示词]  [工具]  [检索]
        │
        │ 组装进图
        ▼
② LangGraph:编排骨架(决定「怎么流转」)
   ┌─────────────────────────────────┐
   │   [模型节点] ──调用──▶ [工具节点]  │
   │        ▲                   │      │
   │        └───── 循环 ────────┘      │
   │                    │             │
   │                    ▼             │
   │                [结束节点]         │
   │                                 │
   │   State:共享状态,可持久化        │
   └─────────────────────────────────┘
维度 LangChain LangGraph
定位 框架积木 底层编排运行时
提供 模型、工具、提示词、检索、中间件 状态、节点、边、持久化、人工介入
抽象层次 较高,开箱即用 较低,完全可控
核心问题 「有哪些能力可用」 「流程怎么走、状态怎么存」
关系 create_agent 建在 LangGraph 之上 是 LangChain Agent 的引擎

五、四层词汇表:图 / 节点 / 链 / 零件

这是最容易绕晕的地方。把它们按层级排好,就清晰了:

层 名字 属于谁 是什么
4 图 Graph LangGraph 用「边」把节点连起来,形成流程
3 节点 Node LangGraph 一个执行步骤,本质是一个函数
2 链 Chain LangChain 用 .pipe() 把零件串起来
1 零件 Component LangChain 模型、工具、提示词、解析器

关键认知:层与层之间是「可以嵌套」,不是「必须嵌套」。 图里必须有节点,但节点里可以没有链。


六、三个最容易搞错的点

6.1 代码里一个 invoke,算不算用了 LangChain?

取决于你 invoke 的是「谁」。

js 复制代码
// ① 调官方 SDK → 不是 LangChain
import OpenAI from "openai";
const client = new OpenAI();
await client.chat.completions.create({ model: "gpt-4o", messages: [...] });

// ② 用 LangChain 的模型类调一次 → 是「用了 LangChain」,但不是「链」
import { ChatOpenAI } from "@langchain/openai";
const model = new ChatOpenAI({ model: "gpt-4o" });
await model.invoke("你好");

// ③ 把多个组件串起来 → 这才是「链」
const chain = prompt.pipe(model).pipe(parser);
await chain.invoke({ question: "你好" });
你 invoke 的是 算 LangChain 吗 算「链」吗
官方 SDK 的 client ❌ 不是 ❌
LangChain 的 model ✅ 是 ❌ 只是单个零件
LangChain 的 chain ✅ 是 ✅ 是

「用了 LangChain」和「建了一条链」是两回事。 invoke 是 LangChain 的统一插头------一个插头也是 LangChain,但只有插上多个设备,它才叫「链」。

6.2 节点上是不是「挂着工具」?

不是。 准确的说法是:

节点是「一个执行步骤」,LangChain 是「装进这个步骤里的零件」,而工具只是零件中的一种。

节点里可以放的还有「调用模型」「检索文档」「处理格式」。工具 ≠ 节点,工具 ≠ LangChain 的全部。

6.3 是不是每个节点里都有一条小链?

不是。 节点本质就是一个函数,里面写什么由你决定:

js 复制代码
// 节点 A:内部是一条小链
const miniChain = prompt.pipe(model).pipe(parser);
async function nodeA(state) {
  const answer = await miniChain.invoke({ q: state.question });
  return { answer };
}

// 节点 B:直接调模型,没有链
async function nodeB(state) {
  const res = await model.invoke(state.messages);
  return { messages: [res] };
}

// 节点 C:执行工具,也没有链
async function nodeC(state) {
  const result = await tool.invoke(state.args);
  return { result };
}

三个都是合法节点。只有 A 里面有「链」,B 和 C 就是一次直接调用。

实际项目里,一个节点通常只做一件事,所以直接调用更常见。链真正有用的地方,是那些固定顺序的多步处理,比如 RAG:

js 复制代码
const ragChain = retriever.pipe(formatDocs).pipe(prompt).pipe(model).pipe(parser);

七、代码:一个最小可运行的 Agent

下面这段代码把「零件层」和「骨架层」用注释分开,对着看就清楚谁是谁。

python 复制代码
# ==================== 【零件层】LangChain ====================
from langchain.chat_models import init_chat_model
from langchain.tools import tool
from langchain_core.messages import SystemMessage, ToolMessage

@tool
def get_weather(city: str) -> str:
    """查询指定城市的当前天气。"""
    return {"北京": "晴,25℃", "上海": "多云,28℃"}.get(city, "未知城市")

@tool
def add(a: int, b: int) -> int:
    """计算两个整数之和。"""
    return a + b

TOOLS = [get_weather, add]
TOOLS_BY_NAME = {t.name: t for t in TOOLS}

model = init_chat_model("openai:gpt-4o", temperature=0)
model_with_tools = model.bind_tools(TOOLS)   # 把工具「告诉」模型

# ==================== 【骨架层】LangGraph ====================
from typing import Annotated
from typing_extensions import TypedDict
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages
from langgraph.checkpoint.memory import MemorySaver

class State(TypedDict):
    # 共享状态;add_messages 是 reducer,新消息是「追加」而非覆盖
    messages: Annotated[list, add_messages]

def call_model(state: State):
    # 节点 1:调用 LangChain 的模型零件
    msgs = [SystemMessage(content="需要时调用工具,最后用中文回答。")] + state["messages"]
    return {"messages": [model_with_tools.invoke(msgs)]}

def call_tools(state: State):
    # 节点 2:执行模型要求的工具(LangChain 的工具零件)
    last = state["messages"][-1]
    results = []
    for call in last.tool_calls:
        fn = TOOLS_BY_NAME[call["name"]]
        results.append(ToolMessage(content=str(fn.invoke(call["args"])), tool_call_id=call["id"]))
    return {"messages": results}

def should_continue(state: State) -> str:
    # 条件边:判断下一步去哪
    return "tools" if getattr(state["messages"][-1], "tool_calls", None) else END

builder = StateGraph(State)
builder.add_node("model", call_model)
builder.add_node("tools", call_tools)

builder.add_edge(START, "model")
builder.add_conditional_edges("model", should_continue, {"tools": "tools", END: END})
builder.add_edge("tools", "model")          # 关键:这条边构成「循环」

app = builder.compile(checkpointer=MemorySaver())   # 编译 + 持久化

if __name__ == "__main__":
    config = {"configurable": {"thread_id": "user-1"}}
    out = app.invoke({"messages": [("user", "北京天气怎么样?再帮我算 3+4")]}, config)
    for m in out["messages"]:
        m.pretty_print()

运行时发生了什么:

步 位置 发生了什么
1 START → model 把用户问题喂给模型
2 model 节点 模型返回带 tool_calls 的消息:要查天气 + 算加法
3 条件边 发现有工具请求 → 去 tools
4 tools 节点 执行两个工具,产出两条 ToolMessage
5 边 tools → model 循环回到模型
6 model 节点 模型这次不再要工具,给出最终回答
7 条件边 无 tool_calls → 走向 END

一个「思考 → 行动 → 再思考」的循环,跑了 2 轮。 这就是一条直线画不出来的东西。

⚠️ 提醒:LangChain / LangGraph 迭代很快,接口在 1.0 之后有过调整。上面的写法是当前主流版本,如果报 import 错误,多半是版本差异。


八、怎么选:一张决策表

你的需求 用什么
只是发一句话、拿一段回复 直接用官方 SDK,连 LangChain 都不用
固定顺序的多步流程(如 RAG) LangChain 的链,够用且简单
需要工具循环、人工审核、断点恢复 LangGraph
懒得自己搭,要开箱即用 Deep Agents 现成脚手架

一条经验法则:

能用 SDK 解决的别上 LangChain;能用链解决的别上图。抽象层越多,调试成本越高。


九、面试怎么答

LangChain:

LangChain 是一个用来构建大模型应用的开发框架。它的核心价值是把大模型和外部世界------数据、工具、记忆------连接起来,并提供一套可组合的标准抽象。早期它的组织方式是「链」,用管道符把组件串起来,所以叫 LangChain;但真实任务往往需要模型自主决定下一步甚至反复循环,所以现在它的重心转向了智能体,底层编排交给 LangGraph。

LangGraph:

LangGraph 是 LangChain 底层的编排运行时,用图来描述智能体流程。它不只是把线性链改成有分支和循环的图,更重要的是引入了共享状态和持久化检查点,因此能做到断点恢复、人工介入、流式输出------这些是普通 Chain 做不到的。LangChain 的 create_agent 就建在它之上。

两者关系:

它们是一套栈的上下两层。LangChain 是上层框架,提供模型、工具、检索这些可组合积木;LangGraph 是下层编排运行时,用图描述流程,靠共享状态和持久化支持循环、分支、断点恢复和人工介入。简单固定流程用 LangChain 就够了;需要智能体自主决策、长时运行、可中断恢复时,就用 LangGraph。

加分点:

  • 它解决的是「标准化」和「可组合」,不是模型能力问题。
  • 抽象是有代价的:多一层封装,调试和学习成本更高;简单场景直接调官方 SDK 反而更清爽。
  • 会做选型判断,比会背文档更加分。

十、总结

一句话记住全部:

LangChain 是让大模型「从能聊天,变成能干活」的那层框架。 LangGraph 是让这份「干活」能循环、能中断、能恢复的那层运行时。 图是骨架,节点是步骤,链是步骤内部的一种写法,零件是最小单位。


参考资料

相关推荐
CoderYanger2 小时前
A.每日一题:856. 括号的分数
java·程序人生·算法·leetcode·面试·职场和发展·学习方法
吴建旭 智宅焕2 小时前
智能家居全国交付知识生产系统的真实性架构:从AI生成内容到可验证交付资产
人工智能·架构·智能家居
辛迪聊物业数字化2 小时前
物业管理系统新手部署与实操指南
数据库·物联网·架构·系统架构
Sam_Deep_Thinking3 小时前
CountDownLatch实现原理
java·后端·面试·程序员
范中勤3 小时前
Python 与 Java:模块、包、对象、反射核心差异总结
java·python·面试·反射·元类
晚风叙码3 小时前
MySQL 增删改查(CRUD)完全指南:从入门到面试
数据库·mysql·面试
mldong4 小时前
审批流程图上那些亮着的线,数据库里一条都没存:jeeflow 工作流引擎的高亮是重算出来的
后端·架构
夏幻灵12 小时前
JavaScript this 面试:五种绑定规则、优先级与常见面试陷阱
开发语言·javascript·面试
Dawson Zhu16 小时前
《Agentic Design Patterns》第 9 章导读:学习与适应(Learning and Adaptation)
人工智能·语言模型·架构·aigc·agi