很多人对 LangChain 的理解停在「把节点串成一条链」,对 LangGraph 的理解停在「把线变成图」。 这两个理解都不算错,但都只摸到了表面。 这篇文章从「是什么 → 解决什么问题 → 两者什么关系」三个角度,把它们讲透。
一、先说结论
- LangChain 是上层框架,提供可组合的「能力积木」:模型、提示词、工具、检索。
- LangGraph 是底层编排运行时,提供「骨架」:状态、节点、边、持久化。
- 两者的关系一句话:LangChain 决定「每一步里放什么」,LangGraph 决定「几步、怎么走」。
二、LangChain:它不是「链」,而是「积木」
2.1 名字的由来
「Chain(链)」这个名字确实来自最早的用法——把几步串起来:
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 运行,分工是这样的:
① 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 的是「谁」。
// ① 调官方 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 是不是每个节点里都有一条小链?
不是。 节点本质就是一个函数,里面写什么由你决定:
// 节点 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:
const ragChain = retriever.pipe(formatDocs).pipe(prompt).pipe(model).pipe(parser);
七、代码:一个最小可运行的 Agent
下面这段代码把「零件层」和「骨架层」用注释分开,对着看就清楚谁是谁。
# ==================== 【零件层】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 是让这份「干活」能循环、能中断、能恢复的那层运行时。 图是骨架,节点是步骤,链是步骤内部的一种写法,零件是最小单位。
参考资料
- LangChain 开源栈总览:www.langchain.com/oss-overvie…
- LangChain 官方文档:docs.langchain.com/oss/python/…
- LangGraph 官方文档:docs.langchain.com/oss/python/…
- LangChain 设计哲学:docs.langchain.com/oss/javascr…