夜雨聆风学习资料网

ARTICLE · 1161344

【LangGraph 源码精读】第 00 期|用了半年 LangGraph,90% 的人连架构都没搞懂!

【LangGraph 源码精读】第 00 期|用了半年 LangGraph,90% 的人连架构都没搞懂!

用了半年LangGraph,90%的人连它的架构都没搞懂:6层架构、8大包、一次invoke的完整链路(30篇源码精读·全局地图)

30篇源码精读系列·第00篇(全局地图)。你用LangGraph做了好几个项目,能熟练写State、加Node、连Edge。但如果面试官问你:LangGraph内部有几层架构?一次invoke从输入到输出经过了多少步?Checkpoint到底存了什么?并行执行为什么不会数据冲突?很多人答不上来。会用和懂架构是两回事。这篇是全局地图,先把架构搞清楚,后面30篇源码精读逐个区域深挖。


一、开头:会用LangGraph,和懂LangGraph架构,是两回事

很多人用LangGraph做了好几个项目,能熟练地写State、加Node、连Edge、配Checkpoint,跑通了ReAct Agent、多Agent协作、人机交互。

但如果问你这几个问题,你能答上来吗?

  • ● LangGraph内部有几层架构?每层负责什么?
  • ● 一次app.invoke()从输入到输出,完整经过了多少步?
  • ● Checkpoint到底存了什么?6个字段分别是什么?
  • ● 两个节点并行执行,为什么状态更新不会冲突?
  • ● prebuilt包为什么不依赖langgraph核心?反过来依赖不会循环吗?
  • ● LangGraph的执行引擎为什么叫Pregel?和Google的Pregel论文有什么关系?

很多人答不上来。会用API和懂底层架构是两回事。 懂架构才能在遇到诡异bug时定位根因,才能做深度定制,才能在面试时讲清楚"为什么"而不只是"怎么用"。

这篇是30篇LangGraph源码精读系列的第00篇——全局地图。在逐行啃源码之前,先把整体架构搞清楚。后面30篇就是在这张地图上逐个区域深挖。


二、LangGraph在LangChain生态中的位置

LangGraph不是孤立的框架,它是LangChain生态中的"编排层"。搞清楚它在生态中的位置,才能理解它为什么这样设计。

层级
项目
职责
和LangGraph的关系
应用层
Deep Agents
高层Agent harness,复杂Agent的开箱即用方案
构建在LangGraph之上
编排层
LangGraph有状态图运行时,Agent的编排和执行引擎
核心,本系列聚焦
模型层
LangChain
模型调用、工具集成、Prompt模板
LangGraph依赖LangChain的消息类型和Runnable协议
可观测层
LangSmith
Tracing、Studio、托管部署
和LangGraph配合,提供可观测性

一句话:LangChain负责"和模型对话",LangGraph负责"让Agent跑起来"。

为什么这样分层? 因为"和模型对话"和"让Agent跑起来"是两个完全不同的问题。模型对话需要处理Prompt、Token、工具调用格式;Agent运行需要处理状态、循环、持久化、并发。LangChain早期把两者混在一起,导致Agent能力弱、不可控。LangGraph独立出来,专注做"运行时",这是它能成为Agent编排标准的关键原因。

面试关联: 面试官问"LangGraph和LangChain什么关系",不要只说"LangGraph是LangChain的一部分"。要说清"LangChain是模型层,LangGraph是编排层,两者解决不同问题,LangGraph依赖LangChain的消息类型但运行时是独立的"——这才是有深度的回答。


三、6层架构总览

LangGraph内部可以清晰地分为6层,从下到上依次是:

层级
名称
核心职责
关键模块
对应源码精读篇数
第6层
用户API层
开发者直接使用的接口
StateGraph、Functional API、prebuilt组件
源码07-11、23-25
第5层
编译层
图的验证、编译、Runnable适配
图验证、CompiledStateGraph、配置管理
源码09-10
第4层
执行引擎层
Pregel BSP引擎,节点调度和状态流转
Pregel、Super-step、Channel、执行器、重试
源码01-06
第3层
持久化层
状态快照、跨线程记忆、序列化
Checkpoint、Store、Serializer
源码12-17、26-27
第2层
传输层
流式输出、事件流、远程调用
Streaming、Event Streaming、SDK
源码20-21、28
第1层
基础设施层
并发、重试、验证、配置、消息处理
执行器、重试、图验证、IO、配置
源码05-06、10

依赖方向:上层依赖下层,下层不依赖上层。 这是经典的分层架构设计——上层可以调用下层的接口,下层不知道上层的存在。这样做的好处是:每一层可以独立替换、独立测试、独立演进。比如你可以不用StateGraph(第6层),直接用Pregel(第4层);也可以不用PostgresSaver,自己实现一个CheckpointSaver。

执行引擎层(第4层)是核心中的核心。 其他层都围绕它服务:用户API层是它的入口,编译层把图编译成它能执行的格式,持久化层保存它的状态,传输层输出它的执行过程,基础设施层提供并发和重试。搞懂了执行引擎层,就搞懂了LangGraph的70%。

面试关联: "LangGraph的架构分几层?"这道题的标准答案就是这6层。重点讲清第4层执行引擎是核心,以及为什么要分层(可替换、可测试、可演进)。


四、8大包结构与职责

LangGraph是一个Monorepo(单体仓库),包含8个独立可安装的Python包。每个包有自己的版本号和依赖管理。

包名
目录
版本
职责
依赖关系
langgraph
libs/langgraph/
1.2.11
核心:StateGraph、Pregel引擎、Channels、Streaming
依赖checkpoint、prebuilt、sdk
langgraph-checkpoint
libs/checkpoint/
4.2.0
持久化基类:BaseCheckpointSaver、Store接口、序列化、MemorySaver
仅依赖langchain-core
langgraph-checkpoint-postgres
libs/checkpoint-postgres/
3.1.2
PostgreSQL持久化:PostgresSaver、PostgresStore、生产级
依赖checkpoint
langgraph-checkpoint-sqlite
libs/checkpoint-sqlite/
3.1.1
SQLite持久化:SqliteSaver、本地开发、sqlite-vec向量
依赖checkpoint
langgraph-prebuilt
libs/prebuilt/
1.1.0
预构建组件:create_react_agent、ToolNode、Messages状态
仅依赖checkpoint和langchain-core
langgraph-sdk
libs/sdk-py/
0.4.x
Python客户端SDK:远程执行、API Server客户端
独立
langgraph-cli
libs/cli/
-
CLI工具:部署、开发调试、本地运行
依赖langgraph
scheduler-kafka
libs/scheduler-kafka/
-
分布式Kafka调度器:水平扩展、分布式执行
依赖langgraph

最巧妙的设计:prebuilt包不依赖langgraph核心,而是langgraph核心依赖prebuilt。

这看起来反直觉——预构建组件(如create_react_agent)应该依赖核心才对,为什么反过来?

原因:避免循环依赖。 create_react_agent内部需要用到StateGraph来构建图,如果prebuilt依赖langgraph核心,而langgraph核心在某些地方又需要引用prebuilt的组件(比如在编译时自动注入ToolNode),就会形成循环依赖:prebuilt → langgraph → prebuilt。

解决方案:prebuilt只依赖底层的checkpoint接口和langchain-core,不依赖langgraph核心。 create_react_agent需要的StateGraph,通过"依赖注入"的方式传入,而不是直接import。langgraph核心在需要使用prebuilt组件时,直接import prebuilt(因为prebuilt不依赖langgraph,所以不会循环)。

这就是经典的"依赖倒置原则"——高层模块不依赖低层模块,两者都依赖抽象。prebuilt和langgraph核心都依赖checkpoint这个抽象接口,而不是互相依赖。

面试关联: "LangGraph的Monorepo有几个包?prebuilt为什么不依赖核心?"这道题能答上来,说明你真的读过源码,而不只是用过API。重点讲清"避免循环依赖"和"依赖倒置原则"。


五、核心执行引擎:Pregel BSP三阶段模型

Pregel执行引擎是LangGraph的心脏,基于Google Pregel论文的BSP(批量同步并行)模型。这是LangGraph区别于其他Agent框架的最核心设计。

5.1 三个核心概念

概念
说明
类比
Channel
状态的载体,节点通信的唯一媒介。每个状态字段对应一个Channel
共享黑板,所有人读同一个黑板,写完后统一更新
PregelNode
订阅某些Channel,被触发后执行,结果写回Channel
工人,看到黑板上的信息后干活,干完把结果写回黑板
Super-step
一轮"读取-并发执行-写回-创建Checkpoint"的完整循环
一轮工作节拍,所有工人同时干活,干完统一更新黑板

5.2 Super-step三阶段

每个Super-step分为三个阶段,严格按顺序执行,阶段之间有同步屏障:

阶段
做什么
关键代码
核心机制
Plan(计划)
根据上一步哪些Channel被更新了,确定这一步要执行哪些节点
prepare_next_tasks()
节点订阅Channel,Channel更新触发节点
Execute(执行)
所有待执行节点并行运行,每个节点有独立的状态副本,互不影响
PregelRunner
状态副本隔离,输入冻结,输出缓冲
Update(更新)
所有节点执行完后,按确定顺序将更新合并到Channel,版本号递增,然后创建Checkpoint
apply_writes()
确定序合并,无数据竞争,结果可复现

最关键的设计:Execute阶段节点之间完全隔离。

每个节点拿到的是Super-step开始时的状态快照(不是引用),节点执行期间修改的是本地副本,其他节点完全看不到。节点的输出先缓冲起来,不立即写入全局状态。只有所有节点都执行完后,才在Update阶段按确定的顺序统一合并。

为什么要这样设计?因为这是并行安全的唯一保证。 如果节点执行期间可以直接修改全局状态,两个节点同时修改同一个字段就会产生数据竞争,结果不可预测。而"状态副本+确定序合并"保证了:同样的输入,永远产生同样的输出,结果100%可复现。

代价是什么? 节点在Execute阶段看不到其他节点的更新。如果两个节点有数据依赖(B需要A的输出),它们不能在同一个Super-step执行,必须分两个Super-step(A先执行,下一个Super-step B再执行)。这就是为什么顺序图的每个节点对应一个Super-step。

面试关联: "LangGraph的并行执行为什么不会数据冲突?"这是高频面试题。标准答案就是"状态副本+确定序合并"——Execute阶段每个节点有独立副本,Update阶段按确定顺序合并。能讲清这个,说明你真的懂Pregel模型。


六、一次invoke的完整链路(从输入到输出)

以最简单的顺序图 START -> A -> B -> END 为例,追踪一次app.invoke(input)的完整执行过程。这12步是理解LangGraph执行流程的关键。

步骤
阶段
发生了什么
状态变化
1
入口
用户调用app.invoke(input, config),传入输入和配置(含thread_id)
-
2
初始化
CompiledStateGraph接收输入,创建初始Channel,将输入写入input Channel
Channel版本=0
3
Checkpoint
如果配置了checkpointer,保存初始Checkpoint(Super-step 0)
Checkpoint 0已保存
4
Super-step 1-Plan
input Channel被更新,触发订阅它的节点A
待执行节点=[A]
5
Super-step 1-Execute
节点A执行,读取状态副本,返回更新{field_a: x}
全局状态不变,A的输出缓冲
6
Super-step 1-Update
按确定序将A的更新合并到Channel,field_a版本+1,创建Checkpoint 1
Channel版本=1,Checkpoint 1已保存
7
Super-step 2-Plan
field_a被更新,触发订阅它的节点B(通过边A->B)
待执行节点=[B]
8
Super-step 2-Execute
节点B执行,返回更新{field_b: y}
全局状态不变,B的输出缓冲
9
Super-step 2-Update
合并B的更新,field_b版本+1,创建Checkpoint 2
Channel版本=2,Checkpoint 2已保存
10
Super-step 3-Plan
field_b被更新,但没有节点订阅它(B->END),待执行节点为空
待执行节点=[]
11
终止
没有待执行节点,所有Channel版本无变化,执行结束
-
12
返回
返回最终状态(所有Channel的当前值)
输出=最终状态

关键点:每个Super-step结束都有一个Checkpoint。 对于顺序图,每个节点对应一个Super-step,所以有多少个节点就有多少个Checkpoint(加上初始Checkpoint)。这就是时间旅行的基础——你可以回到任意一个Checkpoint重新执行。

执行终止的判断条件是什么? 不是"到达END节点",而是"没有待执行节点且所有Channel版本无变化"。END本质上是一个"不订阅任何Channel的虚拟节点",到达END意味着没有新的Channel更新,自然就没有待执行节点,执行终止。

面试关联: "一次invoke的完整流程是什么?"这道题考察你对执行流程的整体理解。能讲清12步(特别是Super-step的Plan/Execute/Update三阶段和Checkpoint的创建时机),说明你对LangGraph的执行流程有深入理解。


七、Channel系统:状态的底层存储

Channel是LangGraph中最核心但也最容易被忽略的概念。你在State里定义的每个字段,底层都对应一个Channel。不理解Channel,就不可能真正理解LangGraph。

Channel类型
行为
适用场景
对应State字段
LastValue
新值直接覆盖旧值
单一值字段
count: int(无reducer)
BinaryTreeAggregate
支持增量追加、删除、更新,用二叉树存储
列表累积、消息管理
messages: Annotated[list, add_messages]
Topic
发布订阅模式,支持动态发送
Send API、动态分支
运行时动态创建的并行分支
DeltaChannel(beta)
只存储增量delta,不重复序列化完整值
长时间运行的线程,减少Checkpoint开销
v1.2新增,长对话优化

Channel的4个核心职责:

  1. 1. 存储当前值
  2. 2. 接收更新,根据reducer合并
  3. 3. 管理版本号(每次更新版本+1)
  4. 4. 支持序列化和反序列化(用于Checkpoint)

版本号是整个执行引擎的"心跳"。 每个Super-step结束后,Pregel检查所有Channel的版本号——如果没有任何Channel的版本号变化,说明没有新的更新,执行终止。版本号还用于判断节点是否需要重新执行(versions_seen记录每个节点看到的Channel版本,如果节点看到的版本和当前版本不一致,说明该节点需要重新执行)。

为什么用Channel而不是直接用字典? 因为字典不支持:并行安全(并发写冲突)、版本管理(无法知道谁更新了)、增量更新(只能整体替换)、序列化(需要手动处理)、时间旅行(无法回溯历史)。Channel系统是LangGraph支持并行执行、Checkpoint、时间旅行的基础,没有Channel,这些功能都实现不了。

面试关联: "LangGraph的State和Channel是什么关系?"标准答案:"State是用户层面的状态定义,每个State字段底层对应一个Channel。Channel负责存储值、管理版本号、处理reducer合并、支持序列化。Channel是LangGraph支持并行执行和Checkpoint的基础。"


八、Checkpoint系统:持久化的四大能力

Checkpoint是LangGraph区别于其他Agent框架的核心特性。一个Checkpoint就是状态在某个Super-step边界的完整快照。没有Checkpoint,就没有持久执行、人机交互、时间旅行。

8.1 Checkpoint数据结构(6个字段)

字段
说明
面试考点
channel_values
所有Channel的当前值(序列化后的状态)
状态快照的核心
channel_versions
每个Channel的版本号
判断执行是否终止
versions_seen
每个节点看到的Channel版本
判断节点是否需要重新执行
tasks
这一步要执行的任务列表(含id、name、error、interrupts)
恢复时知道哪些任务要重跑
parent_config
上一个Checkpoint的配置(形成链表)
时间旅行的基础
metadata
元数据:时间戳、来源、写入记录
审计和调试

8.2 Checkpoint赋予的四大能力

能力
说明
实现原理
生产价值
持久执行
执行中途崩溃,恢复后从最后一个Checkpoint继续,不丢状态
每个Super-step结束保存Checkpoint,恢复时加载最新Checkpoint
长任务不怕崩溃
人机交互
执行到interrupt时暂停,等待人工输入,恢复后继续
interrupt时保存Checkpoint,resume时加载并注入人工输入
高风险操作人工确认
时间旅行
回到任意历史Checkpoint,从那里重新执行,创建分支
Checkpoint不可变,回溯时从历史Checkpoint创建新分支
调试和A/B测试
部分失败恢复
并行节点中一个失败,其他已完成节点的结果不丢
已完成节点的写入存储为pending,恢复时只重跑失败的节点
减少重复计算

最容易搞错的点:Super-step是持久化的最小单位,不是节点。

一个Super-step中所有并行节点都执行完后才创建Checkpoint。如果其中一个节点失败,这个Super-step没有Checkpoint,恢复时整个Super-step重新执行。这就是为什么"节点必须幂等"——因为节点可能被重新执行。

很多人以为"每个节点执行完就保存Checkpoint",这是错的。对于顺序图(一个Super-step只有一个节点),看起来像是每个节点一个Checkpoint,但对于并行图(一个Super-step有多个节点),是所有节点都执行完才保存一个Checkpoint。

面试关联: "Checkpoint存了什么?中断恢复后从哪里继续?"这是高频题。标准答案:Checkpoint存6个字段(channel_values/channel_versions/versions_seen/tasks/parent_config/metadata);中断恢复后整个节点重新执行(不是从断点继续),因为Super-step是持久化最小单位,节点必须幂等。


九、30篇源码精读与架构模块对应关系

这篇是全局地图,后面30篇源码精读在这张地图上逐个区域深挖。以下是30篇与架构模块的对应关系:

架构模块
对应源码精读期数
篇数
核心主题
执行引擎层
01-06
6篇
Pregel、节点调度、Channel、并发、重试
用户API层+编译层
07-11
5篇
StateGraph、条件边、compile、图验证、Functional API
持久化层(Checkpoint)
12-17
6篇
数据模型、接口、MemorySaver、PostgresSaver、序列化
高级功能
18-22
5篇
interrupt、Time Travel、Streaming、Event Streaming、Send API
预构建组件
23-25
3篇
create_react_agent、ToolNode、设计哲学
Store+分布式
26-28
3篇
Store、Store vs Checkpoint、Kafka分布式
设计哲学与总结
29-30
2篇
5个设计哲学、10个可借鉴设计(完结篇)
合计30篇
从执行引擎到设计哲学全覆盖

阅读顺序建议: 先读执行引擎层(01-06),这是核心;再读持久化层(12-17),这是LangGraph最有差异化的部分;然后读用户API层和高级功能;最后读设计哲学。不建议按编号顺序从01读到30,因为预构建组件(23-25)依赖对执行引擎的理解。


十、这张架构图能帮你答哪些面试题

整理了LangGraph架构相关的10道高频面试题,每道题在这篇架构图中都能找到答案:

面试题
答案在哪个章节
考察点
LangGraph和LangChain什么关系?
第二章
生态定位
LangGraph的架构分几层?每层负责什么?
第三章
整体架构
LangGraph的Monorepo有几个包?prebuilt为什么不依赖核心?
第四章
包结构+设计哲学
Pregel是什么?Super-step三阶段是什么?
第五章
执行引擎核心
并行执行为什么不会数据冲突?
第五章
状态副本+确定序合并
一次invoke的完整流程是什么?
第六章
执行流程
State和Channel是什么关系?
第七章
状态底层
Checkpoint存了什么?
第八章
持久化数据结构
中断恢复后从哪里继续?为什么节点必须幂等?
第八章
持久化最小单位
LangGraph的时间旅行是怎么实现的?
第八章
Checkpoint不可变+回溯

这10道题能答上来,LangGraph架构层面的面试就稳了。 后面30篇源码精读会把每道题的答案深入到源码层面。


十一、本期小结

LangGraph架构全景,核心就6句话:

  1. 1. LangGraph是LangChain生态的"编排层",LangChain负责和模型对话,LangGraph负责让Agent跑起来。它构建在LangChain的消息类型和Runnable协议之上,Deep Agents等高层框架构建在LangGraph之上。两者分层是因为"模型对话"和"Agent运行"是两个不同问题。
  2. 2. 内部6层架构:用户API层→编译层→执行引擎层→持久化层→传输层→基础设施层。 上层依赖下层,下层不依赖上层,每层可独立替换和测试。执行引擎层(第4层)是核心中的核心,其他层都围绕它服务。搞懂执行引擎层就搞懂了LangGraph的70%。
  3. 3. Monorepo包含8个独立包,最巧妙的设计是prebuilt不依赖langgraph核心,而是langgraph核心依赖prebuilt——这是为了避免循环依赖,体现了依赖倒置原则:两者都依赖checkpoint抽象接口,而不是互相依赖。
  4. 4. Pregel BSP三阶段模型是心脏:Plan→Execute→Update。 Plan确定待执行节点,Execute并行执行(每个节点有独立状态副本,互不影响),Update按确定序合并更新(无数据竞争、结果可复现)。"状态副本+确定序合并"是并行安全的关键,也是LangGraph最核心的设计。
  5. 5. 一次invoke经过12步,每个Super-step结束创建一个Checkpoint。执行终止的条件是"没有待执行节点且所有Channel版本无变化",不是"到达END"。Channel版本号是整个执行引擎的"心跳"。
  6. 6. Checkpoint赋予四大能力:持久执行、人机交互、时间旅行、部分失败恢复。 Checkpoint包含6个字段,Super-step是持久化的最小单位(不是节点),所以中断恢复后整个节点重新执行,节点必须幂等。

十二、下一期预告

下一期(源码01),执行引擎层第一篇,也是30篇中最核心的一篇:

LangGraph源码精读01:用了半年LangGraph,你知道它的心脏是Google的Pregel吗?BSP模型、Super-step三阶段、从论文到实现逐段讲解

全局地图已经画好,从下一期开始逐个区域深挖。第一站就是心脏——Pregel执行引擎。

你觉得LangGraph最复杂的模块是哪个?评论区聊聊,我优先写你最关心的。


本文为《LangGraph源码精读30篇》系列第00篇(全局地图)。内容基于LangGraph v1.2.11源码结构梳理,版本更新后部分细节可能变化。如有错漏欢迎指正。

相关学习资料