Spring Boot 集成国内AI,包含文心一言、通义千问和讯飞星火平台实战教程
Spring Boot集成国内主流AI平台的详细实现方案,包含文心一言、通义千问和讯飞星火的对接代码,助力快速构建智能应用。
一、项目结构
ai-integration-demo/
├── src/main/java
│ ├── com/example/ai
│ │ ├── config # 配置类
│ │ ├── controller # API控制器
│ │ ├── service # 服务层
│ │ │ ├── impl # 服务实现
│ │ ├── dto # 数据传输对象
├── resources
│ ├── application.yml # 配置文件
二、添加Maven依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- HTTP客户端 -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.11.0</version>
</dependency>
<!-- JSON处理 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<!-- 配置处理 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
三、配置API密钥 (application.yml)
ai:
wenxin:
api-key: YOUR_WENXIN_API_KEY
secret-key: YOUR_WENXIN_SECRET_KEY
api-url: https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions
qianwen:
api-key: YOUR_QIANWEN_API_KEY
api-url: https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation
xinghuo:
api-key: YOUR_XINGHUO_API_KEY
secret: YOUR_XINGHUO_SECRET
appid: YOUR_XINGHUO_APPID
api-url: https://spark-api.xf-yun.com/v3.5/chat
四、配置类
1. AI配置类 (AiProperties.java)
@ConfigurationProperties(prefix = "ai")
@Data
public class AiProperties {
private Wenxin wenxin;
private Qianwen qianwen;
private Xinghuo xinghuo;
@Data
public static class Wenxin {
private String apiKey;
private String secretKey;
private String apiUrl;
}
@Data
public static class Qianwen {
private String apiKey;
private String apiUrl;
}
@Data
public static class Xinghuo {
private String apiKey;
private String secret;
private String appid;
private String apiUrl;
}
}
2. 启用配置类 (AiConfig.java)
@Configuration
@EnableConfigurationProperties(AiProperties.class)
public class AiConfig {
@Bean
public OkHttpClient okHttpClient() {
return new OkHttpClient();
}
}
五、服务层实现
1. 文心一言服务 (WenxinService.java)
@Service
@RequiredArgsConstructor
public class WenxinService {
private final AiProperties aiProperties;
private final OkHttpClient okHttpClient;
// 获取AccessToken
private String getAccessToken() {
String url = "https://aip.baidubce.com/oauth/2.0/token?"
+ "grant_type=client_credentials"
+ "&client_id=" + aiProperties.getWenxin().getApiKey()
+ "&client_secret=" + aiProperties.getWenxin().getSecretKey();
Request request = new Request.Builder()
.url(url)
.get()
.build();
try (Response response = okHttpClient.newCall(request).execute()) {
String responseBody = response.body().string();
ObjectMapper objectMapper = new ObjectMapper();
JsonNode rootNode = objectMapper.readTree(responseBody);
return rootNode.get("access_token").asText();
} catch (Exception e) {
throw new RuntimeException("获取文心一言Token失败", e);
}
}
public String chatCompletion(String prompt) {
String accessToken = getAccessToken();
String url = aiProperties.getWenxin().getApiUrl() + "?access_token=" + accessToken;
JSONObject body = new JSONObject();
body.put("messages", new JSONArray()
.put(new JSONObject()
.put("role", "user")
.put("content", prompt))
);
Request request = new Request.Builder()
.url(url)
.post(RequestBody.create(body.toString(), MediaType.get("application/json")))
.build();
try (Response response = okHttpClient.newCall(request).execute()) {
if (!response.isSuccessful()) {
throw new RuntimeException("文心一言API请求失败: " + response);
}
String responseBody = response.body().string();
JSONObject jsonResponse = new JSONObject(responseBody);
return jsonResponse.getJSONObject("result").getString("content");
} catch (Exception e) {
throw new RuntimeException("调用文心一言API出错", e);
}
}
}
2. 通义千问服务 (QianwenService.java)
@Service
@RequiredArgsConstructor
public class QianwenService {
private final AiProperties aiProperties;
private final OkHttpClient okHttpClient;
public String generateText(String prompt) {
JSONObject body = new JSONObject();
body.put("model", "qwen-turbo");
JSONObject input = new JSONObject();
input.put("prompt", prompt);
body.put("input", input);
JSONObject parameters = new JSONObject();
parameters.put("temperature", 0.85);
parameters.put("top_p", 0.8);
parameters.put("max_tokens", 1500);
body.put("parameters", parameters);
Request request = new Request.Builder()
.url(aiProperties.getQianwen().getApiUrl())
.header("Authorization", "Bearer " + aiProperties.getQianwen().getApiKey())
.post(RequestBody.create(body.toString(), MediaType.get("application/json")))
.build();
try (Response response = okHttpClient.newCall(request).execute()) {
if (!response.isSuccessful()) {
throw new RuntimeException("通义千问API请求失败: " + response);
}
String responseBody = response.body().string();
JSONObject jsonResponse = new JSONObject(responseBody);
return jsonResponse.getJSONObject("output").getString("text");
} catch (Exception e) {
throw new RuntimeException("调用通义千问API出错", e);
}
}
}
3. 讯飞星火服务 (XinghuoService.java)
@Service
@RequiredArgsConstructor
public class XinghuoService {
private final AiProperties aiProperties;
private final OkHttpClient okHttpClient;
public String chat(String prompt) {
try {
// 构造鉴权URL
String authUrl = generateAuthUrl();
// 构造请求体
JSONObject body = new JSONObject();
JSONObject header = new JSONObject();
header.put("app_id", aiProperties.getXinghuo().getAppid());
JSONObject parameter = new JSONObject();
JSONObject chat = new JSONObject();
chat.put("domain", "generalv3.5");
chat.put("temperature", 0.5);
chat.put("max_tokens", 4096);
parameter.put("chat", chat);
JSONObject payload = new JSONObject();
JSONObject message = new JSONObject();
JSONArray text = new JSONArray();
text.put(new JSONObject().put("role", "user").put("content", prompt));
message.put("text", text);
payload.put("message", message);
body.put("header", header);
body.put("parameter", parameter);
body.put("payload", payload);
// 发送请求
Request request = new Request.Builder()
.url(authUrl)
.post(RequestBody.create(body.toString(), MediaType.get("application/json")))
.build();
try (Response response = okHttpClient.newCall(request).execute()) {
if (!response.isSuccessful()) {
throw new RuntimeException("讯飞星火API请求失败: " + response);
}
String responseBody = response.body().string();
JSONObject jsonResponse = new JSONObject(responseBody);
return extractContent(jsonResponse);
}
} catch (Exception e) {
throw new RuntimeException("调用讯飞星火API出错", e);
}
}
// 生成带鉴权信息的URL
private String generateAuthUrl() throws ParseException, InvalidKeyException,
NoSuchAlgorithmException, UnsupportedEncodingException {
String apiUrl = aiProperties.getXinghuo().getApiUrl();
String host = new URL(apiUrl).getHost();
String path = new URL(apiUrl).getPath();
// 创建日期对象
SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
String date = sdf.format(new Date());
// 构造签名
String signatureOrigin = "host: " + host + "\n";
signatureOrigin += "date: " + date + "\n";
signatureOrigin += "POST " + path + " HTTP/1.1";
Mac mac = Mac.getInstance("hmacsha256");
SecretKeySpec secretKeySpec = new SecretKeySpec(aiProperties.getXinghuo().getSecret().getBytes("UTF-8"), "hmacsha256");
mac.init(secretKeySpec);
byte[] signatureSha = mac.doFinal(signatureOrigin.getBytes("UTF-8"));
String signature = Base64.getEncoder().encodeToString(signatureSha);
// 构造授权头
String authorization = String.format("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"",
aiProperties.getXinghuo().getApiKey(), "hmac-sha256", "host date request-line", signature);
return apiUrl + "?authorization=" + Base64.getEncoder().encodeToString(authorization.getBytes("UTF-8"))
+ "&date=" + URLEncoder.encode(date, "UTF-8")
+ "&host=" + URLEncoder.encode(host, "UTF-8");
}
// 提取响应内容
private String extractContent(JSONObject response) {
JSONObject payload = response.getJSONObject("payload");
JSONObject message = payload.getJSONObject("message");
JSONArray text = message.getJSONArray("text");
StringBuilder result = new StringBuilder();
for (int i = 0; i < text.length(); i++) {
JSONObject textObj = text.getJSONObject(i);
if (textObj.has("content")) {
result.append(textObj.getString("content"));
}
}
return result.toString();
}
}
六、统一控制器 (AiController.java)
@RestController
@RequestMapping("/api/ai")
@RequiredArgsConstructor
public class AiController {
private final WenxinService wenxinService;
private final QianwenService qianwenService;
private final XinghuoService xinghuoService;
@PostMapping("/wenxin")
public ResponseEntity<String> wenxinChat(@RequestBody @Valid AiRequest request) {
return ResponseEntity.ok(wenxinService.chatCompletion(request.getPrompt()));
}
@PostMapping("/qianwen")
public ResponseEntity<String> qianwenGenerate(@RequestBody @Valid AiRequest request) {
return ResponseEntity.ok(qianwenService.generateText(request.getPrompt()));
}
@PostMapping("/xinghuo")
public ResponseEntity<String> xinghuoChat(@RequestBody @Valid AiRequest request) {
return ResponseEntity.ok(xinghuoService.chat(request.getPrompt()));
}
@Data
static class AiRequest {
@NotBlank(message = "提示语不能为空")
private String prompt;
}
}
七、安全增强配置
1. 添加API密钥保护(自定义Filter)
@Component
@RequiredArgsConstructor
public class ApiKeyFilter extends OncePerRequestFilter {
private final AiProperties aiProperties;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain)
throws ServletException, IOException {
String clientId = request.getHeader("X-API-CLIENT-ID");
String clientSecret = request.getHeader("X-API-CLIENT-SECRET");
// 验证客户端凭证
if (!isValidCredentials(clientId, clientSecret)) {
response.sendError(HttpStatus.UNAUTHORIZED.value(), "无效的API凭证");
return;
}
filterChain.doFilter(request, response);
}
private boolean isValidCredentials(String clientId, String clientSecret) {
// 这里应该是从数据库或配置中读取验证信息
// 简化示例:使用配置中的文心API密钥做演示
return clientId != null && clientSecret != null
&& clientId.equals("demo-app")
&& clientSecret.equals(aiProperties.getWenxin().getApiKey());
}
}
2. 添加Rate Limiting(使用Resilience4j)
@Configuration
public class RateLimiterConfig {
@Bean
public RateLimiter wenxinRateLimiter() {
return RateLimiter.of("wenxin-limiter",
RateLimiterConfig.custom()
.limitRefreshPeriod(Duration.ofSeconds(10))
.limitForPeriod(5)
.timeoutDuration(Duration.ofSeconds(5))
.build());
}
}
// 在控制器中使用
@RestController
@RequestMapping("/api/ai")
public class AiController {
private final RateLimiter wenxinRateLimiter;
@PostMapping("/wenxin")
@RateLimiter(name = "wenxin-limiter")
public ResponseEntity<String> wenxinChat(@RequestBody AiRequest request) {
// ...
}
}
八、应用入口 (AiIntegrationApplication.java)
@SpringBootApplication
public class AiIntegrationApplication {
public static void main(String[] args) {
SpringApplication.run(AiIntegrationApplication.class, args);
}
}
九、测试示例
使用cURL测试:
# 通义千问测试
curl -X POST http://localhost:8080/api/ai/qianwen \
-H "Content-Type: application/json" \
-d '{"prompt": "用100字介绍Spring Boot"}'
# 文心一言测试
curl -X POST http://localhost:8080/api/ai/wenxin \
-H "Content-Type: application/json" \
-d '{"prompt": "用Java写一个快速排序算法"}'
# 讯飞星火测试
curl -X POST http://localhost:8080/api/ai/xinghuo \
-H "Content-Type: application/json" \
-d '{"prompt": "如何做好电商运营"}'
十、最佳实践建议
- 异步处理:使用@Async注解异步调用AI接口,避免阻塞
- 缓存结果:对常见问题的结果进行缓存,减少API调用
- 错误重试:实现指数退避重试机制处理临时错误
- 流量控制:针对不同AI平台设置不同的QPS限制
- 统一接口:创建统一的AI门面服务,提供平台无关的调用
@Service
public class AiFacadeService {
private enum AiProvider { WENXIN, QIANWEN, XINGHUO }
private final WenxinService wenxinService;
private final QianwenService qianwenService;
private final XinghuoService xinghuoService;
public String unifiedChat(String prompt) {
// 简单轮询策略
AiProvider[] providers = AiProvider.values();
AiProvider provider = providers[(int)(System.currentTimeMillis() % providers.length)];
switch (provider) {
case WENXIN: return wenxinService.chatCompletion(prompt);
case QIANWEN: return qianwenService.generateText(prompt);
case XINGHUO: return xinghuoService.chat(prompt);
default: throw new IllegalStateException("未知的AI提供商");
}
}
}
本项目提供了完整的企业级Spring Boot集成国内主流AI平台的实现方案,可根据实际需求进行扩展和优化。