【AgentScope Java新手村系列】(17)长期记忆系统

简介: 长期记忆 — 废弃 LongTermMemory,改用 MEMORY.md + Compaction 压缩 + MemoryFlush 冲刷 + @Tool 主动写。三层机制互补,框架自动维护,业务方按需定制。

第十七章 长期记忆系统:从 LongTermMemory 到 workspace/MEMORY.md + 中间件驱动

1.x 的 io.agentscope.core.memory.LongTermMemory 及其子类(LongTermMemoryBase / Mem0LongTermMemory 等)在 2.0.0-RC2 中被标记为 @Deprecated(forRemoval = true)

原因:硬编码"知识库"接口很难适配不同业务——什么是"长期"?是按主题、按时间、还是按人?2.0 把这件事下沉到 workspace 文件 + 中间件,业务方自己决定写什么、何时写、写到哪。

本章先给出 1.x 旧 API 的最小示例(仅供维护老项目参考),再讲 2.0 推荐的新做法。

17.1 1.x LongTermMemory 旧 API 回顾

import io.agentscope.core.memory.LongTermMemory;
import io.agentscope.core.memory.LongTermMemoryBase;
import io.agentscope.core.memory.Mem0LongTermMemory;
import io.agentscope.core.ReActAgent;

public class Chapter17_LegacyLongTerm {
   

    public static void main(String[] args) {
   
        LongTermMemory memory = new Mem0LongTermMemory(
                "https://api.mem0.ai",
                System.getenv("MEM0_API_KEY"));

        ReActAgent agent = ReActAgent.builder()
                .name("assistant")
                .sysPrompt("你是一个长期记忆助理。")
                .model(model())
                .longTermMemory(memory)        // 1.x
                .build();
    }
}

2.0 仍可编译ReActAgent.longTermMemory(...) 在 RC2 中标记为 @Deprecated(forRemoval = true),编译通过但会告警。

17.2 2.0 推荐的两层记忆结构

workspace 下两份文件,按不同"时间粒度"组织:

workspace/
├── MEMORY.md          # 长期稳定的事实笔记
└── memory/
    ├── 2026-06-05.md  # 当天事件流
    ├── 2026-06-06.md
    └── 2026-06-07.md

17.2.1 MEMORY.md

跨会话、跨天都会用到的"稳定信息"——

# MEMORY.md

## 用户偏好
- 常驻城市:杭州
- 时区:UTC+8
- 语言:中文

## 长期目标
- 2026 年内学完 Rust

17.2.2 memory/YYYY-MM-DD.md

按天追加的"事件流"——

# 2026-06-07

## 14:32
- 用户问"今天杭州天气",回答:22~28℃,局部多云,建议带伞

## 15:01
- 用户问"我常驻哪里",agent 从 MEMORY.md 知道"杭州",回答一致

17.3 两个核心中间件

io.agentscope.core.middleware 提供两个跟记忆直接相关的中间件:

中间件 何时触发 副作用
CompactionMiddleware 上下文 token 超过阈值 早期消息压成摘要写进 MEMORY.md
MemoryFlushMiddleware 每轮 call 结束 把"该记的"刷到当日 memory/YYYY-MM-DD.md

17.3.1 CompactionMiddleware

CompactionMiddlewareHarnessAgentbuild() 时根据 MemoryConfig 自动挂载,业务方通过 .memory() 配置即可:

HarnessAgent agent = HarnessAgent.builder()
        ...
        .memory(MemoryConfig.builder()
                .compactionEnabled(true)          // 超过 token 阈值自动压缩
                .build())
        .build();

CompactionMiddleware 工作流程:

  1. 监听每轮 call 结束
  2. 检查当前上下文 token 数
  3. 超过阈值 → 把"较旧的消息"让 LLM 总结成几行
  4. 摘要写进 MEMORY.md 的"近期摘要"小节
  5. 旧消息从 AgentState 移除

17.3.2 MemoryFlushMiddleware

import io.agentscope.harness.agent.middleware.MemoryFlushMiddleware;

HarnessAgent agent = HarnessAgent.builder()
        ...
        .memory(MemoryConfig.builder().build())           // 默认开启每轮结束后冲刷记忆
        .build();

MemoryFlushMiddleware 由 HarnessAgent 根据 MemoryConfig 自动挂载,业务方无需手动构造。工作流程:

  1. 监听每轮 call 结束
  2. 让 LLM 决定"本轮是否有值得长期记的事"(事实、用户偏好变化等)
  3. 如果有 → 追加到当日 memory/2026-06-07.md
  4. 没有 → 跳过,不写

注意:每日事件文件不保证一定生成。LLM 可能判断当前对话太短、没有新信息,从而跳过写入。另外 MemoryFlush 是异步回调,进程如果在 flush 完成前退出,文件也来不及创建。实际使用中建议关注 MEMORY.md(CompactionMiddleware 写入,更稳定),memory/*.md 作为辅助查看。

17.3.3 完整配置

HarnessAgent agent = HarnessAgent.builder()
        .name("assistant")
        .sysPrompt("...")
        .model(model())
        .workspace(Path.of("./workspace"))
        .memory(MemoryConfig.builder().build())     // 默认开启 MemoryFlushMiddleware
        .build();                                   // CompactionMiddleware 按 CompactionConfig 挂载

17.4 主 agent 自动读 / 写 MEMORY.md

主 agent 在每轮推理时会自动MEMORY.md 顶部几行作为"已知背景"。如果你想"agent 决定更新 MEMORY.md"——给它 @Tool

@Tool(name = "update_long_term_memory", description = "更新长期记忆")  // 注册为 agent 可调工具
public String updateMemory(
        @ToolParam(name = "section") String section,                   // 比如 "用户偏好"
        @ToolParam(name = "content") String content) {
                   // 比如 "默认中文回答"

    Path memFile = Path.of("./workspace/MEMORY.md");                  // 记忆文件固定路径
    String existing = memFile.toFile().exists()
            ? Files.readString(memFile)                               // 已有记忆 → 追加
            : "# MEMORY.md\n\n";                                      // 新文件 → 创建
    String updated = existing + "\n## " + section + "\n- " + content + "\n";
    Files.writeString(memFile, updated);                              // 写回文件
    return "memory updated";
}

把工具通过 Toolkit 注册进 agent,LLM 看到用户说"以后请默认中文回答"会自己调这个工具写进 MEMORY.md,下次对话时立刻生效。

17.5 完整可运行示例

这个例子在演示什么?

一个 agent 同时运行三种记忆机制,各管各的时间粒度:

  • CompactionMiddleware.compaction() 配置):上下文太长时自动压缩旧消息为摘要,写进 MEMORY.md
  • MemoryFlushMiddleware.memory().flushEnabled(true) 配置):每轮对话结束自动提取重要信息,写进 memory/YYYY-MM-DD.md
  • UpdateMemoryTool@Tool 工具):agent 在对话中主动决定"这件事值得长期记住",自己调工具写 MEMORY.md

三者互补:Compaction 管上下文压缩(被动)、MemoryFlush 管日常记录(自动)、UpdateMemoryTool 管即时决策(主动)。

public class Chapter17_MemoryStack {
   

    public static void main(String[] args) {
   
        DashScopeChatModel model = DashScopeChatModel.builder()
                .apiKey(System.getenv("DASHSCOPE_API_KEY"))
                .modelName("qwen-plus")
                .build();

        // 1. 手工更新记忆的工具(agent 主动决策"记住这个")
        Toolkit toolkit = new Toolkit();
        toolkit.registerTool(new UpdateMemoryTool());

        // 2. agent:三层记忆机制一起跑
        HarnessAgent agent = HarnessAgent.builder()
                .name("assistant")
                .sysPrompt("你是一个有长期记忆的助理。用户告诉你的事如果需要长期记住,调用 update_long_term_memory 工具写下来。")
                .model(model)
                .workspace(Path.of("./workspace"))
                .toolkit(toolkit)
                .compaction(CompactionConfig.builder().build())  // 上下文太长时自动压缩
                .memory(MemoryConfig.builder().build())          // 默认 flush=每轮结束自动冲刷
                .build();

        // 3. 多轮对话(同一个 session,演示跨轮记忆)
        RuntimeContext ctx = RuntimeContext.builder()
                .sessionId("user-9527-2026-06-07")
                .userId("9527")
                .build();

        // Round 1:agent 记住用户基本信息
        agent.call(List.of(new UserMessage("user", "我叫小李,住在杭州。")), ctx).block();
        // Round 2:agent 应该能从记忆里调出信息
        agent.call(List.of(new UserMessage("user", "我叫什么?住在哪?")), ctx).block();
        // Round 3:agent 主动调 update_long_term_memory 写偏好
        agent.call(List.of(new UserMessage("user", "以后请用中文回答。")), ctx).block();
    }
}

跑完你会看到:

  • workspace/MEMORY.md — CompactionMiddleware 写的摘要 + UpdateMemoryTool 写的用户偏好(@ToolParam 缺了这里会是 null)
  • workspace/memory/不一定生成。MemoryFlushMiddleware 的写入取决于 LLM 判断"是否值得记"以及异步回调是否执行完毕
  • Round 2 时 agent 能从上下文记忆里知道"小李 / 杭州"
  • Round 3 时 agent 主动调工具把"中文回答"偏好写进 MEMORY.md

17.6 最小迁移清单(1.x LongTermMemory → 2.0 文件记忆)

1.x 用法 2.0 等价
LongTermMemory.retrieve(query) 业务方手写 @Tool 调自家向量库;或 subagent 用 grep_files
LongTermMemory.record(messages) MemoryFlushMiddleware + update_long_term_memory 工具
LongTermMemoryBase 子类 业务方自己实现 @Tool
agent.longTermMemory(memory) workspace/MEMORY.md + memory/*.md + 中间件

17.7 本章小结

  • 1.x LongTermMemory 在 2.0 中被标记为弃用,未来会移除。
  • 2.0 用 MEMORY.md + memory/YYYY-MM-DD.md 两层文件做长期记忆。
  • CompactionMiddleware 自动压缩 + MemoryFlushMiddleware 自动写入。
  • 业务方可以手写 @Tool 让 agent 主动更新 MEMORY.md。
目录
相关文章
|
8天前
|
人工智能 JSON 自然语言处理
让教学更智慧:用阿里云百炼工作流,自动生成中小学教材内容#小有可为#有温度的AI
通过可视化工作流编排,将大模型推理能力转化为标准化的教学内容生成引擎。教师只需输入教材标题和适用学段,即可自动获得结构完整、符合课程标准的章节内容,大幅降低备课门槛,助力教育资源均衡化。
480 124
|
17天前
|
Linux 程序员 数据格式
【2026最新】Notepad++下载、安装和使用一篇搞定(附中文版安装包)
Notepad++ 是一款免费开源、轻量高效的 Windows 文本编辑器,支持 C/Python/HTML 等 80+ 语言语法高亮、代码折叠、正则替换、编码转换及插件扩展,专为程序员与文本处理用户打造,完美替代系统记事本。(239字)
|
4天前
|
人工智能 安全 Cloud Native
Higress 新发布:AI Gateway 能力增强,Gateway API 及其推理扩展持续打磨
增强 AI 网关能力,持续打磨 Gateway API 及其推理扩展。
312 124
|
12天前
|
机器学习/深度学习 人工智能 调度
🐴 HappyHorse 1.1 现已上线阿里云百炼!快来查收模型使用指南,现在调用享 6 折~
HappyHorse 1.1 是新一代视频生成大模型,全面升级动态表现力、角色一致性、指令遵循、视觉质感与音画协同能力。支持I2V/T2V/R2V三类生成,适配短剧、电商广告、品牌营销等场景,提供高质、流畅、可控的AI视频生产力。
799 5
🐴 HappyHorse 1.1 现已上线阿里云百炼!快来查收模型使用指南,现在调用享 6 折~
|
10天前
|
人工智能 定位技术 SEO
我学 GEO 第 15 天:终于知道AI GEO该如何做?
我是暴走的莉莉酱,边旅行边研究AI GEO的数字游民。专注普通人如何提升“AI可见度”——让AI在回答用户问题时准确识别、理解并推荐你。不讲玄学,只做可测、可调、可持续的GEO实践。
455 127
|
4天前
|
消息中间件 存储 Kafka
Kafka 原生消息入湖能力上线!一键打通实时流与数据湖
阿里云消息队列 Kafka 版正式上线原生消息入湖能力。
266 121
|
3天前
|
人工智能 安全 程序员
终于,Claude Code 封号的原因被曝光了!竟然针对中国用户,植入隐形代码?!
通俗易懂地揭秘 Claude Code 封号的手段,分享一些自己对 AI 编程困境的思考,Codex、Cursor、DeepSeek、智谱 GLM、甚至是豆包,都有所行动了
303 1

热门文章

最新文章