创建一个使用Spring AI配合Dify构建的代码生成工具实例

创建一个使用Spring AI配合Dify构建的代码生成工具实例。这个例子将展示如何集成Dify的API来实现代码生成功能。

项目结构

css 复制代码
code-generator/
├── src/main/java/
│   └── com/example/codegen/
│       ├── CodeGeneratorApplication.java
│       ├── controller/CodeGeneratorController.java
│       ├── service/CodeGeneratorService.java
│       ├── config/DifyConfig.java
│       └── dto/
│           ├── CodeGenerationRequest.java
│           └── CodeGenerationResponse.java
├── src/main/resources/
│   └── application.yml
└── pom.xml

1. Maven依赖配置 (pom.xml)

xml 复制代码
<?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 
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    
    <groupId>com.example</groupId>
    <artifactId>code-generator</artifactId>
    <version>1.0.0</version>
    <packaging>jar</packaging>
    
    <name>Code Generator with Spring AI and Dify</name>
    <description>Code generation tool using Spring AI and Dify</description>
    
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.0</version>
        <relativePath/>
    </parent>
    
    <properties>
        <java.version>17</java.version>
        <spring-ai.version>0.8.1</spring-ai.version>
    </properties>
    
    <dependencies>
        <!-- Spring Boot Starters -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
        
        <!-- Spring AI -->
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-core</artifactId>
            <version>${spring-ai.version}</version>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
            <version>${spring-ai.version}</version>
        </dependency>
        
        <!-- HTTP Client for Dify API -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
        
        <!-- JSON Processing -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>
        
        <!-- Lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        
        <!-- Test Dependencies -->
        <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>
            </plugin>
        </plugins>
    </build>
</project>

2. 应用配置 (application.yml)

yaml 复制代码
server:
  port: 8080

spring:
  application:
    name: code-generator
  ai:
    openai:
      api-key: ${OPENAI_API_KEY:your-openai-api-key}
      chat:
        options:
          model: gpt-3.5-turbo
          temperature: 0.7

# Dify配置
dify:
  api:
    base-url: ${DIFY_API_BASE_URL:https://api.dify.ai/v1}
    key: ${DIFY_API_KEY:your-dify-api-key}
    app-id: ${DIFY_APP_ID:your-dify-app-id}
    timeout: 30000

logging:
  level:
    com.example.codegen: DEBUG
    org.springframework.ai: DEBUG

3. 主应用类

java 复制代码
package com.example.codegen;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

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

4. Dify配置类

java 复制代码
package com.example.codegen.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.WebClient;

import java.time.Duration;

@Configuration
@ConfigurationProperties(prefix = "dify")
@Data
public class DifyConfig {
    
    private Api api = new Api();
    
    @Data
    public static class Api {
        private String baseUrl;
        private String key;
        private String appId;
        private int timeout = 30000;
    }
    
    @Bean
    public WebClient difyWebClient() {
        return WebClient.builder()
                .baseUrl(api.getBaseUrl())
                .defaultHeader("Authorization", "Bearer " + api.getKey())
                .defaultHeader("Content-Type", "application/json")
                .codecs(configurer -> configurer
                        .defaultCodecs()
                        .maxInMemorySize(1024 * 1024)) // 1MB
                .build();
    }
}

5. 数据传输对象

java 复制代码
// CodeGenerationRequest.java
package com.example.codegen.dto;

import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;

@Data
public class CodeGenerationRequest {
    
    @NotBlank(message = "需求描述不能为空")
    @Size(max = 1000, message = "需求描述长度不能超过1000字符")
    private String requirement;
    
    private String language = "java"; // 默认Java
    
    private String framework; // 可选框架
    
    private String additionalContext; // 额外上下文信息
    
    private boolean includeComments = true; // 是否包含注释
    
    private boolean includeTests = false; // 是否生成测试代码
}
// CodeGenerationResponse.java
package com.example.codegen.dto;

import lombok.Data;
import lombok.Builder;
import java.time.LocalDateTime;
import java.util.List;

@Data
@Builder
public class CodeGenerationResponse {
    
    private String code;
    
    private String explanation;
    
    private List<String> suggestions;
    
    private String language;
    
    private String framework;
    
    private LocalDateTime generatedAt;
    
    private String conversationId; // Dify对话ID
    
    private boolean success;
    
    private String errorMessage;
}

6. 代码生成服务

java 复制代码
package com.example.codegen.service;

import com.example.codegen.config.DifyConfig;
import com.example.codegen.dto.CodeGenerationRequest;
import com.example.codegen.dto.CodeGenerationResponse;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.prompt.PromptTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;

@Service
@Slf4j
@RequiredArgsConstructor
public class CodeGeneratorService {
    
    private final ChatClient chatClient;
    private final WebClient difyWebClient;
    private final DifyConfig difyConfig;
    private final ObjectMapper objectMapper = new ObjectMapper();
    
    /**
     * 使用Dify API生成代码
     */
    public Mono<CodeGenerationResponse> generateCodeWithDify(CodeGenerationRequest request) {
        log.info("开始使用Dify生成代码,需求: {}", request.getRequirement());
        
        // 构建Dify请求体
        Map<String, Object> difyRequest = buildDifyRequest(request);
        
        return difyWebClient
                .post()
                .uri("/chat-messages")
                .bodyValue(difyRequest)
                .retrieve()
                .bodyToMono(String.class)
                .timeout(Duration.ofMillis(difyConfig.getApi().getTimeout()))
                .map(response -> parseDifyResponse(response, request))
                .onErrorResume(throwable -> {
                    log.error("Dify API调用失败", throwable);
                    return Mono.just(CodeGenerationResponse.builder()
                            .success(false)
                            .errorMessage("代码生成失败: " + throwable.getMessage())
                            .generatedAt(LocalDateTime.now())
                            .build());
                });
    }
    
    /**
     * 使用Spring AI生成代码(备用方案)
     */
    public CodeGenerationResponse generateCodeWithSpringAI(CodeGenerationRequest request) {
        log.info("使用Spring AI生成代码,需求: {}", request.getRequirement());
        
        try {
            String promptText = buildPromptForSpringAI(request);
            PromptTemplate promptTemplate = new PromptTemplate(promptText);
            Prompt prompt = promptTemplate.create();
            
            ChatResponse response = chatClient.call(prompt);
            String generatedCode = response.getResult().getOutput().getContent();
            
            return CodeGenerationResponse.builder()
                    .code(extractCode(generatedCode))
                    .explanation(extractExplanation(generatedCode))
                    .suggestions(extractSuggestions(generatedCode))
                    .language(request.getLanguage())
                    .framework(request.getFramework())
                    .generatedAt(LocalDateTime.now())
                    .success(true)
                    .build();
                    
        } catch (Exception e) {
            log.error("Spring AI代码生成失败", e);
            return CodeGenerationResponse.builder()
                    .success(false)
                    .errorMessage("代码生成失败: " + e.getMessage())
                    .generatedAt(LocalDateTime.now())
                    .build();
        }
    }
    
    /**
     * 混合模式:优先使用Dify,失败时降级到Spring AI
     */
    public Mono<CodeGenerationResponse> generateCodeHybrid(CodeGenerationRequest request) {
        return generateCodeWithDify(request)
                .flatMap(response -> {
                    if (response.isSuccess()) {
                        return Mono.just(response);
                    } else {
                        log.warn("Dify生成失败,降级到Spring AI");
                        return Mono.just(generateCodeWithSpringAI(request));
                    }
                });
    }
    
    private Map<String, Object> buildDifyRequest(CodeGenerationRequest request) {
        Map<String, Object> difyRequest = new HashMap<>();
        difyRequest.put("inputs", buildInputs(request));
        difyRequest.put("query", buildQuery(request));
        difyRequest.put("response_mode", "blocking");
        difyRequest.put("conversation_id", "");
        difyRequest.put("user", "code-generator-user");
        
        return difyRequest;
    }
    
    private Map<String, String> buildInputs(CodeGenerationRequest request) {
        Map<String, String> inputs = new HashMap<>();
        inputs.put("requirement", request.getRequirement());
        inputs.put("language", request.getLanguage());
        inputs.put("framework", request.getFramework() != null ? request.getFramework() : "");
        inputs.put("include_comments", String.valueOf(request.isIncludeComments()));
        inputs.put("include_tests", String.valueOf(request.isIncludeTests()));
        inputs.put("additional_context", request.getAdditionalContext() != null ? request.getAdditionalContext() : "");
        
        return inputs;
    }
    
    private String buildQuery(CodeGenerationRequest request) {
        StringBuilder query = new StringBuilder();
        query.append("请根据以下需求生成").append(request.getLanguage()).append("代码:\n");
        query.append("需求:").append(request.getRequirement()).append("\n");
        
        if (request.getFramework() != null && !request.getFramework().isEmpty()) {
            query.append("框架:").append(request.getFramework()).append("\n");
        }
        
        if (request.getAdditionalContext() != null && !request.getAdditionalContext().isEmpty()) {
            query.append("额外信息:").append(request.getAdditionalContext()).append("\n");
        }
        
        query.append("要求:\n");
        if (request.isIncludeComments()) {
            query.append("- 包含详细注释\n");
        }
        if (request.isIncludeTests()) {
            query.append("- 包含单元测试\n");
        }
        query.append("- 代码要规范、清晰、可维护\n");
        query.append("- 请提供代码说明和使用建议");
        
        return query.toString();
    }
    
    private CodeGenerationResponse parseDifyResponse(String responseBody, CodeGenerationRequest request) {
        try {
            JsonNode jsonNode = objectMapper.readTree(responseBody);
            String answer = jsonNode.path("answer").asText();
            String conversationId = jsonNode.path("conversation_id").asText();
            
            return CodeGenerationResponse.builder()
                    .code(extractCode(answer))
                    .explanation(extractExplanation(answer))
                    .suggestions(extractSuggestions(answer))
                    .language(request.getLanguage())
                    .framework(request.getFramework())
                    .conversationId(conversationId)
                    .generatedAt(LocalDateTime.now())
                    .success(true)
                    .build();
                    
        } catch (Exception e) {
            log.error("解析Dify响应失败", e);
            return CodeGenerationResponse.builder()
                    .success(false)
                    .errorMessage("响应解析失败: " + e.getMessage())
                    .generatedAt(LocalDateTime.now())
                    .build();
        }
    }
    
    private String buildPromptForSpringAI(CodeGenerationRequest request) {
        return String.format("""
                你是一个专业的软件开发工程师,请根据以下需求生成高质量的%s代码:
                
                需求描述:%s
                
                编程语言:%s
                框架:%s
                是否包含注释:%s
                是否包含测试:%s
                额外上下文:%s
                
                请按以下格式输出:
                
                ## 代码实现
                ```%s
                [生成的代码]
                ```
                
                ## 代码说明
                [详细的代码解释]
                
                ## 使用建议
                - [建议1]
                - [建议2]
                - [建议3]
                """,
                request.getLanguage(),
                request.getRequirement(),
                request.getLanguage(),
                request.getFramework() != null ? request.getFramework() : "无特定框架",
                request.isIncludeComments() ? "是" : "否",
                request.isIncludeTests() ? "是" : "否",
                request.getAdditionalContext() != null ? request.getAdditionalContext() : "无",
                request.getLanguage().toLowerCase()
        );
    }
    
    private String extractCode(String response) {
        // 提取代码块
        String[] lines = response.split("\n");
        StringBuilder code = new StringBuilder();
        boolean inCodeBlock = false;
        
        for (String line : lines) {
            if (line.startsWith("```")) {
                inCodeBlock = !inCodeBlock;
                continue;
            }
            if (inCodeBlock) {
                code.append(line).append("\n");
            }
        }
        
        return code.toString().trim();
    }
    
    private String extractExplanation(String response) {
        // 提取说明部分
        if (response.contains("## 代码说明")) {
            String[] parts = response.split("## 代码说明");
            if (parts.length > 1) {
                String explanation = parts[1];
                if (explanation.contains("## 使用建议")) {
                    explanation = explanation.split("## 使用建议")[0];
                }
                return explanation.trim();
            }
        }
        return "无详细说明";
    }
    
    private List<String> extractSuggestions(String response) {
        List<String> suggestions = new ArrayList<>();
        
        if (response.contains("## 使用建议")) {
            String[] parts = response.split("## 使用建议");
            if (parts.length > 1) {
                String suggestionText = parts[1];
                String[] lines = suggestionText.split("\n");
                
                for (String line : lines) {
                    if (line.trim().startsWith("- ")) {
                        suggestions.add(line.trim().substring(2));
                    }
                }
            }
        }
        
        if (suggestions.isEmpty()) {
            suggestions.add("请确保代码符合最佳实践");
            suggestions.add("建议添加适当的错误处理");
            suggestions.add("考虑添加日志记录");
        }
        
        return suggestions;
    }
}

7. 控制器

java 复制代码
package com.example.codegen.controller;

import com.example.codegen.dto.CodeGenerationRequest;
import com.example.codegen.dto.CodeGenerationResponse;
import com.example.codegen.service.CodeGeneratorService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Mono;

import javax.validation.Valid;

@RestController
@RequestMapping("/api/v1/code")
@RequiredArgsConstructor
@Slf4j
@Validated
public class CodeGeneratorController {
    
    private final CodeGeneratorService codeGeneratorService;
    
    /**
     * 使用Dify生成代码
     */
    @PostMapping("/generate/dify")
    public Mono<ResponseEntity<CodeGenerationResponse>> generateWithDify(
            @Valid @RequestBody CodeGenerationRequest request) {
        
        log.info("收到Dify代码生成请求: {}", request.getRequirement());
        
        return codeGeneratorService.generateCodeWithDify(request)
                .map(response -> ResponseEntity.ok(response))
                .onErrorResume(throwable -> {
                    log.error("Dify代码生成失败", throwable);
                    CodeGenerationResponse errorResponse = CodeGenerationResponse.builder()
                            .success(false)
                            .errorMessage("服务暂时不可用,请稍后重试")
                            .build();
                    return Mono.just(ResponseEntity.ok(errorResponse));
                });
    }
    
    /**
     * 使用Spring AI生成代码
     */
    @PostMapping("/generate/spring-ai")
    public ResponseEntity<CodeGenerationResponse> generateWithSpringAI(
            @Valid @RequestBody CodeGenerationRequest request) {
        
        log.info("收到Spring AI代码生成请求: {}", request.getRequirement());
        
        try {
            CodeGenerationResponse response = codeGeneratorService.generateCodeWithSpringAI(request);
            return ResponseEntity.ok(response);
        } catch (Exception e) {
            log.error("Spring AI代码生成失败", e);
            CodeGenerationResponse errorResponse = CodeGenerationResponse.builder()
                    .success(false)
                    .errorMessage("代码生成失败: " + e.getMessage())
                    .build();
            return ResponseEntity.ok(errorResponse);
        }
    }
    
    /**
     * 混合模式生成代码(推荐)
     */
    @PostMapping("/generate")
    public Mono<ResponseEntity<CodeGenerationResponse>> generateCode(
            @Valid @RequestBody CodeGenerationRequest request) {
        
        log.info("收到混合模式代码生成请求: {}", request.getRequirement());
        
        return codeGeneratorService.generateCodeHybrid(request)
                .map(response -> ResponseEntity.ok(response))
                .onErrorResume(throwable -> {
                    log.error("代码生成完全失败", throwable);
                    CodeGenerationResponse errorResponse = CodeGenerationResponse.builder()
                            .success(false)
                            .errorMessage("代码生成服务暂时不可用")
                            .build();
                    return Mono.just(ResponseEntity.ok(errorResponse));
                });
    }
    
    /**
     * 健康检查
     */
    @GetMapping("/health")
    public ResponseEntity<String> health() {
        return ResponseEntity.ok("Code Generator Service is running");
    }
}

8. 使用示例

启动应用

bash 复制代码
# 设置环境变量
export OPENAI_API_KEY=your-openai-api-key
export DIFY_API_BASE_URL=https://api.dify.ai/v1
export DIFY_API_KEY=your-dify-api-key
export DIFY_APP_ID=your-dify-app-id

# 启动应用
mvn spring-boot:run

API调用示例

bash 复制代码
# 生成Java Spring Boot控制器代码
curl -X POST http://localhost:8080/api/v1/code/generate \
  -H "Content-Type: application/json" \
  -d '{
    "requirement": "创建一个用户管理的REST API,包含CRUD操作",
    "language": "java",
    "framework": "Spring Boot",
    "includeComments": true,
    "includeTests": false,
    "additionalContext": "使用JPA进行数据持久化"
  }'

响应示例

json 复制代码
{
  "code": "@RestController\n@RequestMapping(\"/api/users\")\npublic class UserController {\n    // 生成的代码...\n}",
  "explanation": "这个控制器实现了用户管理的基本CRUD操作...",
  "suggestions": [
    "建议添加输入验证",
    "考虑添加分页支持",
    "建议实现异常处理"
  ],
  "language": "java",
  "framework": "Spring Boot",
  "generatedAt": "2025-01-15T10:30:00",
  "conversationId": "conv-123456",
  "success": true,
  "errorMessage": null
}

9. 扩展功能

添加代码模板管理

java 复制代码
@Service
public class CodeTemplateService {
    
    public String getTemplate(String language, String type) {
        // 根据语言和类型返回代码模板
        return switch (language.toLowerCase()) {
            case "java" -> getJavaTemplate(type);
            case "python" -> getPythonTemplate(type);
            case "javascript" -> getJavaScriptTemplate(type);
            default -> "";
        };
    }
    
    private String getJavaTemplate(String type) {
        return switch (type) {
            case "controller" -> """
                @RestController
                @RequestMapping("/api/{resource}")
                public class {ClassName} {
                    // Controller implementation
                }
                """;
            case "service" -> """
                @Service
                public class {ClassName} {
                    // Service implementation
                }
                """;
            default -> "";
        };
    }
}

这个实例展示了如何使用Spring AI配合Dify构建一个功能完整的代码生成工具。主要特点包括:

  1. 双引擎支持:同时支持Dify和Spring AI
  2. 容错机制:Dify失败时自动降级到Spring AI
  3. 灵活配置:支持多种编程语言和框架
  4. 结构化输出:返回代码、说明和建议
  5. 异步处理:使用WebFlux实现非阻塞调用
  6. 完整的REST API:提供标准的HTTP接口
相关推荐
草履虫建模8 分钟前
RuoYi-Cloud 微服务本地部署详细流程实录(IDEA + 本地 Windows 环境)
java·spring boot·spring cloud·微服务·云原生·架构·maven
Mintopia1 小时前
AI 与 HuggingFace API 对接指南:从底层原理到 JS 实战
前端·javascript·aigc
Warren982 小时前
使用 Spring Boot 集成七牛云实现图片/文件上传
java·前端·javascript·vue.js·spring boot·后端·ecmascript
逍岚子3 小时前
MCP第3章:开发案例合集(typescript-sdk + python-sdk)
llm·aigc·mcp
潘多编程3 小时前
Spring Boot + Angular 实现安全登录注册系统:全栈开发指南
spring boot·安全·angular.js
xiangzhihong83 小时前
使用Spring Boot+Vue3开源的即时通讯 IM 系统
前端·spring boot
探索java3 小时前
Spring Boot自定义Starter:从原理到实战全解析
java·spring boot·后端
别来无恙14912 小时前
Spring Boot + ECharts 极简整合指南:从零实现动态数据可视化大屏
spring boot·信息可视化·echarts
蔡大锅13 小时前
Datawhale AI夏令营 - RAG task2方案介绍
aigc