news 2026/9/10 15:52:24

Agent 跨会话记忆的生产落地:LangGraph MemoryStore 如何让 Agent 记住你是谁

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Agent 跨会话记忆的生产落地:LangGraph MemoryStore 如何让 Agent 记住你是谁

Agent 最让人头疼的问题之一,就是它"不记事"。

用户上一轮告诉你"我偏好用 Python 写后端",下一轮对话 Agent 又问你"你用什么语言"。用户说"帮我查一下上周那个工单的状态",Agent 反问"哪个工单?"——因为每个新会话都是一张白纸。

如果你的 Agent 接入的是客服、运维、或者任何需要持续服务的场景,这种"每次对话都失忆"的问题,直接决定了用户愿不愿意用第二次。

对话级记忆和跨会话记忆的区别

很多团队已经在做一件事:在单次对话里管理上下文。比如用滑动窗口截断历史、把旧对话摘要塞进系统提示词、或者用 Compaction API 压缩长对话。这些手段解决的是"这次对话别超 Token 上限"的问题,但解决不了"这次对话认不出上次对话的人"。

这是两个不同的记忆维度:

  • 会话内记忆(within-thread):当前对话的上下文,包括历史消息、中间状态、工具调用结果。对话结束就清空。
  • 跨会话记忆(cross-thread):跨越多次对话的持久化信息,比如用户偏好、关键事实、历史行为。对话结束,这些信息还在。

会话内记忆靠的是上下文窗口管理,而跨会话记忆需要的是一个存储层。以前这个存储层得自己搭——选数据库、设计 Schema、写 CRUD、还要考虑怎么把存进去的东西跟 Agent 的推理流程衔接起来。LangGraph v0.5 发布的 MemoryStore,就是把这件事从"你自己搭"变成了"框架帮你接好"。

MemoryStore 做了什么

LangGraph 之前已经有 Checkpoint 机制,用来保存每个 step 的执行状态,支持断点续跑。但 Checkpoint 是按 thread 隔离的,thread A 看不到 thread B 的数据。MemoryStore 是独立于 thread 的持久化存储,所有 thread 共享同一个 store,天然支持跨会话数据共享。

它的核心 API 只有三个操作:

store.put(namespace, key, value) # 写入记忆 store.get(namespace, key) # 读取单条记忆 store.search(namespace, query) # 搜索记忆

Namespace 是一个元组,用来做数据隔离。最常见的用法是按用户隔离:

store.put( namespace=("user", user_id, "preferences"), key="programming_language", value={"lang": "Python", "framework": "FastAPI"} )

这样每个用户的记忆互不干扰,不同 namespace 之间天然隔离。同一个 namespace 下的多条 key 可以按 query 搜索,框架内置了向量搜索能力,不依赖外部向量数据库。

从单次对话到持续记忆的工程转变

接入 MemoryStore 之后,Agent 的工作流多了一个"记忆层"。

以前一个典型的 Agent 循环是:

  1. 接收用户输入
  2. 组装上下文(当前对话历史 + 系统提示词)
  3. 调用 LLM 获取回复
  4. 如果 LLM 请求工具调用,执行工具,返回结果
  5. 重复 2-4

接入 MemoryStore 之后,第 2 步之前多了一个步骤:从 store 中检索当前用户的相关记忆,注入到上下文中。第 4 步工具执行完之后,如果产生了有价值的信息,同步写入 store。

这个变化看起来不大,但对 Agent 的行为影响是质的:

  • 用户说"按上次的方案来",Agent 真的知道"上次的方案"是什么
  • 用户说"不要发邮件,用 Slack 通知",Agent 记住这个偏好,之后所有对话都不再问
  • 用户说"帮我查一下昨天那个异常",Agent 知道"昨天那个异常"指的是哪个

记忆检索的时机和粒度

MemoryStore 的 search 方法支持按 query 做语义匹配,不是简单的前缀匹配。这意味着 Agent 可以检索"和当前问题相关的记忆",而不是"和关键词完全匹配的记忆"。

但这里有一个工程上容易踩的坑:检索时机

如果每轮对话都全量检索,Token 消耗会迅速膨胀。特别是当 store 里积累了上百条记忆时,把所有记忆一股脑塞进上下文,和没做记忆管理的效果一样差——Token 照样爆。

比较好的做法是分层检索:

  • 高频记忆:在 Agent 初始化时加载,比如用户的语言偏好、通知偏好、时区设置。这些信息几乎每次对话都会用到,适合常驻上下文。
  • 场景记忆:根据当前对话的意图触发检索。比如用户提到"工单"时,才去检索和历史工单相关的记忆。
  • 临时记忆:工具执行过程中产生的中间结果,只在当前 step 使用,不需要持久化。

MemoryStore 的 namespace 设计天然支持这种分层。高频记忆放在("user", uid, "profile"),场景记忆放在("user", uid, "context", "tickets"),search 的时候限定 namespace 范围,减少无效检索。

记忆写入的判定标准

比检索更难的,是"什么时候该写记忆"。

LLM 的回复里包含大量信息,但并不是所有信息都值得记住。如果每轮对话都把 Agent 的回复原文写进 store,store 很快就会变成一堆垃圾数据,检索时反而引入噪声。

MemoryStore 自己不做"什么值得记"的判定——这个判定需要应用层来做。常见的做法是让 Agent 在完成关键工具调用后,通过一个专门的"记忆写入"工具来触发存储:

class WriteMemory(Tool): """当发现对后续对话有价值的用户信息时,写入记忆。""" def execute(self, namespace: tuple, key: str, value: dict): store.put(namespace, key, value) return "记忆已保存"

这个工具的调用权交给 LLM,由 LLM 判断"这条信息值得记住"。实际效果取决于 Prompt 中对"什么值得记"的定义。如果 Prompt 写得太宽泛,LLM 会把什么都记进去;写得太严格,又可能漏掉关键信息。

一个更可控的方式是:在工具执行结果返回后,在应用层用规则做一次过滤,只有满足条件的信息才写入 store。比如"用户明确表达偏好"、"工具返回了关键数据"、"用户的指令对后续对话有约束力"。

记忆的更新和冲突

跨会话记忆还有一个容易被忽略的问题:记忆更新

用户在第一次对话中说"我偏好 Python",store 里记了{"lang": "Python"}。第五次对话时用户说"最近切到 Go 了",这时候应该更新还是追加?

MemoryStore 的 put 方法是按 key 覆盖的,同一个 key 的多次 put 以最后一次为准。这符合大多数场景的需求——用户的最新偏好覆盖旧偏好。但有些场景需要保留历史版本,比如用户偏好频繁变化时,需要知道变化轨迹。

这种情况下,可以用时间戳作为 key 的一部分,或者自己在 value 里维护版本号。MemoryStore 本身不做版本管理,这部分需要应用层自己处理。

生产环境的三个关注点

第一,存储后端的选择。InMemoryStore 只适合开发和测试。生产环境需要对接持久化存储,LangGraph 提供了对 PostgreSQL、Redis 等后端的支持。选择时需要考虑跨线程/跨进程的并发写入冲突——同一个用户的两次对话可能同时写入 store,需要做好乐观锁或最后写入者胜出的策略。

第二,检索的延迟预算。MemoryStore 的 search 如果走向量检索,延迟会比 key-value 的 get 高一个数量级。在 Agent 的主循环里,每一步的延迟都是累加的。如果每次检索记忆都要等 200ms,十步对话就多出两秒。建议高频记忆走 get(毫秒级),场景记忆走 search(可接受百毫秒级),并根据对话的实时性要求做取舍。

第三,记忆量的增长管理。跨会话记忆会随着时间持续增长,不像会话内记忆在对话结束后就释放。需要定期做记忆的归档和清理。比如三个月前的用户偏好如果再也没有被更新过,可以归档到冷存储;空 namespace 可以清理掉。这部分不是 MemoryStore 的能力范围,需要在应用层配合定时任务。

什么时候该上跨会话记忆

不是所有 Agent 都需要跨会话记忆。如果你的 Agent 场景是"每次对话独立、用户不关心上下文延续",比如一次性的文档问答、单次代码生成,那会话内记忆就够用了。

但如果你正在做的是用户持续使用的服务型 Agent——客服助手、运维机器人、个人助理、开发辅助——跨会话记忆就是必需品。没有它,用户每次对话都要重新交代背景,体验和第一版聊天机器人没有区别。

LangGraph MemoryStore 的价值不在于它做了什么特别复杂的事,而在于它把"跨会话记忆"这个原本需要自己从头搭建的能力,变成了框架内的一等公民。三个 API 方法、一个 namespace 概念,接上就能用。对于已经在用 LangGraph 的团队,这是一个低成本、高回报的工程选择——前提是搞清楚记忆的写入策略和检索边界,不要一股脑全存、全搜。

最后

我们整理出这套 AI 大模型突围资料包:

✅ 从零到一的 AI 学习路径图
✅ 大模型调优实战手册(附医疗/金融等大厂真实案例)
✅ 百度/阿里专家闭门录播课
✅ 大模型当下最新行业报告
✅ 真实大厂面试真题
✅ 2025 最新岗位需求图谱

所有资料 ⚡️ ,朋友们如果有需要 《AI大模型入门+进阶学习资源包》,下方扫码获取~

资料展示

下面是我整理的AI大模型学习资料和工具包预览,适合收藏后按主题逐步学习。

需要这份AI大模型资料清单的话,在评论区回复「清单」即可;我会根据大家的问题继续补充对应的实战内容。

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

会议室音响系统视频会议优化实战指南

远程会议中,最让人头疼的往往不是网络卡顿,而是“听得见却听不清”。当你费力辨认对方含糊的语句,或者因为背景里的键盘声、空调噪音而不得不反复确认时,沟通效率已经大打折扣。更糟糕的是,那种尖锐的啸叫声突然刺破耳…

作者头像 李华
网站建设 2026/9/2 17:45:47

Python经典图像绘制:三层架构与生产级图表实战

1. 什么是“经典的Python图像绘制”?它到底在解决什么问题?“经典的Python图像绘制”,这八个字乍看平平无奇,但背后藏着一条贯穿Python数据科学、教学演示、工程报告乃至创意表达的底层脉络。它不是指某一段特定代码,也…

作者头像 李华
网站建设 2026/9/2 22:45:46

Claude Code隐藏配置EFFORT_LEVEL与ADDITIONAL_DIRECTORIES_CLAUDE_MD深度解析

1. 项目概述:深入Claude Code的隐藏配置 如果你正在使用Claude Code,无论是作为日常开发的辅助工具,还是探索AI编程的新边界,那么你很可能已经熟悉了它的基础设置。我们通常会配置API密钥、选择模型、调整一些基础参数&#xff0c…

作者头像 李华
网站建设 2026/9/1 12:12:52

基于波动方程的有杆抽油系统MATLAB物理建模与参数反演诊断

1. 项目概述:这不是一个“跑通代码”的练习,而是一次真实工况下的系统级建模实战 我做抽油机建模诊断快八年了,从大庆油田现场数据采集开始,到后来在胜利、长庆多个采油厂做状态监测系统落地,踩过的坑比写过的代码还多…

作者头像 李华
网站建设 2026/9/3 8:23:26

视频加水印怎么加?新手也能快速上手的四个好用方法

自己辛苦拍摄并剪辑好的原创视频,发布没多久就被别人下载使用,甚至去掉原有标识直接发布。这种感受相信不少人都体会过。要想有效避免内容被他人占用,一个稳妥的办法就是在发布前给视频加上属于自己的水印标识。 视频加水印怎么加&#xff1…

作者头像 李华
网站建设 2026/8/31 5:07:44

AI大模型应用开发实战:从Prompt工程到多Agent协作系统

1. 背景与核心概念:AI 浪潮为什么不可避免过去两年,AI 领域的变化速度几乎超出了所有人的预期。从大语言模型(LLM)的快速迭代,到 AI 编程助手进入日常开发流程,再到 AI Agent 开始承担复杂任务,…

作者头像 李华