创建一个使用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构建一个功能完整的代码生成工具。主要特点包括:
- 双引擎支持:同时支持Dify和Spring AI
- 容错机制:Dify失败时自动降级到Spring AI
- 灵活配置:支持多种编程语言和框架
- 结构化输出:返回代码、说明和建议
- 异步处理:使用WebFlux实现非阻塞调用
- 完整的REST API:提供标准的HTTP接口