agentscope-ai / agentscope-ai/agentscope-java

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

Ouverte
#2,694 0 commentaires 0 réactions 0 personnes assignées Voir sur GitHub
area/core/memory bug
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.

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.