(十二)分清状态、上下文与持久化资料
1. 状态保存本次任务的进度
现在回看两种对象的保存位置。RunState 包含问题、证据、回答、时长、动作编号和当前状态,交给检查点保存;RunContext 包含当前用户、索引和 PlanStore 对象,每次执行时重新建立并注入节点。
| 信息 | 本次值或对象 | 重开时的处理 |
|---|---|---|
| 任务数据 | question、minutes=35、hits、answer、operation_id | 从同一线程的检查点恢复 |
| 执行依赖 | owner=alice、NoteIndex 实例、PlanStore 实例 | 按当前身份与数据目录重新创建 |
| 正式业务 | 已确认计划的数据库行 | 从 plans.sqlite3 查询 |
这样恢复任务时,已有的证据和回答仍保留在状态中;重建索引对象只是准备本次运行的依赖,并不意味着重新执行 retrieve。接下来执行哪个节点,由检查点中的 next 决定。
第八节用 ToolRuntime 给工具传依赖,这里的节点用 Runtime 接收依赖。两者都是在执行时取得具体对象,但所服务的调用层次不同:
| 执行入口 | 类型声明 | 本次提供的对象 |
|---|---|---|
agent.invoke 调度工具 |
ToolRuntime[AgentContext] |
AgentContext 包含 owner 与 index |
graph.invoke 调度业务节点 |
Runtime[RunContext] |
RunContext 还包含 plans 与可替换的 model |
schema 参数接收上下文的类型,invoke 的 context 参数接收这次使用的实例。把类型说明和实际对象对应起来,就能判断某个节点从哪里拿到了当前用户、连接入口或模型。
2. 检查点与长期资料
checkpointer 保存一个线程的图状态;线程由 configurable.thread_id 定位。这里的 thread 指一项持续任务或对话,与第八章操作系统线程不是同一概念。
InMemorySaver 把检查点放在内存中,适合测试;进程结束后不会保留。本项目用 langgraph.checkpoint.sqlite.SqliteSaver 写入 checkpoints.sqlite3,重新打开后继续读取同一线程。检查点与持久化
# 从持久化文件打开检查点,config 中使用相同的任务标识。
from langgraph.checkpoint.sqlite import SqliteSaver
from studyagent.workflow import build_graph
config = {"configurable": {"thread_id": "alice:numpy-1"}}
with SqliteSaver.from_conn_string("data/checkpoints.sqlite3") as saver:
graph = build_graph(saver)
snapshot = graph.get_state(config)
print(snapshot.values) # 读取状态;这里不会重新提交一个问题。跨任务的偏好、资料或长期记忆可以使用 LangGraph Store 等持久化结构保存;plans.sqlite3 在本项目中承担正式计划的业务存储。检查点记录“这项任务走到了哪里”,业务记录回答“用户已经保存了哪些计划”。聊天历史很长时,还要选择近期消息与需要的摘要;数据库保存过的所有消息不必每轮全部发送给模型。