Skip to content

长期记忆

长期记忆(Long-Term Memory, LTM)让 Agent 跨会话记住用户偏好、历史事实与项目背景。AgentScope 2.x 把长期记忆实现为中间件而非独立模块——三套后端(AgenticMemory / Mem0 / ReMe)都以 Middleware 形式挂载,通过 on_system_prompt / on_reply / on_reasoning 等 hook 介入 Agent 执行链,或通过 list_tools() 向 Agent 暴露 search_memory / add_memory 等工具。

版本基线:本文以 Python agentscope 2.0.4(PyPI,2026-07-07)为准,要求 Python >=3.11。 导入路径为 from agentscope.middleware import AgenticMemoryMiddleware, Mem0Middleware, ReMeMiddleware (源:src/agentscope/middleware/__init__.py)。三套后端分别在 2.0.3 / 2.0.4 引入: Mem0Middleware 随 2.0.3 发布(PR #1775,2026-06-17),AgenticMemoryMiddlewareReMeMiddleware 随 2.0.4 发布(PR #1927 / #1972,2026-06-30 / 2026-07-02)。官方文档站的 Long-Term Memory 页面可能滞后于源码,尤其 ReMeMiddleware 的文档页尚未收录——以源码与 release notes 为准。

为什么需要长期记忆

Agent 的上下文(Context)是单会话内的消息历史,会话结束即消亡。但很多场景需要跨会话延续:

  • 用户偏好:用户在上一轮说"我用 TypeScript",下一轮 Agent 应记住这一点。
  • 历史事实:用户上周提过项目截止日期,今天 Agent 应仍能引用。
  • 反馈记忆:用户纠正过"不要在回复末尾加总结",Agent 应在未来所有会话遵守。

这些信息的共同特征是:不属于当前会话的上下文,但需要在未来的会话中被检索并注入。长期记忆 中间件负责在每轮 reply 前检索相关记忆、注入上下文,并在 reply 后把新的可持久事实写回存储。

前端类比

如果你来自前端,长期记忆就是 IndexedDBlocalStorage

  • Context(上下文)像 React 组件的 state——组件卸载(会话结束)即销毁,只在本会话内有效。
  • 长期记忆像 IndexedDB——跨页面刷新(跨会话)持久化,下次打开时主动查询并加载。
  • MEMORY.md 索引文件(AgenticMemory 后端)像 localStorage 的 key 列表——先读索引知道有哪些 记忆条目,再按需读取具体内容。
  • search_memory 工具像 IndexedDB 的索引查询——Agent 主动发起检索,按相关性取回记忆。

AgentScope 原生语义:长期记忆不是把整个会话历史存盘(那是 Context 压缩与卸载的职责),而是 由 LLM 或中间件从会话中抽取可持久事实(用户偏好、项目决策、外部引用指针),写入独立存储, 在后续会话中按需检索注入。它与 IndexedDB 的区别在于:写入什么、何时检索由 LLM 决定 (agentic 模式)或由中间件自动完成(static_control 模式),而非应用代码显式控制。长期记忆存的是 "关于用户的可复用事实",不是"会话日志"。

三后端对比

三套长期记忆中间件共享同一套 hook 机制,但存储形式、检索方式与引入版本不同:

中间件后端存储形式引入版本检索方式写入方式适用场景
AgenticMemoryMiddlewareMarkdown 文件MEMORY.md 索引 + 话题文件2.0.4LLM 选择相关文件 + 异步注入Agent 用 Write 工具主动写无外部依赖、可读可审阅、本地优先
Mem0Middlewaremem0向量数据库(Qdrant)2.0.3向量相似度搜索中间件自动写回 / Agent 调工具已有 mem0 基础设施、需要语义检索
ReMeMiddlewareReMe记忆卡片(文件库)2.0.4关键词 / 向量搜索中间件自动写回(所有模式)需要 ReMe 工具链、自动记录优先

关键差异:

  • AgenticMemory:LLM 自主决定何时保存什么,Agent 通过 Read / Write / Edit 工具直接操作 Markdown 文件。中间件不提供 list_tools()(返回空列表),只负责注入记忆指令与异步检索。
  • Mem0:支持三种控制模式(static_control / agent_control / both)。static_control 模式 下中间件全自动检索与写回,Agent 完全不感知;agent_control 模式下暴露 search_memory / add_memory 工具由 Agent 按需调用。
  • ReMe:写入在所有模式下都是自动的(reply 后通过 auto_memory 任务写回),mode 参数只 控制检索方式。agent_control / both 模式暴露 memory_search 工具,但没有 add_memory 工具——Agent 不需要手动写记忆。

AgenticMemoryMiddleware

AgenticMemoryMiddleware 是文件式长期记忆:记忆以 Markdown 文件存储在工作目录下,MEMORY.md 作为 索引,每个话题是独立的 .md 文件。中间件通过 on_system_prompt 把记忆指令与 MEMORY.md 快照注入 系统提示词,通过 on_reply + on_reasoning 异步检索相关记忆文件并注入上下文。Agent 自己用 Write / Read / Edit 工具管理记忆文件——中间件不代劳写入。

构造参数(源:_longterm_memory/_agentic_memory/_middleware.py):

参数类型默认值作用
workdirstr必填Agent 工作目录,记忆文件存放根目录
memory_dirstr"Memory"记忆子目录名(MEMORY.md 与话题文件存于此)
parametersParameters | NoneNone用户可调参数(见下表)
backendBackendBase | NoneLocalBackend()存储后端,可换 Docker / E2B 实现远程隔离

Parameters 主要字段:

字段类型默认值作用
memory_max_tokensint4000MEMORY.md 注入系统提示词的最大 token 数
retrieval_asyncboolTrue是否在 reply 期间异步检索相关记忆文件
retrieval_modelChatModelBase | NoneNone检索用的 LLM,None 时复用 Agent 自身模型
retrieval_max_tokens_per_mdint2000单个记忆文件注入上下文的最大 token 数
retrieval_max_filesint200检索时最多扫描的记忆文件数

Agent 自己写记忆AgenticMemoryMiddleware 不覆盖 list_tools(),因此 await mw.list_tools() 返回空列表。Agent 需要通过 Toolkit(tools=[Read(), Write(), Edit()]) 获得文件操作工具,靠中间件 注入的系统提示词指令自主决定何时写记忆文件。这是"agentic"的真正含义——LLM 自主管理记忆。

python
import asyncio
import os

from agentscope.agent import Agent
from agentscope.credential import DashScopeCredential
from agentscope.message import UserMsg
from agentscope.middleware import AgenticMemoryMiddleware
from agentscope.model import DashScopeChatModel
from agentscope.tool import Edit, Read, Toolkit, Write


async def main() -> None:
    mw = AgenticMemoryMiddleware(workdir="./my_agent_workspace")

    agent = Agent(
        name="memory_agent",
        system_prompt="你是一个严谨的中文助手,会主动记住用户的偏好与事实。",
        model=DashScopeChatModel(
            credential=DashScopeCredential(
                api_key=os.environ["DASHSCOPE_API_KEY"],
            ),
            model="qwen-plus",
        ),
        middlewares=[mw],
        # Agent 用 Read/Write/Edit 工具自主管理 Markdown 记忆文件
        # mw.list_tools() 返回空列表,不需要合并
        toolkit=Toolkit(tools=[Read(), Write(), Edit()]),
    )

    # 第一轮:Agent 会用 Write 工具把用户偏好写入 Memory/ 目录
    result = await agent.reply(
        UserMsg(name="user", content="我喜欢用 TypeScript 写前端,后端用 Python。"),
    )
    print(result.get_text_content())

    # 第二轮(可以是新会话):中间件会从 MEMORY.md 索引中检索相关记忆
    result = await agent.reply(
        UserMsg(name="user", content="帮我写一个 hello world。"),
    )
    print(result.get_text_content())


asyncio.run(main())

运行后,./my_agent_workspace/Memory/ 目录下会出现 MEMORY.md 索引文件和若干话题 .md 文件 (如 user_role.md),每个文件带 frontmatter(name / description / type),可以被人类直接 阅读与编辑。下次启动 Agent 时,中间件会读取这些文件并注入上下文。

Mem0Middleware

Mem0Middleware 基于 mem0 后端,支持向量相似度检索。它有三种 控制模式与三种构造路径。

构造参数(源:_longterm_memory/_mem0/_middleware.py):

参数类型默认值作用
user_idstr必填mem0 的用户命名空间,隔离不同用户的记忆
clientAsyncMemory | AsyncMemoryClient | NoneNone预构建的 mem0 客户端,给定后优先使用,忽略其余后端参数
chat_modelChatModelBase | NoneNonemem0 提取记忆用的 LLM(无 client 时必填)
embedding_modelEmbeddingModelBase | NoneNonemem0 向量化记忆用的嵌入模型(无 client 时必填)
mem0_configMemoryConfig | NoneNone自定义 mem0 配置(向量库 / 历史 DB 等)
modeLiteral["static_control", "agent_control", "both"]"both"控制模式(见下文)
agent_idstr | NoneNone更细粒度的命名空间,按 Agent 隔离记忆
top_kint5每次检索返回的最大记忆数
thresholdfloat | NoneNone最小相似度阈值,None 由 mem0 决定
scope_search_by_agentboolTrueTrue 时搜索同时按 user_id + agent_id 过滤
await_writeboolTrueTrue 时写回操作内联等待;False 时后台异步写

三种控制模式:

模式自动检索自动写回暴露工具适用
static_controlAgent 不感知记忆,中间件全自动
agent_controlsearch_memory + add_memoryAgent 自主决定何时检索与写入
both(默认)search_memory + add_memory既有自动兜底,又有按需工具
python
import asyncio
import os

from agentscope.agent import Agent
from agentscope.credential import DashScopeCredential
from agentscope.embedding import DashScopeEmbeddingModel
from agentscope.message import UserMsg
from agentscope.middleware import Mem0Middleware
from agentscope.model import DashScopeChatModel
from agentscope.tool import Toolkit


async def main() -> None:
    chat_model = DashScopeChatModel(
        credential=DashScopeCredential(
            api_key=os.environ["DASHSCOPE_API_KEY"],
        ),
        model="qwen-plus",
    )
    embedding_model = DashScopeEmbeddingModel(
        credential=DashScopeCredential(
            api_key=os.environ["DASHSCOPE_API_KEY"],
        ),
        model="text-embedding-v3",
    )

    mw = Mem0Middleware(
        user_id="alice",
        chat_model=chat_model,
        embedding_model=embedding_model,
        mode="both",  # 既自动检索/写回,又暴露 search_memory / add_memory 工具
    )

    agent = Agent(
        name="memory_agent",
        system_prompt="你是一个严谨的中文助手。",
        model=chat_model,
        middlewares=[mw],
        toolkit=Toolkit(tools=await mw.list_tools()),
    )

    result = await agent.reply(
        UserMsg(name="user", content="记住我喜欢用 TypeScript 写前端。"),
    )
    print(result.get_text_content())


asyncio.run(main())

mem0 依赖Mem0Middleware 需要 mem0 包的异步客户端(AsyncMemoryAsyncMemoryClient)。安装方式:pip install "agentscope[mem0]"pip install mem0。同步客户端 Memory / MemoryClient 不被支持,中间件会抛 TypeErrorembedding_model 的向量维度必须与 mem0 向量库匹配——默认 Qdrant 期望 1536 维(DashScope text-embedding-v3 默认输出 1024 维, 需确认 mem0 配置中的向量维度一致)。

ReMeMiddleware

ReMeMiddleware 基于 ReMe 工具链——一个构建在 AgentScope 之上的文件式记忆工具包。与 Mem0 不同,ReMe 被内嵌进进程运行(无需单独启动服务),且写入在 所有模式下都是自动的:reply 结束后中间件自动把本轮对话增量通过 ReMe 的 auto_memory 任务写回。 mode 参数只控制检索方式。

构造参数(源:_longterm_memory/_reme/_middleware.py):

参数类型默认值作用
workspace_dirstr".reme"ReMe 工作区(记忆库)目录
configstr"default"ReMe 配置名或路径(默认用 ReMe 内置的 default.yaml
parametersParameters | NoneNone用户可调参数(见下表)

Parameters 字段:

字段类型默认值作用
chat_modelChatModelBase | NoneNone注入 ReMe 的 LLM,None 时 ReMe 用自身配置的凭据
embedding_modelEmbeddingModelBase | NoneNone注入 ReMe 的嵌入模型,给定后启用向量检索;否则仅关键词检索
modeLiteral["static_control", "agent_control", "both"]"both"检索模式(写入始终自动)
top_kint5每次检索返回的最大记忆数

三种模式(只影响检索,写入始终自动):

模式自动检索注入暴露工具自动写回
static_control
agent_controlmemory_search
both(默认)memory_search

add_memory 工具:ReMe 的设计哲学是"写入全自动"——reply 结束后中间件自动提取本轮对话 增量并写回,Agent 不需要(也不能)手动添加记忆。list_tools()agent_control / both 模式 下只返回 memory_search 工具。

python
import asyncio
import os

from agentscope.agent import Agent
from agentscope.credential import DashScopeCredential
from agentscope.message import UserMsg
from agentscope.middleware import ReMeMiddleware
from agentscope.model import DashScopeChatModel
from agentscope.tool import Toolkit


async def main() -> None:
    chat_model = DashScopeChatModel(
        credential=DashScopeCredential(
            api_key=os.environ["DASHSCOPE_API_KEY"],
        ),
        model="qwen-plus",
    )

    mw = ReMeMiddleware(
        workspace_dir="./my_reme_workspace",
        parameters=ReMeMiddleware.Parameters(
            chat_model=chat_model,
            mode="both",  # 自动检索 + 暴露 memory_search 工具;写入始终自动
        ),
    )

    agent = Agent(
        name="memory_agent",
        system_prompt="你是一个严谨的中文助手。",
        model=chat_model,
        middlewares=[mw],
        toolkit=Toolkit(tools=await mw.list_tools()),
    )

    result = await agent.reply(
        UserMsg(name="user", content="记住我下周五要做项目演示。"),
    )
    print(result.get_text_content())

    # 显式关闭内嵌的 ReMe 应用(AgentScope 不管理中间件生命周期)
    await mw.close()


asyncio.run(main())

ReMe 依赖ReMeMiddleware 需要 reme-ai 包。安装方式: pip install "agentscope[reme]"pip install reme-ai。未安装时构造不会报错,但首次使用 (_build_app)会抛 ImportErrorsession_idagent.state.session_id 实时读取(不存储在 中间件上),因此同一个中间件实例可被多个 Agent 安全共享,各会话写入互不干扰。

文档滞后说明ReMeMiddleware 在 2.0.4 才引入(PR #1972,2026-07-02),截至本文写作时 官方文档站的 Long-Term Memory 页面可能尚未收录 ReMe 相关内容。以上构造参数与模式说明均来自源码 _longterm_memory/_reme/_middleware.py,请以源码与 release notes 为准。

与短期上下文、RAG 的区别

长期记忆容易与上下文压缩(Context)和检索增强生成(RAG)混淆,三者职责不同:

维度长期记忆(LTM)上下文压缩(Context)RAG
生命周期跨会话持久单会话内按需检索,不持久
存储内容关于用户的可复用事实当前会话的消息历史外部知识库的文档片段
数据来源Agent 自身对话中提取Agent 自身对话历史外部文档 / 数据库
注入方式中间件 hook 或工具调用上下文压缩 / 卸载中间件 on_reasoning 注入
典型场景"记住我用 TypeScript""长任务上下文超限,压缩保留摘要""检索公司 Wiki 中的 API 文档"

一句话区分:

  • LTM 是自身记忆——Agent 记住"关于用户的事",跨会话复用(本页)。
  • Context 是会话内压缩——同一会话中上下文太长时压缩保留摘要,会话结束即消亡 (见 上下文管理)。
  • RAG 是外部知识——从外部知识库检索文档注入上下文,不是 Agent 自己的记忆 (见 RAG)。

与 1.x Memory 的关系

AgentScope 1.x 有一个独立的 agentscope.memory 模块,提供 InMemoryMemory / PermanentMemory 等 记忆实现,ReActAgent 通过 long_term_memory 参数直接挂载。2.x 把 agentscope.memory 模块完全 移除,长期记忆以中间件形式回归,通过 middlewares=[mw] 装配。

两者的关键区别:

维度1.x agentscope.memory2.x LTM Middleware
形态独立模块,Agent 直接持有中间件,包裹 Agent 执行链
装配ReActAgent(long_term_memory=...)Agent(middlewares=[mw])
检索Agent 内部固定逻辑hook 介入 / 工具暴露,模式可选
后端内置 SimpleMemory / PermanentMemoryAgenticMemory / Mem0 / ReMe 三后端
写入record_to_memory 固定三档回退由 LLM 自主 / 中间件自动 / Agent 工具

⚠️ 1.x 仅作历史对照from agentscope.memory import ... 在 2.x 已不可用,会抛 ImportError。1.x 的 ReActAgent.long_term_memory 参数也已移除。迁移到 2.x 时,把原 long_term_memory 替换为对应的中间件装配,详见 1.x 到 2.x 迁移

常见错误

  • 误用 agentscope.memory:1.x 的 agentscope.memory 模块在 2.x 已移除。导入 from agentscope.memory import ... 会抛 ImportError。2.x 的长期记忆在 agentscope.middleware 下,导入 from agentscope.middleware import AgenticMemoryMiddleware 等。
  • LTM 与 Context 混淆:长期记忆跨会话持久,存储"关于用户的可复用事实";Context 是单会话内的 消息压缩,会话结束即消亡。不要用 LTM 替代 Context 压缩,也不要指望 Context 能跨会话记住用户。
  • AgenticMemory 忘了给文件工具AgenticMemoryMiddleware 不提供 list_tools()(返回空列表), Agent 需要通过 Toolkit(tools=[Read(), Write(), Edit()]) 获得文件操作工具才能写记忆文件。如果只 传 toolkit=Toolkit(tools=await mw.list_tools()),Agent 没有文件工具,无法保存任何记忆。
  • Mem0 extra 未装Mem0Middleware 需要 mem0 包的异步客户端。未安装时构造不会立即报错,但 首次使用会抛 ImportError。安装 pip install "agentscope[mem0]"
  • ReMe extra 未装ReMeMiddleware 需要 reme-ai 包。未安装时首次使用会抛 ImportError,提示 pip install "agentscope[reme]"
  • Mem0 嵌入维度不匹配embedding_model 的向量维度必须与 mem0 向量库配置一致。默认 Qdrant 期望 1536 维,如果嵌入模型输出不同维度(如 DashScope text-embedding-v3 默认 1024 维),需要在 mem0_config 中调整向量库维度或选择匹配的嵌入模型,否则写入或检索会报错。
  • ReMe 期望手动写记忆:ReMe 的 list_tools() 只返回 memory_search,没有 add_memory 工具。 写入由中间件在 reply 后自动完成。如果代码中尝试调用 add_memory,会找不到该工具。

先修

  • RAG - 理解中间件检索注入机制,与长期记忆对比
  • 中间件 - 理解 hook 生命周期与洋葱模型

下一步

  • Agent Skills - 把可复用能力封装为 Skill,与长期记忆互补

官方参考

学习文档整合站点