LangGraph InMemorySaver 深度解析:与 Message History 的范式对比
在 LangChain 生态中,记忆机制经历了从"消息容器"到"状态快照"的范式跃迁。本文将深入解析
InMemorySaver的工作原理,并与传统的 Message History(如ConversationBufferMemory)进行全面对比,帮助你在 2026 年的 Agent 开发中做出正确选择。
一、从图片说起:InMemorySaver 到底在做什么?
让我们先回到你提供的代码片段:
python
from langgraph.checkpoint.memory import InMemorySaver
# 创建短期记忆实例
memory = InMemorySaver()
# 创建 Agent
agent = create_agent(
model=llm, # 聊天模型
tools=tools, # 工具列表
system_prompt=system_prompt,
checkpointer=memory # 传入记忆组件 ← 关键在这里
)
这行 checkpointer=memory 的背后,是 LangGraph 对"记忆"的重新定义。它不再只是保存对话记录,而是保存整个 Agent 的执行状态快照。
二、核心概念:Checkpoint 到底是什么?
2.1 Checkpoint 的本质
在 LangGraph 中,Checkpoint(检查点) 是图执行过程中每个节点完成后的完整状态快照。它保存的是:
- 当前图的
State(所有字段的完整值) - 已执行节点的输出
- 条件边的路由决策
- 工具调用的中间结果
- 循环计数器、重试次数等控制变量
简单来说:Checkpoint 保存的是"Agent 执行到哪一步了",而不仅仅是"之前聊了什么"。
2.2 InMemorySaver 的角色
InMemorySaver 是 LangGraph 提供的最简单的 Checkpointer 实现:
python
from langgraph.checkpoint.memory import InMemorySaver
checkpointer = InMemorySaver()
# 等价于:checkpointer = MemorySaver() # 旧别名,向后兼容
它的特点是:
| 特性 | 说明 |
|---|---|
| 存储位置 | 进程内存(RAM) |
| 生命周期 | 随进程启动而创建,随进程结束而消失 |
| 适用场景 | 开发测试、单进程演示、单元测试 |
| 线程隔离 | 通过 thread_id 区分不同会话 |
| 持久化 | ❌ 不支持(进程重启数据丢失) |
三、InMemorySaver 的工作原理
3.1 状态流转示意
用户输入 → [START] → Node A (LLM调用) → Checkpoint 保存 →
→ Node B (工具调用) → Checkpoint 保存 →
→ Node C (条件路由) → Checkpoint 保存 → [END]
↑
每个节点后自动保存完整 State
3.2 代码示例:断点续跑
python
from langgraph.graph import StateGraph, START, END
from langgraph.checkpoint.memory import InMemorySaver
from typing import TypedDict
class State(TypedDict):
query: str
result: str
step_count: int
def step1(state: State) -> dict:
return {"result": f"处理: {state['query']}", "step_count": 1}
def step2(state: State) -> dict:
return {"result": state["result"] + " → 完成", "step_count": 2}
builder = StateGraph(State)
builder.add_node("step1", step1)
builder.add_node("step2", step2)
builder.add_edge(START, "step1")
builder.add_edge("step1", "step2")
builder.add_edge("step2", END)
# 编译时传入 checkpointer
app = builder.compile(checkpointer=InMemorySaver())
# 通过 thread_id 标识会话
config = {"configurable": {"thread_id": "session-001"}}
# 第一次运行
result1 = app.invoke({"query": "你好", "result": "", "step_count": 0}, config)
print(result1) # {'query': '你好', 'result': '处理: 你好 → 完成', 'step_count': 2}
# 第二次运行:自动从上次 checkpoint 恢复
result2 = app.invoke({"query": "再见"}, config)
# 注意:这里传入的 query 会被合并到已有状态中
3.3 与 thread_id 的配合
thread_id 是 Checkpoint 机制的核心标识符:
python
# 用户 A 的会话
config_a = {"configurable": {"thread_id": "user-a"}}
# 用户 B 的会话(完全隔离)
config_b = {"configurable": {"thread_id": "user-b"}}
# 同一用户的新会话
config_a_new = {"configurable": {"thread_id": "user-a-new"}}
每个 thread_id 对应一条独立的"状态时间线",互不干扰。
四、Message History:传统记忆的运作方式
4.1 传统 LangChain Memory 家族
在 LangGraph 出现之前,LangChain 提供了多种 Memory 实现:
python
from langchain.memory import (
ConversationBufferMemory, # 保存完整对话
ConversationBufferWindowMemory, # 只保留最近 k 轮
ConversationSummaryMemory, # 自动总结历史
ConversationSummaryBufferMemory, # 结合窗口与总结
VectorStoreRetrieverMemory, # 向量检索记忆
)
⚠️ 重要提示 :截至 2026 年,
ConversationBufferMemory等经典 Memory 类已被官方标记为 deprecated,迁移到 LangGraph 的 checkpointer 是推荐做法。
4.2 Message History 的本质
传统 Memory 的核心是 消息列表的管理:
python
from langchain.memory import ConversationBufferMemory
memory = ConversationBufferMemory(return_messages=True)
# 手动保存对话
memory.save_context(
{"input": "我叫小明"},
{"output": "你好小明!"}
)
# 加载历史(仅返回消息列表)
history = memory.load_memory_variables({})
# {'history': [HumanMessage(content='我叫小明'), AIMessage(content='你好小明!')]}
关键特点:
- 只保存
HumanMessage和AIMessage - 需要手动或通过 Chain 注入到 Prompt 中
- 不保存任何业务状态(如工具调用结果、循环计数等)
- 通过
memory_key嵌入到 Prompt 模板
4.3 在 LCEL 中的使用
python
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.runnables.history import RunnableWithMessageHistory
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个 helpful 助手。"),
MessagesPlaceholder(variable_name="history"), # 历史消息占位
("human", "{input}")
])
chain = prompt | llm
# 包装为带历史记忆的链
chain_with_history = RunnableWithMessageHistory(
chain,
get_session_history=get_session_history, # 返回 BaseChatMessageHistory
input_messages_key="input",
history_messages_key="history",
)
五、全面对比:InMemorySaver vs Message History
5.1 对比总览
| 维度 | InMemorySaver (Checkpoint) | Message History (传统 Memory) |
|---|---|---|
| 保存对象 | 完整图状态(TypedDict) | 消息列表(Message List) |
| 粒度 | 状态级:节点输出、变量、路由决策 | 内容级:仅用户/AI 对话内容 |
| 作用范围 | 整个 LangGraph 图的所有节点 | 通常只影响 LLM 的 Prompt |
| 生命周期管理 | 通过 thread_id 自动管理 |
需手动管理 session_id |
| 断点续跑 | ✅ 支持(从任意 checkpoint 恢复) | ❌ 不支持(仅追加消息) |
| 错误恢复 | ✅ 支持(节点级重试、回滚) | ❌ 不支持(需从头开始) |
| 人机交互 (HITL) | ✅ 原生支持(interrupt 机制) |
❌ 需自行实现 |
| 时间旅行调试 | ✅ 支持(回溯到任意状态) | ❌ 不支持 |
| 并行分支 | ✅ 支持(多状态副本管理) | ❌ 不支持 |
| 持久化选项 | InMemory / SQLite / Postgres / Redis | 内存 / Redis / 文件 |
| 2026 官方推荐 | ✅ 唯一推荐方式 | ⚠️ 已废弃 |
5.2 深度对比:三个关键差异
差异 1:保存内容的本质不同
Message History 只保存聊天记录:
python
# 传统 Memory 的内容
[
HumanMessage(content="搜索北京天气"),
AIMessage(content="我来帮您查询..."),
FunctionMessage(content="{'temp': 25, 'weather': '晴'}"), # 工具结果
AIMessage(content="北京今天晴天,25度"),
]
# 仅此而已!没有中间状态
InMemorySaver 保存完整执行状态:
python
# Checkpoint 保存的内容(示意)
{
"messages": [...], # 消息列表(包含在内)
"tool_calls": [{"name": "get_weather", "args": {"city": "北京"}}],
"tool_outputs": [{"temp": 25, "weather": "晴"}],
"retry_count": 0, # 重试计数器
"next_node": "synthesize", # 下一个要执行的节点
"user_confirmed": True, # 用户确认状态
"token_budget": 3500, # 剩余 token 预算
}
# 包含所有业务状态!
差异 2:恢复能力的根本不同
场景:Agent 执行到第 5 个节点时服务器崩溃
| 机制 | 恢复行为 |
|---|---|
| Message History | 只能拿到前 4 轮对话记录,第 5 个节点的中间变量、条件判断全部丢失,必须从头重新执行 |
| InMemorySaver | 从第 4 个节点完成后的 checkpoint 恢复,第 5 个节点可以直接继续执行,无需重复前 4 步 |
差异 3:架构层级的不同
┌─────────────────────────────────────────────────────────────┐
│ LangGraph 架构层级 │
├─────────────────────────────────────────────────────────────┤
│ 应用层: Agent 业务逻辑 (create_agent, create_react_agent) │
├─────────────────────────────────────────────────────────────┤
│ 图层: StateGraph (节点、边、条件路由) │
├─────────────────────────────────────────────────────────────┤
│ 状态层: State (TypedDict, 包含 messages + 业务字段) │
├─────────────────────────────────────────────────────────────┤
│ 持久层: Checkpointer (InMemorySaver / PostgresSaver) │ ← InMemorySaver 在这里
│ - 保存完整 State 快照 │
│ - 支持断点续跑、HITL、时间旅行 │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ 传统 LangChain 架构层级 │
├─────────────────────────────────────────────────────────────┤
│ 应用层: Chain / Agent (LLMChain, AgentExecutor) │
├─────────────────────────────────────────────────────────────┤
│ 提示层: PromptTemplate (包含 {history} 占位符) │
├─────────────────────────────────────────────────────────────┤
│ 记忆层: Memory (ConversationBufferMemory) │ ← Message History 在这里
│ - 仅管理消息列表 │
│ - 通过 memory_key 注入 Prompt │
└─────────────────────────────────────────────────────────────┘
六、生产环境升级路径
6.1 开发 → 测试 → 生产
python
# 阶段 1:开发(内存,快速迭代)
from langgraph.checkpoint.memory import InMemorySaver
checkpointer = InMemorySaver()
# 阶段 2:本地持久化(单机测试)
from langgraph.checkpoint.sqlite import SqliteSaver
checkpointer = SqliteSaver.from_conn_string("checkpoints.db")
# 阶段 3:生产(分布式、高可用)
from langgraph.checkpoint.postgres import PostgresSaver
checkpointer = PostgresSaver.from_conn_string(DATABASE_URL)
await checkpointer.setup() # 首次运行建表
API 完全一致,只需替换 Checkpointer 实现,无需改动业务代码。
6.2 与长期记忆(Long-term Memory)的配合
LangGraph 的完整记忆架构是双轨制:
python
from langgraph.checkpoint.memory import InMemorySaver # 短期记忆
from langgraph.store.memory import InMemoryStore # 长期记忆
# 短期记忆:线程级,随对话保存/恢复
checkpointer = InMemorySaver()
# 长期记忆:用户级,跨会话持久化
store = InMemoryStore()
def assistant(state, *, store, config):
user_id = config["configurable"]["user_id"]
# 1. 召回长期记忆(用户偏好)
prefs = store.search((user_id, "preferences"))
# 2. 使用短期记忆(当前对话状态)+ 长期记忆生成回复
reply = llm.invoke(state["messages"] + prefs)
# 3. 保存新发现到长期记忆
if new_fact := extract_fact(state["messages"]):
store.put((user_id, "preferences"), new_fact["key"], new_fact["value"])
return {"messages": [reply]}
app = graph.compile(checkpointer=checkpointer, store=store)
thread_id选择短期记忆槽位,user_id选择长期记忆命名空间。
七、实战代码:完整对比示例
7.1 传统 Message History 方式(已废弃)
python
# ❌ 不推荐:2026 年已废弃的写法
from langchain.memory import ConversationBufferMemory
from langchain.chains import ConversationChain
memory = ConversationBufferMemory()
chain = ConversationChain(llm=llm, memory=memory)
# 只能进行简单对话,无法处理工具调用、循环、条件分支
response = chain.predict(input="调用工具 A")
# 如果工具 A 执行失败,没有重试机制,必须从头开始
7.2 LangGraph InMemorySaver 方式(推荐)
python
# ✅ 推荐:2026 年标准写法
from langgraph.prebuilt import create_react_agent
from langgraph.checkpoint.memory import InMemorySaver
from langchain_core.tools import tool
@tool
def risky_tool(query: str) -> str:
# 一个可能失败的工具
if "error" in query:
raise ValueError("工具执行失败")
return f"结果: {query}"
# 创建带 checkpoint 的 Agent
agent = create_react_agent(
model=llm,
tools=[risky_tool],
checkpointer=InMemorySaver(),
)
config = {"configurable": {"thread_id": "demo"}}
# 工具失败后自动重试(LangGraph 内置)
result = agent.invoke(
{"messages": [{"role": "user", "content": "使用 risky_tool 查询 error"}]},
config=config
)
# 即使失败,也能从 checkpoint 恢复,无需重新调用 LLM
八、关键追问:有了 InMemorySaver,就不需要 Message History 了?
这是一个非常自然的问题,也是很多开发者的第一反应。答案是:ConversationBufferMemory 确实不需要了,但"记忆"这件事仍然需要分两层来理解。
8.1 InMemorySaver 已经包含了消息历史
在 LangGraph 的 State 定义中,messages 字段是天然存在的:
python
from typing import TypedDict, Annotated
from langchain_core.messages import AnyMessage
from langgraph.graph.message import add_messages
class State(TypedDict):
messages: Annotated[list[AnyMessage], add_messages] # 消息历史在这里
query: str
tool_results: dict
retry_count: int
当 InMemorySaver 保存 checkpoint 时,完整的对话消息列表已经被包含在内。所以:
- ✅
ConversationBufferMemory能做的(保存对话历史)→ Checkpointer 能做 - ✅
ConversationBufferWindowMemory能做的(窗口截断)→ 通过State自定义逻辑实现 - ✅
ConversationSummaryMemory能做的(自动总结)→ 可以在节点中实现 - ❌
VectorStoreRetrieverMemory(向量检索记忆)→ 这是长期记忆,Checkpointer 不管这个
结论:传统的 Message History 类已被 Checkpointer 完全覆盖,且能力更强。官方也已将其标记为 deprecated,新工程不应再使用。
8.2 但 InMemorySaver 有致命局限:进程重启即消失
这是很多人踩过的坑:
python
# 开发时这样写没问题
from langgraph.checkpoint.memory import InMemorySaver
checkpointer = InMemorySaver()
# 但生产环境如果直接部署...
# 服务器重启 → 所有 checkpoint 丢失 → 用户回来对话断了
# 多实例部署 → 实例 A 的内存,实例 B 访问不到 → 负载均衡下会话错乱
# nightly 重启 → 昨天聊的内容全没了 → 用户体验极差
生产环境必须升级:
python
# 阶段 1:开发(内存,快速迭代)
from langgraph.checkpoint.memory import InMemorySaver
checkpointer = InMemorySaver()
# 阶段 2:本地持久化(单机测试)
from langgraph.checkpoint.sqlite import SqliteSaver
checkpointer = SqliteSaver.from_conn_string("checkpoints.db")
# 阶段 3:生产(分布式、高可用)
from langgraph.checkpoint.postgres import PostgresSaver
checkpointer = PostgresSaver.from_conn_string(DATABASE_URL)
await checkpointer.setup() # 首次运行建表
API 完全一致,只需替换 Checkpointer 实现,业务代码零改动。
8.3 更关键的:短期记忆 ≠ 长期记忆
LangGraph 2026 年引入了双轨记忆架构,这是理解"记忆"的完整图景:
┌─────────────────────────────────────────────────────────────┐
│ 用户与 Agent 交互 │
└─────────────────────────────────────────────────────────────┘
│
┌─────────────────────┼─────────────────────┐
▼ ▼ ▼
当前对话状态 跨会话用户知识 消息展示
│ │ │
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ Checkpointer │ │ Store │ │ Message List │
│ (短期记忆) │ │ (长期记忆) │ │ (UI 展示) │
│ │ │ │ │ │
│ • 完整 State │ │ • 用户偏好 │ │ • 只读展示 │
│ • 节点状态 │ │ • 跨会话事实 │ │ • 前端渲染 │
│ • 工具中间结果│ │ • 知识图谱 │ │ │
│ • 循环计数器 │ │ │ │ │
└───────────────┘ └───────────────┘ └───────────────┘
│ │
▼ ▼
InMemorySaver InMemoryStore
PostgresSaver PostgresStore
(随用随换) (随用随换)
短期记忆(Checkpointer)解决的问题:
- 当前对话的完整上下文
- 多步 Agent 执行状态(工具调用、条件路由)
- 断点续跑、人机交互(HITL)
- 节点级重试、错误恢复
长期记忆(Store)解决的问题:
- 用户说"我叫小明" → 下次开新会话还记得
- 用户偏好"我喜欢简洁回答" → 跨会话保持一致风格
- 积累用户画像、知识图谱 → 越用越懂用户
python
from langgraph.checkpoint.memory import InMemorySaver # 短期记忆
from langgraph.store.memory import InMemoryStore # 长期记忆
checkpointer = InMemorySaver()
store = InMemoryStore()
def assistant(state, *, store, config):
user_id = config["configurable"]["user_id"]
# 1. 召回长期记忆(用户偏好)
prefs = store.search((user_id, "preferences"))
# 2. 使用短期记忆(当前对话状态)+ 长期记忆生成回复
reply = llm.invoke(state["messages"] + prefs)
# 3. 保存新发现到长期记忆
if new_fact := extract_fact(state["messages"]):
store.put((user_id, "preferences"), new_fact["key"], new_fact["value"])
return {"messages": [reply]}
app = graph.compile(checkpointer=checkpointer, store=store)
thread_id选择短期记忆槽位,user_id选择长期记忆命名空间。两者配合才是完整的记忆方案。
8.4 简单聊天场景:不需要上 LangGraph
如果你只是做一个简单的聊天机器人,没有工具调用、没有多步工作流、不需要断点续跑,那么引入 LangGraph 的图复杂度是过度设计。
这时候更轻量的选择是 RunnableWithMessageHistory:
python
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_community.chat_message_histories import ChatMessageHistory
# 简单的消息历史管理(不需要图的复杂度)
store = {} # 内存存储,生产环境换成 Redis
def get_session_history(session_id: str):
if session_id not in store:
store[session_id] = ChatMessageHistory()
return store[session_id]
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个 helpful 助手。"),
MessagesPlaceholder(variable_name="history"),
("human", "{input}")
])
chain = prompt | llm
chain_with_history = RunnableWithMessageHistory(
chain,
get_session_history=get_session_history,
input_messages_key="input",
history_messages_key="history",
)
# 使用
response = chain_with_history.invoke(
{"input": "你好"},
config={"configurable": {"session_id": "user-123"}}
)
选择建议:
| 场景 | 推荐方案 | 原因 |
|---|---|---|
| 简单聊天机器人 | RunnableWithMessageHistory |
轻量、无需图的复杂度 |
| 带工具调用的 Agent | LangGraph + Checkpointer |
需要状态管理和断点续跑 |
| 多步工作流 | LangGraph + Checkpointer |
需要节点级控制和恢复 |
| 需要人机交互 | LangGraph + Checkpointer |
interrupt 机制原生支持 |
| 跨会话用户记忆 | LangGraph + Store |
长期记忆需要独立存储层 |
8.5 本节小结
有了
InMemorySaver,确实不需要ConversationBufferMemory了------功能被完全覆盖且更强大。但"记忆"这件事仍然需要两层:短期记忆(Checkpointer 管当前会话状态)+ 长期记忆(Store 管跨会话用户知识)。
简单聊天不需要 LangGraph ------
RunnableWithMessageHistory是更轻量的选择。
八、总结:一张图看懂选择
你的 Agent 需要记忆?
│
┌───────────────┴───────────────┐
▼ ▼
只需要对话上下文 需要状态管理、断点续跑、HITL
│ │
▼ ▼
使用 RunnableWithMessageHistory 使用 LangGraph + Checkpointer
(BaseChatMessageHistory) (InMemorySaver / PostgresSaver)
│ │
▼ ▼
消息追加到 Prompt 完整 State 快照 + 节点级恢复
│ │
▼ ▼
适合简单聊天机器人 适合复杂 Agent、多步工作流
关键结论
-
InMemorySaver 不是 Memory 的替代品,而是升级品 :它包含了 Message History 的能力(因为
State中可以包含messages字段),同时提供了状态级持久化。 -
2026 年官方唯一推荐:LangChain 经典 Memory 类已废弃,新工程应直接使用 LangGraph checkpointer。
-
从内存到持久化零成本切换 :
InMemorySaver→SqliteSaver→PostgresSaver的 API 完全一致,开发时用最简单的内存版,上线时无缝切换。 -
短期记忆 + 长期记忆双轨并行 :用
checkpointer管理当前会话状态,用store管理跨会话的用户知识,两者配合才是完整的记忆方案。
参考资源
后续我们将深入探讨 LangGraph 的状态管理、条件路由、人机交互等核心机制,帮助你构建生产级的 AI Agent。