# 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 - [ ] 配置服务注册和发现 - [ ] 数据库表结构迁移 - [ ] 前端页面迁移 - [ ] 集成测试 - [ ] 部署配置