# 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
4.0.0
com.pig4cloud
pigx
6.4.0
pigx-dify
pom
Dify AI integration module
pigx-dify-api
pigx-dify-biz
```
### 2.2 pigx-dify-api 结构
```xml
com.pig4cloud
pigx-dify
6.4.0
pigx-dify-api
Dify API interfaces and entities
com.pig4cloud
pigx-common-core
com.baomidou
mybatis-plus-annotation
org.springdoc
springdoc-openapi-starter-webmvc-api
```
### 2.3 pigx-dify-biz 结构
```xml
com.pig4cloud
pigx-dify
6.4.0
pigx-dify-biz
Dify business implementation
com.pig4cloud
pigx-dify-api
com.pig4cloud
pigx-common-security
com.pig4cloud
pigx-common-log
com.pig4cloud
pigx-common-mybatis
com.pig4cloud
pigx-common-swagger
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-undertow
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-config
org.apache.httpcomponents.client5
httpclient5
org.springframework
spring-webflux
org.springframework.boot
spring-boot-starter-webflux
org.springframework.boot
spring-boot-maven-plugin
```
## 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 {
@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 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 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
```
## 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
- [ ] 配置服务注册和发现
- [ ] 数据库表结构迁移
- [ ] 前端页面迁移
- [ ] 集成测试
- [ ] 部署配置