Spring Boot 集成国内AI,包含文心一言、通义千问和讯飞星火平台实战教程

发布于:2025-06-14 ⋅ 阅读:(15) ⋅ 点赞:(0)


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": "如何做好电商运营"}'

十、最佳实践建议

  1. 异步处理:使用@Async注解异步调用AI接口,避免阻塞
  2. 缓存结果:对常见问题的结果进行缓存,减少API调用
  3. 错误重试:实现指数退避重试机制处理临时错误
  4. 流量控制:针对不同AI平台设置不同的QPS限制
  5. 统一接口:创建统一的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平台的实现方案,可根据实际需求进行扩展和优化。