大模型应用
LangGraph 状态持久化与记忆配置:用…
当 LangGraph 图需要持久化状态、记住对话、回溯历史或配置子图 checkpointer 作用域时使用。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 59/100 ×0.15
适用场景
LangGraph 状态持久化与记忆配置特定
解决思路
- 选择 checkpointer:InMemorySaver 用于测试与开发(非生产可用);SqliteSaver 用于本地开发(部分可用);PostgresSaver 用于生产(生产可用)。
- 在 compile 时传入 checkpointer(如 .compile(checkpointer=checkpointer)),并在每次 invoke 时始终提供 thread_id,例如 config = {"configurable": {"thread_id": "conversation-1"}},否则状态不会持久化。
- 生产环境使用 PostgresSaver.from_conn_string(os.environ["DATABASE_URL"])(TS 为 PostgresSaver.fromConnString(process.env.DATABASE_URL!)),并在部署时运行一次 setup()(如 PostgresSaver.from_conn_string(...).setup())来建表,而不是在应用启动时运行。
- 用不同的 thread_id 隔离不同用户/会话的状态,例如 alice_config = {"configurable": {"thread_id": "user-alice"}}、bob_config = {"configurable": {"thread_id": "user-bob"}}。
- 时间旅行:用 graph.get_state_history(config) 浏览检查点历史(TS 中为异步可迭代,需 for await 收集到数组),用 graph.invoke(None, past.config)(TS 为 graph.invoke(null, past.config))从过去的检查点重放。
- 从过去检查点分叉:先 graph.update_state(past.config, {"messages": ["edited"]}) 修改状态,再用 graph.invoke(None, fork_config) 恢复执行。
- 手动更新状态:用 graph.update_state(config, {"data": "manually_updated"}) 修改状态,再用 graph.invoke(None, config) 恢复执行。
- 子图 checkpointer 作用域选择:checkpointer=False 表示子图不需要 interrupt 或持久化,最简单、无检查点开销;省略 checkpointer(默认 None)表示需要 interrupt() 但不需要多轮记忆,每次调用全新开始但可暂停/恢复,并行执行安全(每次调用有唯一命名空间);checkpointer=True 表示需要跨调用记住状态(多轮对话),每次调用从上一次继续。
- 注意:有状态子图(checkpointer=True)不支持在单个节点内多次调用同一子图实例,因为会写入同一检查点命名空间而冲突。
- 并行运行多个不同的有状态子图时,把每个子图包在各自的 StateGraph 中并使用唯一节点名以保证命名空间隔离,例如用 create_sub_agent 包装:StateGraph(MessagesState).add_node(name, agent).add_edge("__start__", name).compile()。
- 注意:通过 add_node 添加为节点的子图已自动获得基于名称的命名空间,无需上述包装。
- 长期记忆(Store):用 InMemoryStore 创建 store,用 store.put(("alice", "preferences"), "language", {"preference": "short responses"}) 保存跨线程用户偏好。
- 在节点中通过 Runtime 访问 store:def respond(state, runtime: Runtime): prefs = runtime.store.get((state["user_id"], "preferences"), "language")(TS 中为 runtime.store?.get(...)),不要直接访问 store 变量。
- 编译时同时传入 checkpointer 和 store:builder.compile(checkpointer=checkpointer, store=store),这样不同 thread_id 的线程可共享同一长期记忆。
- Store 基本操作:store.put(...) 写入、store.get(...) 读取、store.search(..., filter={...}) 搜索、store.delete(...) 删除。
- 修复:update_state 会经过 reducer,若状态为 items: Annotated[list, operator.add],graph.update_state(config, {"items": ["C"]}) 会追加为 ["A","B","C"];要替换需用 Overwrite,如 graph.update_state(config, {"items": Overwrite(["C"])})(TS 为 new Overwrite(["C"]))。
适用边界 · 注意事项
- 不需要持久化、记忆或时间旅行时不必引入 checkpointer,避免额外开销。
- 生产环境不要使用 InMemorySaver(进程重启数据丢失),应使用 PostgresSaver。
- 不要在有状态子图(checkpointer=True)于单个节点内并行运行同一子图实例,会产生命名空间冲突。