Agent Scope Java 2.x 系列【19】Harness:从零搭建 MySQL 文件系统

文章目录

  • [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.mdknowledge/、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:分布式持久化存储组件一站式统一配置入口

解决痛点 :不用分别单独注入 AgentStateStoreBaseStore、沙箱快照、沙箱锁四类组件,统一封装后传给 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 时配置:

  1. 本地文件工作区
  2. 注入分布式存储
  3. 启用远程文件系统(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.mdMEMORY.mdtools.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 0x1FUnit 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  | {...}

相关推荐
keyanbanyungong1 小时前
AI绘图行业乱象:科学失真、素材侵权,MedPeer如何重构科研可视化行业
人工智能
qq3621967051 小时前
阿里裁员新消息(2026最新动态汇总)
java·开发语言·前端
a1117761 小时前
“黑夜流星“个人引导页 网页html
java·前端·html
咕咕AI学堂1 小时前
并发编程模式:从生产者-消费者到 Actor 的工程实践
人工智能
指掀涛澜天下惊2 小时前
AI 基础知识十九 强化学习前言
人工智能·机器学习·强化学习
砚底藏山河2 小时前
沪深A股:如何获取基金持股数据
java·python·数据分析·maven
X54先生(人文科技)2 小时前
《元创力》纪实录·卷宗2.2 会议室的裂缝:当“真实高于完美”第一次被写在会议纪要里
人工智能·开源·ai写作·零知识证明
代码改善世界2 小时前
【C++进阶】C++11:列表初始化、右值引用与移动语义、完美转发全解析
java·开发语言·c++
武子康2 小时前
调查研究-178 Google 官方 Agent Skills 仓库解读:AI Agent 时代,知识正在从「提示词」变成「可安装能力包」
人工智能·openai