LangGraph 的持久化管理,核心目的是:让图(Graph)在多次调用、异常中断甚至进程重启后,仍能"记住"上次的执行状态,实现真正的有状态智能体。整套机制分成两层:
-
短期记忆(线程级)------ Checkpointer
-
长期记忆(跨线程/跨会话)------ Store 抽象
一、短期记忆:Checkpointer 机制
1. 原理
-
图编译时传入一个
checkpointer实例 -
每次
invoke/stream结束,LangGraph 自动把 整个 State 快照到一个"检查点" -
下次用相同的
thread_id调用,自动从最新快照恢复,实现"接着聊" -
支持人工中断(Human-in-the-loop):中断时也会落盘,重启后
app.invoke(..., config=config)继续跑
2. 官方已实现的后端
| 后端类 | 持久性 | 适用场景 | 安装命令 |
|---|---|---|---|
InMemorySaver |
❌ 进程结束即失 | 单元测试、快速体验 | 内置 |
SqliteSaver |
✅ 本地文件 | 单机小应用 | pip install langgraph-checkpoint-sqlite |
PostgresSaver |
✅ 分布式库 | 生产、高并发 | pip install langgraph-checkpoint-postgres |
RedisSaver |
✅ 内存级KV | 高速读写、重启不丢 | pip install langgraph-checkpoint-redis |
3. 最小可运行示例(SQLite)
python
# 1. 安装依赖
# pip install langgraph langgraph-checkpoint-sqlite
from typing_extensions import TypedDict
from langgraph.graph import StateGraph, START, END
from langgraph.checkpoint.sqlite import SqliteSaver
import sqlite3
# 1) 定义状态
class State(TypedDict):
count: int
# 2) 节点函数
def increment(state: State) -> State:
return {"count": state.get("count", 0) + 1}
# 3) 建图
builder = StateGraph(State)
builder.add_node("inc", increment)
builder.add_edge(START, "inc")
builder.add_edge("inc", END)
# 4) 编译 + 持久化
conn = sqlite3.connect("checkpoints.db", check_same_thread=False)
checkpointer = SqliteSaver(conn)
graph = builder.compile(checkpointer=checkpointer)
# 5) 运行两轮
config = {"configurable": {"thread_id": "session-1"}}
print(graph.invoke({"count": 0}, config)) # {'count': 1}
print(graph.invoke({}, config)) # {'count': 2}
python
{'count': 1}
{'count': 2}
-
第二次调用没给初始值,依旧拿到 2,因为状态被自动恢复
-
把文件
checkpoints.db拷到另一台机器,状态仍在
人工中断恢复示例
python
# pip install langgraph langgraph-checkpoint-sqlite
import sqlite3, asyncio
from contextlib import asynccontextmanager
from langgraph.checkpoint.sqlite.aio import AsyncSqliteSaver
from langgraph.graph import StateGraph, START, END
from langgraph.checkpoint.sqlite import SqliteSaver
from langgraph.types import interrupt, Command
from typing_extensions import TypedDict
class State(TypedDict):
count: int
# 1) 节点:累加后人工确认
def add_and_confirm(state: State) -> State:
new_count = state["count"] + 1
# ===== 人工中断点 =====
state["count"] = 5
human = interrupt({"question": f"新 count={new_count},确认继续吗?(yes/no)"})
if human.strip().lower() != "yes":
raise ValueError("用户拒绝,流程终止")
return {"count": new_count}
# 2) 建图
builder = StateGraph(State)
builder.add_node("add", add_and_confirm)
builder.add_edge(START, "add")
builder.add_edge("add", END)
async def main():
# 3) 绑定持久化
# conn = sqlite3.connect("demo.db", check_same_thread=False)
# checkpointer = AsyncSqliteSaver(conn)
# AsyncSqliteSaver.from_conn_string("demo.db")
async with AsyncSqliteSaver.from_conn_string("demo.db") as checkpointer:
graph = builder.compile(checkpointer=checkpointer)
# 4) 第一次运行:触发中断
config = {"configurable": {"thread_id": "demo"}}
print("--- 第一次调用,会中断 ---")
try:
async for chunk in graph.astream({"count": 0}, config):
print("显示",chunk)
except Exception as e:
# 中断异常被外部捕获,流程暂停
print(">>> 捕获中断,模拟前端弹窗 <<<")8
# 5) 人工输入后恢复
print("--- 人工输入 'yes' 后恢复 ---")
async for chunk in graph.astream(Command(resume="yes"), config):
print(chunk)
if __name__ == "__main__":
asyncio.run(main())
python
--- 第一次调用,会中断 ---
显示 {'__interrupt__': (Interrupt(value={'question': '新 count=1,确认继续吗?(yes/no)'}, id='7a25377a8d5078cd498f0d826f3f73b4'),)}
--- 人工输入 'yes' 后恢复 ---
{'add': {'count': 1}}
human = interrupt({"question": f"新 count={new_count},确认继续吗?(yes/no)"}) 会中断返回,把当前 State 落盘(Checkpointer),图冻结在这一行,后面的代码暂时不会执行。
再次调用,graph.astream(Command(resume="yes"), config) 此时会从之前中断的函数再次执行(函数重新执行),human = interrupt({"question": f"新 count={new_count},确认继续吗?(yes/no)"}),这个时候human接受到值为yes。
invoke 和 astream
-
invoke:同步调用,图跑完后一次性返回最终 State(适合脚本、单元测试)。 -
astream:异步生成器,每过一个节点就 yield 一次中间快照(适合聊天 UI、实时日志、进度条)。
| 方法 | 类型 | 输入 | 返回 | 典型耗时 |
|---|---|---|---|---|
graph.invoke(input, config?, **kwargs) |
同步 | 单 dict | 终态 dict | 整图跑完 |
graph.astream(input, config?, **kwargs) |
异步 | 单 dict | AsyncIterator[dict] | 逐节点实时 |
| 需求 | 用 invoke | 用 astream |
|---|---|---|
| 快速验证业务逻辑 | ✅ 一行代码 | ❌ 需 async for |
| 聊天机器人逐句回复 | ❌ 会阻塞整图 | ✅ 每节点 yield 可立即推给前端 |
| 进度条/实时日志 | ❌ 拿不到中间态 | ✅ 每步快照可刷新 UI |
| 中断/继续 (Human-in-the-Loop) | ✅ 支持 | ✅ 支持(更常用) |
| 批跑离线任务 | ✅ 简单高效 | ❌ 无必要 |
python
# 图定义略
graph = builder.compile()
# ① invoke:阻塞直到终点
final_state = graph.invoke({"count": 0})
print(final_state) # {'count': 3}
# ② astream:异步逐节点产出
async for snapshot in graph.astream({"count": 0}):
print(snapshot)
# 输出顺序类似
# {'node_a': {'count': 1}}
# {'node_b': {'count': 2}}
# {'count': 3} # 终态
前端体验差异:
-
invoke要等 3 秒才一次性把结果吐给前端; -
astream每 1 秒就能收到一次快照,页面可实时展示"节点 A 完成→节点 B 完成..."。