文章目录
- [1. 架构概览](#1. 架构概览)
- [2. 环境准备](#2. 环境准备)
-
- [2.1 MySQL 安装](#2.1 MySQL 安装)
- [2.2 创建数据库](#2.2 创建数据库)
- [3. 项目配置](#3. 项目配置)
-
- [3.1 Maven 依赖](#3.1 Maven 依赖)
- [3.2 schema.sql --- 建表](#3.2 schema.sql — 建表)
- [3.3 相关配置](#3.3 相关配置)
-
- [3.3.1 应用配置:application.yml](#3.3.1 应用配置:application.yml)
- [3.3.2 JDBC 分布式存储配置](#3.3.2 JDBC 分布式存储配置)
- [3.4 构建 HarnessAgent](#3.4 构建 HarnessAgent)
- [4. 工作原理](#4. 工作原理)
-
- [4.1 命名空间路由](#4.1 命名空间路由)
- [4.2 数据读写流程](#4.2 数据读写流程)
- [4.3 Overlay 模式](#4.3 Overlay 模式)
- [5. 验证](#5. 验证)
-
- [5.1 启动服务](#5.1 启动服务)
- [5.2 发送对话](#5.2 发送对话)
- [5.3 检查 .agentscope](#5.3 检查 .agentscope)
- [5.4 检查 MySQL 数据](#5.4 检查 MySQL 数据)
将
AgentScope HarnessAgent的工作区从本地磁盘迁移到MySQL,实现多实例共享记忆、技能、会话日志。
1. 架构概览
┌───────────────┐ ┌───────────────┐
│ 实例 A │ │ 实例 B │
│ HarnessAgent │ │ HarnessAgent │
└───────┬───────┘ └───────┬───────┘
│ │
└──────────┬──────────┘
│
┌────────▼────────┐
│ MySQL Server │
│ │
│ agentscope_store │ ← 工作区 KV(JdbcStore)
│ agent_state │ ← Agent 会话状态(MysqlAgentStateStore)
└──────────────────┘
核心组件:
| 组件 | 作用 | 存储位置 |
|---|---|---|
JdbcStore |
工作区文件 KV 存储(MEMORY.md、skills、sessions 等) | agentscope_store 表 |
MysqlAgentStateStore |
Agent 会话状态持久化 | agent_state 表(框架自动创建) |
RemoteFilesystemSpec |
将工作区路由到远程存储 | 配置层,不存数据 |
运行逻辑:
- 本地磁盘
AGENTS.md、knowledge/、skills/仅作为只读模板,可以通过Git统一同步部署; - 运行时动态产生数据(
MEMORY.md、对话记忆、会话日志、任务数据)自动写入Mysql; - 用户 alice 对应的 KV 完整键示例:
agents/customer-service/users/alice/memory/xxx - 请求打到任意副本,读取到的用户记忆完全一致,满足多副本一致性要求;
- 模式硬性约束:共享存储模式禁止执行
Shell,如需运行脚本必须切换沙箱模式或本地模式。
2. 环境准备
2.1 MySQL 安装
bash
# Docker 方式(推荐)
docker run -d --name mysql-agentscope \
-e MYSQL_ROOT_PASSWORD=root123 \
-e MYSQL_DATABASE=agentscope \
-p 3306:3306 \
mysql:8.0 \
--character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
2.2 创建数据库
sql
CREATE DATABASE IF NOT EXISTS agentscope
DEFAULT CHARACTER SET utf8mb4
DEFAULT COLLATE utf8mb4_unicode_ci;
3. 项目配置
3.1 Maven 依赖
在 pom.xml 中添加:
xml
<!-- AgentScope Harness -->
<dependency>
<groupId>io.agentscope</groupId>
<artifactId>agentscope-harness</artifactId>
<version>2.0.0-RC2</version>
</dependency>
<!-- AgentScope MySQL 扩展(提供 JdbcStore + MysqlAgentStateStore) -->
<dependency>
<groupId>io.agentscope</groupId>
<artifactId>agentscope-extensions-mysql</artifactId>
<version>2.0.0-RC2</version>
</dependency>
<!-- Spring Boot JDBC -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- MySQL 驱动 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
3.2 schema.sql --- 建表
文件路径:src/main/resources/schema.sql
sql
-- JdbcStore KV 表
-- 关键:MySQL utf8mb4 下联合主键最大 3072 字节
-- VARCHAR(300) + VARCHAR(200) = 500 字符 × 4 字节 = 2000 字节,安全落在限制内
CREATE TABLE IF NOT EXISTS agentscope_store (
namespace_path VARCHAR(300) NOT NULL COMMENT '命名空间路径,用 0x1F 分隔',
item_key VARCHAR(200) NOT NULL COMMENT '条目 Key',
value_json LONGTEXT NOT NULL COMMENT 'JSON 序列化的值',
version BIGINT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
updated_at BIGINT NOT NULL DEFAULT 0 COMMENT '更新时间(epoch millis)',
PRIMARY KEY (namespace_path, item_key)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
3.3 相关配置
3.3.1 应用配置:application.yml
yaml
server:
port: 8090
spring:
application:
name: agentscope-demo
datasource:
url: jdbc:mysql://localhost:3306/agentscope?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: ${MYSQL_PASSWORD:root123}
sql:
init:
mode: always
schema-locations: classpath:schema.sql
agentscope:
api-key: ${DASHSCOPE_API_KEY:your-api-key}
3.3.2 JDBC 分布式存储配置
DistributedStore:分布式持久化存储组件一站式统一配置入口
解决痛点 :不用分别单独注入 AgentStateStore、BaseStore、沙箱快照、沙箱锁四类组件,统一封装后传给 HarnessAgent.Builder 一键挂载存储体系。
示例 1:同介质统一存储(Redis 全套承载):
java
DistributedStore store = RedisDistributedStore.fromJedis(jedis);
示例 2:混合异构存储(MySQL 存业务数据,Redis 做沙箱控制):
java
DistributedStore store = DistributedStore.builder()
.agentStateStore(mysqlStore.agentStateStore())
.baseStore(mysqlStore.baseStore())
.sandboxSnapshotSpec(redisStore.sandboxSnapshotSpec())
.sandboxExecutionGuard(redisStore.sandboxExecutionGuard())
.build();
这里,使用配置 Agent 会话状态、工作区使用 JDBC 存储:
java
@Configuration
public class AgentScopeConfig {
// ==================== JDBC 分布式存储 ====================
@Bean
public DistributedStore distributedStore(DataSource dataSource) {
return DistributedStore.builder()
// Agent 会话状态走 MySQL(自动建表)
.agentStateStore(new MysqlAgentStateStore(dataSource, true))
// 工作区文件 KV 走 MySQL(表由 schema.sql 创建,不自动建表)
.baseStore(JdbcStore.builder(dataSource).initializeSchema(false).build())
.build();
}
}
3.4 构建 HarnessAgent
构建 HarnessAgent 时配置:
- 本地文件工作区
- 注入分布式存储
- 启用远程文件系统(
BaseStore自动注入)
java
@Configuration
public class AgentScopeConfig {
// ==================== HarnessAgent ====================
@Bean
public HarnessAgent harnessAgent(Model model, DistributedStore store, Toolkit toolkit) {
Path workspacePath = Paths.get(
System.getProperty("user.home"), ".agentscope", "workspace", "demo-agent");
try {
java.nio.file.Files.createDirectories(workspacePath);
} catch (Exception ignored) {}
return HarnessAgent.builder()
.name("harness-demo")
.model(model)
.workspace(workspacePath)
.toolkit(toolkit)
.sysPrompt("你是一个有用的 AI 助手。")
// 注入分布式存储
.distributedStore(store)
// 启用远程文件系统(BaseStore 自动注入)
.filesystem(new RemoteFilesystemSpec()
.isolationScope(IsolationScope.USER))
.maxIters(5)
.build();
}
}
在 CompositeFilesystem 实例中,可以看到优先使用【远程文件系统】:

4. 工作原理
4.1 命名空间路由
RemoteFilesystemSpec 将工作区目录按路径前缀分片路由到 agentscope_store 表的不同命名空间:
| 工作区路径 | MySQL namespace_path 前缀 |
|---|---|
AGENTS.md、MEMORY.md、tools.json |
agents/harness-demo/users/<uid>/ + root |
memory/ |
.../memory |
skills/ |
.../skills |
subagents/ |
.../subagents |
knowledge/ |
.../knowledge |
agents/<id>/sessions/ |
.../sessions |
agents/<id>/tasks/ |
.../tasks |
每个 namespace_path 段之间用 ASCII 0x1F(Unit Separator)分隔,支持前缀搜索。
4.2 数据读写流程
text
Agent 读取 AGENTS.md
│
├─ RemoteFilesystem.read("AGENTS.md")
│ └─ JdbcStore.get(["agents","harness-demo","users","uid","root"], "AGENTS.md")
│ └─ SELECT value_json FROM agentscope_store
│ WHERE namespace_path = 'agentsharness-demousersuidroot'
│ AND item_key = 'AGENTS.md'
│
├─ 如果远程没有 → 回退到本地工作区模板文件(Overlay 下层)
│
Agent 写入 MEMORY.md(copy-on-write)
│
└─ RemoteFilesystem.write("MEMORY.md", content)
└─ JdbcStore.put(["agents","harness-demo","users","uid","root"], "MEMORY.md", value)
└─ UPDATE ... SET value_json = ?, version = version + 1
WHERE namespace_path = ? AND item_key = ?
4.3 Overlay 模式
每条路由采用双层结构:
- 上层(RemoteFilesystem) :可读写,数据存入
MySQL,用户修改的版本在这里 - 下层(LocalFilesystem,只读):本地工作区模板文件作为基线
Agent 读取时优先取上层(MySQL),上层没有则回退到下层(本地模板)。写入始终去上层。
5. 验证
5.1 启动服务
bash
mvn spring-boot:run -pl agentscope-demo
观察日志确认没有报错:
JdbcStore built: table=agentscope_store, dialect=...
HarnessAgent built: name=harness-demo (JDBC RemoteFilesystem mode)
5.2 发送对话
bash
curl "http://localhost:8090/agent/harness/call?query=今天天气怎么样&userId=demo&sessionId=test-001"

5.3 检查 .agentscope
本地磁盘并不是没有任何数据,有些数据会永远同步写入本地磁盘:

5.4 检查 MySQL 数据
sql
-- 查看命名空间分布
SELECT namespace_path, COUNT(*) AS items
FROM agentscope_store
GROUP BY namespace_path
ORDER BY namespace_path;
-- 查看具体条目
SELECT namespace_path, item_key, LEFT(value_json, 100) AS preview, version
FROM agentscope_store
ORDER BY namespace_path, item_key;
预期会看到类似数据:
namespace_path | item_key | preview
agents/harness-demo/users/demo/root/ | MEMORY.md | {"content":"...","encoding":"utf-8"}
agents/harness-demo/users/demo/sessions/ | test-001.log | {...}
