agentscope-ai / agentscope-ai/agentscope-java
[Bug]:CompactionMiddleware 自建 MemoryFlushManager,绕过 disableMemoryHooks()——「记忆已关闭」时仍会写记忆文件并额外调用 LLM
- Langage dominant
- Java
- Étoiles
- 5.6k
- Forks
- 1.3k
- Merge moyen
- 4 j 12 h
- PR mergées (30 j)
- 77
Description
> Labels 建议:`bug` / `harness` / `memory`
## 环境
| | |
|---|---|
| agentscope-harness | 2.0.2(2.0.0 起即如此) |
| 场景 | 调用方显式 `disableMemoryHooks()` + `disableMemoryTools()`,即「完全不使用长期记忆」 |
## 问题
调用 `HarnessAgent.Builder.disableMemoryHooks()` 后,`MemoryFlushMiddleware` 与 `MemoryMaintenanceMiddleware` 都不会注册,看起来记忆功能已彻底关闭。
但 `CompactionMiddleware` **自己 new 了一个 `MemoryFlushManager`**,完全不看这个开关:
```java
// CompactionMiddleware.java:102-104
MemoryFlushManager flushManager =
new MemoryFlushManager(workspaceManager, model);
ConversationCompactor compactor =
new ConversationCompactor(model, flushManager);
```
而 `CompactionConfig` 的两个相关默认值**都是 true**:
```java
// CompactionConfig.java:273/282/283
private int triggerMessages = 50;
private boolean flushBeforeCompact = true;
private boolean offloadBeforeCompact = true;
```
于是在「记忆已关闭」的前提下,只要会话长到 `triggerMessages`(默认 50 条),压缩前仍会:
1. **执行一次记忆抽取** —— 额外一次 LLM 调用,并把结果写进 `memory/.md`
2. **把整份 messages offload 进 session JSONL**
## 实际后果(我们踩到的)
我们的服务在很长一段时间里都是「记忆关闭」状态(`disableMemoryHooks()` + `disableMemoryTools()`),workspace 挂在 NAS 上。后来准备启用长期记忆、检查 NAS 时,发现上面**已经躺着一批记忆日更文件和会话 JSONL** —— 全部是这条路径在「记忆已关闭」期间写出来的。
也就是说:
- **成本**:每次触发压缩都多一次 LLM 调用,而调用方认为自己关闭了这项功能
- **数据**:产生了从未被审阅、也不预期存在的记忆文件;一旦后续启用记忆,这些旧文件会被 `memory_search` 之类的入口读到
- **认知**:`disableMemoryHooks()` 的语义被违反,且没有任何日志提示
## 复现
1. `HarnessAgent.builder().disableMemoryHooks().disableMemoryTools()`,不设置 `compaction(...)`
2. 跑一个超过 50 条消息的会话,触发压缩
3. 观察 workspace:`memory/.md` 被创建;同时可观察到一次额外的 LLM 调用
## 规避方式(供其他遇到的人参考)
必须**无条件显式**设置 compaction 配置,不能依赖默认值:
```java
builder.compaction(CompactionConfig.builder()
.flushBeforeCompact(false)
.offloadBeforeCompact(false)
.build());
```
## 建议
任一即可:
- `CompactionMiddleware` 中的 flush / offload 受 `disableMemoryHooks` 约束(关闭时跳过,等价于把两个 flag 视为 false)
- 或者把 `MemoryFlushManager` 由外部注入,让它与其他记忆组件共享同一套开关
- 最低限度:在 `disableMemoryHooks()` 与 `CompactionConfig` 的 javadoc 里写明「compaction 内部的 flush/offload **不受** `disableMemoryHooks` 管辖,需单独关闭」
个人认为第一种最符合直觉:一个名为 "disable memory hooks" 的开关,不应该留下一条仍在写记忆文件的路径。
Guide de contribution
Ouvrir le guide de contribution
Évaluation
Cette issue n'a pas encore été évaluée.