如何让AI智能体(Agent)像人类一样拥有持久的记忆,从而在复杂的连续任务中保持上下文感知和深度理解?这已成为构建高级智能体的核心挑战。本文将深入探讨Agent Memory的核心概念,并聚焦于LangGraph框架下的长短期记忆实现,详解短期会话与长期知识的存储、管理、语义检索等技巧。更进一步地,我们将通过一个引入MCP协议的实战案例,手把手带你构建一个真实的融合长记忆机制的Multi-Agent系统,直观展示中断、记忆与协作的融合。

基于大语言模型(LLM)的智能体(Agent)系统中,记忆机制是实现持续、连贯和个性化交互的核心基石,通过记忆,可以让Agent记住过往的交互,保持上下文的一致性,并能从反馈中学习,适应用户的偏好。
本文核心要点概述:
- 介绍Agent Memory的基本情况
- LangGraph长短期记忆详解及案例说明:包含短期记忆实现、管理方法,长期记忆的实现方法,以及搭建了融合postgres数据库、集成Embedding服务进行语义搜索等可用于生产环境的真实案例。
- 引入MCP协议构建真实的Agent长记忆应用:搭建一个基于supervisor架构,集成中断机制、长短期记忆机制的multi-agent系统。
一、记忆机制介绍
1. Agent Memory是什么?

上图中(来源于Mem0[1]),左边是没有Memory的agent,右边是有Memory的agent,后者可以根据用户的过往信息(素食主义者、不喜欢乳制品)给出更合理的响应(不含乳制品的素食菜单),而前者的回答显然是不合适的。
简单来说,Memory是赋予Agent记忆能力的技术和架构,能够让Agent像人一样记住过去的交互、学到的知识、执行过的任务及未来的计划,是将一个LLM转变为能够执行复杂、长期任务的真正”智能体“的核心所在。
2. 关于Agent Memory我们需要考虑什么?
- 如何获取记忆:通过和用户交互、环境交互…
- 怎么组织记忆:模型参数、模型上下文、数据库
- 怎么利用记忆:RAG、Few-shot…
3. 有哪些Memory类型?
关于Memory的分类,有许多种分类体系,这里我们只讨论最常见及最易于理解的。
正如人类利用长短期记忆进行有效的交互和学习一样,Agent的记忆机制通常划分为短期记忆(short-term memory)和长期记忆(long-term memory),短期记忆决定了Agent在微观任务上的即时表现,而长期记忆则作为持久知识库,决定了Agent在宏观时间尺度上的智能深度和个性化水平,通过两者配合,Agent才能表现出连贯性、上下文感知能力,才会显得更智能。
4. Agent Memory如何工作?
Agent通常通过以下几步来有效地管理记忆,使得每次于用户的交互都更加精准智能:
- 记忆存储:通过设计一系列策略来存储重要的交互信息,这些信息可能来源于对话内容、历史数据或任务要求等等。
- 记忆更新:记忆会随着交互的发生,不断地进行更新,例如用户的偏好、最新的近况等等。记忆更新使得Agent能够不断优化其响应。
- 记忆检索:Agent根据当下的需求,去记忆中检索需要的记忆内容,从而提供更加智能的回复。
5. Agent Memory怎么实现?
- 物理外挂:即外置数据库和 RAG,需要检索当前query相关的内容,例如:Mem0、ACE。好处是即插即用,坏处是不够end-to-end
- Memory as Reasoning / Tool:通过训练Reasoning或Tool的方式动态更新context,例如:MemAgent、memory-R1。好处是更接近end-to-end,但不是很灵活。
- 参数更新:LLM本身就是一个Memory体,所有参数都是它的Memory,通过更新参数来更新记忆,这种方式是最本质的,但也是最难实现的。
二、LangGraph中的记忆管理
LangGraph[2]作为一款面向多智能体协作与状态管理的框架,其设计了巧妙的记忆管理系统,旨在为Agent提供在不同交互中存储、检索和利用信息的能力。它区分了两种主要的记忆类型:短期记忆和长期记忆。在实际使用中,通过这两种记忆协同,既能保障实时任务的高效执行,又支持了跨任务、跨周期的经验复用。
- short-term memory(通过Checkpointer实现):针对单个对话线程,核心价值在于保障对话的临时性,使得Agent能够跟踪会话中的多轮对话,可以在该线程内的任何时刻被回忆。
- long-term memory(通过Store实现):可以跨对话线程共享,可以在任何时间,任何线程中被回忆,而不像短期记忆局限于单个对话。

通过下表,可以更清晰的看到两者的区别:

1. LangGraph记忆的架构基础
要想更好的理解LangGraph中的记忆机制,首先需要理解其支持双轨记忆系统的核心概念。
(1) Checkpointer
LangGraph有一个内置的持久化(Persistence)层,通过checkpointer实现,能够持久化存储图状态,这使得开发记忆功能和人类干预功能成为可能。
当使用检查点编译一个图时,检查点会在每个super-step保存图状态的checkpoint,这些checkpoint被保存到一个thread中,可以在图执行后访问。因为threads允许在执行后访问图的状态,所以可以实现记忆、人机协作、时间旅行、容错等多种强大的功能。

工作流程:
(2) Thread
为了管理多个独立的对话,LangGraph使用了thread的概念。thread_id是由checkpointer保存的每个checkpoint的唯一id,是激活和区分不同对话线程的唯一key。在调用图的invoke或stream方法时,通过configurable字典传入一个thread_id,就代表这次操作属于thread_id这个特定的对话。
(3) Store
如上所述,图状态可以由checkpointer在每个super-step写入线程,从而实现状态的持久化。但是,如果想在多个线程之间保留一些信息的话,那么就需要用到Store。Store本质上是一个暴露给图节点和工具的键值数据库,与checkpointer的自动化快照不同,Store需要显式和主动的进行操作。

(4) Namespace
Store中的数据通常通过更持久的标识来组织。user_id是最常见的,用于关联用户的所有信息,此外,namespace提供了一种数据隔离机制,例如,使用使用 (“memories”, user_id) 这样的元组作为命名空间,可以将用户的记忆与其他类型的数据(如用户偏好 (“preferences”, user_id))清晰地分离开来,避免数据冲突,保持知识库的整洁有序。
2. 短期记忆详解
(1) InMemorySaver内存会话临时存储
对于开发、原型设计和测试阶段,最简单快捷的方式是使用InMemorySaver。它将所有的对话状态存储在内存中的一个Python字典里。
①设置记忆管理检查点
② 定义大模型并创建agent
如果是底层自定义api在图构建阶段传入检查点的代码是graph = builder.compile(checkpointer=checkpointer)。
③ 短期记忆-内存后端
执行上面代码,可以看到输出如下:
短期记忆与线程相关,在对话时,需要在配置中传入thread_id。通过上面的结果我们可以看到,当我们传入相同的thread_id时,agent就可以记住用户的名字,然而当我们更换thread_id时,agent就不记得用户的名字了。
需要注意的是,InMemorySaver将所有状态都保存在内存中,一旦程序终止,那么所有对话历史都会消失。
(2) 数据库持久化存储
可以发现,上面一小节的代码在应用程序结束后再启动,记忆就又消失了。这是因为InMemorySaver仅仅是把记忆保存在内存中,应用程序结束后释放内存记忆就消失了。在生产环境中常常使用数据库支持的检查点记录器持久化保存记忆,以保证数据的可靠性和服务的连续性。
这里我们以postgres数据库为例来说明,怎么持久化地保存记忆数据。
① 首先安装以下依赖:
② 安装postgres数据库,具体的安装方法可以参考:Linux下安装PostgreSQL_linux安装postgresql-CSDN博客。这里选择以源码的方式进行安装,安装包从官网(PostgreSQL: Downloads)下载,选择最新的postgresql-18.0.tar.gz。
③ 安装数据库成功后,编码如下代码。
DB_URI是数据库连接的URL。想要自动保存在数据库中的State需要在PostgresSaver.from_conn_string(DB_URI)上下文中操作。
运行一次上述代码后,关闭应用程序后重启,再次运行上述代码,print结果如下:
可以看到,记忆已经被保存了。我们检查数据库可以发现,postgres数据库中出现了四个表:

上述表中,checkpoints表是”状态快照“表,每当程序执行一个step时,它就会在这张表中创建一条新记录,这条记录就是一个检查点的快照。查询该表,可以得到如下结果:

接下来,我们来分析每一列的含义:

理解了上面checkpoints表后,那么不禁会问,真正的消息内容被存到了哪里呢?真正的消息内容存储在checkpoint_writes表中,如下:

除了PostgreSQL之外,LangGraph还支持MongoDB、Redis等数据库。
(3) 子图中的记忆
当构建复杂的、由多个子图嵌套而成的应用时,需要更灵活的记忆管理策略。
- 记忆继承(默认):默认情况下,子图会继承其父图的checkpointer。这意味着整个嵌套图共享同一个对话状态,数据可以在父子图之间无缝流动。这对于将一个大型任务分解为多个模块化子任务非常有用。
- 记忆隔离:在某些场景下,例如构建多智能体系统,希望每个智能体(由一个子图表示)拥有自己独立的内存空间,互不干扰。此时,可以在编译子图时设置checkpointer=True。
如下代码,可以在子图中直接使用父图的短期记忆:
如果子图希望使用自己的短期记忆,那么需要在编译子图时,显示传入子图的检查点:
(4) 工具中的记忆交互
① 在工具中读取状态:
LangGraph允许工具直接访问和读取当前的图状态,使其具备上下文感知能力。
核心机制:state: Annotated[CustomState, InjectedState],InjectedState的作用是在调用这个工具时,将当前的完整状态对象作为第一个参数传递到工具中,使得这个工具能根据当前状态来执行更智能的操作。
返回结果如下:
② 在工具中写入状态:
如果要在工具执行期间修改图的记忆,那么可以直接从工具返回状态更新。这对于持久化中间结果、传递信息给后续工具等非常有用。
核心机制:工具返回Command对象。此时,LangGraph会将其返回值解释为对状态的直接修改指令。Command(update={…})中的字典定义了要更新的状态字段及其新值。这允许工具在完成其主要任务的同时,将结果写回智能体的短期记忆中,从而影响后续的决策。
输出结果如下:


3. 长期记忆详解
LangGraph中的长期记忆允许系统在不同对话中保留信息,是跨对话线程共享的,可以在任何时间、任何线程中被回忆。与短期记忆不同,长期记忆保存在自定义的命名空间中,每个记忆都组织在一个自定义的namespace和一个唯一的key下。
记忆存储:LangGraph将长期记忆存储为JSON文档,使用Store进行管理,允许存储结构化和非结构化的数据。
记忆更新时机:
- 热路径(Hot Path):在应用程序逻辑运行时实时创建记忆(store.put()),优点是实时更新,但可能增加程序复杂性、延迟等问题。
- 后台(Background):作为单独的异步任务创建记忆(store.put()),优点是避免主应用延迟、逻辑分离,难点在于确定更新频率和触发时机。
记忆检索:
- store.get():根据命名空间和键精确获取记忆。
- store.search():在指定命名空间内实现灵活记忆检索,不但可以通过命名空间和标识符,更可以通过语义检索到记忆内容。通常需要Store配置一个embed来支持语义搜索。
记忆的应用:
- 语义记忆:存储事实和概念。分为以下两种情况:Profile:将关于用户、组织或代理自身的特定信息存储为一个持续更新的JSON文档,需要模型来生成新的Profile或更新已有JSON档案;Collection:将记忆存储为一组独立的文档,易于生成,但检索和更新较为复杂,且可能难以捕获记忆间的完整上下文。在应用时,可以将检索到的记忆作为上下文或系统指令的一部分传递给LLM,用于个性化响应和回答事实性问题。
- 情景记忆:存储过去的事件或行为经验。通常通过few-shot example prompt来实现,以指导模型完成任务。
- 程序记忆:存储执行任务的规则或指令。通常通过修改代码自身的prompt来实现,将其应用于LLM。
(1) InMemoryStore
与Checkpointer类似,InMemoryStore用于快速开发和原型验证。它将所有数据存储在内存中。
输出结果如下,可以看到在工具函数中成功调用store查找到了保存的用户信息:

(2) 数据库持久化存储
为了让记忆真正”长期“,生产环境必须使用数据库支持的Store,LangGraph目前主要支持PostgresStore和RedisStore。我们以PostgresStore为例来进行说明。
① 首先,先安装对应的包:
② Postgres数据库的安装,请参考上文。
③ 接下来进行示例说明。整体过程与Checkpointer类似,关键区别在于Store是怎样在节点内部被访问和使用的。
输出结果如下:
在第一次对话时,对话线程id为3,agent被要求记住用户的名字,并且根据代码逻辑,用户名字信息是通过store.put()写入数据库的。第二次对话时,线程id为4,当被问起用户的名字时,agent通过store.search()办法从数据库中检索到了这个信息,并成功回答,这展示了Store的跨记忆存储能力。
(3) 长期知识赋能工具
① 在工具中读取长期记忆:
参考上文中,长期记忆-InMemoryStore中的示例。
其中,核心在于store = get_store() ,这个函数是一个上下文感知的辅助函数,能够在工具执行时,自动获取并返回compile或create_react_agent中传入的store实例。
② 在工具中写入长期记忆:
首先需要定义要存储的数据内容,即UserInfo,它为LLM提供了一个清晰的结构化输出格式,当LLM决定调用save_user_info的工具时,会自动生成一个包含name字段的字典。然后调用store.put()方法,将数据存储下来。

(4) 语义搜索
Store最强大的功能之一是支持语义搜索,这能将Store从一个简单的键值数据库,转变为一个功能完备的向量数据库。智能体不再只能通过精确的关键词来检索记忆,而是能够根据概念的相似性来查找相关信息。这实际就是一套RAG流程。
下面我们将基于自定义部署的Embedding服务,来演示如何进行长期记忆语义搜索。特别说明的是,代码仅供演示使用,实际使用可以参考下面代码,编写更规范的代码。
① 首先我们需要自己部署一个Embedding服务,这里我们以Qwen3-Embedding-4B为例。
② 创建自定义Embedding类,这个类需要继承自langchain.embeddings.base.Embeddings,这个类的作用是负责与Embedding服务进行通信。
③ 将自定义的Embedding类集成到工作流中,通过在Store中配置index来启用语义搜索。
④ 语义查询测试。
输出如下,尽管查询没有”披萨“这个词,但是通过Embedding模型计算,知道披萨和饿了是相近的语义,因此成功检索出了相关的记忆。
4. 短期记忆管理策略
随着对话的进行,短期记忆(对话历史)会不断增长,可能会超出LLM的上下文窗口,导致请求调用失败,或者使LLM反应变慢、变差。这时,就需要对记忆进行管理了。常见的解决办法有:
- 修剪消息(trim messages):移除前 N 条或后 N 条消息(在调用 LLM 之前)。最简单直接,但信息丢失严重,适合短期任务、无状态问答机器人、近期上下文最重要的应用。
- 删除消息(delete messages):从LangGraph状态中永久删除消息。可以精确的控制移除内容,但需要自定义逻辑来判断哪些消息需要删除,适合用于移除不再需要的冗余系统消息、工具输出或错误信息。
- 总结消息(summarize messages):汇总历史记录中的早期消息并将其替换为摘要。保留了核心语义信息,但计算成本高,实现相对复杂,适合用于长期连续对话、需要维持深度长期上下文的智能体。
- 自定义策略:例如消息过滤等。
(1) 修剪消息
管理对话历史的一个重要概念是限制传递给模型的消息数量,trim_messages就是LangChain提供的一个实用函数,它根据指定的策略、token限制、模型要求以及是否包含系统消息等来裁剪消息列表,它的主要目的是确保对话历史不会超出模型的上下文窗口大小。
它的解决策略是:当消息历史过长时,从开头或结尾丢弃一部分消息,以确保总长度符合限制。
发起请求如下:
输出打印如下:
模型最终的输出为:

可以看出,传递给模型的消息内容已经被裁剪,修剪的过程为:
- 保留系统消息,include_system=True
- strategy=”last”,反转消息列表,以便从最新的消息开始处理
- 累积token数量,当达到max_tokens限制,那么进行修剪
- 修剪时,由于allow_partial=False,因此,保留的消息都是完整的;且start_notallow=”human”,所以修剪后第一条非system prompt是用户消息
虽然对传递给模型的历史消息进行了裁剪,但是查询state可以发现,历史记录仍被完整的保留在内存中,没有被删除。
(2) 删除消息
这种方法允许从状态中永久移除特定的消息。要删除消息,不能直接从状态的messages列表中移除,而是使用RemoveMessage函数,从graph state中直接删除消息来管理对话历史。为了让RemoveMessage生效,需要使用带有add_messages reducer的状态键,例如MessagesState。
删除特定消息:
输出如下,当请求完成时,如果消息数量>2,那么最早的两条消息会被删除。

清空所有消息:
输出如下,请求完成后,会立即删除所有消息记录。

(3) 总结消息
通过修剪、删除来管理历史消息,会有丢失信息的问题。为了避免这个问题,可以进行消息总结,也就是通过调用LLM对历史对话进行摘要,并将摘要作为新的上下文传入,以在减少消息数量的同时保留关键信息。

① 首先,安装LangMem,这是一个由LangChain维护的库,提供了用于在agent中管理记忆的工具。
② langmem库提供了一个预构建的SummarizationNode,可以极大地简化实现过程:
输出如下:

如果需要在agent中实现的话,那么将SummarizationNode传入pre_model_hook即可。SummarizationNode会自动检查历史消息的长度,当token数量超过阈值时,触发一次总结,然后将”摘要 + 最新消息“的组合传递给model。其中,initial_summary_prompt用于第一次生成摘要时的prompt模板,existing_summary_prompt用于更新现有摘要的prompt模板,final_prompt是将摘要与剩余的消息合并后的prompt模板。
State中的context字段用于存储运行中的摘要信息, 避免在每次调用时都重复总结。
(4) 检查点管理
对有状态的agent的记忆进行检查、管理和重置,对于监控agent和提高用户使用体验都必不可少,LangGraph提供了以下的一些工具,用来对检查点进行管理。
查看最近的短期记忆,也就是最近的检查点的状态:
查看线程的所有短期记忆,会按时间顺序返回这个线程所有的历史检查点:
删除一个线程的所有短期记忆,一般用于重启对话场景:
5. 引入MCP协议构建真实的Agent长记忆应用
本节将介绍如何基于Model Context Protocol(MCP)协议,使用LangGraph-Supervisor框架构建一个实用的、集成中断机制、有长记忆的多Agent系统。MCP是一种社区共建的AI开放协议,它标准化了应用向AI提供上下文的方式,极大简化了工具集成过程。
接下来,我们从头开始搭建multi-agent系统,模拟一个用户去进行旅游信息查询,并进行酒店预定,然后酒店管理侧可以查询用户的预定信息。整个Demo我们将展示Supervisor框架的搭建、人工介入、长短期记忆的应用等。

我们将逐步构建multi-agent工作流的每个组件,它包含三个子智能体,三个专门的 ReAct(推理和行动)子智能体,然后它们将组合起来创建一个包含额外步骤的多智能体工作流。
我们的工作流从以下开始:
- human_input:用户输入;admin_input:管理员输入
- supervisor协调三个子agent,根据input内容,选择合适的agent进行工作
- 当supervisor选择调用search_assistant的时候,那么查询信息,并将结果返回
- 当supervisor选择调用hotel_assistant的时候,那么把用户的预定信息,更新到Store中
- 当supervisor选择调用booking_info_assistant,会先进行verify_info,中断图的执行以请求管理员ID,当输入管理员ID后,接着判断管理员ID是否符合要求,如果不符合,那么不进行记忆查询,如果符合,则查询记忆,并返回。
(1) 步骤一:环境准备与安装
(2) 步骤二:模型初始化
(3) 步骤三:初始化长短期记忆
(4) 步骤四:工具与助手配置
① 搜索助手

② 酒店预定助手
定义图节点之间流动的共享数据结构,将需要存储的记忆格式化。
定义预定酒店子智能体,并将用户预定历史存储下来。
③ 查询助手
用户的预定信息都是需要保密的,只有特定的管理员才可以进行查询,因此,需要设计中断机制,审核请求查询用户的权限是否符号要求,即:在正式查询前,先中断一下,要求输入管理员ID信息;等输入后,接着执行图,再去判断管理员ID信息是否符合要求;只有符合才能正常进行用户信息查询。
查询工具定义:
定义子图的状态:
创建新的图节点,负责中断和验证:
构建包含中断节点的子agent:
(5) 步骤五:Supervisor架构构建
基于上述组件,我们将构建一个完整的Supervisor架构工作流。
(6) 步骤六:系统运行
① 第一次交互: 查询北京火锅店
输出:
② 第二次交互:根据上一步推荐的火锅店查询酒店
输出:
可以看到,supervisor记得上文中提到过的第一个推荐的火锅店,这是短期记忆的典型应用。
③ 第三次交互:预定酒店
输出:
成功调用预定酒店助手,并完成酒店预定。
④ 第四次交互:管理员查询预定信息
第一次运行,触发中断并输出:
接着,程序模拟管理员输入正确的ID后,继续执行图,booking_info_assistant查询到长期记忆,并输出:
最终,supervisor返回最终的结果:
6. 未来工作
(1) 更智能的记忆管理策略
在上述的示例(预定酒店)中,我们仅将用户预定信息直接进行存储、检索,但对于supervisor来说,记住和不同用户的过往交互是非常重要的,在后续的交互中,才能针对不同的用户,给出更合适的回应。让Agent能自主决定记忆的存储、遗忘、更新和检索优先级,才能真正模拟人类的记忆过程。因此,未来需要改进设计更智能的记忆管理策略。
(2) 记忆驱动的多智能体系统架构选择
在上述示例(预定酒店)中,我们选择了Supervisor架构进行实现,但这显然存在缺陷,管理员系统不应该和用户系统使用同一个中央智能体,当系统功能越来越完善时,这样的设计会使得supervisor非常繁杂、且难以维护,Supervisor架构更适合需要明确控制流程和集中决策的场景。融合记忆功能的Multi-Agent系统可以根据应用场景选择更合适的架构,例如Hierarchical架构,可以用于不同层级的记忆服务于不同目的(个体、团队、全局)的场景;Custom架构,预先定义好各个Agent的记忆走向,构建更灵活的系统。
文章来自:51CTO
