agentscope-ai / agentscope-ai/agentscope-java

[Bug]:CompactionMiddleware 自建 MemoryFlushManager,绕过 disableMemoryHooks()——「记忆已关闭」时仍会写记忆文件并额外调用 LLM

Abierto
#2,694 0 comentarios 0 reacciones 0 asignados Ver en GitHub
area/core/memory bug
Lenguaje dominante
Java
Estrellas
5.6k
Forks
1.3k
Merge medio
4 d 12 h
PR fusionados (30 d)
77

Descripción

> 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" 的开关,不应该留下一条仍在写记忆文件的路径。

Guía de contribución

Abrir la guía de contribución

Evaluación

Este issue todavía no se ha evaluado.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.