生成代码工程

This commit is contained in:
root 2026-05-27 14:34:57 +08:00
parent 1dfee83f7d
commit bc1d9974e9
22 changed files with 16160 additions and 2 deletions

121
README.md
View File

@ -1,3 +1,120 @@
# 商城
# 多智能体协同研发辅助系统 - 底座平台
暂无描述
## 项目简介
本项目是一个基于 Spring Boot 3.x 构建的多智能体协同研发辅助系统底座平台,提供智能体注册与发现、执行流编排、任务调度、上下文管理等核心能力,支持第三方智能体快速接入。
## 技术栈
- **Java 17**
- **Spring Boot 3.2.5**
- **Maven**
- **Knife4j / Swagger OpenAPI 3.0**(接口文档)
## 核心功能
| 模块 | 说明 |
|------|------|
| 智能体管理 | 智能体注册、注销、查询、心跳检测、能力标签发现 |
| 执行流管理 | 执行流创建、查询、删除、触发执行 |
| 任务调度 | 执行流解析、依赖排序、节点状态跟踪(预留扩展) |
| 上下文管理 | 全局数据 + 节点输出 + 元信息分层传递(预留扩展) |
| 接口文档 | 集成 Knife4j + Swagger 3提供可视化 API 调试页面 |
## 快速启动
### 前提条件
- JDK 17+
- Maven 3.6+
### 编译与运行
```bash
# 克隆项目后进入目录
cd multi-agent-platform
# 编译打包
mvn clean package -DskipTests
# 运行
java -jar target/demo-0.0.1-SNAPSHOT.jar
# 或者直接使用 Maven 运行
mvn spring-boot:run
```
### 访问接口文档
启动后访问以下地址:
- **Knife4j UI**: http://localhost:8080/doc.html
- **Swagger UI**: http://localhost:8080/swagger-ui.html
- **OpenAPI JSON**: http://localhost:8080/v3/api-docs
## 健康检查
```bash
curl http://localhost:8080/health
# 返回: {"status":"UP","timestamp":"...","service":"multi-agent-platform"}
```
## API 概览
| 接口 | 方法 | 路径 | 说明 |
|------|------|------|------|
| 健康检查 | GET | `/health` | 系统健康状态 |
| 注册智能体 | POST | `/api/v1/agent/register` | 注册新智能体 |
| 注销智能体 | DELETE | `/api/v1/agent/unregister?id=xxx` | 注销指定智能体 |
| 查询智能体列表 | GET | `/api/v1/agent/list?capability=xxx` | 按能力标签或查询全部 |
| 查询智能体详情 | GET | `/api/v1/agent/{id}` | 查询单个智能体 |
| 更新心跳 | PUT | `/api/v1/agent/{id}/heartbeat` | 更新智能体心跳 |
| 创建执行流 | POST | `/api/v1/flow` | 创建执行流配置 |
| 获取执行流 | GET | `/api/v1/flow/{id}` | 获取执行流详情 |
| 查询所有执行流 | GET | `/api/v1/flow` | 获取全部执行流 |
| 删除执行流 | DELETE | `/api/v1/flow/{id}` | 删除执行流 |
| 触发执行流 | POST | `/api/v1/flow/execute` | 触发执行流运行 |
| 查询执行状态 | GET | `/api/v1/flow/execution/{executionId}` | 查询执行进度 |
## 项目结构
```
src/main/java/com/example/demo/
├── DemoApplication.java # 启动类
├── config/
│ └── OpenApiConfig.java # Swagger/Knife4j 配置
├── controller/
│ ├── HealthController.java # 健康检查
│ ├── BusinessController.java # 智能体管理 API
│ └── FlowController.java # 执行流管理 API
├── model/
│ ├── BusinessItem.java # 智能体元数据模型
│ ├── ExecutionFlow.java # 执行流配置模型
│ └── dto/
│ ├── ApiResponse.java # 统一响应封装
│ ├── AgentRegisterRequest.java # 注册请求
│ └── FlowExecuteRequest.java # 执行触发请求
├── service/
│ ├── BusinessService.java # 智能体服务接口
│ ├── BusinessServiceImpl.java # 智能体服务实现(内存)
│ ├── FlowService.java # 执行流服务接口
│ └── FlowServiceImpl.java # 执行流服务实现(内存)
src/test/java/com/example/demo/
├── DemoApplicationTests.java # 应用启动测试
└── BusinessServiceTest.java # 智能体服务单元测试
```
## 设计说明
### 当前实现(内存存储)
所有业务数据基于 `ConcurrentHashMap` 存储在内存中,无需安装任何外部中间件即可启动运行。适用于功能验证、开发调试与接口联调。
### 后续扩展预留
- **Repository 层**:当前 Service 直接操作内存 Map后续可抽取 Repository 接口,对接 MySQL/PostgreSQL
- **缓存层**:可引入 Redis 实现分布式缓存与心跳检测
- **消息队列**:可引入 MQ 实现异步任务调度与事件通知
- **调度引擎**:当前 `executeFlow` 为模拟实现,后续可对接真正的拓扑排序 + 线程池调度
- **认证授权**:可集成 Spring Security + JWT + RBAC
- **智能体 SDK**:可提供标准 SDK 封装注册、心跳、执行等流程

14557
events.ndjson Normal file

File diff suppressed because one or more lines are too long

44
generation.json Normal file

File diff suppressed because one or more lines are too long

71
pom.xml Normal file
View File

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.5</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>multi-agent-platform</name>
<description>多智能体协同研发辅助系统 - 底座平台</description>
<properties>
<java.version>17</java.version>
<knife4j.version>4.4.0</knife4j.version>
</properties>
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Knife4j / Swagger OpenAPI (Spring Boot 3.x Jakarta) -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
<version>${knife4j.version}</version>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,24 @@
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* 多智能体协同研发辅助系统 - 底座平台启动类
* <p>
* 负责初始化 Spring 应用上下文启动嵌入式 Web 服务器
* 并提供智能体注册执行流编排与任务调度等核心能力
* </p>
*/
@SpringBootApplication
public class DemoApplication {
/**
* 应用主入口
*
* @param args 命令行参数
*/
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}

View File

@ -0,0 +1,35 @@
package com.example.demo.config;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* OpenAPI / Knife4j 接口文档自动配置类
* <p>
* 提供标准化的 API 文档元信息包括标题版本描述和联系方式
* 集成 Knife4j 增强 UI 以提升接口调试体验
* </p>
*/
@Configuration
public class OpenApiConfig {
/**
* 构建自定义 OpenAPI 实例
*
* @return 包含文档元信息的 OpenAPI 对象
*/
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.info(new Info()
.title("多智能体协同研发辅助系统 API")
.version("1.0.0")
.description("底座平台接口文档,支持智能体注册、执行流编排与任务调度")
.contact(new Contact()
.name("开发团队")
.email("dev@example.com")));
}
}

View File

@ -0,0 +1,129 @@
package com.example.demo.controller;
import com.example.demo.model.BusinessItem;
import com.example.demo.model.dto.AgentRegisterRequest;
import com.example.demo.model.dto.ApiResponse;
import com.example.demo.service.BusinessService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 智能体管理控制器
* <p>
* 提供智能体注册注销查询与心跳检测的 RESTful 接口
* </p>
*/
@Tag(name = "智能体管理", description = "智能体注册、注销、查询与心跳检测")
@RestController
@RequestMapping("/api/v1/agent")
public class BusinessController {
private final BusinessService businessService;
/**
* 构造注入智能体管理服务
*
* @param businessService 智能体管理服务
*/
public BusinessController(BusinessService businessService) {
this.businessService = businessService;
}
/**
* 注册新的智能体
*
* @param request 注册请求 DTO
* @return 注册成功的智能体元数据
*/
@Operation(summary = "注册智能体", description = "向底座注册一个新的智能体实例")
@PostMapping("/register")
public ResponseEntity<ApiResponse<BusinessItem>> register(@RequestBody AgentRegisterRequest request) {
BusinessItem item = new BusinessItem(
request.getId(),
request.getName(),
request.getVersion(),
request.getServiceUrl(),
request.getCapabilities(),
request.getInputSchema(),
request.getOutputSchema(),
request.isStreamingSupport(),
request.getHealthCheckEndpoint(),
"active"
);
BusinessItem registered = businessService.register(item);
return ResponseEntity.ok(ApiResponse.success("注册成功", registered));
}
/**
* 注销指定智能体
*
* @param id 智能体唯一标识
* @return 操作结果
*/
@Operation(summary = "注销智能体", description = "根据 ID 注销已注册的智能体")
@DeleteMapping("/unregister")
public ResponseEntity<ApiResponse<Void>> unregister(
@Parameter(description = "智能体 ID") @RequestParam String id) {
boolean removed = businessService.unregister(id);
if (removed) {
return ResponseEntity.ok(ApiResponse.success("注销成功", null));
}
return ResponseEntity.ok(ApiResponse.error(404, "智能体未找到: " + id));
}
/**
* 查询智能体列表
*
* @param capability 可选的能力标签过滤
* @return 智能体列表
*/
@Operation(summary = "查询智能体列表", description = "按能力标签查询或查询全部已注册智能体")
@GetMapping("/list")
public ResponseEntity<ApiResponse<List<BusinessItem>>> list(
@Parameter(description = "能力标签(可选)") @RequestParam(required = false) String capability) {
List<BusinessItem> agents;
if (capability != null && !capability.isBlank()) {
agents = businessService.findByCapability(capability);
} else {
agents = businessService.findAll();
}
return ResponseEntity.ok(ApiResponse.success(agents));
}
/**
* 查询单个智能体详情
*
* @param id 智能体 ID
* @return 智能体详情
*/
@Operation(summary = "查询智能体详情", description = "根据 ID 查询单个智能体详细信息")
@GetMapping("/{id}")
public ResponseEntity<ApiResponse<BusinessItem>> getById(
@Parameter(description = "智能体 ID") @PathVariable String id) {
return businessService.findById(id)
.map(agent -> ResponseEntity.ok(ApiResponse.success(agent)))
.orElse(ResponseEntity.ok(ApiResponse.error(404, "智能体未找到: " + id)));
}
/**
* 更新指定智能体的心跳时间
*
* @param id 智能体 ID
* @return 操作结果
*/
@Operation(summary = "更新心跳", description = "更新指定智能体的最近心跳时间戳")
@PutMapping("/{id}/heartbeat")
public ResponseEntity<ApiResponse<Void>> heartbeat(
@Parameter(description = "智能体 ID") @PathVariable String id) {
boolean updated = businessService.updateHeartbeat(id);
if (updated) {
return ResponseEntity.ok(ApiResponse.success("心跳更新成功", null));
}
return ResponseEntity.ok(ApiResponse.error(404, "智能体未找到: " + id));
}
}

View File

@ -0,0 +1,125 @@
package com.example.demo.controller;
import com.example.demo.model.ExecutionFlow;
import com.example.demo.model.dto.ApiResponse;
import com.example.demo.model.dto.ExecutionResult;
import com.example.demo.model.dto.FlowExecuteRequest;
import com.example.demo.service.FlowService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 执行流管理控制器
* <p>
* 提供执行流的创建查询删除触发执行与状态查询的 RESTful 接口
* </p>
*/
@Tag(name = "执行流管理", description = "执行流的创建、查询、删除、触发执行与状态跟踪")
@RestController
@RequestMapping("/api/v1/flow")
public class FlowController {
private final FlowService flowService;
/**
* 构造注入执行流管理服务
*
* @param flowService 执行流服务
*/
public FlowController(FlowService flowService) {
this.flowService = flowService;
}
/**
* 创建新的执行流配置
*
* @param flow 执行流配置 JSON
* @return 创建成功的执行流
*/
@Operation(summary = "创建执行流", description = "创建新的执行流配置,包含节点、边关系和上下文映射")
@PostMapping
public ResponseEntity<ApiResponse<ExecutionFlow>> createFlow(@RequestBody ExecutionFlow flow) {
ExecutionFlow created = flowService.createFlow(flow);
return ResponseEntity.ok(ApiResponse.success("创建成功", created));
}
/**
* 获取指定执行流详情
*
* @param id 执行流 ID
* @return 执行流详情
*/
@Operation(summary = "获取执行流", description = "根据 ID 获取执行流配置详情")
@GetMapping("/{id}")
public ResponseEntity<ApiResponse<ExecutionFlow>> getFlow(
@Parameter(description = "执行流 ID") @PathVariable String id) {
return flowService.getFlow(id)
.map(flow -> ResponseEntity.ok(ApiResponse.success(flow)))
.orElse(ResponseEntity.ok(ApiResponse.error(404, "执行流未找到: " + id)));
}
/**
* 查询所有执行流
*
* @return 执行流列表
*/
@Operation(summary = "查询所有执行流", description = "获取全部已创建的执行流配置列表")
@GetMapping
public ResponseEntity<ApiResponse<List<ExecutionFlow>>> listFlows() {
List<ExecutionFlow> flows = flowService.listFlows();
return ResponseEntity.ok(ApiResponse.success(flows));
}
/**
* 删除指定执行流
*
* @param id 执行流 ID
* @return 操作结果
*/
@Operation(summary = "删除执行流", description = "根据 ID 删除指定的执行流配置")
@DeleteMapping("/{id}")
public ResponseEntity<ApiResponse<Void>> deleteFlow(
@Parameter(description = "执行流 ID") @PathVariable String id) {
boolean deleted = flowService.deleteFlow(id);
if (deleted) {
return ResponseEntity.ok(ApiResponse.success("删除成功", null));
}
return ResponseEntity.ok(ApiResponse.error(404, "执行流未找到: " + id));
}
/**
* 触发执行流运行
*
* @param request 执行触发请求
* @return 执行结果
*/
@Operation(summary = "触发执行流", description = "手动触发指定执行流运行,返回执行记录 ID 和状态")
@PostMapping("/execute")
public ResponseEntity<ApiResponse<ExecutionResult>> executeFlow(@RequestBody FlowExecuteRequest request) {
ExecutionResult result = flowService.executeFlow(
request.getFlowId(),
request.getTriggeredBy(),
request.getTriggerMode());
return ResponseEntity.ok(ApiResponse.success("执行已触发", result));
}
/**
* 查询指定执行记录的状态与结果
*
* @param executionId 执行记录 ID
* @return 执行详情
*/
@Operation(summary = "查询执行状态", description = "根据执行记录 ID 查询执行进度与结果详情")
@GetMapping("/execution/{executionId}")
public ResponseEntity<ApiResponse<ExecutionResult>> getExecution(
@Parameter(description = "执行记录 ID") @PathVariable String executionId) {
return flowService.getExecutionResult(executionId)
.map(result -> ResponseEntity.ok(ApiResponse.success(result)))
.orElse(ResponseEntity.ok(ApiResponse.error(404, "执行记录未找到: " + executionId)));
}
}

View File

@ -0,0 +1,37 @@
package com.example.demo.controller;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* 系统健康检查控制器
* <p>
* 提供系统运行状态检查接口可用于 Kubernetes 存活/就绪探针
* </p>
*/
@Tag(name = "系统管理", description = "系统健康检查等基础管理接口")
@RestController
public class HealthController {
/**
* 健康检查接口
*
* @return 包含状态时间戳和服务名称的健康信息
*/
@Operation(summary = "健康检查", description = "返回系统当前运行状态")
@GetMapping("/health")
public ResponseEntity<Map<String, Object>> health() {
Map<String, Object> result = new LinkedHashMap<>();
result.put("status", "UP");
result.put("timestamp", LocalDateTime.now().toString());
result.put("service", "multi-agent-platform");
return ResponseEntity.ok(result);
}
}

View File

@ -0,0 +1,137 @@
package com.example.demo.model;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
/**
* 智能体元数据模型
* <p>
* 表示一个已注册的智能体实例包含智能体的唯一标识名称版本
* 服务地址能力标签列表输入输出 Schema流式支持状态健康检查端点
* 当前状态以及生命周期时间戳等信息
* </p>
*/
public class BusinessItem {
/** 智能体唯一标识 */
private String id;
/** 智能体名称 */
private String name;
/** 智能体版本号 */
private String version;
/** 智能体 Web 服务地址 */
private String serviceUrl;
/** 智能体能力标签列表 */
private List<String> capabilities;
/** 输入 SchemaJSON Schema 格式) */
private Map<String, Object> inputSchema;
/** 输出 SchemaJSON Schema 格式) */
private Map<String, Object> outputSchema;
/** 是否支持流式输出SSE */
private boolean streamingSupport;
/** 健康检查接口路径 */
private String healthCheckEndpoint;
/** 智能体状态active / inactive / pending_review */
private String status;
/** 最近一次心跳时间 */
private LocalDateTime lastHeartbeat;
/** 注册时间 */
private LocalDateTime registeredAt;
public BusinessItem() {
}
/**
* 全参构造器
*
* @param id 智能体 ID
* @param name 名称
* @param version 版本
* @param serviceUrl 服务地址
* @param capabilities 能力标签
* @param inputSchema 输入 Schema
* @param outputSchema 输出 Schema
* @param streamingSupport 是否支持流式
* @param healthCheckEndpoint 健康检查端点
* @param status 状态
*/
public BusinessItem(String id, String name, String version, String serviceUrl,
List<String> capabilities, Map<String, Object> inputSchema,
Map<String, Object> outputSchema, boolean streamingSupport,
String healthCheckEndpoint, String status) {
this.id = id;
this.name = name;
this.version = version;
this.serviceUrl = serviceUrl;
this.capabilities = capabilities;
this.inputSchema = inputSchema;
this.outputSchema = outputSchema;
this.streamingSupport = streamingSupport;
this.healthCheckEndpoint = healthCheckEndpoint;
this.status = status;
this.registeredAt = LocalDateTime.now();
this.lastHeartbeat = LocalDateTime.now();
}
// ---------- Getters / Setters ----------
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getVersion() { return version; }
public void setVersion(String version) { this.version = version; }
public String getServiceUrl() { return serviceUrl; }
public void setServiceUrl(String serviceUrl) { this.serviceUrl = serviceUrl; }
public List<String> getCapabilities() { return capabilities; }
public void setCapabilities(List<String> capabilities) { this.capabilities = capabilities; }
public Map<String, Object> getInputSchema() { return inputSchema; }
public void setInputSchema(Map<String, Object> inputSchema) { this.inputSchema = inputSchema; }
public Map<String, Object> getOutputSchema() { return outputSchema; }
public void setOutputSchema(Map<String, Object> outputSchema) { this.outputSchema = outputSchema; }
public boolean isStreamingSupport() { return streamingSupport; }
public void setStreamingSupport(boolean streamingSupport) { this.streamingSupport = streamingSupport; }
public String getHealthCheckEndpoint() { return healthCheckEndpoint; }
public void setHealthCheckEndpoint(String healthCheckEndpoint) { this.healthCheckEndpoint = healthCheckEndpoint; }
public String getStatus() { return status; }
public void setStatus(String status) { this.status = status; }
public LocalDateTime getLastHeartbeat() { return lastHeartbeat; }
public void setLastHeartbeat(LocalDateTime lastHeartbeat) { this.lastHeartbeat = lastHeartbeat; }
public LocalDateTime getRegisteredAt() { return registeredAt; }
public void setRegisteredAt(LocalDateTime registeredAt) { this.registeredAt = registeredAt; }
}

View File

@ -0,0 +1,195 @@
package com.example.demo.model;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
/**
* 执行流配置模型
* <p>
* 表示一个完整的执行流定义包含节点列表边关系上下文映射配置
* 以及执行流的基本元信息如名称描述创建时间等
* </p>
*/
public class ExecutionFlow {
/** 执行流唯一标识 */
private String id;
/** 执行流名称 */
private String name;
/** 执行流描述 */
private String description;
/** 关联项目 ID预留 */
private String projectId;
/** 节点列表 */
private List<FlowNode> nodes;
/** 边关系列表 */
private List<FlowEdge> edges;
/** 上下文映射配置 */
private Map<String, ContextMapping> contextMapping;
/** 创建时间 */
private LocalDateTime createdAt;
/** 更新时间 */
private LocalDateTime updatedAt;
public ExecutionFlow() {
}
/**
* 全参构造器
*
* @param id 执行流 ID
* @param name 名称
* @param description 描述
* @param nodes 节点列表
* @param edges 边关系列表
* @param contextMapping 上下文映射
*/
public ExecutionFlow(String id, String name, String description,
List<FlowNode> nodes, List<FlowEdge> edges,
Map<String, ContextMapping> contextMapping) {
this.id = id;
this.name = name;
this.description = description;
this.nodes = nodes;
this.edges = edges;
this.contextMapping = contextMapping;
this.createdAt = LocalDateTime.now();
this.updatedAt = LocalDateTime.now();
}
// ---------- Getters / Setters ----------
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
public String getProjectId() { return projectId; }
public void setProjectId(String projectId) { this.projectId = projectId; }
public List<FlowNode> getNodes() { return nodes; }
public void setNodes(List<FlowNode> nodes) { this.nodes = nodes; }
public List<FlowEdge> getEdges() { return edges; }
public void setEdges(List<FlowEdge> edges) { this.edges = edges; }
public Map<String, ContextMapping> getContextMapping() { return contextMapping; }
public void setContextMapping(Map<String, ContextMapping> contextMapping) { this.contextMapping = contextMapping; }
public LocalDateTime getCreatedAt() { return createdAt; }
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
public LocalDateTime getUpdatedAt() { return updatedAt; }
public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; }
// ---------- 内部嵌套类 ----------
/**
* 执行流节点定义
*/
public static class FlowNode {
private String nodeId;
private String type; // agent_call, condition, merge
private String agentId;
private Map<String, Object> config;
private Position position;
public FlowNode() {}
public FlowNode(String nodeId, String type, String agentId, Map<String, Object> config) {
this.nodeId = nodeId;
this.type = type;
this.agentId = agentId;
this.config = config;
}
public String getNodeId() { return nodeId; }
public void setNodeId(String nodeId) { this.nodeId = nodeId; }
public String getType() { return type; }
public void setType(String type) { this.type = type; }
public String getAgentId() { return agentId; }
public void setAgentId(String agentId) { this.agentId = agentId; }
public Map<String, Object> getConfig() { return config; }
public void setConfig(Map<String, Object> config) { this.config = config; }
public Position getPosition() { return position; }
public void setPosition(Position position) { this.position = position; }
}
/**
* 节点位置坐标
*/
public static class Position {
private double x;
private double y;
public Position() {}
public Position(double x, double y) {
this.x = x;
this.y = y;
}
public double getX() { return x; }
public void setX(double x) { this.x = x; }
public double getY() { return y; }
public void setY(double y) { this.y = y; }
}
/**
* 执行流边关系定义
*/
public static class FlowEdge {
private String source;
private String target;
public FlowEdge() {}
public FlowEdge(String source, String target) {
this.source = source;
this.target = target;
}
public String getSource() { return source; }
public void setSource(String source) { this.source = source; }
public String getTarget() { return target; }
public void setTarget(String target) { this.target = target; }
}
/**
* 节点上下文映射配置
*/
public static class ContextMapping {
private String inputFrom;
public ContextMapping() {}
public ContextMapping(String inputFrom) {
this.inputFrom = inputFrom;
}
public String getInputFrom() { return inputFrom; }
public void setInputFrom(String inputFrom) { this.inputFrom = inputFrom; }
}
}

View File

@ -0,0 +1,60 @@
package com.example.demo.model.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;
import java.util.Map;
/**
* 智能体注册请求 DTO
*/
@Schema(description = "智能体注册请求")
public class AgentRegisterRequest {
@Schema(description = "智能体唯一标识", example = "agent-code-gen-001")
private String id;
@Schema(description = "智能体名称", example = "代码生成智能体")
private String name;
@Schema(description = "版本号", example = "1.0.0")
private String version;
@Schema(description = "Web 服务地址", example = "http://service-host:8080")
private String serviceUrl;
@Schema(description = "能力标签列表", example = "[\"代码生成\", \"代码补全\"]")
private List<String> capabilities;
@Schema(description = "输入 SchemaJSON Schema")
private Map<String, Object> inputSchema;
@Schema(description = "输出 SchemaJSON Schema")
private Map<String, Object> outputSchema;
@Schema(description = "是否支持流式输出", example = "true")
private boolean streamingSupport;
@Schema(description = "健康检查端点", example = "/health")
private String healthCheckEndpoint;
// ---------- Getters / Setters ----------
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getVersion() { return version; }
public void setVersion(String version) { this.version = version; }
public String getServiceUrl() { return serviceUrl; }
public void setServiceUrl(String serviceUrl) { this.serviceUrl = serviceUrl; }
public List<String> getCapabilities() { return capabilities; }
public void setCapabilities(List<String> capabilities) { this.capabilities = capabilities; }
public Map<String, Object> getInputSchema() { return inputSchema; }
public void setInputSchema(Map<String, Object> inputSchema) { this.inputSchema = inputSchema; }
public Map<String, Object> getOutputSchema() { return outputSchema; }
public void setOutputSchema(Map<String, Object> outputSchema) { this.outputSchema = outputSchema; }
public boolean isStreamingSupport() { return streamingSupport; }
public void setStreamingSupport(boolean streamingSupport) { this.streamingSupport = streamingSupport; }
public String getHealthCheckEndpoint() { return healthCheckEndpoint; }
public void setHealthCheckEndpoint(String healthCheckEndpoint) { this.healthCheckEndpoint = healthCheckEndpoint; }
}

View File

@ -0,0 +1,88 @@
package com.example.demo.model.dto;
import java.time.LocalDateTime;
import java.util.Map;
/**
* 统一 API 响应封装
* <p>
* 所有接口返回的统一数据格式包含状态码消息时间戳和具体数据
* </p>
*
* @param <T> 数据类型
*/
public class ApiResponse<T> {
/** 状态码200 表示成功 */
private int code;
/** 提示消息 */
private String message;
/** 返回数据 */
private T data;
/** 响应时间戳 */
private LocalDateTime timestamp;
private ApiResponse() {
this.timestamp = LocalDateTime.now();
}
/**
* 创建成功响应
*
* @param data 数据对象
* @param <T> 数据类型
* @return 成功响应实例
*/
public static <T> ApiResponse<T> success(T data) {
ApiResponse<T> resp = new ApiResponse<>();
resp.code = 200;
resp.message = "success";
resp.data = data;
return resp;
}
/**
* 创建成功响应自定义消息
*
* @param message 自定义消息
* @param data 数据对象
* @param <T> 数据类型
* @return 成功响应实例
*/
public static <T> ApiResponse<T> success(String message, T data) {
ApiResponse<T> resp = new ApiResponse<>();
resp.code = 200;
resp.message = message;
resp.data = data;
return resp;
}
/**
* 创建失败响应
*
* @param code 错误码
* @param message 错误消息
* @param <T> 数据类型
* @return 失败响应实例
*/
public static <T> ApiResponse<T> error(int code, String message) {
ApiResponse<T> resp = new ApiResponse<>();
resp.code = code;
resp.message = message;
resp.data = null;
return resp;
}
// ---------- Getters ----------
public int getCode() { return code; }
public String getMessage() { return message; }
public T getData() { return data; }
public LocalDateTime getTimestamp() { return timestamp; }
}

View File

@ -0,0 +1,72 @@
package com.example.demo.model.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import java.time.LocalDateTime;
import java.util.Map;
/**
* 执行流执行结果 DTO
*/
@Schema(description = "执行结果")
public class ExecutionResult {
@Schema(description = "执行记录 ID", example = "exec-20260101-001")
private String executionId;
@Schema(description = "执行流 ID")
private String flowId;
@Schema(description = "执行状态", example = "running / completed / failed")
private String status;
@Schema(description = "当前执行节点")
private String currentNode;
@Schema(description = "开始时间")
private LocalDateTime startTime;
@Schema(description = "结束时间")
private LocalDateTime endTime;
@Schema(description = "节点输出数据")
private Map<String, Object> nodeOutputs;
@Schema(description = "错误信息")
private String errorMessage;
public ExecutionResult() {}
/**
* 创建执行中的结果
*
* @param executionId 执行 ID
* @param flowId 执行流 ID
* @param currentNode 当前节点
*/
public ExecutionResult(String executionId, String flowId, String currentNode) {
this.executionId = executionId;
this.flowId = flowId;
this.status = "running";
this.currentNode = currentNode;
this.startTime = LocalDateTime.now();
}
// ---------- Getters / Setters ----------
public String getExecutionId() { return executionId; }
public void setExecutionId(String executionId) { this.executionId = executionId; }
public String getFlowId() { return flowId; }
public void setFlowId(String flowId) { this.flowId = flowId; }
public String getStatus() { return status; }
public void setStatus(String status) { this.status = status; }
public String getCurrentNode() { return currentNode; }
public void setCurrentNode(String currentNode) { this.currentNode = currentNode; }
public LocalDateTime getStartTime() { return startTime; }
public void setStartTime(LocalDateTime startTime) { this.startTime = startTime; }
public LocalDateTime getEndTime() { return endTime; }
public void setEndTime(LocalDateTime endTime) { this.endTime = endTime; }
public Map<String, Object> getNodeOutputs() { return nodeOutputs; }
public void setNodeOutputs(Map<String, Object> nodeOutputs) { this.nodeOutputs = nodeOutputs; }
public String getErrorMessage() { return errorMessage; }
public void setErrorMessage(String errorMessage) { this.errorMessage = errorMessage; }
}

View File

@ -0,0 +1,28 @@
package com.example.demo.model.dto;
import io.swagger.v3.oas.annotations.media.Schema;
/**
* 执行流触发请求 DTO
*/
@Schema(description = "执行流触发请求")
public class FlowExecuteRequest {
@Schema(description = "执行流 ID", example = "flow-001")
private String flowId;
@Schema(description = "触发模式", example = "manual")
private String triggerMode;
@Schema(description = "触发人", example = "user-001")
private String triggeredBy;
// ---------- Getters / Setters ----------
public String getFlowId() { return flowId; }
public void setFlowId(String flowId) { this.flowId = flowId; }
public String getTriggerMode() { return triggerMode; }
public void setTriggerMode(String triggerMode) { this.triggerMode = triggerMode; }
public String getTriggeredBy() { return triggeredBy; }
public void setTriggeredBy(String triggeredBy) { this.triggeredBy = triggeredBy; }
}

View File

@ -0,0 +1,63 @@
package com.example.demo.service;
import com.example.demo.model.BusinessItem;
import java.util.List;
import java.util.Optional;
/**
* 智能体管理服务接口
* <p>
* 提供智能体的注册注销查询心跳更新等核心操作
* 后续可扩展为对接数据库或远程注册中心的实现
* </p>
*/
public interface BusinessService {
/**
* 注册一个新的智能体
*
* @param item 智能体元数据
* @return 注册成功的智能体
*/
BusinessItem register(BusinessItem item);
/**
* 注销指定 ID 的智能体
*
* @param id 智能体唯一标识
* @return 如果找到并注销返回 true否则 false
*/
boolean unregister(String id);
/**
* 根据 ID 查询智能体
*
* @param id 智能体唯一标识
* @return 包含智能体的 Optional
*/
Optional<BusinessItem> findById(String id);
/**
* 查询所有已注册的智能体
*
* @return 智能体列表
*/
List<BusinessItem> findAll();
/**
* 根据能力标签查询智能体
*
* @param capability 能力标签
* @return 匹配的智能体列表
*/
List<BusinessItem> findByCapability(String capability);
/**
* 更新指定智能体的心跳时间
*
* @param id 智能体唯一标识
* @return 更新成功返回 true否则 false
*/
boolean updateHeartbeat(String id);
}

View File

@ -0,0 +1,69 @@
package com.example.demo.service;
import com.example.demo.model.BusinessItem;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;
/**
* 智能体管理服务实现基于内存存储
* <p>
* 使用 {@link ConcurrentHashMap} 在内存中维护智能体注册信息
* 适用于功能验证与开发阶段后续可扩展为基于数据库或注册中心的实现
* </p>
*/
@Service
public class BusinessServiceImpl implements BusinessService {
/** 内存存储key = 智能体 ID, value = 智能体元数据 */
private final ConcurrentHashMap<String, BusinessItem> agentStore = new ConcurrentHashMap<>();
@Override
public BusinessItem register(BusinessItem item) {
item.setStatus("active");
item.setRegisteredAt(LocalDateTime.now());
item.setLastHeartbeat(LocalDateTime.now());
agentStore.put(item.getId(), item);
return item;
}
@Override
public boolean unregister(String id) {
return agentStore.remove(id) != null;
}
@Override
public Optional<BusinessItem> findById(String id) {
return Optional.ofNullable(agentStore.get(id));
}
@Override
public List<BusinessItem> findAll() {
return new ArrayList<>(agentStore.values());
}
@Override
public List<BusinessItem> findByCapability(String capability) {
return agentStore.values().stream()
.filter(agent -> agent.getCapabilities() != null
&& agent.getCapabilities().stream()
.anyMatch(cap -> cap.equalsIgnoreCase(capability)))
.collect(Collectors.toList());
}
@Override
public boolean updateHeartbeat(String id) {
BusinessItem agent = agentStore.get(id);
if (agent == null) {
return false;
}
agent.setLastHeartbeat(LocalDateTime.now());
return true;
}
}

View File

@ -0,0 +1,70 @@
package com.example.demo.service;
import com.example.demo.model.ExecutionFlow;
import com.example.demo.model.dto.ExecutionResult;
import java.util.List;
import java.util.Optional;
/**
* 执行流管理服务接口
* <p>
* 提供执行流的创建查询删除以及执行触发等核心操作
* 后续可扩展为支持持久化存储与分布式调度引擎
* </p>
*/
public interface FlowService {
/**
* 创建新的执行流配置
*
* @param flow 执行流配置
* @return 创建成功的执行流
*/
ExecutionFlow createFlow(ExecutionFlow flow);
/**
* 根据 ID 查询执行流
*
* @param id 执行流 ID
* @return 包含执行流的 Optional
*/
Optional<ExecutionFlow> getFlow(String id);
/**
* 查询所有执行流
*
* @return 执行流列表
*/
List<ExecutionFlow> listFlows();
/**
* 删除指定 ID 的执行流
*
* @param id 执行流 ID
* @return 如果找到并删除返回 true否则 false
*/
boolean deleteFlow(String id);
/**
* 触发执行流运行
* <p>
* 当前为模拟实现返回执行中的结果
* 后续将对接拓扑排序 + 线程池调度引擎进行真实执行
* </p>
*
* @param flowId 执行流 ID
* @param triggeredBy 触发人
* @param triggerMode 触发模式
* @return 执行结果包含执行 ID 与状态
*/
ExecutionResult executeFlow(String flowId, String triggeredBy, String triggerMode);
/**
* 查询执行结果
*
* @param executionId 执行记录 ID
* @return 执行结果
*/
Optional<ExecutionResult> getExecutionResult(String executionId);
}

View File

@ -0,0 +1,99 @@
package com.example.demo.service;
import com.example.demo.model.ExecutionFlow;
import com.example.demo.model.dto.ExecutionResult;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 执行流管理服务实现基于内存存储
* <p>
* 使用 {@link ConcurrentHashMap} 在内存中维护执行流配置与执行记录
* 当前 executeFlow 为模拟实现仅演示执行流触发流程
* </p>
*/
@Service
public class FlowServiceImpl implements FlowService {
/** 执行流存储key = flow ID */
private final ConcurrentHashMap<String, ExecutionFlow> flowStore = new ConcurrentHashMap<>();
/** 执行结果存储key = execution ID */
private final ConcurrentHashMap<String, ExecutionResult> executionStore = new ConcurrentHashMap<>();
/** 自增执行计数器 */
private final AtomicInteger execCounter = new AtomicInteger(0);
@Override
public ExecutionFlow createFlow(ExecutionFlow flow) {
flow.setCreatedAt(LocalDateTime.now());
flow.setUpdatedAt(LocalDateTime.now());
flowStore.put(flow.getId(), flow);
return flow;
}
@Override
public Optional<ExecutionFlow> getFlow(String id) {
return Optional.ofNullable(flowStore.get(id));
}
@Override
public List<ExecutionFlow> listFlows() {
return new ArrayList<>(flowStore.values());
}
@Override
public boolean deleteFlow(String id) {
return flowStore.remove(id) != null;
}
@Override
public ExecutionResult executeFlow(String flowId, String triggeredBy, String triggerMode) {
ExecutionFlow flow = flowStore.get(flowId);
if (flow == null) {
ExecutionResult err = new ExecutionResult();
err.setExecutionId("err-" + execCounter.incrementAndGet());
err.setFlowId(flowId);
err.setStatus("failed");
err.setErrorMessage("执行流未找到: " + flowId);
err.setStartTime(LocalDateTime.now());
err.setEndTime(LocalDateTime.now());
return err;
}
// 模拟执行过程
String execId = "exec-" + System.currentTimeMillis();
ExecutionResult result = new ExecutionResult(execId, flowId,
flow.getNodes() != null && !flow.getNodes().isEmpty()
? flow.getNodes().get(0).getNodeId()
: null);
// 模拟短暂延迟后标记为完成
// 真实场景应异步执行此处同步模拟
Map<String, Object> mockOutputs = new LinkedHashMap<>();
if (flow.getNodes() != null) {
for (ExecutionFlow.FlowNode node : flow.getNodes()) {
Map<String, Object> nodeResult = new LinkedHashMap<>();
nodeResult.put("status", "simulated_ok");
nodeResult.put("message", "节点 " + node.getNodeId() + " 模拟执行完成");
mockOutputs.put(node.getNodeId(), nodeResult);
}
}
result.setNodeOutputs(mockOutputs);
result.setStatus("completed");
result.setEndTime(LocalDateTime.now());
executionStore.put(execId, result);
return result;
}
@Override
public Optional<ExecutionResult> getExecutionResult(String executionId) {
return Optional.ofNullable(executionStore.get(executionId));
}
}

View File

@ -0,0 +1,17 @@
server:
port: 8080
spring:
application:
name: multi-agent-platform
springdoc:
swagger-ui:
path: /swagger-ui.html
api-docs:
path: /v3/api-docs
knife4j:
enable: true
setting:
language: zh-CN

View File

@ -0,0 +1,105 @@
package com.example.demo;
import com.example.demo.model.BusinessItem;
import com.example.demo.service.BusinessService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.*;
/**
* 智能体管理服务单元测试
* <p>
* 验证 BusinessService 的注册注销查询和心跳更新等核心功能
* </p>
*/
@SpringBootTest
class BusinessServiceTest {
@Autowired
private BusinessService businessService;
/**
* 每个测试前清理数据由于是内存存储重建上下文即可
*/
@BeforeEach
void setUp() {
// 当前内存实现在 Spring 上下文重启后自动清空
}
@Test
void testRegisterAndFindById() {
BusinessItem item = createTestAgent("agent-test-001", "测试智能体", "代码生成");
BusinessItem registered = businessService.register(item);
assertNotNull(registered);
assertEquals("active", registered.getStatus());
Optional<BusinessItem> found = businessService.findById("agent-test-001");
assertTrue(found.isPresent());
assertEquals("测试智能体", found.get().getName());
}
@Test
void testUnregister() {
BusinessItem item = createTestAgent("agent-test-002", "临时智能体", "文档生成");
businessService.register(item);
boolean removed = businessService.unregister("agent-test-002");
assertTrue(removed);
Optional<BusinessItem> found = businessService.findById("agent-test-002");
assertFalse(found.isPresent());
}
@Test
void testFindAll() {
businessService.register(createTestAgent("agent-test-003", "智能体A", "代码生成"));
businessService.register(createTestAgent("agent-test-004", "智能体B", "测试验证"));
List<BusinessItem> all = businessService.findAll();
assertTrue(all.size() >= 2);
}
@Test
void testFindByCapability() {
businessService.register(createTestAgent("agent-test-005", "代码生成器", "代码生成"));
businessService.register(createTestAgent("agent-test-006", "测试验证器", "测试验证"));
List<BusinessItem> result = businessService.findByCapability("代码生成");
assertTrue(result.stream().anyMatch(a -> a.getName().equals("代码生成器")));
}
@Test
void testUpdateHeartbeat() {
businessService.register(createTestAgent("agent-test-007", "心跳测试", "通用"));
boolean updated = businessService.updateHeartbeat("agent-test-007");
assertTrue(updated);
boolean notFound = businessService.updateHeartbeat("non-existent");
assertFalse(notFound);
}
/**
* 创建测试用的智能体对象
*/
private BusinessItem createTestAgent(String id, String name, String capability) {
return new BusinessItem(
id,
name,
"1.0.0",
"http://localhost:8081",
List.of(capability),
null,
null,
true,
"/health",
"active"
);
}
}

View File

@ -0,0 +1,16 @@
package com.example.demo;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
/**
* 应用启动测试
*/
@SpringBootTest
class DemoApplicationTests {
@Test
void contextLoads() {
// 验证 Spring 上下文能正常加载
}
}