状态要先定身份
Agent 的可恢复性,第一步不是把状态存下来,而是先给每条可复用状态一个稳定身份。LangGraph 5 月底修的一个细节很典型:当消息没有 id 时,如果异步 checkpoint 线程先把 id=None 序列化了,后面每次 get_state() / resume 都可能重新生成 UUID;同一条消息在 trace、UI、RemoveMessage 里就变成了“不同对象”。
这不是 LangGraph 独有的问题,而是所有 Agent runtime 都会遇到的顺序问题:reducer、serializer、background writer、UI projection 看起来只是内部实现,但一旦并发或异步写入介入,“什么时候补默认值”就会变成协议边界。默认值如果在 reducer 里补,可能已经晚于持久化;如果在恢复时补,就会破坏 replay;更稳的做法是在进入 durable write path 前,把 message/tool-call/task 这类实体的 identity 固化。
工程上可以把它当成一个检查清单:凡是会被 checkpoint、trace、前端增量渲染、人工干预或删除引用到的对象,都不应该依赖“读取时再生成”的 id。OPC 如果要承载长期 Agent 会话,尤其要把 state identity 当成 schema 的一部分,而不是存储层的附带字段。
你现在的 Agent 状态里,哪些对象一旦重放就必须还是“同一个”?这些 id 是在进入持久化前确定的,还是在某个后处理/reducer/UI 层才补上的?
来源:
- LangGraph 1.2.2 release:stable IDs before DeltaChannel checkpoint writes
- PR #7913:assign stable IDs to id=None BaseMessages before DeltaChannel checkpoint writes
- LangGraph checkpoint 4.1.1 / PR #7892:checkpoint serializer revival 收紧,说明恢复路径也在被当作安全与兼容边界处理