avatar

命令行小屋

A text-focused Halo theme

  • Ai
  • Linux
  • 游戏
  • 数据库
  • Apache Hadoop
  • Windows
  • 手机
主页 告别失忆 Agent:LangChain Memory 双轨制完全指南
文章

告别失忆 Agent:LangChain Memory 双轨制完全指南

发表于 最近 更新于 最近
作者 KennethCheng
394~507 分钟 阅读

从 Checkpoint 到 Store,让 Agent 真正"记住"你

🎯 写在最前

想象这样一个场景:

用户:「你好,我叫李雷,是个男生。」
Agent:「你好李雷!」

(第二天)

用户:「我是谁?」
Agent:「抱歉,我不知道。」

这就是典型的失忆 Agent——它只能看到当前对话窗口里的内容,一旦会话结束或上下文超出 token 限制,就什么都不记得了。

在 LangChain 中,这套"记忆"机制被抽象成了短期记忆与长期记忆两条平行轨道:

  • 短期记忆 负责单次会话的对话上下文(Checkpointer)
  • 长期记忆 负责跨会话、跨用户的持久化数据(Store)

本文会带你:

  • ✅ 理解 LangChain Memory 的核心概念(Checkpoint / Thread / Store / Namespace)
  • ✅ 掌握短期记忆的构建与自定义 State
  • ✅ 用工具让模型"看见"自己的记忆
  • ✅ 落地长期记忆的最佳实践
  • ✅ 通过对比表一眼看懂二者差异

📑 目录

  1. 为什么 Agent 必须有记忆?
  2. 核心概念 60 秒速览
  3. 短期记忆:让对话"接着聊"
  4. 用工具让模型主动读取记忆
  5. 长期记忆:跨会话的知识库
  6. 短期 vs 长期:一表看懂
  7. 实战选型建议
  8. 写在最后

一、为什么 Agent 必须有记忆?

记忆是维持历史交互信息的系统,对 Agent 至关重要——它能让 Agent 从反馈中学习、根据用户偏好调整策略。没有记忆的 Agent,本质上只是一个"函数调用器",而不是真正的对话伙伴。

Agent 内部以「消息序列」的形式保存交互历史,典型的 Agent State 长这样:

human
你好
AI
你好
tool
调用结果
AI
回复
human
谢谢

Agent State 是一个不断追加的消息队列,既包含人类、AI 的发言,也包含工具调用的结果。


二、核心概念 60 秒速览

在 LangChain/LangGraph 中,「记忆」由两条平行的轨道组成:

LangChain Memory
短期记忆
Checkpoint
长期记忆
Store
Super-step
单步快照
Thread
线程 = 一次会话
Checkpointer
InMemorySaver 等
Namespace
命名空间元组
Key
独立键
Store
InMemoryStore 等

执行流程上,每个 super-step 都会产出一个 Checkpoint,组成一条 Thread:

Checkpointnode_2node_1Start用户Checkpointnode_2node_1Start用户invoke()snapshot① (Start)执行snapshot② (node_1)执行snapshot③ (node_2)

💡 简单记忆法:

  • Thread = 一次会话
  • Checkpoint = 会话中的一个时间切面
  • Super-step = 一次「模型推理 + 工具执行 + 状态更新」的最小单元

三、短期记忆:让对话"接着聊"

LangChain 通过 Checkpointer(检查点管理器) 实现短期记忆:

检查点管理器会在每个 super-step 保存图的状态快照(checkpoint)。这些 checkpoint 被保存到一个 thread 中,可以在图执行后访问。由于线程允许在图执行后访问其状态,因此可以实现多种强大功能。

3.1 最简示例:两个独立会话

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

agent = create_agent(
    model=model,
    checkpointer=InMemorySaver(),
)

# 会话 1:李雷
agent.invoke(
    {"messages": [{"role": "user", "content": "你好,我叫李雷,是男生"}]},
    {"configurable": {"thread_id": "1"}},
)

# 会话 2:韩梅梅
agent.invoke(
    {"messages": [{"role": "user", "content": "你好,我叫韩梅梅,是女生"}]},
    {"configurable": {"thread_id": "2"}},
)

# 同 thread_id 共享历史
res = agent.invoke(
    {"messages": [{"role": "user", "content": "我是谁?"}]},
    {"configurable": {"thread_id": "1"}},
)
# "你就是李雷——你之前告诉我你是个男生,名字叫李雷。"
Thread #2 - 韩梅梅
AI: 你好韩梅梅
human: 我叫韩梅梅
Thread #1 - 李雷
AI: 你好李雷
human: 我叫李雷
human: 我是谁?
AI: 你是李雷
InMemorySaver
Checkpointer

3.2 进阶:自定义 State

记忆的本质是记录数据。除了默认的 messages,我们可以给 State 加任意字段:

from typing import Literal
from langchain.agents import AgentState

class CustomAgentState(AgentState):
    user_name: str
    gender: Literal["male", "female"]

memory_saver = InMemorySaver()
agent = create_agent(
    model=model,
    checkpointer=memory_saver,
    state_schema=CustomAgentState,   # 注入自定义字段
)

res = agent.invoke(
    {
        "messages": [{"role": "user", "content": "你好!"}],
        "user_name": "李雷",
        "gender":   "male",
    },
    {"configurable": {"thread_id": "1"}},
)

print(res["user_name"], res["gender"])

⚠️ 重要提醒:模型默认只能看到 messages。自定义字段必须通过 Middleware(中间件) 或工具显式注入到 prompt,否则 Agent 不会感知到。


四、用工具让模型主动读取记忆

上一节提到,自定义字段默认不可见。LangChain 提供了两种主流方案让模型"看见"记忆:

  1. 工具读取(Tool-based):模型主动调用工具读 state
  2. 中间件注入(Middleware):在 before_model / after_model 钩子里读写

4.1 通过工具读取 State

from langchain.tools import tool, ToolRuntime

@tool
def get_user_info(runtime: ToolRuntime) -> str:
    """查看用户信息。"""
    user_name = runtime.state["user_name"]
    gender    = runtime.state["gender"]
    return f"User Name: {user_name}, Gender: {gender}"

agent = create_agent(
    model=model,
    tools=[get_user_info],
    checkpointer=memory_saver,
    state_schema=CustomAgentState,
)

res = agent.invoke(
    {"messages": [{"role": "user", "content": "我是谁?"}]},
    {"configurable": {"thread_id": "1"}},
)
# "你是李雷,一位男性。需要我帮你做些什么吗?"

整条 tool-calling 链路如下:

runtime.stateTool: get_user_infoAI ModelHumanruntime.stateTool: get_user_infoAI ModelHuman模型决定调用工具你好你好,有什么可以帮你我是谁?get_user_info()读取 user_name / gender李雷 / maleUser Name: 李雷, Gender: male你是李雷,一位男性

4.2 通过中间件注入(更灵活)

我们还可以灵活地自定义 before_model、after_model 中间件,实现多样化的记忆写入和读取。中间件适合需要批量、隐式处理记忆的场景,比如:

# 伪代码示意
@before_model
def inject_user_info(state: AgentState):
    """把 state 里的 user_name 拼进 system prompt"""
    user_name = state.get("user_name", "游客")
    return {
        "messages": [
            SystemMessage(f"当前用户:{user_name}"),
            *state["messages"],
        ]
    }

五、长期记忆:跨会话的知识库

短期记忆解决了"同一会话上下文"问题,但用户的偏好、知识、习惯需要跨会话复用——这就是长期记忆的舞台。

LangChain 将长期记忆以 JSON 文档的形式存储在 store 对象中。store 中的每个记忆都组织在自定义命名空间和独立键下。命名空间通常包含用户或组织 ID 或其他标签,便于信息组织。

5.1 基本读写

from langgraph.store.memory import InMemoryStore

store = InMemoryStore()

# 定义命名空间(本质是元组路径)
namespace_1 = ("六年级", "1班")
namespace_2 = ("五年级", "2班")

# 写入
store.put(namespace_1, "张三", {
    "exam":   "期末考试",
    "scores": {"英语": 90, "数学": 95},
    "date":   "2026-01-15",
})
store.put(namespace_1, "李四", {
    "exam":   "期末考试",
    "scores": {"英语": 80, "数学": 85},
    "date":   "2026-01-15",
})
store.put(namespace_2, "王五", {
    "exam":   "期末考试",
    "scores": {"英语": 95, "数学": 100},
    "date":   "2026-01-15",
})

# 读取
li_info = store.get(("六年级", "1班"), "李四")
# Item(namespace=['六年级','1班'], key='李四', value={...}, ...)

5.2 Store 内部结构

InMemoryStore
namespace_1
(六年级, 1班)
namespace_2
(五年级, 2班)
key: 张三
{exam, scores, date}
key: 李四
{exam, scores, date}
key: 王五
{exam, scores, date}

💡 命名空间本质就是元组路径,例如 ("六年级", "1班") 等价于文件系统里的 \六年级\1班\,非常适合做层级化组织。

5.3 长期记忆的杀手锏:search

Store 除了 put / get / delete,还内置了基于 embedding 的语义搜索:

# 嵌入语义搜索:输入"张三的英语成绩"
results = store.search(("六年级", "1班"), query="张三的英语成绩")

这让长期记忆天然适合 RAG 和知识库场景。


六、短期 vs 长期:一表看懂

维度短期记忆 InMemorySaver长期记忆 InMemoryStore
create_agent 入参checkpointerstore
查询方式thread_id + checkpoint_id(namespace, key) 任意查询
数据关联与特定 thread 绑定与 Store 对象绑定,可跨 thread
运行时访问runtime.state / runtime.contextruntime.store
存储内容完整 State 快照(含对话历史)键值对(不含对话内容)
持久化实现InMemorySaver / PostgresSaver / SqliteSaverInMemoryStore / PostgresStore / SqliteStore
典型场景对话上下文、长任务执行用户画像、知识库
常用方法put / get / get_tuple / listput / get / delete / search / list_namespaces

二者分工可以用下面这张图总结:

长期记忆
短期记忆
对话上下文
长任务
用户偏好
知识库
Store
键值对
Checkpointer
State 快照
多轮聊天
长任务执行
用户画像
RAG 检索

七、实战选型建议

✅ 用短期记忆的场景:

  • 多轮对话机器人
  • 长任务执行(需要回滚到某个 step)
  • 工具调用密集、需要上下文传递的 Agent

✅ 用长期记忆的场景:

  • 用户偏好 / 画像("用户喜欢简洁回答")
  • 跨会话知识("上次问过什么")
  • RAG 知识库

✅ 进阶组合:两者经常一起用

create_agent
checkpointer
store
state_schema
tools
middleware
短期:对话上下文
长期:知识 / 偏好
结构化状态
工具主动读取
隐式注入 / 拦截

🚀 生产环境三件套:

  1. 把 InMemorySaver → PostgresSaver
  2. 把 InMemoryStore → PostgresStore
  3. 加上 中间件 做日志、审计、人机协同

八、写在最后

LangChain 的 Memory 体系看起来组件众多,但本质上就是两条平行的轨道:

短期记忆告诉你「刚才发生了什么」,
长期记忆告诉你「用户是谁、世界是什么」。

二者配合,Agent 才能从「金鱼记忆」进化成「老朋友」。

希望这篇笔记能帮你把 Memory 系统彻底拿下。Happy hacking!🎉


📌 参考:

  • LangChain 官方文档:Memory & Checkpointing
  • LangGraph 文档:Persistence / Store
Ai, LangChain
LangChain Ai Python
许可协议:  CC BY 4.0
分享

相关文章

8月 4, 2026

零代码造 Agent 的时代来了:LangSmith Fleet 完全上手指南

让业务人员 5 分钟用自然语言打造会自我进化的生产级 AI 智能体 本文配套所有架构图均为 Mermaid 源码,可直接复制到任何支持 Mermaid 的 Markdown 编辑器中渲染。 📑 目录 为什么需要 LangSmith Fleet? Fleet 到底是什么? Fleet 的三大核心特性

8月 3, 2026

别让你的 AI Agent 裸奔:Sandbox 沙箱隔离从入门到选型

你的 AI Agent 会写代码、跑命令、操作文件 —— 但你真的放心让它直接跑在你的电脑上吗? 如果 Agent 误读了某个 prompt 来一句 rm -rf /,或者 curl 到了不安全网络…… 沙箱(Sandbox),就是给 Agent 套的"笼子"。 本文将讲清两种主流方案: 模式一:A

8月 3, 2026

用 Remotion Skills + DeepAgents,让 AI 帮你"写"视频代码

一行自然语言描述 → 一个完整的 React 视频项目。这是程序化视频生成的新范式。 一、背景:为什么需要 Remotion Skills? 传统视频制作流程是这样的: #bytemd-mermaid-1785761231546-190{font-family:"trebuchet ms",verd

下一篇

用 Remotion Skills + DeepAgents,让 AI 帮你"写"视频代码

上一篇

上下文工程完全指南:用「写、选、压、隔」四把手术刀,根治 LLM 的"上下文崩溃"

最近更新

  • 零代码造 Agent 的时代来了:LangSmith Fleet 完全上手指南
  • 别让你的 AI Agent 裸奔:Sandbox 沙箱隔离从入门到选型
  • 用 Remotion Skills + DeepAgents,让 AI 帮你"写"视频代码
  • 告别失忆 Agent:LangChain Memory 双轨制完全指南
  • 上下文工程完全指南:用「写、选、压、隔」四把手术刀,根治 LLM 的"上下文崩溃"

热门标签

samsung WireGuard Chevereto docker 破解 llama LangChain Ai Python Gemma

目录

©2026 命令行小屋. 保留部分权利。

使用 Halo 主题 Chirpy