详情

首页手游攻略 AgentScope Java新手村系列 第17篇 长期记忆系统

AgentScope Java新手村系列 第17篇 长期记忆系统

佚名 2026-07-07 09:18:00

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

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),编译通过但会告警。

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

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 工作流程:

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

17.3.2 MemoryFlushMiddleware

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

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

监听每轮 call 结束 让 LLM 决定"本轮是否有值得长期记的事"(事实、用户偏好变化等) 如果有 → 追加到当日 memory/2026-06-07.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";// 新文件 → 创建String updated = existing "## " section "- " content "";Files.writeString(memFile, updated);// 写回文件return "memory updated";}

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

17.5 完整可运行示例

这个例子在演示什么?

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。
点击查看更多
推荐专题
热门阅读