LangChain LangGraph
Module 1 Module 2 Module 3
Module 1 · 基础能力
1 1.1a 基础模型
2 1.1b Prompting
3 1.2a Tools
4 1.2b Web Search
5 1.3 Memory
6 1.4 Multimodal
7 1.5 Personal Chef
SUM Module Summary
HomeLangChainModule 1 · 基础能力1.3 Memory
📓 Notebook 📖 Explained
LANGCHAIN MODULE 1 · LESSON 1.3

Agent 记忆
InMemorySaver · thread_id · 跨调用持久化

没有记忆的 Agent 每次对话都从零开始。通过 InMemorySaver + thread_id,让 Agent 记住每个用户的对话历史。

1 无记忆的 Agent:每次 invoke 都是全新对话

默认情况下,create_agent 创建的 Agent没有记忆。每次 agent.invoke() 都是完全独立的:Agent 不知道之前说过什么,也不知道用户叫什么名字。

agent = create_agent(deepseek_model())

# 第一次对话:告诉 Agent 我的名字和爱好
response1 = agent.invoke({
    "messages": [HumanMessage(content="Hello my name is Seán and my favourite colour is green")]
})
print(response1['messages'][-1].content)

# 第二次对话(独立的 invoke):问 Agent 我的爱好
response2 = agent.invoke({
    "messages": [HumanMessage(content="What's my favourite colour?")]
})
print(response2['messages'][-1].content)
执行输出(无记忆)
第一次: Hello Seán! Green is a wonderful colour...

第二次: I don't have information about your favourite colour. Could you please tell me?

第二次调用时,Agent 完全不记得第一次对话——它不知道用户叫 Seán,也不知道最爱绿色。每次 invoke 都是一个全新的、无上下文的对话。

2 有记忆 vs 无记忆:直观对比

无记忆 Agent(默认)

用户: 我叫 Seán,最爱绿色
AI: 你好 Seán!绿色很好看...
— 下次调用 —
用户: 我的最爱颜色是什么?
AI: 我不知道你最喜欢的颜色...
✗ 无法跨调用记住用户信息

有记忆 Agent(InMemorySaver)

用户: 我叫 Seán,最爱绿色
AI: 你好 Seán!绿色很好看...
— 下次调用(同 thread_id)—
用户: 我的最爱颜色是什么?
AI: 你最爱的颜色是绿色!😊
✓ 完整记住对话历史

3 Checkpointer:LangGraph 的状态持久化机制

LangGraph 的记忆机制叫做 Checkpointer(检查点)。它的工作原理很简单:

Checkpointer 不是"记忆模型"

Checkpointer 不会让 LLM 本身记住什么——LLM 每次调用都是无状态的。Checkpointer 做的是:把历史消息作为上下文一起传给 LLM,让 LLM 能"看到"之前说过什么。本质上是把历史消息放进了这次调用的上下文窗口。

Checkpointer 类型存储位置适用场景
InMemorySaver Python 进程内存 开发/测试,进程重启后消失
SqliteSaver SQLite 文件 本地持久化,单机生产环境
PostgresSaver PostgreSQL 数据库 多实例、高并发生产环境
LangGraph Cloud 托管云存储 完全托管的云端部署

4 InMemorySaver:最简单的内存记忆方案

create_agent 里传入 checkpointer=InMemorySaver(),即可为 Agent 开启记忆功能:

from langgraph.checkpoint.memory import InMemorySaver
from langchain.agents import create_agent

agent = create_agent(
    deepseek_model(),
    checkpointer=InMemorySaver(),   # 开启内存记忆
)

光有 checkpointer 还不够——还需要通过 config 参数传入 thread_id,告诉 Agent 这次对话属于哪个"线程"(即哪个用户)。

5 thread_id:区分不同用户的对话上下文

thread_id 是对话的唯一标识符。同一个 thread_id 的多次 invoke 共享消息历史;不同 thread_id 的对话完全隔离,互不干扰。

# config 字典:指定这次 invoke 属于哪个线程
config = {"configurable": {"thread_id": "1"}}

# 第一次调用:告知名字和爱好
response1 = agent.invoke(
    {"messages": [HumanMessage(content="Hello my name is Seán and my favourite colour is green")]},
    config   # 传入 config
)

# 第二次调用:同一个 config(同一个 thread_id)
response2 = agent.invoke(
    {"messages": [HumanMessage(content="What's my favourite colour?")]},
    config   # 同一个 config = 同一个对话历史
)

print(response2['messages'][-1].content)
执行输出(有记忆)
Based on what you told me earlier, your favourite colour is **green**! 😊
thread_id 的命名

在实际应用中,thread_id 通常是用户 ID 或会话 ID,例如 "user_12345""session_abc123"。这样不同用户各自有独立的对话历史,互不干扰。同一个用户的多次对话(同一个 session)用相同的 thread_id,就能持续记住上下文。

6 完整多轮对话演示

下面是完整的两轮对话代码,展示记忆在实际多轮对话中的工作效果:

from langgraph.checkpoint.memory import InMemorySaver
from langchain.agents import create_agent
from pprint import pprint

# 创建有记忆的 Agent
agent = create_agent(
    deepseek_model(),
    checkpointer=InMemorySaver()
)

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

# 轮次 1:建立上下文
response1 = agent.invoke(
    {"messages": [{"role": "user", "content": "Hello my name is Seán and my favourite colour is green"}]},
    config
)

# 轮次 2:利用上下文
response2 = agent.invoke(
    {"messages": [{"role": "user", "content": "What's my favourite colour?"}]},
    config
)

# 查看第二次 invoke 的完整消息历史
for msg in response2["messages"]:
    pprint(msg.content)
    print()
完整消息历史(4条,跨两次 invoke)
'Hello my name is Seán and my favourite colour is green'

"Hello Seán! It's nice to meet you. Green is a wonderful favourite colour—it's associated with nature, growth, and harmony..."

"What's my favourite colour?"

'Based on what you told me earlier, your favourite colour is **green**! 😊'

注意消息历史包含了两次 invoke 的所有消息(共 4 条)。第二次调用时,Agent 看到了第一次对话里 Seán 提到的绿色,所以能正确回答。

每次只传新消息,不要重复传历史

使用有记忆的 Agent 时,每次 invoke 只需要传当前轮次的新消息,不需要手动拼接历史消息。Checkpointer 会自动把历史加载进来。如果你手动把历史消息也传进去,消息就会重复出现两次,导致行为异常。

7 记忆的局限性与生产环境方案

InMemorySaver 的局限

生产环境记忆方案对比

策略原理适用场景
InMemorySaver 全消息历史存内存 开发测试、Demo
SqliteSaver / PostgresSaver 全消息历史存数据库 持久化需求、中小型应用
消息摘要 定期把历史消息压缩为摘要,节省上下文空间 长期对话,上下文有限的模型
滑动窗口 只保留最近 N 条消息 只需要短期上下文的场景
向量数据库记忆 历史对话嵌入存向量库,检索相关历史 超长期对话,智能记忆检索
Lesson 1.3 核心要点
InMemorySaver
  • checkpointer=InMemorySaver()
  • • 进程内存,重启后消失
  • • 开发测试最快上手
thread_id
  • config = {"configurable": {"thread_id": "1"}}
  • • 同 thread_id = 共享对话历史
  • • 实际用用户ID或会话ID