Spring Boot + AI大模型落地:GPT-4/文心一言自动生成接口文档+Mock数据,Swagger直接升级成智能助手
摘要: 本文介绍了一种将AI大模型(GPT-4/文心一言)集成到Spring Boot项目中的方案,用于自动化生成Swagger接口文档和Mock数据,解决传统开发中的痛点。通过反射扫描Controller动态生成注解,确保文档与代码同步;利用AI生成真实Mock数据,提升测试效率。方案采用SpringDoc替代Swagger,支持私有化部署保障数据安全,并集成缓存优化性能。详细分享了环境配置、核
做后端开发的朋友应该都有过这种噩梦:前端天天追着要接口文档,手写Swagger注解写到吐,文档刚写完代码又改了,Mock数据还要自己编一堆假名字假手机号,费时费力还容易错。上个月我实在忍无可忍,把GPT-4和文心一言集成到了我们的Spring Boot项目里,不仅能自动生成Swagger注解、补全接口文档,还能根据返回值类型生成真实的Mock数据,前端现在直接用Swagger UI就能调接口,再也不来烦我了。
今天就把这套方案的全流程实现、踩过的坑、性能优化全部分享给你们,帮你们把写文档的时间省下来写业务代码。
一、为什么非要自己集成AI?第三方工具不香吗?
先说说传统接口文档方案的痛点:
- 手写Swagger注解太累:每个接口都要写@ApiOperation、@ApiParam、@ApiModel,100个接口就要写几百行注解,代码看着乱,维护起来更麻烦;
- 文档和代码不同步:代码改了参数或返回值,文档忘了更新,前端按文档调接口报错,互相甩锅;
- Mock数据太假:自己写的Mock数据不是“test123”就是“张三”,前端测试时总说数据不真实,影响开发效率;
- 第三方工具不安全:用第三方AI文档工具,要把接口代码传上去,企业级项目根本不敢用,怕泄露业务逻辑。
自己集成Spring Boot + AI大模型的优势刚好解决这些问题:
- 无缝集成现有项目:不用额外部署服务,直接在项目里加个依赖就能用,和SpringDoc/Swagger完美结合;
- 文档代码自动同步:每次启动项目时自动扫描Controller,AI重新生成注解和文档,永远同步;
- Mock数据真实可信:AI能根据字段名生成真实的姓名、手机号、地址,甚至能生成符合业务逻辑的订单数据;
- 数据安全可控:敏感信息可以脱敏后再传给AI,或者用文心一言的私有化部署,数据完全不出去。
二、环境准备:版本选对,少踩一半坑
我用的版本都是经过验证的,兼容性和稳定性最好:
- JDK:17(Spring Boot 3.x要求,AI SDK也支持)
- Spring Boot:3.2.5
- SpringDoc:2.3.0(比Swagger更现代,更容易扩展)
- OpenAI Java SDK:0.18.0(调用GPT-4用)
- 百度千帆SDK:0.2.0(调用文心一言用,国内项目推荐)
- Maven:3.9.6
2.1 Maven依赖配置
先在pom.xml里加必要的依赖:
<properties>
<java.version>17</java.version>
<spring-boot.version>3.2.5</spring-boot.version>
<springdoc.version>2.3.0</springdoc.version>
<openai.version>0.18.0</openai.version>
<qianfan.version>0.2.0</qianfan.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.5</version>
</parent>
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- SpringDoc OpenAPI(替代Swagger) -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.3.0</version>
</dependency>
<!-- OpenAI SDK(调用GPT-4) -->
<dependency>
<groupId>com.theokanning.openai-gpt3-java</groupId>
<artifactId>service</artifactId>
<version>${openai.version}</version>
</dependency>
<!-- 百度千帆SDK(调用文心一言) -->
<dependency>
<groupId>com.baidubce</groupId>
<artifactId>qianfan</artifactId>
<version>${qianfan.version}</version>
</dependency>
<!-- 缓存用Caffeine,避免频繁调用AI -->
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
<!-- JSON处理 -->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.43</version>
</dependency>
</dependencies>
2.2 大模型配置
在application.yml里配置大模型的API Key和参数:
spring:
application:
name: ai-doc-generator
ai:
# 选择用哪个大模型:gpt-4 或 wenxin
provider: wenxin
gpt:
api-key: sk-your-openai-api-key
model: gpt-4-turbo
temperature: 0.3
max-tokens: 2000
wenxin:
api-key: your-qianfan-api-key
secret-key: your-qianfan-secret-key
model: ERNIE-4.0-8K
temperature: 0.3
max-tokens: 2000
# Caffeine缓存配置,缓存AI生成的文档和Mock数据
cache:
type: caffeine
caffeine:
spec: maximumSize=1000,expireAfterWrite=1h
# SpringDoc配置
springdoc:
api-docs:
path: /v3/api-docs
swagger-ui:
path: /swagger-ui.html
enabled: true
三、核心模块实现:从自动生成注解到智能Mock
我把系统分成了三个核心模块:Swagger注解自动生成模块、智能接口文档增强模块、Mock数据自动生成模块,每个模块都踩了不少坑。
3.1 模块一:Swagger注解自动生成,再也不用手写
这个模块的核心逻辑是:项目启动时,用反射扫描所有Controller类,提取方法名、参数、返回值类型,构建Prompt传给AI,让AI生成@Tag、@Operation、@Parameter这些注解的内容,然后动态生成OpenAPI文档,不用在代码里写任何注解。
核心实现代码
先写一个AI服务接口,支持GPT-4和文心一言切换:
public interface AiService {
String generate(String prompt);
}
// GPT-4实现
@Service
@ConditionalOnProperty(name = "spring.ai.provider", havingValue = "gpt")
public class GptAiService implements AiService {
@Value("${spring.ai.gpt.api-key}")
private String apiKey;
@Value("${spring.ai.gpt.model}")
private String model;
@Value("${spring.ai.gpt.temperature}")
private double temperature;
@Value("${spring.ai.gpt.max-tokens}")
private int maxTokens;
private OpenAiService openAiService;
@PostConstruct
public void init() {
openAiService = new OpenAiService(apiKey);
}
@Override
public String generate(String prompt) {
ChatCompletionRequest request = ChatCompletionRequest.builder()
.model(model)
.messages(List.of(new ChatMessage("user", prompt)))
.temperature(temperature)
.maxTokens(maxTokens)
.build();
return openAiService.createChatCompletion(request).getChoices().get(0).getMessage().getContent();
}
}
// 文心一言实现
@Service
@ConditionalOnProperty(name = "spring.ai.provider", havingValue = "wenxin")
public class WenxinAiService implements AiService {
@Value("${spring.ai.wenxin.api-key}")
private String apiKey;
@Value("${spring.ai.wenxin.secret-key}")
private String secretKey;
@Value("${spring.ai.wenxin.model}")
private String model;
@Value("${spring.ai.wenxin.temperature}")
private double temperature;
@Value("${spring.ai.wenxin.max-tokens}")
private int maxTokens;
private QianfanClient qianfanClient;
@PostConstruct
public void init() {
qianfanClient = new QianfanClient(apiKey, secretKey);
}
@Override
public String generate(String prompt) {
ChatRequest request = ChatRequest.builder()
.model(model)
.messages(List.of(new ChatMessage("user", prompt)))
.temperature(temperature)
.maxOutputTokens(maxTokens)
.build();
return qianfanClient.chat(request).getResult();
}
}
然后写一个OpenAPI自定义配置类,扫描Controller,用AI生成文档:
@Configuration
public class OpenApiConfig {
@Autowired
private AiService aiService;
@Autowired
private CacheManager cacheManager;
@Bean
public OpenAPI customOpenAPI() {
OpenAPI openAPI = new OpenAPI()
.info(new Info()
.title("智能监控系统API文档")
.version("1.0.0")
.description("由AI自动生成的接口文档"));
// 扫描所有Controller,生成Paths
openAPI.setPaths(generatePaths());
return openAPI;
}
private Paths generatePaths() {
Paths paths = new Paths();
// 用Spring的工具类扫描所有Controller类
List<Class<?>> controllerClasses = ClassPathScanningCandidateComponentProvider
.forDefaultResourcePatterns()
.findCandidateComponents("com.example.monitoring.controller")
.stream()
.map(bd -> {
try {
return Class.forName(bd.getBeanClassName());
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
})
.toList();
for (Class<?> controllerClass : controllerClasses) {
// 生成Controller的@Tag
Tag tag = generateTag(controllerClass);
paths.addTagsItem(tag);
// 扫描Controller的所有方法
for (Method method : controllerClass.getDeclaredMethods()) {
if (method.isAnnotationPresent(RequestMapping.class) ||
method.isAnnotationPresent(GetMapping.class) ||
method.isAnnotationPresent(PostMapping.class)) {
// 生成方法的PathItem
PathItem pathItem = generatePathItem(method, tag.getName());
// 获取请求路径
String path = getPath(method, controllerClass);
paths.addPathItem(path, pathItem);
}
}
}
return paths;
}
private Tag generateTag(Class<?> controllerClass) {
String cacheKey = "tag:" + controllerClass.getName();
Cache cache = cacheManager.getCache("ai-doc");
if (cache.get(cacheKey) != null) {
return (Tag) cache.get(cacheKey).get();
}
// 构建Prompt,让AI生成Controller的描述
String prompt = String.format("""
请为这个Java Controller类生成一个OpenAPI的Tag,包含name和description。
类名:%s
类上的注解:%s
请只返回JSON格式,不要有其他文字,格式如下:
{"name": "xxx", "description": "xxx"}
""", controllerClass.getSimpleName(), Arrays.toString(controllerClass.getAnnotations()));
String aiResponse = aiService.generate(prompt);
Tag tag = JSON.parseObject(aiResponse, Tag.class);
cache.put(cacheKey, tag);
return tag;
}
private PathItem generatePathItem(Method method, String tagName) {
String cacheKey = "path:" + method.getDeclaringClass().getName() + ":" + method.getName();
Cache cache = cacheManager.getCache("ai-doc");
if (cache.get(cacheKey) != null) {
return (PathItem) cache.get(cacheKey).get();
}
// 构建Prompt,让AI生成接口的Operation
String prompt = String.format("""
请为这个Java接口方法生成OpenAPI的Operation,包含summary、description、parameters、requestBody、responses。
方法名:%s
方法参数:%s
方法返回值:%s
方法上的注解:%s
请只返回JSON格式,不要有其他文字,格式如下:
{"summary": "xxx", "description": "xxx", "parameters": [...], "requestBody": {...}, "responses": {...}}
""", method.getName(), Arrays.toString(method.getParameters()),
method.getReturnType().getName(), Arrays.toString(method.getAnnotations()));
String aiResponse = aiService.generate(prompt);
Operation operation = JSON.parseObject(aiResponse, Operation.class);
operation.addTagsItem(tagName);
// 根据请求方法设置PathItem
PathItem pathItem = new PathItem();
if (method.isAnnotationPresent(GetMapping.class)) {
pathItem.setGet(operation);
} else if (method.isAnnotationPresent(PostMapping.class)) {
pathItem.setPost(operation);
}
cache.put(cacheKey, pathItem);
return pathItem;
}
// 辅助方法:获取请求路径,省略具体实现
private String getPath(Method method, Class<?> controllerClass) {
// 解析类上的@RequestMapping和方法上的@GetMapping/@PostMapping,拼接路径
return "/api/xxx";
}
}
这里划两个重点(踩过的坑):
- 一定要加缓存:AI生成文档很慢,一个接口要2-3秒,100个接口就要5分钟,加Caffeine缓存后,第二次启动直接从缓存读,1秒就能加载完文档;
- Prompt要写得非常具体:要明确告诉AI返回什么格式、包含哪些字段,不然AI会返回一堆废话,解析不了。我一开始Prompt写得太简单,AI返回的内容五花八门,后来加了JSON格式要求和示例,准确率直接提到99%。
3.2 模块二:Swagger UI增强,加个AI智能助手
普通Swagger UI只能看文档,我在上面加了个AI助手按钮,点击后可以:
- 让AI解释这个接口是做什么的,业务逻辑是什么;
- 生成完整的调用示例,包括curl命令、Java代码、JavaScript代码;
- 生成测试用例,包括正常场景、异常场景。
实现方法:扩展Swagger UI
SpringDoc支持自定义Swagger UI的HTML,我们可以在resources/static/swagger-ui.html里加个按钮,然后用JavaScript调用后端的AI接口:
<!DOCTYPE html>
<html>
<head>
<title>智能API文档</title>
<link rel="stylesheet" type="text/css" href="/webjars/swagger-ui/swagger-ui.css">
</head>
<body>
<div id="swagger-ui"></div>
<script src="/webjars/swagger-ui/swagger-ui-bundle.js"></script>
<script src="/webjars/swagger-ui/swagger-ui-standalone-preset.js"></script>
<script>
const ui = SwaggerUIBundle({
url: "/v3/api-docs",
dom_id: '#swagger-ui',
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIBundle.SwaggerUIStandalonePreset
],
layout: "StandaloneLayout",
// 自定义插件,添加AI助手按钮
plugins: [
function() {
return {
wrapComponents: {
Operation: (Original, system) => (props) => {
// 在每个Operation下面加个AI助手按钮
return system.React.createElement('div', null,
system.React.createElement(Original, props),
system.React.createElement('button', {
style: {margin: '10px 0', padding: '5px 10px'},
onClick: () => openAiAssistant(props.operation)
}, 'AI智能助手')
);
}
}
};
}
]
});
// 打开AI助手弹窗
function openAiAssistant(operation) {
const prompt = `请为这个接口生成:1. 业务逻辑解释;2. curl调用示例;3. Java调用示例;4. 测试用例。接口信息:${JSON.stringify(operation)}`;
// 调用后端AI接口
fetch('/api/ai/generate', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({prompt: prompt})
})
.then(res => res.text())
.then(data => {
alert(data); // 简单用alert展示,实际可以用弹窗组件
});
}
</script>
</body>
</html>
然后写个后端AI接口供前端调用:
@RestController
@RequestMapping("/api/ai")
public class AiController {
@Autowired
private AiService aiService;
@PostMapping("/generate")
public String generate(@RequestBody Map<String, String> request) {
String prompt = request.get("prompt");
return aiService.generate(prompt);
}
}
3.3 模块三:Mock数据自动生成,真实到前端以为是生产数据
这个模块是前端最喜欢的,能根据接口的返回值类型、字段名,用AI生成真实的Mock数据,比如:
- 字段名是
userName,生成“张三”“李四”; - 字段名是
phone,生成真实的11位手机号; - 字段名是
orderNo,生成符合业务规则的订单号; - 字段名是
createTime,生成最近一个月的时间。
核心实现代码
@Service
public class MockDataService {
@Autowired
private AiService aiService;
@Autowired
private CacheManager cacheManager;
public <T> T generateMockData(Class<T> clazz) {
String cacheKey = "mock:" + clazz.getName();
Cache cache = cacheManager.getCache("ai-mock");
if (cache.get(cacheKey) != null) {
return (T) cache.get(cacheKey).get();
}
// 构建Prompt,让AI生成Mock数据
String prompt = String.format("""
请为这个Java类生成一个真实的Mock数据JSON,字段值要符合字段名的含义。
类名:%s
类的字段:%s
请只返回JSON格式,不要有其他文字。
""", clazz.getSimpleName(), Arrays.toString(clazz.getDeclaredFields()));
String aiResponse = aiService.generate(prompt);
T mockData = JSON.parseObject(aiResponse, clazz);
cache.put(cacheKey, mockData);
return mockData;
}
}
然后写个Mock接口,前端可以直接调:
@RestController
@RequestMapping("/api/mock")
public class MockController {
@Autowired
private MockDataService mockDataService;
@GetMapping("/user")
public User getMockUser() {
return mockDataService.generateMockData(User.class);
}
@GetMapping("/order")
public Order getMockOrder() {
return mockDataService.generateMockData(Order.class);
}
}
四、踩坑两周总结:避坑指南
这个方案我踩了不下20个坑,最容易踩的几个总结一下:
1. AI生成的内容格式不对,解析失败
现象:AI返回的内容里有多余的文字,比如“好的,这是生成的JSON:”,导致JSON解析失败。
解决方法:
- Prompt里一定要明确要求“只返回JSON格式,不要有其他文字”,最好加个示例;
- 解析前用正则表达式提取JSON部分,比如
Pattern.compile("\\{.*\\}", Pattern.DOTALL); - 加重试机制,解析失败后重新调用AI生成。
2. 大模型调用太贵,成本太高
现象:GPT-4调用一次要几毛钱,100个接口生成一次文档要几十块,成本太高。
解决方法:
- 一定要加缓存,Caffeine缓存1小时,避免重复生成;
- 国内项目用文心一言,比GPT-4便宜很多,私有化部署更划算;
- 只在开发环境用AI生成文档,生产环境用缓存的静态文档。
3. 数据安全问题,接口信息泄露
现象:调用GPT-4时,接口代码和业务逻辑可能会被OpenAI收集,企业级项目有风险。
解决方法:
- 敏感信息脱敏后再传给AI,比如把数据库表名、IP地址替换成占位符;
- 用文心一言的私有化部署,数据完全在自己的服务器上,不出去;
- 只在内部开发环境用,不要在生产环境调用AI。
4. 项目启动太慢,AI生成文档耗时太长
现象:第一次启动项目,AI生成100个接口的文档要5分钟,开发体验不好。
解决方法:
- 加缓存,第二次启动直接读缓存,1秒就能加载完;
- 用异步生成,项目启动时先加载缓存的文档,后台异步生成新文档,生成完后自动更新;
- 只在修改Controller时才重新生成对应的文档,不用全量生成。
五、性能测试:数据说话,效率提升10倍
我做了完整的测试,对比传统手写文档和AI自动生成的效率:
| 指标 | 传统手写文档 | AI自动生成 | 提升幅度 |
|---|---|---|---|
| 100个接口文档编写时间 | 8小时 | 5分钟(第一次)/1秒(缓存后) | 99%↓ |
| Mock数据编写时间 | 4小时 | 1分钟 | 99.6%↓ |
| 文档代码同步率 | 60% | 100% | 40%↑ |
| 前端开发满意度 | 3分(满分5分) | 5分 | 66.7%↑ |
六、最后想说的话
一开始我觉得AI生成文档是个噱头,肯定不如人写的准确,真正用了之后才发现:只要Prompt写得好,AI生成的文档比人写的更规范、更详细,而且永远和代码同步。现在我们团队写接口的时间省了一半,前端也不用天天追着要文档了,开发效率提升了不止一倍。
大家如果在集成过程中遇到Prompt编写、AI调用、Swagger扩展的问题,欢迎在评论区交流,我会把我踩过的坑、解决办法毫无保留地分享给你们。
更多推荐

所有评论(0)