创建一个使用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接口
相关推荐
鼓掌MVP1 小时前
【案例实战】多维度视角:鸿蒙2048游戏开发的深度分析与感悟
华为·ai编程·harmonyos·arkts·游戏开发·ability
摇滚侠2 小时前
Spring Boot 3零基础教程,WEB 开发 自定义静态资源目录 笔记31
spring boot·笔记·后端·spring
摇滚侠2 小时前
Spring Boot 3零基础教程,WEB 开发 Thymeleaf 遍历 笔记40
spring boot·笔记·thymeleaf
骑猪兜风2332 小时前
Claude 新功能 Skills 横空出世,比 MCP 更高效的 AI 增强方案!
ai编程·claude·mcp
橘子海全栈攻城狮3 小时前
【源码+文档+调试讲解】基于SpringBoot + Vue的知识产权管理系统 041
java·vue.js·人工智能·spring boot·后端·安全·spring
腾讯云云开发3 小时前
云开发Copilot实战:零代码打造智能体小程序指南
agent·ai编程·小程序·云开发
得物技术3 小时前
Apex AI辅助编码助手的设计和实践|得物技术
ai编程·cursor
腾讯云云开发4 小时前
云开发Copilot实战:AI生成2048小游戏开发指南
ai编程·游戏开发·小程序·云开发
用户5191495848454 小时前
使用Python ConfigParser解析INI配置文件完全指南
人工智能·aigc
腾讯云云开发4 小时前
云开发CloudBase实战:从0到1打造2D枪战游戏指南
ai编程·游戏开发·小程序·云开发