LangGraph 是怎么让 Agent “记住“对话的?拆解 thread 与 Checkpoint

大模型本身是"过目就忘"的——每次调用都是一张白纸。可你用 LangGraph 搭的 Agent,却能续聊、能恢复、甚至能"回到三步之前重新跑"。这背后靠的是两个核心概念:「thread(一次对话)」「Checkpoint(每一步的状态快照)」。这篇文章用 6 张图把 LangGraph 的会话管理彻底讲透,并在最后引申一下生产级框架 DeepAgents 在它之上做了哪些加固。

开场:模型没记性,记性是"框架"给的

先说个反直觉的事实:大模型 API 是**无状态(stateless)**的。它每次被调用,只能看到这一次请求里塞进去的内容,**「根本不记得」**上一轮你说过什么。

那"连续对话"是怎么来的?靠框架在背后维护一份历史,每次调用都重新递给模型。这层"管历史"的基础设施,就是**「会话管理(Session Management)」**。

不同框架给出的答案差异很大。LangGraph 的答案尤其有特点——它没有单独造一个"会话模块",而是把会话管理**「收进了一个更通用的抽象」**:状态图(StateGraph)+ 检查点(Checkpoint)。理解了这套抽象,你不仅懂了它怎么记对话,还顺带理解了它为什么能做到时间旅行、断点续跑这些别家做不到的事。

我们从最外层的 thread 开始往里剥。


一、一次对话 = 一个 thread

在 LangGraph 里,一段连续对话被称为一个 「thread」(线程,但跟操作系统的线程没关系,理解成"对话线"更准确)。每个 thread 由一个 thread_id 唯一标识。

你调用 Agent 时,thread_id 不是写在请求体里,而是放在一个叫 config.configurable 的配置包里传进去:

config = {"configurable": {"thread_id": "abc-123"}}# 第一轮await agent.ainvoke({"messages": [HumanMessage("帮我建个项目")]}, config=config)# 第二轮——只要带上同一个 thread_id,它就接着上一轮聊await agent.ainvoke({"messages": [HumanMessage("再加个测试")]}, config=config)

注意第二轮:我们只塞了一句新消息,「完全没有手动把第一轮的历史拼进去」。LangGraph 自己根据 thread_id 把这个 thread 之前的状态捞了出来、接着往后跑。这就是 thread 的意义——「它是"自动续聊"的钥匙」

换一个 thread_id,就是开一段全新的、互不干扰的对话。多用户、多会话的隔离,本质上就是发不同的 thread_id。(DeepAgents 里用 UUID7 来生成新的 thread id。)

那么问题来了:LangGraph 凭什么能根据 thread_id 把历史"捞出来"?答案在下一层——Checkpoint。


二、核心机制:每走一步,拍一张快照

这是 LangGraph 会话管理**「最该理解的一点」:它的存储模型不是"一个消息数组",而是「一连串状态快照」**。

LangGraph 把 Agent 的运行看成一张图,每执行一个节点(比如"调一次模型"“跑一个工具”),就把当时的**「完整状态」**拍一张快照存下来,这张快照就叫一个 「Checkpoint」

每个 Checkpoint 有三个关键标识:

  • thread_id:属于哪段对话;
  • checkpoint_id:这是该对话里的第几张快照(单调递增);
  • parent_checkpoint_id:上一张快照是谁——靠它,所有快照串成一条**「链」**。

落到存储里(以 SQLite 为例),就是这样一张表,主键是三元组 (thread_id, checkpoint_ns, checkpoint_id)

PRIMARY KEY (thread_id, checkpoint_ns, checkpoint_id)-- 还有 parent_checkpoint_id 字段,把快照前后串起来

checkpoint_ns(namespace)是给子图用的命名空间,主 Agent 默认是空串,先不用管它。

为什么要存"快照链"而不是"消息数组"?因为快照链能干两件数组干不了的事:「精确恢复到任意一步」,以及**「从任意一步岔出新分支」**(第六节细说)。代价是体积更大——这点 DeepAgents 有专门优化,最后一节会讲。


三、快照里到底装了什么:State 与 channels

既然每个 Checkpoint 是"完整状态的快照",那这个"状态"是什么?

在 LangGraph 里,状态(State)是一个**「带类型的字典」**,里面是若干个字段,每个字段叫一个 「channel(通道)」。对一个对话 Agent 来说,最核心的 channel 就是 messages——对话历史本身。

channel 有个很关键的特性:「它不是简单赋值,而是带"归并规则(reducer)"的」。比如 messages 这个 channel 的规则是"追加"——你这一步返回几条新消息,框架就把它们**「追加」**到已有历史后面,而不是覆盖。这就是为什么你每轮只用返回新消息,历史会自动累积。

除了 messages,State 里还能放别的 channel。DeepAgents 就额外塞了几个私有字段,比如:

  • _summarization_event:记录"上次在哪儿压缩过、摘要是什么";
  • _context_tokens:当前上下文用了多少 token。

这些私有 channel 跟着 Checkpoint 一起持久化,但**「不会」**直接发给模型——它们是会话管理自己的"账本"。

一句话记住:「Checkpoint 存的是整个 State(所有 channel),而不只是聊天记录。」 这也是为什么 LangGraph 能恢复的不仅是"说过的话",还有 Agent 运行到一半的各种中间状态。


四、Checkpoint 存哪儿?可插拔的 Checkpointer

负责"把 Checkpoint 写进去、读出来"的组件,叫 「Checkpointer」。它是一个接口,后端可以随意替换:

Checkpointer存储介质典型场景
MemorySaver进程内存测试、临时跑、demo(重启即丢)
AsyncSqliteSaver本地 SQLite 文件单机持久化(DeepAgents CLI 默认)
AsyncPostgresSaverPostgreSQL生产、多实例共享

用法就是编译 graph 时把它传进去:

from langgraph.checkpoint.memory import MemorySaveragent = create_agent(model, tools, checkpointer=MemorySaver())

「关键点:没有 checkpointer,就没有记忆。」 如果你编译 graph 时不传 checkpointer,那它就是无状态的——每次调用都从头开始,thread_id 也救不了你。这是新手最容易踩的坑:明明传了 thread_id 却发现不记事,十有八九是忘了配 checkpointer。

DeepAgents 的 CLI 在生产模式下默认用 AsyncSqliteSaver,把所有对话落到 ~/.deepagents/sessions.db 这个文件里。它甚至还会直接查这张表来实现"会话列表""删除会话"这类管理功能,绕过 Agent 直接读底层数据,图个快。


五、恢复对话:同一个 thread_id 就够了

有了 thread + checkpointer,"恢复对话"这件听起来很复杂的事,就变得朴素得不像话:

「继续聊」:用同一个 thread_id 再发一次请求就行。LangGraph 自动找到这个 thread 的最新 Checkpoint,把状态恢复出来,接着往后跑。程序重启过?没关系,只要 checkpointer 是持久化的(SQLite/Postgres),历史还在磁盘上。

「把历史读出来」(比如刷新 UI 要重新渲染对话):调 aget_state

state = await agent.aget_state(config)   # config 里带着 thread_idmessages = state.values["messages"]       # 历史消息都在这儿

「手动改状态」(比如插入一条系统提示、或人工干预):调 aupdate_state,它会基于当前快照生成一张新快照。

一个工程细节:DeepAgents 在客户端-服务端模式下,服务器重启后可能出现"磁盘上有 Checkpoint、但内存里的 thread 记录没了"的错位,它专门写了个 aensure_thread 来先确保 thread 记录存在,再操作状态。生产级框架的麻烦,往往都藏在这种边角料里。


六、杀手锏:时间旅行与分叉

快照链相比"消息数组"最大的优势,在这一节兑现。

因为每一步都留了快照、快照之间又有父子链,所以你能做两件很酷的事:

「① 时间旅行(time-travel)」:在 config 里指定一个**「历史」**的 checkpoint_id,就能让 Agent"回到那一刻"的状态。配合 get_state_history 把整条链列出来,你可以挑任意一张快照重放。

# 列出这个 thread 的所有历史快照async for snapshot in agent.aget_state_history(config):    print(snapshot.config["configurable"]["checkpoint_id"])# 指定回到某一张old_config = {"configurable": {"thread_id": "abc-123", "checkpoint_id": "xxx"}}await agent.ainvoke(new_input, config=old_config)

「② 分叉(fork)」:从历史某张快照重新跑、且给不同的输入,就会**「岔出一条新的快照分支」**——原来的历史完好无损,新的探索另起一条线。这对"我想试试换个方向会怎样"的场景极其有用。

值得说明的是:「这是 LangGraph 框架层提供的能力」。建立在它之上的 DeepAgents 出于产品简洁性考虑,目前**「没有把时间旅行/分叉暴露给终端用户」**——它只用 checkpoint_id 做了"会话列表缓存失效"之类的小事。能力在底座,用不用是上层产品的选择。


七、别混淆:Session(短期)vs Store(长期记忆)

聊到这里要澄清一个特别容易搞混的概念。我们前面讲的所有东西——thread、Checkpoint——管的都是**「一段对话内部」的记忆,是「短期」**的、按 thread 隔离的。

但 Agent 还需要另一种记忆:「跨对话的长期记忆」。比如"这个用户偏好用中文"“上个月帮他建过一个电商项目”——这些信息不该绑死在某一个 thread 里,换一段新对话也得记得。

LangGraph 把这两件事**「分得很干净」**:

CheckpointerStore
管什么一段对话的状态(messages 等)跨对话的长期知识
隔离维度thread_id按命名空间(如按 user)
生命周期跟随这段会话长期留存
典型内容对话历史、运行中间态用户画像、学到的技能/事实

设计你自己的 Agent 时,先想清楚每条信息该进哪边:「"只在这次对话有用"的进 Checkpoint,"换个对话也得记得"的进 Store。」 想不清楚,后面就是数据串台和隐私泄露的坑。


八、引申:DeepAgents 在 LangGraph 之上做了什么加固

LangGraph 给的是通用底座,但直接拿去跑长任务(比如让 Agent 写一整个项目)会遇到两个现实问题。DeepAgents 作为生产级框架,针对性地做了加固:

[图 6:两种记忆 + DeepAgents 的生产级加固] (看下半部分:DeltaChannel + Summarization)

「加固一:DeltaChannel——给快照"瘦身"。」 前面说快照链体积大,到底有多大?如果每张快照都把全量 messages 拷一遍,存储量会随对话轮数按 「O(N²)」 膨胀(第 N 轮要存前 N 条 × N 张快照)。DeepAgents 用一个叫 DeltaChannel 的机制:平时只存"这一步新增了什么(delta)",每隔 50 步才拍一张全量快照,把增长压回 「O(N)」。对长任务来说,这是从"撑不住"到"扛得住"的区别。

「加固二:SummarizationMiddleware——上下文压缩 + 落盘。」 对话太长撑爆窗口时,它会:

  1. 把要丢弃的旧历史**「先归档」**到一个 Markdown 文件(按 thread 一个文件,路径形如 /conversation_history/{thread_id}.md);
  2. 用一段 LLM 摘要替换掉模型输入里的旧消息;
  3. 在 State 的 _summarization_event 字段里记下"在哪儿切的、归档到哪了"。

妙处在于:压缩是**「非破坏式」的——原始历史落了盘,Agent 随时能 read_file 翻回来;摘要、切点都跟着 Checkpoint 一起持久化,所以「恢复对话时连"压缩状态"也能一并恢复」**。(这部分我之前单独写过一篇深读,感兴趣的可以翻文末延伸阅读。)

一句话总结这一节:「LangGraph 负责"能记、能恢复",DeepAgents 负责"长期跑也不崩、不丢"。」


结语:把会话管理"藏"进通用抽象

回头看,LangGraph 处理会话管理的思路很有辨识度:「它不把"对话记忆"当成一个特殊模块,而是当成"状态图 + 检查点"这套通用机制的一个自然结果。」

  • 一次对话 = 一个 thread
  • 记忆 = 每一步的 Checkpoint 快照;
  • 续聊 = 同一个 thread_id
  • 后悔药 = 沿快照链时间旅行 / 分叉;
  • 长期记忆 = 另一套 Store,跟会话分开。

这套设计的好处是**「统一而强大」**——你为"让 Agent 跑复杂流程"配的检查点机制,顺手就把会话管理给解决了,还白送了时间旅行。代价是抽象层级偏高、快照体积偏大,需要 DeepAgents 这类上层框架再做一层调教,才能稳稳地扛住真实的长任务。

下次你用 LangGraph 搭 Agent,发现"它怎么不记事"时,先别慌——大概率只是忘了给它配一个 checkpointer 而已。

学AI大模型的正确顺序,千万不要搞错了

🤔2026年AI风口已来!各行各业的AI渗透肉眼可见,超多公司要么转型做AI相关产品,要么高薪挖AI技术人才,机遇直接摆在眼前!

有往AI方向发展,或者本身有后端编程基础的朋友,直接冲AI大模型应用开发转岗超合适!

就算暂时不打算转岗,了解大模型、RAG、Prompt、Agent这些热门概念,能上手做简单项目,也绝对是求职加分王🔋

在这里插入图片描述

📝给大家整理了超全最新的AI大模型应用开发学习清单和资料,手把手帮你快速入门!👇👇

学习路线:

✅大模型基础认知—大模型核心原理、发展历程、主流模型(GPT、文心一言等)特点解析
✅核心技术模块—RAG检索增强生成、Prompt工程实战、Agent智能体开发逻辑
✅开发基础能力—Python进阶、API接口调用、大模型开发框架(LangChain等)实操
✅应用场景开发—智能问答系统、企业知识库、AIGC内容生成工具、行业定制化大模型应用
✅项目落地流程—需求拆解、技术选型、模型调优、测试上线、运维迭代
✅面试求职冲刺—岗位JD解析、简历AI项目包装、高频面试题汇总、模拟面经

以上6大模块,看似清晰好上手,实则每个部分都有扎实的核心内容需要吃透!

我把大模型的学习全流程已经整理📚好了!抓住AI时代风口,轻松解锁职业新可能,希望大家都能把握机遇,实现薪资/职业跃迁~

这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值