news 2026/9/7 20:43:12

【LangChain进阶03:Long-term memory】—— LangChain 跨会话存储(Store)实战:让 Agent 记住你,而不是只记住对话

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【LangChain进阶03:Long-term memory】—— LangChain 跨会话存储(Store)实战:让 Agent 记住你,而不是只记住对话

LangChain 跨会话存储(Store)实战:让 Agent 记住你,而不是只记住对话

Checkpointer 解决了「单个对话内记忆」——同一线程里的多轮对话它能记住。但换个线程、隔天再来,它就又把你忘了。因为用户的偏好、学习进度、账号信息,这些应该跨对话存在,而不是绑死在一次聊天里。

这就是 Store(跨会话存储)的地盘。这篇文章讲清楚:Store 和 Checkpointer 的区别、Store 的基本操作、怎么在 Agent 里用 Store,以及持久化选型。


一、先厘清:Checkpointer vs Store

这是理解记忆体系最关键的对比。两者分工不同,缺一不可:

维度CheckpointerStore
作用域单个对话线程(thread_id)跨所有对话线程
数据类型Agent 状态快照(自动管理)任意键值数据(手动管理)
典型用途多轮对话记忆用户偏好、知识库、配置
数据组织thread_id → checkpoint(namespace, key) → value

✅ 一句话总结:Checkpointer 负责「对话到哪了」,Store 负责「用户是谁、会什么、喜欢什么」。两者配合,才能构建有持续记忆的智能 Agent。


二、Store 的基本操作

Store 用命名空间(namespace)+ 键(key)+ 值(value)的层级结构组织数据。namespace 是元组(类似文件夹层级),key 是字符串(类似文件名),value 是字典。

fromlanggraph.store.memoryimportInMemoryStore store=InMemoryStore()# 写入数据:put(namespace, key, value)store.put(("users","user_001"),# 命名空间"preferences",# 键{# 值"theme":"dark","language":"zh-CN","level":"入门",})store.put(("users","user_001"),"progress",{"completed_courses":["HTML 基础","Python 基础"],"total_hours":35,})# 读取数据:get(namespace, key)prefs=store.get(("users","user_001"),"preferences")print(f"偏好设置:{prefs.value}")progress=store.get(("users","user_001"),"progress")print(f"学习进度:{progress.value}")# 搜索数据:search(namespace)all_user_data=store.search(("users","user_001"))print(f"\n用户的所有数据 ({len(all_user_data)}项):")foriteminall_user_data:print(f"{item.key}:{item.value}")# 删除数据:delete(namespace, key)store.delete(("users","user_001"),"preferences")deleted=store.get(("users","user_001"),"preferences")print(f"\n删除后:{deleted}")# None

运行结果:

偏好设置: {'theme': 'dark', 'language': 'zh-CN', 'level': '入门'} 学习进度: {'completed_courses': ['HTML 基础', 'Python 基础'], 'total_hours': 35} 用户的所有数据 (2 项): preferences: {'theme': 'dark', 'language': 'zh-CN', 'level': '入门'} progress: {'completed_courses': ['HTML 基础', 'Python 基础'], 'total_hours': 35} 删除后: None

四个核心操作

操作方法说明
写入store.put(namespace, key, value)存数据
读取store.get(namespace, key)取单条
搜索store.search(namespace)列某个 namespace 下所有条目
删除store.delete(namespace, key)删单条

三、在 Agent 中使用 Store

把 Store 传给create_agent(),Agent 里的所有工具都能通过InjectedStore注解访问它。看一个课程顾问的例子——课程目录和用户会员信息都存在 Store 里,工具按需读。

fromdotenvimportload_dotenv load_dotenv()fromtypingimportAnnotatedfromlanggraph.store.baseimportBaseStorefromlanggraph.store.memoryimportInMemoryStorefromlangchain.toolsimporttool,InjectedStorefromlangchain.agentsimportcreate_agentfromlangchain.chat_modelsimportinit_chat_modelfromlangchain.messagesimportHumanMessage# 创建 Store 并预置数据store=InMemoryStore()store.put(("runoob","courses"),"catalog",{"Python3 基础教程":{"price":"免费","hours":20,"level":"入门"},"Python 数据分析":{"price":"会员","hours":30,"level":"进阶"},"Java 面向对象":{"price":"免费","hours":25,"level":"进阶"},})store.put(("runoob","users"),"user_vip_001",{"name":"小明","membership":"VIP","joined":"2024-01-15",})@tooldefquery_course_info(course_name:str,store:Annotated[BaseStore,InjectedStore()],)->str:"""查询菜鸟教程 RUNOOB 中课程的详细信息。 Args: course_name: 课程名称 """item=store.get(("runoob","courses"),"catalog")catalog=item.valueifitemelse{}ifcourse_nameincatalog:info=catalog[course_name]return(f"《{course_name}》- 价格:{info['price']},"f"时长:{info['hours']}小时,难度:{info['level']}")returnf"未找到课程《{course_name}》"@tooldefget_user_membership(user_id:str,store:Annotated[BaseStore,InjectedStore()],)->str:"""查询用户会员信息。 Args: user_id: 用户 ID """item=store.get(("runoob","users"),user_id)ifitemisNone:returnf"未找到用户{user_id}"user=item.valuereturn(f"用户{user['name']}{user['membership']}会员,"f"注册日期{user['joined']}")model=init_chat_model("deepseek:deepseek-v4-flash",temperature=0)agent=create_agent(model=model,tools=[query_course_info,get_user_membership],store=store,system_prompt="你是菜鸟教程 RUNOOB 的课程顾问。",)# 查询课程信息(数据来自 Store)result=agent.invoke({"messages":[HumanMessage(content="Python3 基础教程多少钱?")]})print(f"查询课程:{result['messages'][-1].content}")# 查询用户信息(数据来自 Store)result=agent.invoke({"messages":[HumanMessage(content="帮我查一下用户 user_vip_001 的信息")]})print(f"查询用户:{result['messages'][-1].content}")

运行结果:

查询课程: 《Python3 基础教程》是免费的,学习时长约20小时,难度为入门级别。 查询用户: 用户小明是 VIP 会员,注册日期为 2024年1月15日。

🔴 重点:关键在store: Annotated[BaseStore, InjectedStore()]。它告诉 LangChain,「这个参数是注入进来的 Store」——模型看不到它(不会出现在工具签名里),但工具运行时能直接读写 Store。


四、Store 的持久化

InMemoryStore数据在程序重启后丢失,和InMemorySaver一样只适合开发和测试。生产环境用数据库版。

# 开发阶段fromlanggraph.store.memoryimportInMemoryStore store=InMemoryStore()# 生产环境(需要 PostgreSQL)# from langgraph.store.postgres import PostgresStore# store = PostgresStore.from_conn_string("postgresql://...")

⚠️ 注意:生产环境建议用PostgresStore(数据库持久化),并配合PostgresSaver(Checkpointer)一起用——前者管跨会话长期记忆,后者管单线程对话状态。


五、Store 使用建议

场景namespace 示例key 示例说明
用户偏好("users", user_id)preferences主题、语言、通知设置
学习进度("users", user_id)progress已完成课程、学习时长
知识库("kb", collection)doc_id文档、FAQ、产品信息
会话摘要("sessions", thread_id)summary长对话的摘要,供 Checkpointer 之外使用

🔴 重点:Store 的数据是跨线程的,这正是它和 Checkpointer 的根本区别。今天在 A 线程存的偏好,明天在 B 线程也能取到。


六、总结:你真正需要记住的这几件事

  1. Checkpointer = 短期记忆(对话到哪了)Store = 长期记忆(用户是谁、会什么)
  2. Store 用 (namespace, key) → value 的层级结构组织数据,四个核心操作:put / get / search / delete。
  3. 在 Agent 里用InjectedStore注解把 Store 注入工具,模型看不到、工具能读写。
  4. 开发用InMemoryStore,生产用PostgresStore,最好和PostgresSaver一起上。
  5. Store 跨线程共享——这是跨会话记忆的关键,也是和 Checkpointer 的本质区别。

验证清单

  • put/get/search/delete操作 Store
  • 工具里能通过InjectedStore读 Store 数据
  • 同一 Store 在不同 thread_id(跨会话)都能读到
  • InMemoryStore重启后数据丢失、PostgresStore持久化
  • 能说出 Store 和 Checkpointer 的职责边界

参考资源

  • LangChain 官方 · Long-term memory: https://docs.langchain.com/oss/python/langchain/long-term-memory
  • LangGraph 官方 · Stores / Persistence: https://docs.langchain.com/oss/python/langgraph/stores
  • 菜鸟教程 · LangChain 跨会话存储 Store: https://www.runoob.com/langchain/langchain-store.html

说明:文中模型名与代码示例以官方文档和菜鸟教程为准,具体 API 细节请以你安装的 LangChain / LangGraph 版本为准。

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

CUDA环境配置完整指南:从驱动安装到PyTorch验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/7 20:40:11

从QQ空间数据导出看开源项目:模拟请求实现个人数据备份

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/7 20:39:27

毕业论文神器!盘点2026年当红之选的一键生成论文工具

一天写完毕业论文在2026年已不再是天方夜谭。最新实测显示,2026年最炸裂的一键生成论文工具正在颠覆传统写作方式,覆盖选题、文献、写作、降重、排版全流程,真正实现高效搞定毕业论文。 一、全流程王者:一站式搞定论文全链路&…

作者头像 李华
网站建设 2026/9/7 20:37:44

Oracle MINUS 集合运算实战:差集用法、NULL 陷阱与性能优化

1. 集合运算家族:MINUS 在 Oracle 里的位置1.1 集合运算到底是什么很多 DBA 和开发刚接触 Oracle 的时候,看到 MINUS 这个关键字都会愣了一下。它跟 SELECT、INSERT 这些词放在一起有点不太像 SQL 命令,反而更像是数学课上的东西。实际上&…

作者头像 李华
网站建设 2026/9/7 20:36:22

CKEditor粘贴Word图片不丢失:两代编辑器无损方案详解

做过富文本编辑器需求的朋友应该都有体会,在CKEditor里粘贴Word内容是前端开发中一个绕不开的硬骨头。文字格式还能靠样式清洗兜底,真正让人头皮发麻的是图片——粘贴过来要么不显示,要么直接被插件过滤掉,要么虽然显示了但是变得…

作者头像 李华
网站建设 2026/9/7 20:35:35

竖线 |:管道、按位或、掩码组合

一、前言在 Linux 学习过程中,绝大多数人都会被同一个符号 | 搞混淆:命令行里它是管道、代码里它是位运算、系统函数参数里它是标志叠加。很多人疑惑:明明都是竖线,为什么功能完全不同?标准答案:符号本身没…

作者头像 李华