Files
urbanLifeline/.kiro/specs/urbanlifeline-to-pigx-migration/pigx-dify-architecture.md
2026-01-14 15:42:26 +08:00

756 lines
21 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# pigx-dify 模块架构设计
## 1. 模块概述
### 1.1 定位
pigx-dify 是 pigx 平台的 AI 服务模块,专门用于集成 Dify AI 平台,提供智能体管理、知识库管理和 AI 对话功能。
### 1.2 核心功能
- 智能体Agent管理
- 知识库Knowledge管理
- AI 对话Chat功能
- Dify API 集成
- 流式响应支持SSE
### 1.3 技术栈
- Spring Boot 3.5.8
- Spring Cloud 2025.0.0
- MyBatis-Plus 3.5.14
- MySQL 8.0
- Dify API Client
- SSE (Server-Sent Events)
## 2. 模块结构
### 2.1 Maven 项目结构
```xml
<!-- pigx-dify/pom.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx</artifactId>
<version>6.4.0</version>
</parent>
<artifactId>pigx-dify</artifactId>
<packaging>pom</packaging>
<description>Dify AI integration module</description>
<modules>
<module>pigx-dify-api</module>
<module>pigx-dify-biz</module>
</modules>
</project>
```
### 2.2 pigx-dify-api 结构
```xml
<!-- pigx-dify-api/pom.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
<parent>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-dify</artifactId>
<version>6.4.0</version>
</parent>
<artifactId>pigx-dify-api</artifactId>
<description>Dify API interfaces and entities</description>
<dependencies>
<dependency>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-common-core</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-annotation</artifactId>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-api</artifactId>
</dependency>
</dependencies>
</project>
```
### 2.3 pigx-dify-biz 结构
```xml
<!-- pigx-dify-biz/pom.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
<parent>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-dify</artifactId>
<version>6.4.0</version>
</parent>
<artifactId>pigx-dify-biz</artifactId>
<description>Dify business implementation</description>
<dependencies>
<!-- pigx dependencies -->
<dependency>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-dify-api</artifactId>
</dependency>
<dependency>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-common-security</artifactId>
</dependency>
<dependency>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-common-log</artifactId>
</dependency>
<dependency>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-common-mybatis</artifactId>
</dependency>
<dependency>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-common-swagger</artifactId>
</dependency>
<!-- Spring Boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
<!-- Spring Cloud -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- HTTP Client for Dify API -->
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webflux</artifactId>
</dependency>
<!-- SSE Support -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
```
## 3. 包结构设计
### 3.1 pigx-dify-api 包结构
```
pigx-dify-api/
└── src/main/java/com/pig4cloud/pigx/dify/api/
├── entity/ # 实体类
│ ├── TbAgent.java # 智能体
│ ├── TbChat.java # 聊天会话
│ ├── TbChatMessage.java # 聊天消息
│ └── TbKnowledge.java # 知识库
├── dto/ # 数据传输对象
│ ├── AgentDTO.java
│ ├── ChatDTO.java
│ ├── ChatMessageDTO.java
│ └── KnowledgeDTO.java
├── vo/ # 视图对象
│ ├── AgentVO.java
│ ├── ChatVO.java
│ └── KnowledgeVO.java
├── feign/ # Feign接口
│ └── RemoteDifyService.java
└── constant/ # 常量定义
└── DifyConstant.java
```
### 3.2 pigx-dify-biz 包结构
```
pigx-dify-biz/
└── src/main/java/com/pig4cloud/pigx/dify/
├── DifyApplication.java # 启动类
├── config/ # 配置类
│ ├── DifyConfig.java # Dify配置
│ ├── WebConfig.java # Web配置
│ └── AsyncConfig.java # 异步配置
├── controller/ # 控制器
│ ├── AgentController.java # 智能体管理
│ ├── ChatController.java # 对话管理
│ └── KnowledgeController.java # 知识库管理
├── service/ # 服务层
│ ├── AgentService.java
│ ├── ChatService.java
│ ├── KnowledgeService.java
│ └── impl/
│ ├── AgentServiceImpl.java
│ ├── ChatServiceImpl.java
│ └── KnowledgeServiceImpl.java
├── mapper/ # 数据访问层
│ ├── AgentMapper.java
│ ├── ChatMapper.java
│ ├── ChatMessageMapper.java
│ └── KnowledgeMapper.java
├── client/ # 外部API客户端
│ ├── DifyApiClient.java # Dify API客户端
│ ├── dto/ # Dify API DTO
│ │ ├── DifyRequest.java
│ │ └── DifyResponse.java
│ └── callback/
│ └── StreamCallback.java # 流式回调
└── handler/ # 处理器
├── SseHandler.java # SSE处理
└── GlobalExceptionHandler.java # 全局异常处理
```
## 4. 核心代码设计
### 4.1 启动类
```java
package com.pig4cloud.pigx.dify;
import com.pig4cloud.pigx.common.feign.annotation.EnablePigxFeignClients;
import com.pig4cloud.pigx.common.security.annotation.EnablePigxResourceServer;
import com.pig4cloud.pigx.common.swagger.annotation.EnablePigxDoc;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@EnablePigxDoc
@EnablePigxResourceServer
@EnablePigxFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class DifyApplication {
public static void main(String[] args) {
SpringApplication.run(DifyApplication.class, args);
}
}
```
### 4.2 配置类
```java
package com.pig4cloud.pigx.dify.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Data
@Configuration
@ConfigurationProperties(prefix = "dify")
public class DifyConfig {
/**
* Dify API基础URL
*/
private String apiBaseUrl = "https://api.dify.ai/v1";
/**
* 默认API Key可被智能体配置覆盖
*/
private String defaultApiKey;
/**
* 连接超时(毫秒)
*/
private Integer connectTimeout = 10000;
/**
* 读取超时(毫秒)
*/
private Integer readTimeout = 30000;
/**
* 流式响应超时(毫秒)
*/
private Integer streamTimeout = 60000;
/**
* 是否启用调试日志
*/
private Boolean debug = false;
}
```
### 4.3 实体设计
```java
package com.pig4cloud.pigx.dify.api.entity;
import com.baomidou.mybatisplus.annotation.*;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.time.LocalDateTime;
@Data
@TableName("tb_agent")
@EqualsAndHashCode(callSuper = true)
public class TbAgent extends Model<TbAgent> {
@TableId(type = IdType.ASSIGN_UUID)
private String agentId;
private String name;
private String description;
private String difyApiKey;
private String difyAgentId;
private String config; // JSON配置
private String icon;
private Integer status; // 0:禁用 1:启用
@TableField(fill = FieldFill.INSERT)
private Long tenantId;
@TableField(fill = FieldFill.INSERT)
private String createBy;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.UPDATE)
private String updateBy;
@TableField(fill = FieldFill.UPDATE)
private LocalDateTime updateTime;
@TableLogic
private Integer delFlag;
}
```
### 4.4 Controller设计
```java
package com.pig4cloud.pigx.dify.controller;
import com.pig4cloud.pigx.common.core.util.R;
import com.pig4cloud.pigx.common.security.annotation.Inner;
import com.pig4cloud.pigx.common.security.util.SecurityUtils;
import com.pig4cloud.pigx.dify.api.dto.ChatDTO;
import com.pig4cloud.pigx.dify.service.ChatService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
@RestController
@RequiredArgsConstructor
@RequestMapping("/chat")
@Tag(name = "对话管理")
public class ChatController {
private final ChatService chatService;
@Operation(summary = "创建对话")
@PostMapping
@PreAuthorize("@pms.hasPermission('dify_chat_add')")
public R<ChatDTO> createChat(@RequestBody ChatDTO chatDTO) {
chatDTO.setUserId(SecurityUtils.getUser().getId());
chatDTO.setTenantId(SecurityUtils.getUser().getTenantId());
return R.ok(chatService.createChat(chatDTO));
}
@Operation(summary = "流式对话")
@PostMapping("/stream/{chatId}")
@PreAuthorize("@pms.hasPermission('dify_chat_message')")
public SseEmitter streamChat(@PathVariable String chatId,
@RequestBody String message) {
return chatService.streamChat(chatId, message, SecurityUtils.getUser());
}
@Operation(summary = "获取对话历史")
@GetMapping("/{chatId}/messages")
@PreAuthorize("@pms.hasPermission('dify_chat_view')")
public R<?> getChatMessages(@PathVariable String chatId) {
return R.ok(chatService.getChatMessages(chatId));
}
}
```
## 5. 数据库设计
### 5.1 数据表DDL
```sql
-- 智能体表
CREATE TABLE `tb_agent` (
`agent_id` varchar(36) NOT NULL COMMENT '智能体ID',
`name` varchar(100) NOT NULL COMMENT '名称',
`description` varchar(500) DEFAULT NULL COMMENT '描述',
`dify_api_key` varchar(255) DEFAULT NULL COMMENT 'Dify API Key',
`dify_agent_id` varchar(100) DEFAULT NULL COMMENT 'Dify Agent ID',
`config` text COMMENT '配置信息(JSON)',
`icon` varchar(255) DEFAULT NULL COMMENT '图标',
`status` tinyint DEFAULT '1' COMMENT '状态 0:禁用 1:启用',
`tenant_id` bigint NOT NULL DEFAULT '1' COMMENT '租户ID',
`create_by` varchar(64) DEFAULT NULL COMMENT '创建人',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_by` varchar(64) DEFAULT NULL COMMENT '更新人',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`del_flag` char(1) DEFAULT '0' COMMENT '删除标记',
PRIMARY KEY (`agent_id`),
KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='智能体表';
-- 聊天会话表
CREATE TABLE `tb_chat` (
`chat_id` varchar(36) NOT NULL COMMENT '会话ID',
`agent_id` varchar(36) NOT NULL COMMENT '智能体ID',
`user_id` bigint NOT NULL COMMENT '用户ID',
`title` varchar(200) DEFAULT NULL COMMENT '会话标题',
`conversation_id` varchar(100) DEFAULT NULL COMMENT 'Dify会话ID',
`status` tinyint DEFAULT '1' COMMENT '状态 0:关闭 1:活跃',
`tenant_id` bigint NOT NULL DEFAULT '1' COMMENT '租户ID',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`del_flag` char(1) DEFAULT '0' COMMENT '删除标记',
PRIMARY KEY (`chat_id`),
KEY `idx_user_id` (`user_id`),
KEY `idx_agent_id` (`agent_id`),
KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='聊天会话表';
-- 聊天消息表
CREATE TABLE `tb_chat_message` (
`message_id` varchar(36) NOT NULL COMMENT '消息ID',
`chat_id` varchar(36) NOT NULL COMMENT '会话ID',
`content` text NOT NULL COMMENT '消息内容',
`role` varchar(20) NOT NULL COMMENT '角色(user/ai/system)',
`dify_message_id` varchar(100) DEFAULT NULL COMMENT 'Dify消息ID',
`parent_message_id` varchar(36) DEFAULT NULL COMMENT '父消息ID',
`metadata` text COMMENT '元数据(JSON)',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`message_id`),
KEY `idx_chat_id` (`chat_id`),
KEY `idx_create_time` (`create_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='聊天消息表';
-- 知识库表
CREATE TABLE `tb_knowledge` (
`knowledge_id` varchar(36) NOT NULL COMMENT '知识库ID',
`title` varchar(200) NOT NULL COMMENT '标题',
`description` text COMMENT '描述',
`dify_dataset_id` varchar(100) DEFAULT NULL COMMENT 'Dify数据集ID',
`status` tinyint DEFAULT '1' COMMENT '状态 0:禁用 1:启用',
`tenant_id` bigint NOT NULL DEFAULT '1' COMMENT '租户ID',
`create_by` varchar(64) DEFAULT NULL COMMENT '创建人',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_by` varchar(64) DEFAULT NULL COMMENT '更新人',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`del_flag` char(1) DEFAULT '0' COMMENT '删除标记',
PRIMARY KEY (`knowledge_id`),
KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='知识库表';
```
## 6. 配置文件
### 6.1 bootstrap.yml
```yaml
server:
port: 9500
spring:
application:
name: @project.artifactId@
profiles:
active: @profiles.active@
cloud:
nacos:
discovery:
server-addr: ${NACOS_HOST:pigx-register}:${NACOS_PORT:8848}
config:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
file-extension: yml
shared-configs:
- data-id: common.yml
refresh: true
- data-id: db.yml
refresh: true
```
### 6.2 application.yml
```yaml
# Dify配置
dify:
api-base-url: ${DIFY_API_BASE_URL:https://api.dify.ai/v1}
default-api-key: ${DIFY_DEFAULT_API_KEY:}
connect-timeout: 10000
read-timeout: 30000
stream-timeout: 60000
debug: false
# MyBatis-Plus配置
mybatis-plus:
mapper-locations: classpath:/mapper/*.xml
type-aliases-package: com.pig4cloud.pigx.dify.api.entity
configuration:
map-underscore-to-camel-case: true
# 安全配置
security:
oauth2:
resource:
ignore-urls:
- /actuator/**
- /v3/api-docs/**
```
## 7. 服务注册
### 7.1 路由配置
在 pigx-gateway 中添加路由:
```yaml
spring:
cloud:
gateway:
routes:
- id: pigx-dify
uri: lb://pigx-dify
predicates:
- Path=/dify/**
filters:
- StripPrefix=1
```
### 7.2 Feign配置
```java
package com.pig4cloud.pigx.dify.api.feign;
import com.pig4cloud.pigx.common.core.constant.ServiceNameConstants;
import com.pig4cloud.pigx.common.core.util.R;
import com.pig4cloud.pigx.dify.api.dto.ChatDTO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(contextId = "remoteDifyService",
value = ServiceNameConstants.DIFY_SERVICE)
public interface RemoteDifyService {
@GetMapping("/chat/{chatId}")
R<ChatDTO> getChatInfo(@PathVariable("chatId") String chatId);
}
```
## 8. 部署配置
### 8.1 Docker配置
```dockerfile
FROM pig4cloud/java:8-jre
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
COPY target/pigx-dify-biz.jar /app.jar
ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/app.jar"]
```
### 8.2 K8s部署
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: pigx-dify
namespace: pigx
spec:
replicas: 1
selector:
matchLabels:
app: pigx-dify
template:
metadata:
labels:
app: pigx-dify
spec:
containers:
- name: pigx-dify
image: pigx/pigx-dify:latest
ports:
- containerPort: 9500
env:
- name: NACOS_HOST
value: "pigx-register"
- name: DIFY_API_BASE_URL
value: "https://api.dify.ai/v1"
- name: DIFY_DEFAULT_API_KEY
valueFrom:
secretKeyRef:
name: dify-secret
key: api-key
```
## 9. 集成测试
### 9.1 单元测试
```java
@SpringBootTest
class ChatServiceTest {
@Autowired
private ChatService chatService;
@MockBean
private DifyApiClient difyApiClient;
@Test
void testCreateChat() {
// 测试创建对话
ChatDTO chatDTO = new ChatDTO();
chatDTO.setAgentId("test-agent");
chatDTO.setUserId(1L);
ChatDTO result = chatService.createChat(chatDTO);
assertNotNull(result.getChatId());
}
}
```
### 9.2 API测试
```http
### 创建对话
POST http://localhost:9999/dify/chat
Authorization: Bearer {{token}}
Content-Type: application/json
{
"agentId": "agent-001",
"title": "测试对话"
}
### 发送消息(流式)
POST http://localhost:9999/dify/chat/stream/{{chatId}}
Authorization: Bearer {{token}}
Content-Type: text/plain
你好,请介绍一下自己
```
## 10. 监控告警
### 10.1 健康检查
```java
@Component
public class DifyHealthIndicator implements HealthIndicator {
@Autowired
private DifyApiClient difyApiClient;
@Override
public Health health() {
try {
// 检查Dify API连通性
boolean isHealthy = difyApiClient.checkHealth();
if (isHealthy) {
return Health.up()
.withDetail("dify", "Available")
.build();
}
} catch (Exception e) {
return Health.down()
.withDetail("dify", "Unavailable")
.withException(e)
.build();
}
return Health.down().build();
}
}
```
### 10.2 日志配置
```xml
<!-- logback-spring.xml -->
<configuration>
<logger name="com.pig4cloud.pigx.dify" level="INFO"/>
<logger name="com.pig4cloud.pigx.dify.client" level="DEBUG"/>
</configuration>
```
## 11. 安全考虑
### 11.1 API Key管理
- API Key 加密存储
- 支持多租户隔离
- 定期轮换机制
### 11.2 数据隔离
- 租户级别数据隔离
- 用户权限验证
- 敏感信息脱敏
### 11.3 限流配置
```java
@Configuration
public class RateLimitConfig {
@Bean
public RedisRateLimiter redisRateLimiter() {
return new RedisRateLimiter(10, 20); // 10 requests per second
}
}
```
## 12. 迁移清单
- [ ] 创建 Maven 模块结构
- [ ] 迁移实体类和 Mapper
- [ ] 迁移 Service 层业务逻辑
- [ ] 迁移 Controller 层接口
- [ ] 适配权限注解
- [ ] 迁移 DifyApiClient
- [ ] 配置服务注册和发现
- [ ] 数据库表结构迁移
- [ ] 前端页面迁移
- [ ] 集成测试
- [ ] 部署配置