LangGraph 的持久化

LangGraph 的持久化管理,核心目的是:让图(Graph)在多次调用、异常中断甚至进程重启后,仍能"记住"上次的执行状态,实现真正的有状态智能体。整套机制分成两层:

  1. 短期记忆(线程级)------ Checkpointer

  2. 长期记忆(跨线程/跨会话)------ 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 AsyncIteratordict 逐节点实时
需求 用 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 完成..."。

相关推荐
青 春 记 忆7 小时前
Dify Docker Compose 通用无损升级指南:从备份、双版本预演到切换与回滚
运维·人工智能·python·docker·容器
GlueNa2SiO37 小时前
03-Flask模板引擎Jinja2详解
笔记·python·flask
临沂GEO9 小时前
GEO搜索优化科普|正规地理位置流量运营入门指南
大数据·人工智能·python·流量运营
大模型码小白10 小时前
Spring AI Tool 实现自然语言操作 MySQL 数据库详解
服务器·开发语言·数据库·人工智能·python·mysql·spring
荷蒲11 小时前
【小白量化Qbuddy】利用AI学习中文Python
人工智能·python·学习
数据狐(Datafox)12 小时前
京东商品列表API技术解析与落地应用(含标准 JSON 示例)
java·大数据·前端·人工智能·python·数据分析·json
量化吞吐机13 小时前
2026年下半年手工交易规则走向量化表达,产品该先接住哪一步
人工智能·python
Metaphor69213 小时前
使用 Python 读取和删除 Excel 文件属性
python·excel
迷迭香yy14 小时前
Python构建转融券多空识别系统从接口到因子的全流程 IG50免费开源股票数据API接口
开发语言·python·开源
月光船幽幽15 小时前
真实即粗糙,光滑是伪造
人工智能·python