在langgraph中,我们对节点输出进行持久化。每一个超步都会进行存储(持久化工具我选择的是PgSQL)。
注:超步------一轮 "读取 → 并发执行 → 写回 → 存档" 的循环。langgraph的整个运行流程也就由多个超步接起来的。 其中,超步会保存其后续节点运行的结果,当后续某一个节点运行失败时,在重新运行时,就能知道哪些节点是运行成功的,哪些节点是运行失败的,再次执行时,就只需要重新运行失败的节点。
例:

其中,我将node_joke节点手动抛出异常,模拟节点运行失败:
python
def node_joke(state: OverallState) -> OverallState:
logger.info(f"node_joke 已执行")
topic = state["topic"]
#人为抛出异常模拟
time.sleep(5)
raise Exception("人为抛出异常~")
joke = model.invoke([HumanMessage(f"请创制关于{topic}的笑话,尽可能简单,不超过一百字")]).content
return {
"joke": joke,
}
查询该节点的超步内容如下:
StateSnapshot(
values={'topic': '冰美式:布偶猫'},
next=('node_poem', 'node_joke'),
config={
'configurable': {
'thread_id': '123',
'checkpoint_ns': '',
'checkpoint_id': '1f1b021f-c0e6-68e9-8001-c2c0746964d8'
}
},
metadata={
'step': 1,
'source': 'loop',
'parents': {}
},
created_at='2026-09-14T09:52:23.440806+00:00',
parent_config={
'configurable': {
'thread_id': '123',
'checkpoint_ns': '',
'checkpoint_id': '1f1b021f-c0e0-6aaf-8000-67f32d1bda3b'
}
},
tasks=(
# 并行任务1:node_poem 执行成功
PregelTask(
id='77983d76-c61a-d56b-ded6-0a0c87dfee86',
name='node_poem',
path=('__pregel_pull', 'node_poem'),
error=None,
interrupts=(),
state=None,
result={
'poem': '《冰美式与布偶猫》\n冰盏凝香消暑气,蓝瞳映雪卧云茵。\n偶然拾得闲情趣,半日清欢属此身。'
}
),
# 并行任务2:node_joke 执行失败,手动抛出异常
PregelTask(
id='ec36d000-59ad-e1ab-1ea4-f9234be55d06',
name='node_joke',
path=('__pregel_pull', 'node_joke'),
error="Exception('人为抛出异常~')",
interrupts=(),
state=None,
result=None
)
),
interrupts=()
)
可以看到node_joke抛出异常,而并行节点的node_poem正常运行。
这时,将代码就行修复后,我们需要重新运行graph时,我们只需要传入 None和config,不需要传入具体参数,就只会运行失败节点:
python
result_1 = graph.invoke(
None,
config=config
)
再吃查看其超步内容如下:

可以看到结果正常。