agentscope-ai / agentscope-ai/agentscope-java
[Bug]: 当前 main 默认 ObjectStoreTranscriptStore 的 segment key 不匹配 RemoteFilesystemSpec 路由,session 历史无法写入远程/MySQL
- 主要语言
- Java
- 星标
- 5.6k
- 派生
- 1.3k
- 平均合并
- 4 天 12 小时
- 30 天内合并 PR
- 77
描述
## 环境
| | |
|---|---|
| agentscope-harness | `v2.0.2-95-gb4361103`(当前 main) |
| store | `agentscope-extensions-mysql`(`JdbcStore` → MySQL 8.0) |
| filesystem | `RemoteFilesystemSpec` with `IsolationScope.USER` |
| 场景 | 非 sandbox,CompositeFilesystem + 远程 store |
## 问题
在 v2.0.2 中,session JSONL 会走 `MemoryFlushMiddleware → offloadMessages → SessionTree.scheduleMirror()`,最终通过 `RemoteFilesystem.uploadFiles()` 写入 MySQL 的 `agentscope_store` 表。
当前 `main` 分支引入了 `TranscriptStore` 体系,默认使用 `ObjectStoreTranscriptStore`:
```java
// HarnessAgent.java ~L2410
if (effectiveTranscriptStore == null) {
if (wsManager.getFilesystem() != null) {
effectiveTranscriptStore = new ObjectStoreTranscriptStore(wsManager.getFilesystem());
} else {
effectiveTranscriptStore = new FilesystemTranscriptStore(...);
}
}
```
`ObjectStoreTranscriptStore.appendSegment()` 生成的 key 为:
```text
default/{agentId}/{sessionId}/events/{seqStart}-{seqEnd}-{writerId}.jsonl
```
而 `RemoteFilesystemSpec` 注册的路由是:
```java
routes.put("agents/" + effectiveAgentId + "/sessions/", overlayRoute(...));
```
`default/{agentId}/{sessionId}/...` 与 `agents/{agentId}/sessions/...` 不匹配,因此 `CompositeFilesystem.routeForPath()` 会 fallback 到 `defaultBackend`(`LocalFilesystem`),session segment 只写本地 workspace,**不进 `RemoteFilesystem`,不进 MySQL**。
## 复现
```java
HarnessAgent.builder()
.agentId("agent-qa")
.name("agent-qa")
.distributedStore(new MysqlDistributedStore(dataSource))
.filesystem(new RemoteFilesystemSpec())
.build();
```
运行一次完整对话后:
```sql
SELECT * FROM agentscope_store WHERE namespace_path LIKE '%sessions%';
-- 预期:有 agents␟agent-qa␟users␟...␟sessions␟ 前缀的记录
-- 实际:没有 session 相关记录
```
本地 workspace 会出现:
```text
workspace//default/agent-qa//events/0-5-xxx.jsonl
```
## 根因
1. `ObjectStoreTranscriptStore` 的 segment key layout 是 `{tenant}/{agentId}/{sessionId}/events/...`,与 `RemoteFilesystemSpec` 的 `{agents}/{agentId}/sessions/` 路由前缀不一致。
2. 即使手动调整 key 前缀去匹配 `agents/{agentId}/sessions/`,`USER` scope 下还带有 `users/{userId}` 层级,而 `TranscriptRef` 中没有 `userId`,难以正确构造命中路由的 key。
3. 框架目前没有内置基于 JDBC/MySQL 的 `TranscriptStore` 实现,用户无法通过 `.transcriptStore(...)` 直接接入已有 DataSource。
## 影响
1. 升级到当前 main 后,原先 v2.0.2 能写入 MySQL 的 session 历史会"静默丢失"到本地盘。
2. 在 K8s / emptyDir / 多副本场景下,本地 workspace 随 Pod 销毁,session 无法跨副本恢复。
3. 用户配了 `RemoteFilesystemSpec + JdbcStore` 后,会误以为 session 已持久化到 MySQL,但实际上没有。
## 建议
任一即可:
1. **官方提供 `JdbcTranscriptStore` / `RdbmsTranscriptStore` 实现**
直接通过 JDBC 同步写入独立表(如 `agentscope_transcript_segments`),不依赖 `RemoteFilesystemSpec` 路由匹配。
2. **调整默认 `ObjectStoreTranscriptStore` 的 key layout 以匹配 `RemoteFilesystemSpec` 路由**
默认生成 `agents/{agentId}/sessions/{sessionId}/events/...` 或兼容 `IsolationScope` 的 key,并确保 `TranscriptMiddleware` 传入的 `RuntimeContext` 携带 `userId` 以支持 USER scope。
3. **至少提供配置开关**
例如 `.transcriptStore(TranscriptStore.legacyMirror())` 或 `.disableTranscriptStore()`,让用户能显式选择行为,避免静默降级到本地盘。
## 相关
- #2297 — `agentName` 与 `agentId` 不一致导致 v2.0.2 session 路由失败
- #2691 — v2.0.2 中 session 写本地副本 + 异步 mirror 的设计缺陷
贡献指南
评估
这个 Issue 还没有评估数据。