Skip to content
页面导航
精简

AgentScope-Builder 启动原理详解

本文档面向初学者,从零开始拆解 agentscope-builder 项目从构建到运行的每一个环节。


一、项目概览

1.1 Builder 是什么?

AgentScope-Builder 是一个 Agent 构建平台,提供可视化 Web UI 让用户创建、配置和管理 AI Agent。它是一个典型的前后端一体项目:

技术说明
后端Spring Boot WebFlux (响应式)Netty 服务器、JPA 数据持久化、JWT 认证
前端React + Vite SPA打包为静态资源嵌入后端 JAR
Agent 框架HarnessAgent多租户隔离的 Agent 运行时
模型DashScope qwen-max (默认)支持切换 OpenAI / Anthropic 等
数据库嵌入式 H2 (默认)支持 MySQL / PostgreSQL

1.2 核心技术栈

┌─────────────────────────────────────────────────┐
│  浏览器 → http://localhost:8080                   │
│  ┌───────────────┐  ┌────────────────────────┐  │
│  │  React SPA    │  │  Spring Boot WebFlux   │  │
│  │  (前端页面)    │←│  REST API + SSE 流式   │  │
│  └───────────────┘  └────────────────────────┘  │
│                      │                           │
│                      ├─ JWT 认证 (Security)      │
│                      ├─ JPA (H2/MySQL)           │
│                      └─ BuilderBootstrap         │
│                         │                        │
│                         ├─ HarnessAgent           │
│                         ├─ SessionsTool           │
│                         ├─ ChatUiChannel          │
│                         └─ DashScopeChatModel     │
│                              │                   │
│                              ↓                   │
│                        DashScope API             │
└─────────────────────────────────────────────────┘

二、构建过程详解

2.1 构建命令

bash
# 从项目根目录构建 builder(-am 表示同时构建依赖模块)
mvn clean package -DskipTests -pl agentscope-examples/agents/agentscope-builder -am

2.2 Maven 构建流程

Builder 是一个 多模块项目,不能独立构建。-am(also-make)会让 Maven 自动先构建 builder 所依赖的上游模块:

构建顺序(Reactor 顺序):
  1. agentscope-parent       (根 POM,定义 BOM)
  2. agentscope-core         (核心框架)
  3. agentscope-harness      (HarnessAgent 运行时)
  4. agentscope-extensions   (扩展模块父 POM)
  5. agentscope-extensions-model-dashscope  (DashScope 模型)
  6. agentscope-extensions-mysql            (MySQL/JDBC 存储)
  7. agentscope-extensions-channel-*        (IM 频道:钉钉/飞书/企微/GitHub/GitLab)
  8. agentscope-extensions-skill-git-repository (技能仓库)
  9. agentscope-extensions-nacos-skill      (Nacos 技能)
 10. agentscope-builder      ← 最终目标

为什么不能单独构建? Builder 的 pom.xml 引用了 agentscope-bomagentscope-dependencies-bom 两个 BOM,它们定义了所有 agentscope 模块的版本号。这些是 SNAPSHOT 版本,只存在于项目内部(本地 Maven 仓库中没有),必须通过 Maven reactor 从根目录一起构建。

2.3 Fat JAR 与前端打包

Builder 使用 spring-boot-maven-plugin 生成 可执行 Fat JAR(与 codingagent 不同,codingagent 的 <skip>true</skip> 跳过了 repackage):

构建产物:
  agentscope-builder-2.0.0-SNAPSHOT.jar   ← Fat JAR(可直接 java -jar 运行)
  agentscope-builder-2.0.0-SNAPSHOT.jar.original  ← 原始 thin JAR(不含依赖)

前端打包 通过 frontend-maven-plugin 在 Maven 的 generate-resources 阶段自动完成:

前端构建步骤:
  1. install-node-and-npm → 安装 Node v20.19.2 + npm 10.9.2 到 target/ 目录
  2. npm install          → 安装前端依赖 (package.json)
  3. npm run build        → Vite 构建 → 输出到 frontend/dist/
  → Maven 将 frontend/dist/ 复制到 src/main/resources/static/
  → 最终打包进 Fat JAR 的 classpath:/static/ 中

这意味着:你不需要手动安装 Node.js 或运行 npm!Maven 会自动下载 Node 并构建前端。生成的 Fat JAR 包含了前端所有静态资源。


三、启动过程详解

3.1 启动命令

bash
# 一键启动(端口 8080)
java -jar agentscope-builder-2.0.0-SNAPSHOT.jar

# 指定不同端口
java -jar agentscope-builder-2.0.0-SNAPSHOT.jar --server.port=8082

# 切换到 MySQL 数据库
java -jar agentscope-builder-2.0.0-SNAPSHOT.jar --spring.profiles.active=jdbc

3.2 启动全景流程(7 个阶段)

  JVM 启动


  ┌─────────────────────────────────────────┐
  │ 阶段 1: Spring Boot 自动配置            │
  │   @SpringBootApplication 扫描组件        │
  │   加载 application.yml                   │
  └─────────────────┬───────────────────────┘


  ┌─────────────────────────────────────────┐
  │ 阶段 2: JPA + 数据库初始化              │
  │   H2 DataSource → Hibernate DDL → 种子   │
  └─────────────────┬───────────────────────┘


  ┌─────────────────────────────────────────┐
  │ 阶段 3: Spring Bean 组装                │
  │   BuilderConfig → Model → BaseStore     │
  │   → BuilderBootstrap → SecurityConfig   │
  └─────────────────┬───────────────────────┘


  ┌─────────────────────────────────────────┐
  │ 阶段 4: BuilderBootstrap 核心 3-Phase   │
  │   Phase1: Session 基础设施              │
  │   Phase2: Agent 构建 + SessionsTool     │
  │   Phase3: Gateway + Channel 注册        │
  └─────────────────┬───────────────────────┘


  ┌─────────────────────────────────────────┐
  │ 阶段 5: Workspace 脚手架                │
  │   自动生成 agentscope.json + scaffold   │
  └─────────────────┬───────────────────────┘


  ┌─────────────────────────────────────────┐
  │ 阶段 6: Security + Netty 服务器启动     │
  │   JWT 过滤器 + CORS + SPA fallback      │
  └─────────────────┬───────────────────────┘


  ┌─────────────────────────────────────────┐
  │ 阶段 7: 应用就绪                        │
  │   http://localhost:8080 可访问           │
  └─────────────────────────────────────────┘

阶段 1: Spring Boot 自动配置

入口类io.agentscope.builder.BuilderApp

java
@SpringBootApplication
public class BuilderApp {
    public static void main(String[] args) {
        SpringApplication.run(BuilderApp.class, args);
    }
}

@SpringBootApplication 是三个注解的组合:

  • @SpringBootConfiguration → 标记为配置类
  • @EnableAutoConfiguration → 自动配置 Spring Boot 组件
  • @ComponentScan → 扫描 io.agentscope.builder 包下所有组件

配置文件加载顺序

  1. application.yml(基础配置,总是加载)
  2. application-{profile}.yml(仅当激活对应 profile 时加载)

阶段 2: JPA + 数据库初始化

2.1 DataSource 创建

默认使用嵌入式 H2 文件数据库:

数据库路径: ${user.home}/.agentscope-builder/db
JDBC URL: jdbc:h2:file:${user.home}/.agentscope-builder/db;AUTO_SERVER=TRUE;MODE=MYSQL
驱动: org.h2.Driver
用户: sa / 密码: 空

为什么放在 user.home 而不是项目目录? 这是故意设计——数据库文件与工作空间分离,避免工作空间卷意外包含数据库表。AUTO_SERVER=TRUE 允许多个进程同时连接同一个 H2 文件。

2.2 Hibernate DDL 自动建表

yaml
spring.jpa.hibernate.ddl-auto: update   # 默认值

update 模式意味着:Hibernate 在启动时对比 Entity 类和数据库表结构,自动创建缺失的表和列。这适合开发环境。

主要表结构:

表名Entity 类说明
builder_userUserEntity用户表 (userId PK, username, passwordHash, rolesCsv)
builder_agentAgentEntityAgent 定义表 (ownerId + agentId 唯一约束)
builder_agent_shareAgentShareEntityAgent 分享/ACL 表
builder_user_marketplaceUserMarketplaceEntity用户技能市场偏好

2.3 种子数据

yaml
spring.sql.init:
  mode: always      # 每次启动都运行
  platform: h2      # 只运行 data-h2.sql

两层种子机制

  1. data-h2.sql — 创建两个演示账户(仅 H2 模式下运行):

    bob   / bob    (role: user)
    alice / alice  (role: user)

    使用 MERGE INTO ... KEY(user_id) 保证幂等性(重复运行不会报错)。

  2. JpaUserStore.@PostConstruct — 如果 admin 用户不存在,自动创建:

    admin / admin   (role: user,admin)

注意defer-datasource-initialization: true 确保 data-h2.sql 在 Hibernate 建表之后执行,否则 builder_user 表还没建好就运行 SQL 会报错。


阶段 3: Spring Bean 组装

Builder 的核心 Bean 由 BuilderConfig 类组装,这是整个启动的心脏:

3.1 Model Bean(模型连线)

优先级规则

① 已有 Model Bean → 直接使用(其他 @Configuration 提供的)
② builder.dashscope.api-key 已设置 → 自动创建 DashScopeChatModel
③ 两者都没有 → 无模型启动(agent 调用会失败)

代码逻辑:

java
@Bean
@ConditionalOnMissingBean(Model.class)                    // ① 没有其他 Model Bean
@ConditionalOnExpression("'${builder.dashscope.api-key:}' != ''")  // ② api-key 不为空
public Model dashscopeModel() {
    return DashScopeChatModel.builder()
        .apiKey(dashscopeApiKey)
        .modelName("qwen-max")
        .stream(true)
        .build();
}

关键设计:使用 @ConditionalOnMissingBean 而不是硬编码创建,让 Operator 可以通过自定义 @Configuration 注入任何模型(OpenAI、Anthropic 等)。

3.2 BaseStore Bean(分布式文件存储)

java
@Bean
@ConditionalOnMissingBean(BaseStore.class)
public BaseStore baseStore(DataSource dataSource) {
    return JdbcStore.builder(dataSource).initializeSchema(true).build();
}

默认使用 JdbcStore(基于 Spring DataSource),自动创建存储 schema。Operator 可以覆盖为 Redis/SQLite 等实现。

3.3 BuilderBootstrap Bean(Agent 编排中心)

java
@Bean
public BuilderBootstrap builderBootstrap(
        Optional<Model> modelOpt,           // 模型(可能为空)
        ToolEventBus toolEventBus,           // 工具事件总线(SSE 流式推送)
        BaseStore baseStore,                 // 分布式文件存储(必须提供)
        Optional<AgentStateStore> sessionOpt) // Agent 状态存储(可选)

为什么用 Optional<Model> 而不是直接注入? 避免循环依赖——dashscopeModel() 方法和 builderBootstrap() 方法在同一个 BuilderConfig 类中,如果 builderBootstrap 直接依赖 Model,Spring 会在创建 dashscopeModel Bean 时发现 builderBootstrap 还没准备好,导致循环依赖错误。


阶段 4: BuilderBootstrap 核心 3-Phase 组装

BuilderBootstrap.Builder.build() 是整个 Agent 运行时的组装引擎,分为 3 个 Phase:

Phase 1: 构建 Session 基础设施

1. 读取 ~/.agentscope/builder/agentscope.json 配置
2. 解析 main agent 的 subagent entries
3. 创建 WorkspaceManager → 管理 workspace 文件系统
4. 创建 DefaultAgentManager → 管理子 agent 实例池
5. 创建 SessionStore (sessions.json) → 持久化 session 注册表
6. 创建 SessionAgentManager → 全量 session 管理器
7. 创建 HarnessGateway → 消息路由网关
8. 创建 TaskRepository → 任务持久化
9. 创建 SessionsTool → 注入到每个 Agent 的子 agent 调度工具
10. 创建 OutboundTool → 注入到每个 Agent 的主动推送工具

Phase 2: 构建 Agent 实例

对于每个配置中的 agent(来自 agentscope.json 和程序化注册):

1. 创建 HarnessAgent.Builder
2. 应用 agentscope.json 中的配置 (name, sysPrompt, workspace, model, skills)
3. 注入共享 Model(如果有)
4. 注入 SessionsTool(子 agent 调度)
5. 注入 OutboundTool(频道推送)
6. 注入 ToolNotificationMiddleware(工具调用事件中间件)
7. 注入 AgentStateStore(状态持久化)
8. 配置 Filesystem(根据 store 类型选择 Local/Remote)
9. 调用 programmatic configurator(自定义配置)
10. b.build() → 生成 HarnessAgent 实例

Phase 3: 连接 Gateway + 注册 Channel

1. 将所有 agent 注册到 HarnessGateway
2. 绑定 main agent 到 gateway
3. 解析 agentscope.json 中的频道配置(钉钉/飞书/企微/GitHub/GitLab)
4. 创建 ChatUiChannel(Web UI 交互频道)
5. 注册所有频道到 ChannelManager

阶段 5: Workspace 脚手架

如果 ~/.agentscope/builder/agentscope.json 不存在,BuilderConfig 会 自动生成

java
private void ensureAgentscopeConfig() throws IOException {
    if (Files.exists(configFile)) return;  // 已存在则跳过
    
    // 自动生成最小配置
    String agentsJson = """
    {
      "main": "default",
      "agents": {
        "default": {
          "name": "builder-agent",
          "sysPrompt": "You are a helpful assistant built with AgentScope Builder..."
        }
      }
    }
    """;
    Files.writeString(configFile, agentsJson);
    
    // 同时脚手架 workspace 目录
    WorkspaceScaffolder.scaffold(workspaceRoot, agentName, agentSysPrompt);
}

WorkspaceScaffolder 创建的默认文件结构:

~/.agentscope/builder/workspace/
├── AGENTS.md                ← 从模板生成,含 {{NAME}}/{{SYSPROMPT}} 占位符
├── tools.json               ← 默认工具配置
├── skills/
│   ├── example-skill/
│   │   └── SKILL.md         ← 示例技能
│   └── ...                  ← 更多技能目录
├── subagents/
│   └── README.md            ← 子 agent 说明
├── memory/
│   └── .gitkeep             ← 空标记文件
└── knowledge/               ← 知识库目录

关键writeIfMissing 语义意味着——已有文件永远不会被覆盖,即使重新启动也不会破坏用户自定义的内容。


阶段 6: Security + Netty 服务器启动

6.1 SecurityConfig(JWT 认证)

java
@EnableWebFluxSecurity
public class SecurityConfig {
    securityWebFilterChain:
        /api/auth/login  → permitAll (公开登录接口)
        /actuator/health → permitAll (公开健康检查)
        /api/**          → authenticated (需 JWT Token)
        /**              → permitAll (静态资源,React SPA)
}

JwtAuthFilter(自定义 WebFilter)的工作流程:

每个请求:
  1. 检查 Authorization header
  2. 提取 Bearer Token
  3. JwtService.parse(token) → 解析 JWT Claims
  4. 提取 userId + roles
  5. 构建 UsernamePasswordAuthenticationToken
  6. 写入 ReactiveSecurityContextHolder
  → 后续 Controller 通过 @Authentication 获取当前用户

6.2 WebConfig(SPA Fallback)

java
@Bean
public RouterFunction<ServerResponse> spaFallback() {
    // 对所有非 /api、非 /actuator、无文件扩展名的路径
    // 返回 /static/index.html(React Router 在客户端处理路由)
    return RouterFunctions.route()
        .GET(request -> !path.startsWith("/api") 
                       && !path.contains(".") 
                       && !path.startsWith("/actuator"),
             request -> ServerResponse.ok()
                .contentType(TEXT_HTML)
                .bodyValue(indexHtml))
        .build();
}

为什么需要 SPA Fallback? React 是单页应用(SPA),使用客户端路由(如 /agents/123/chat)。当浏览器直接访问这些路径时,服务器需要返回 index.html,让 React Router 在前端处理路由,而不是返回 404。

6.3 Netty 服务器

Spring Boot WebFlux 使用 Netty(而非 Tomcat)作为 HTTP 服务器:

  • 非阻塞、事件驱动
  • 天然支持 SSE(Server-Sent Events)流式推送
  • 适合响应式编程模型

阶段 7: 应用就绪

启动完成后,以下端点可用:

端点方法说明
http://localhost:8080GETReact SPA 前端页面
POST /api/auth/loginPOSTJWT 登录认证
GET /api/auth/meGET当前用户信息
POST /api/agents/{id}/chat/streamPOSTSSE 流式聊天
POST /api/agents/{id}/chat/sendPOST同步聊天
GET /api/agentsGETAgent 列表
GET /api/user/profileGET用户资料
GET /actuator/healthGET健康检查

四、配置参数速查表

4.1 服务器配置

参数默认值环境变量说明
server.port8080SERVER_PORTHTTP 端口

4.2 数据库配置

参数默认值环境变量说明
spring.datasource.urljdbc:h2:file:~/.agentscope-builder/dbBUILDER_DB_URL数据库 URL
spring.datasource.driver-class-nameorg.h2.DriverBUILDER_DB_DRIVERJDBC 驱动
spring.datasource.usernamesaBUILDER_DB_USER数据库用户
spring.datasource.passwordBUILDER_DB_PASSWORD数据库密码
spring.jpa.hibernate.ddl-autoupdateBUILDER_JPA_DDL_AUTODDL 模式

4.3 Agent 配置

参数默认值环境变量说明
builder.dashscope.api-keyDASHSCOPE_API_KEYDashScope API Key
builder.dashscope.model-nameqwen-maxBUILDER_MODEL_NAME模型名称
builder.dashscope.streamtrue流式输出
builder.agent.namebuilder-agentBUILDER_AGENT_NAMEAgent 名称
builder.agent.sys-promptYou are a helpful assistant...系统提示词
builder.workspaceJVM 当前目录BUILDER_WORKSPACE工作目录

4.4 安全配置

参数默认值环境变量说明
builder.jwt.secretbuilder-default-dev-secret-change-in-production-32charsBUILDER_JWT_SECRETJWT 签名密钥(≥32字符)

五、多租户架构详解

Builder 是一个 多租户 平台,每个用户拥有独立的 Agent 会话空间:

用户 bob 登录 → JWT Token 包含 userId="bob"
  → ChatController 接收请求
  → ChatUiChannel 使用 DmScope.PER_PEER
  → 每个用户获得独立的 (userId, agentId) 会话
  → HarnessGateway 路由消息到对应 agent 实例

Filesystem 隔离

CompositeFilesystem 结构:
  ├── LocalFilesystem (只读,共享模板)
  │   └── AGENTS.md, skills/, subagents/, knowledge/

  └── RemoteFilesystem (每个用户的写入空间)
      └── [agents, <agentId>, memory/]     ← 每用户独立
      └── [agents, <agentId>, sessions/]    ← 每用户独立
      └── [agents, <agentId>, tasks/]       ← 每用户独立
      └── activity/                         ← 共享(跨用户可见)

IsolationScope.USER:每个用户看到自己的 memory、sessions、tasks,但共享模板和 activity。


六、前端构建与 SPA 部署详解

6.1 前端构建时机

前端在 Maven 构建阶段 就完成了打包(不是启动时):

Maven generate-resources 阶段:
  frontend-maven-plugin:
    1. install-node-and-npm → 下载 Node v20.19.2 到 target/
    2. npm install          → 安装依赖到 frontend/node_modules/
    3. npm run build        → Vite 打包 → frontend/dist/
    
  → dist/ 中的文件被复制到 src/main/resources/static/
  → 打包进 Fat JAR

6.2 SPA 运行机制

浏览器请求流程:
  1. 首次访问 http://localhost:8080
     → Spring 返回 /static/index.html
     → 浏览器加载 React SPA
  
  2. SPA 内部路由跳转 (如 /agents/chat)
     → React Router 在客户端处理,不发新请求
  
  3. SPA 直接刷新 (如 F5 刷新 /agents/chat)
     → 请求到达 Spring → WebConfig.spaFallback 检测到无文件扩展名
     → 返回 index.html → React Router 处理路由
  
  4. API 请求 (如 /api/agents)
     → Spring Security JWT 过滤器验证 Token
     → ChatController/AgentController 处理

七、常见启动问题与解决

7.1 Maven 构建失败:找不到 agentscope-bom

错误: Could not find artifact io.agentscope:agentscope-bom:pom:2.0.0-SNAPSHOT

原因:在子目录单独运行 mvn,无法解析项目内部的 SNAPSHOT BOM。

解决:必须从项目根目录运行,使用 -pl 指定子模块:

bash
mvn clean package -DskipTests -pl agentscope-examples/agents/agentscope-builder -am

7.2 端口冲突

错误: Web server failed to start. Port 8080 was already in use.

解决

bash
# 方案 1: 指定不同端口
java -jar builder.jar --server.port=8082

# 方案 2: 先停止占用 8080 的服务
stop-all.bat

7.3 DashScope API Key 未配置

警告: No model configured. Set builder.dashscope.api-key...

解决

bash
# 方案 1: 环境变量
set DASHSCOPE_API_KEY=sk-xxx

# 方案 2: application.yml 中配置
builder.dashscope.api-key: sk-xxx

7.4 H2 数据库锁

错误: Database may be already in use: "Locked by another process"

原因:另一个 builder 实例正在使用同一个 H2 文件。

解决:停止之前的实例,或使用 AUTO_SERVER=TRUE(已默认配置)允许多进程访问。

7.5 前端构建失败(无 Node.js)

如果 frontend-maven-plugin 构建失败:

bash
# 手动构建前端
cd agentscope-builder/frontend
npm install
npm run build
# 然后回到项目根目录重新 Maven 构建
mvn clean package -DskipTests -pl agentscope-examples/agents/agentscope-builder -am

八、启动脚本

已创建一键启动脚本 start-builder.bat

bat
@echo off
chcp 65001 >nul
title AgentScope-Builder (port 8080)

set DASHSCOPE_API_KEY=sk-xxx   ← 替换为你的 API Key

java -jar agentscope-builder-2.0.0-SNAPSHOT.jar --server.port=8080
pause

九、关键术语解释

术语解释
Fat JAR包含所有依赖库的可执行 JAR,java -jar 直接运行
Thin JAR只含项目代码不含依赖,需要classpath才能运行
Spring Boot WebFlux响应式 Web 框架,使用 Netty 服务器,支持 SSE
SSE (Server-Sent Events)服务器向浏览器单向推送文本事件的协议,用于流式输出
JWT (JSON Web Token)无状态认证令牌,包含 userId + roles,无需 session
H2 Database嵌入式 Java 数据库,无需安装,数据存储在文件中
JPA (Java Persistence API)Java 对象-关系映射标准,Hibernate 是其实现
HarnessAgentAgentScope 的核心 Agent 运行时,支持工具调用/子agent/频道
BuilderBootstrapAgent 编排引擎,负责读取配置→创建 Agent→启动频道
ChatUiChannelWeb UI 交互频道,处理浏览器 → Agent 的消息路由
HarnessGateway消息路由网关,将 inbound 消息分发到正确的 agent
SessionAgentManager全量会话管理器,跟踪每个 (userId, agentId) 的活跃会话
CompositeFilesystem混合文件系统,只读本地层 + 可写远程层,实现多租户隔离
BaseStore分布式文件存储接口,JDBC/Redis/SQLite 等实现
DmScope.PER_PEER每个对话方独立会话的策略(多租户隔离)
WorkspaceScaffolder工作空间脚手架,首次启动时自动创建默认文件结构
SPA Fallback将非 API 请求返回 index.html,让前端路由处理
ReactorMaven 的构建顺序计算引擎,解决多模块依赖关系