news 2026/10/15 12:03:00

LangGraph 短期记忆:Thread 与 Checkpoint,让你的 Agent 记得上一句聊了啥

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
LangGraph 短期记忆:Thread 与 Checkpoint,让你的 Agent 记得上一句聊了啥

一、为什么需要短期记忆?

我们先想一个最朴素的问题:你用 LangGraph 写了一个最简单的问答 Graph,用户第一句说"我叫小明",第二句问"我叫什么"——Agent 答得出来吗?

答不出来。

默认情况下,LangGraph 的每一次invoke都是无状态的:节点函数只看这一轮传进来的state,跑完就扔。想要让它在同一场对话里记住前面说过什么,就必须引入 LangGraph 的短期记忆机制。

短期记忆的核心只有两个东西:

概念作用类比
Thread给一场对话起个"会话 ID"微信里一个聊天窗口
Checkpoint把某一时刻的完整 state 存成快照游戏存档点
Checkpointer负责存快照、读快照的组件存档系统

一句话:Thread 是身份证,Checkpoint 是存档,Checkpointer 是存档管理员。


二、整体架构图

短期记忆在 LangGraph 里的位置,可以用下面这张图概括:

命中快照

每个 super-step 结束

写入新快照

用户请求
thread_id=xxx

Runtime

Checkpointer
读取该 thread 最新快照

恢复 state

LangGraph 图执行

持久化存储
SQLite/Postgres/Memory

返回结果

关键点:

  1. 每个 super-step(一次节点执行完)都会自动落一次盘,不是你手动存;
  2. 下次同一个thread_id再来请求,Checkpointer 自动把最近一次的 state 捞出来喂给图;
  3. 存储后端可以换(内存 / SQLite / PostgreSQL),业务代码完全不动。

三、Thread:给对话一个身份

Thread 本身不是一个"数据结构",它就是一个字符串 ID(比如"user-001-session-01")。你在调用图的时候通过config传进去:

config={"configurable":{"thread_id":"thread-1"}}

LangGraph 看到这个thread_id,就会去找这个会话对应的所有历史快照。不同的thread_id之间完全隔离,A 用户的对话 B 用户看不到。

小提示:thread_id你自己起名字就行,生产环境一般用「用户ID + 会话ID」拼出来。


四、Checkpoint:一次执行的完整快照

每次图执行一步(或者一轮完整跑完),LangGraph 会把当前 state 完整序列化成一份Checkpoint。它里面通常包括:

  • 所有节点写到 state 里的数据(消息列表、中间变量……);
  • 当前执行到哪一步了(下一步该走哪个节点);
  • 自定义的一些元信息。

你可以把它理解成"游戏存档":不仅存了你的等级装备(数据),还存了你现在在哪个地图哪个存档点(执行位置)。这也是为什么 LangGraph 能做"中断后恢复"和"人工介入"——本质就是从某个 Checkpoint 接着跑。


五、Checkpointer:真正干活的组件

光有 Thread 和 Checkpoint 的概念还不够,你得在编译图的时候显式挂一个 Checkpointer,LangGraph 才会自动帮你存快照。

最常用的是SqliteSaver(持久化到本地文件)和MemorySaver(存在内存里,重启就没)。

5.1 最小可跑示例

fromlanggraph.graphimportStateGraph,START,ENDfromlanggraph.checkpoint.memoryimportMemorySaverfromtypingimportTypedDictfromlangchain_core.messagesimportHumanMessage,AIMessage# 1. 定义 stateclassChatState(TypedDict):messages:list# 2. 假装是个 LLM 节点defchat_node(state:ChatState):last=state["messages"][-1].contentreturn{"messages":[AIMessage(content=f"你刚才说的是:{last}")]}# 3. 建图builder=StateGraph(ChatState)builder.add_node("chat",chat_node)builder.add_edge(START,"chat")builder.add_edge("chat",END)# 4. 关键:挂 Checkpointercheckpointer=MemorySaver()graph=builder.compile(checkpointer=checkpointer)# 5. 用同一个 thread_id 连续对话config={"configurable":{"thread_id":"t-1"}}graph.invoke({"messages":[HumanMessage("我叫小明")]},config)resp=graph.invoke({"messages":[HumanMessage("我叫什么?")]},config)print(resp["messages"][-1].content)# 输出:你刚才说的是:我叫什么?

注意第 4 步和第 5 步:

  • builder.compile(checkpointer=checkpointer)—— 这一行加上,短期记忆就生效了;
  • 两次invoke用的是同一个thread_id,第二次进来时 Checkpointer 会自动把第一次的 messages 塞进 state。

5.2 换成 SQLite,重启不丢

fromlanggraph.checkpoint.sqliteimportSqliteSaverwithSqliteSaver.from_conn_string("chat.db")ascheckpointer:graph=builder.compile(checkpointer=checkpointer)# ... 跑对话

生产环境推荐SqliteSaver(单机)或langgraph-checkpoint-postgres(多实例部署)。换后端的时候,业务代码一行都不用改。


六、查看 Thread 状态:人是怎么"看见"记忆的?

挂了 Checkpointer 之后,你随时可以把某个 thread 的历史捞出来:

# 获取某个 thread 的最新 statestate=graph.get_state(config)print(state.values)# 当前 state 里有啥print(state.next)# 下一步要走哪个节点(如果是中断状态会很有用)# 遍历这个 thread 的所有历史快照forsnapingraph.get_state_history(config):print(snap.config,snap.metadata)

get_state_history特别有用:它能列出这个会话每一次存档点。配合"人工介入"功能,你可以让用户回退到任意一个历史存档点重新跑——相当于"撤销对话"。


七、几个新手必踩的坑

  1. 忘了传thread_id:invoke时 config 里没带thread_id,Checkpointer 不知道存到哪个会话里,等于白挂。
  2. 每次都新建MemorySaver:在函数里compile图、每次请求新建 checkpointer,快照存在新对象里,下次又读不到了。Checkpointer 要复用。
  3. state 里塞了不可序列化的对象:比如数据库连接、文件句柄。Checkpoint 要序列化落盘,这种字段会直接报错。
  4. 以为短期记忆能跨会话:换了thread_id就是新会话,老对话"看不见"。想要跨 Thread 记忆,得用 Store(下篇讲)。

八、小结

  • 短期记忆 =Thread(会话ID)+ Checkpoint(快照)+ Checkpointer(存档器);
  • 编译图时compile(checkpointer=...)一行接入,每个 super-step 自动存档;
  • 同一个thread_id连续调用,Agent 就能记住本场对话的上下文;
  • 存储后端可插拔:Memory(调试用)→ SQLite(单机生产)→ Postgres(分布式);
  • get_state/get_state_history是调试和做"撤销/人工介入"的核心 API。

下一篇我们聊长期记忆 Store——怎么让 Agent 跨会话记住"这个用户喜欢喝美式不加糖"这种跟具体对话无关的偏好。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/15 12:02:12

大型集团HR数字员工选型避坑:2026年如何把六成事务时间还给战略

面向 500 人以上集团的人力资源负责人与 HRIT 决策者:2026 年"HR数字员工"已从概念走进采购清单,但市场上把"带 AI 标签的表单工具"包装成数字员工的产品不在少数。本文给出一套可操作的选型框架——先讲清数字员工的真实边界&#…

作者头像 李华
网站建设 2026/10/15 12:01:57

Figma插件ponytail:设计即代码的轻量级协同实践

1. 项目概述:从“ponytail”热词切入,我们到底在聊什么?最近刷技术社区、设计平台甚至短视频推荐流,频繁撞见“ponytail”这个词——不是马尾辫的字面意思,也不是某款小众香水或乐队名。它正以“ponytail skill”“pon…

作者头像 李华
网站建设 2026/10/15 12:01:33

沉浸式解压潮玩馆:设计、运营与用户体验优化

1. 项目背景与市场定位 在当代快节奏生活中,解压娱乐需求呈现爆发式增长。长治作为新兴消费城市,近年来涌现出一批特色鲜明的解压主题娱乐场所。这类场馆通过沉浸式体验设计,为都市人群提供释放压力的创新空间。 与传统娱乐场所不同&#xf…

作者头像 李华
网站建设 2026/10/15 12:01:31

WinCE下WiFi驱动开发:从NDIS架构到注册表配置的完整指南

简介:Wince下的Wifi实现是一份围绕Windows CE无线网络开发的示例工程,面向嵌入式开发者与物联网设备程序员,用于理解Wi-Fi驱动集成、WLAN API调用及上层应用编写流程。压缩包共21个文件,体积约68KB,以C源文件、头文件及…

作者头像 李华
网站建设 2026/10/15 12:01:28

Hive 直接读写 Elasticsearch 索引实战:建表、查询、写入与避坑指南

1. 为什么要在 Hive 里直接操作 ES 索引 大数据栈里有个很常见的尴尬局面:数据已经通过 Logstash 或 Kafka 管道灌进了 Elasticsearch,索引按天滚动,查询和聚合在 Kibana 上跑得飞起,但一旦要做离线报表、跨月对账、或者把 ES 里的…

作者头像 李华
网站建设 2026/10/15 12:01:26

.NET项目自动化构建与部署实战:Arbess与GitLab CI/CD集成

1. 项目背景与核心价值 在当代软件开发流程中,自动化构建与部署已成为提升团队效能的必备环节。对于.NET技术栈的项目而言,传统的手动编译发布方式不仅耗时费力,还容易因人为操作导致环境差异问题。最近我在一个企业级Web应用项目中&#xff…

作者头像 李华