news 2026/4/18 8:18:13

使用 Spring Boot WebClient 调用大模型 API(OpenAI、文心一言、通义千问)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
使用 Spring Boot WebClient 调用大模型 API(OpenAI、文心一言、通义千问)

在当今 AI 时代,大模型 API(如 OpenAI 的 GPT、百度的文心一言、阿里云的通义千问)已成为开发者集成智能功能的核心工具。Spring Boot作为现代 Java 开发的首选框架,其内置的WebClient(基于 Reactor 的非阻塞 HTTP 客户端)是调用 REST API 的高效、灵活的方式。本文将详细介绍如何使用 Spring Boot 的WebClient来调用主流大模型 API,帮助你快速上手。


一、为什么选择 WebClient?

特性

RestTemplate

WebClient

同步/异步

同步(阻塞)

异步(非阻塞,响应式)

线程模型

每个请求占用一个线程

事件驱动,高并发

流式处理

不支持

支持响应流(Streaming)

错误处理

复杂

链式调用,简洁

Spring 生态

旧版(Spring 5 开始弃用)

Spring 5+ 推荐

推荐使用WebClient:它更符合现代微服务架构的需求,能显著提升系统吞吐量。


二、项目准备

1. 创建 Spring Boot 项目

使用 Spring Initializr 创建项目,选择以下依赖:

  • Spring Webflux(自动包含WebClient
  • Lombok(可选,简化 DTO 代码)
2.pom.xml依赖
<dependencies> <!-- Spring WebFlux (包含 WebClient) --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> <!-- JSON 处理(Jackson 自动包含) --> <!-- 可选:Lombok 简化 DTO --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <scope>provided</scope> </dependency> </dependencies>
3. 读取 API 密钥(推荐使用环境变量)

application.yml中配置密钥(切勿硬编码):

api: openai: key: ${OPENAI_API_KEY} # 从环境变量读取 wenxin: api-key: ${WENXIN_API_KEY} secret-key: ${WENXIN_SECRET_KEY} tongyi: key: ${TONGYI_API_KEY}

在服务类中注入:

@Service public class ApiConfig { @Value("${api.openai.key}") private String openaiApiKey; @Value("${api.wenxin.api-key}") private String wenxinApiKey; @Value("${api.wenxin.secret-key}") private String wenxinSecretKey; @Value("${api.tongyi.key}") private String tongyiApiKey; }

三、WebClient 基础配置

创建一个WebClientConfig类,封装通用配置:

import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.client.reactive.ReactorClientHttpConnector; import org.springframework.web.reactive.function.client.WebClient; import reactor.netty.http.client.HttpClient; @Configuration public class WebClientConfig { // 可选:配置超时、重试、连接池 @Bean public WebClient webClient() { HttpClient httpClient = HttpClient.create() .responseTimeout(java.time.Duration.ofSeconds(30)); // 请求超时 30 秒 return WebClient.builder() .clientConnector(new ReactorClientHttpConnector(httpClient)) .build(); } }

💡提示:生产环境中应配置重试策略(如Retry)、日志跟踪等。


四、调用 OpenAI API

1. OpenAI API 简介
  • 端点https://api.openai.com/v1/chat/completions
  • 必需头Authorization: Bearer <API_KEY>
  • 请求体:JSON 格式,包含modelmessages等字段。
  • 官方文档:OpenAI API Reference
2. DTO 定义
import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.util.List; // 请求体 @Data @NoArgsConstructor @AllArgsConstructor class OpenAiRequest { private String model; // 模型名,如 "gpt-3.5-turbo" private List<Message> messages; } @Data @NoArgsConstructor @AllArgsConstructor class Message { private String role; // "user", "assistant", "system" private String content; } // 响应体(简化版,仅展示关键字段) @Data class OpenAiResponse { private List<Choice> choices; @Data static class Choice { private Message message; } }
3. 服务实现
import org.springframework.beans.factory.annotation.Value; import org.springframework.http.MediaType; import org.springframework.stereotype.Service; import org.springframework.web.reactive.function.client.WebClient; import reactor.core.publisher.Mono; @Service public class OpenAiService { private final WebClient webClient; private final String apiKey; public OpenAiService(WebClient.Builder webClientBuilder, @Value("${api.openai.key}") String apiKey) { this.webClient = webClientBuilder .baseUrl("https://api.openai.com/v1") .defaultHeader("Authorization", "Bearer " + apiKey) .build(); this.apiKey = apiKey; } public Mono<String> chat(String prompt) { // 构造请求体 OpenAiRequest request = new OpenAiRequest( "gpt-3.5-turbo", List.of(new Message("user", prompt)) ); // 发送请求 return webClient.post() .uri("/chat/completions") .contentType(MediaType.APPLICATION_JSON) .bodyValue(request) .retrieve() .bodyToMono(OpenAiResponse.class) .map(response -> response.getChoices().get(0).getMessage().getContent()); } }
4. 使用示例(Controller)
import org.springframework.web.bind.annotation.*; import reactor.core.publisher.Mono; @RestController @RequestMapping("/ai") public class AiController { private final OpenAiService openAiService; public AiController(OpenAiService openAiService) { this.openAiService = openAiService; } @GetMapping("/ask") public Mono<String> askOpenAi(@RequestParam String question) { return openAiService.chat(question); } }

🌟测试
发送 GET 请求http://localhost:8080/ai/ask?question=你好,将返回 GPT 的回答。


五、调用文心一言 API

1. 文心一言 API 简介
  • 获取访问令牌(Access Token)
    • 首先需调用 OAuth 2.0 获取access_token
    • 端点:https://aip.baidubce.com/oauth/2.0/token
    • 参数:grant_type=client_credentials&client_id=<API_KEY>&client_secret=<SECRET_KEY>
  • 聊天接口
    • 端点:https://aip.baidubce.com/rpc/2.0/ai/custom/v1/wenxinworkshop/chat/completions?access_token=<TOKEN>
    • 请求体格式类似 OpenAI,但字段名不同。

📌注意:文心一言需在百度智能云控制台创建应用并获取密钥。

2. DTO 定义
// 访问令牌响应 @Data class WenxinTokenResponse { private String access_token; private String expires_in; } // 文心一言请求体 @Data @NoArgsConstructor @AllArgsConstructor class WenxinRequest { private String model = "eb-instant"; // 模型名(如 eb-instant、ernie-3.5-4k-0205) private List<Message> messages; } // 文心一言响应体 @Data class WenxinResponse { private List<Choice> result; @Data static class Choice { private String content; } }
3. 服务实现
import org.springframework.beans.factory.annotation.Value; import org.springframework.http.MediaType; import org.springframework.stereotype.Service; import org.springframework.web.reactive.function.client.WebClient; import reactor.core.publisher.Mono; @Service public class WenxinService { private final WebClient webClient; private final String apiKey; private final String secretKey; public WenxinService(WebClient.Builder webClientBuilder, @Value("${api.wenxin.api-key}") String apiKey, @Value("${api.wenxin.secret-key}") String secretKey) { this.webClient = webClientBuilder.build(); this.apiKey = apiKey; this.secretKey = secretKey; } // Step 1: 获取 Access Token private Mono<String> getAccessToken() { return webClient.post() .uri("https://aip.baidubce.com/oauth/2.0/token") .queryParam("grant_type", "client_credentials") .queryParam("client_id", apiKey) .queryParam("client_secret", secretKey) .retrieve() .bodyToMono(WenxinTokenResponse.class) .map(WenxinTokenResponse::getAccess_token); } // Step 2: 调用聊天接口 public Mono<String> chat(String prompt) { return getAccessToken().flatMap(accessToken -> { WenxinRequest request = new WenxinRequest( List.of(new Message("user", prompt)) ); return webClient.post() .uri("https://aip.baidubce.com/rpc/2.0/ai/custom/v1/wenxinworkshop/chat/completions") .queryParam("access_token", accessToken) .contentType(MediaType.APPLICATION_JSON) .bodyValue(request) .retrieve() .bodyToMono(WenxinResponse.class) .map(resp -> resp.getResult().get(0).getContent()); }); } }
4. Controller 使用
@RestController @RequestMapping("/ai") public class AiController { private final WenxinService wenxinService; public AiController(WenxinService wenxinService) { this.wenxinService = wenxinService; } @GetMapping("/wenxin") public Mono<String> askWenxin(@RequestParam String question) { return wenxinService.chat(question); } }

六、调用通义千问 API

1. 通义千问 API 简介
  • 端点https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation
  • 必需头Authorization: Bearer <API_KEY>
  • 模型dall-e-xl(图像)或qwen-plus(文本)
  • 官方文档:通义千问 API 文档

📌注意:通义千问由阿里云提供,需在阿里云控制台获取 API 密钥。

2. DTO 定义
// 请求体 @Data @NoArgsConstructor @AllArgsConstructor class TongyiRequest { private String model = "qwen-long"; // 模型名 private List<Message> input = new ArrayList<>(); private Parameters parameters = new Parameters(); @Data @NoArgsConstructor @AllArgsConstructor static class Parameters { private float temperature = 0.7f; // 随机性 private int max_tokens = 800; // 最多生成 token 数 } } // 响应体 @Data class TongyiResponse { private Output output; @Data static class Output { private List<Text> text; @Data static class Text { private String content; } } }
3. 服务实现
import org.springframework.beans.factory.annotation.Value; import org.springframework.http.MediaType; import org.springframework.stereotype.Service; import org.springframework.web.reactive.function.client.WebClient; import reactor.core.publisher.Mono; @Service public class TongyiService { private final WebClient webClient; private final String apiKey; public TongyiService(WebClient.Builder webClientBuilder, @Value("${api.tongyi.key}") String apiKey) { this.webClient = webClientBuilder .baseUrl("https://dashscope.aliyuncs.com") .defaultHeader("Authorization", "Bearer " + apiKey) .defaultHeader("Content-Type", MediaType.APPLICATION_JSON) .build(); this.apiKey = apiKey; } public Mono<String> chat(String prompt) { TongyiRequest request = new TongyiRequest(); request.getInput().add(new Message("user", prompt)); return webClient.post() .uri("/api/v1/services/aigc/text-generation/generation") .bodyValue(request) .retrieve() .bodyToMono(TongyiResponse.class) .map(resp -> resp.getOutput().getText().get(0).getContent()); } }
4. Controller 使用
@RestController @RequestMapping("/ai") public class AiController { private final TongyiService tongyiService; public AiController(TongyiService tongyiService) { this.tongyiService = tongyiService; } @GetMapping("/tongyi") public Mono<String> askTongyi(@RequestParam String question) { return tongyiService.chat(question); } }

七、错误处理与最佳实践

1. 优雅处理 HTTP 错误

使用onStatus()捕获 4xx/5xx 错误:

public Mono<String> chat(String prompt) { return webClient.post() .uri("/chat/completions") .bodyValue(request) .retrieve() .onStatus(httpStatus -> httpStatus.value() >= 400, clientResponse -> { // 读取错误信息 return clientResponse.bodyToMono(String.class) .flatMap(errorBody -> Mono.error(new RuntimeException( "API 调用失败: " + httpStatus.getReasonPhrase() + ", " + errorBody ))); }) .bodyToMono(OpenAiResponse.class) .map(...); }
2. 重要最佳实践

实践

原因

密钥隔离

使用环境变量、Vault 或 KMS,绝不硬编码在代码中

超时设置

避免请求长时间挂起(如.responseTimeout(Duration.ofSeconds(30))

重试机制

对 5xx 错误使用Retry(如Retry.backoff(3, Duration.ofSeconds(1))

流式处理

大模型响应可能很长,支持流式输出(如 OpenAI 的stream=true

日志与监控

记录请求参数、响应码、耗时,方便排查问题

令牌刷新

文心一言的access_token有有效期(24 小时),需定期刷新

响应式编程

在 Reactive 项目中,避免使用.block(),直接返回Mono/Flux

3. 流式输出示例(OpenAI)
public Flux<String> streamChat(String prompt) { OpenAiRequest request = new OpenAiRequest("gpt-3.5-turbo", List.of(new Message("user", prompt))); request.setStream(true); // 开启流式 return webClient.post() .uri("/chat/completions") .bodyValue(request) .accept(MediaType.TEXT_EVENT_STREAM) // SSE 格式 .exchangeToFlux(clientResponse -> clientResponse.bodyToFlux(String.class)) .filter(chunk -> !chunk.trim().isEmpty()) .map(chunk -> chunk.split("data: ")[1]) .filter(data -> !data.equals("[\u200b]")) // 过滤心跳 .map(data -> { /* 解析 JSON 得到内容 */ }); }

八、完整项目结构

src ├── main │ ├── java │ │ └── com.example.demo │ │ ├── DemoApplication.java │ │ ├── config │ │ │ └── WebClientConfig.java │ │ ├── controller │ │ │ └── AiController.java │ │ ├── dto │ │ │ ├── OpenAiRequest.java │ │ │ ├── WenxinRequest.java │ │ │ └── TongyiRequest.java │ │ ├── service │ │ │ ├── OpenAiService.java │ │ │ ├── WenxinService.java │ │ │ └── TongyiService.java │ │ └── ApiConfig.java │ └── resources │ └── application.yml

九、总结

通过本文,你掌握了:

  1. 如何配置 Spring Boot 的WebClient作为高性能 HTTP 客户端。
  2. 三大主流大模型 API 的调用流程
    • OpenAI:直接传递Bearer Token
    • 文心一言:先获取access_token,再带参调用。
    • 通义千问:使用Bearer方式传递 API 密钥。
  1. 响应式编程实践:使用Mono/Flux处理异步调用,避免线程阻塞。
  2. 生产级考量:错误处理、密钥管理、超时重试、流式输出等。

💡下一步建议

  • 集成Spring AI(官方支持的 AI 框架),简化大模型调用。
  • 尝试流式输出,提升用户体验(如实时显示模型思考过程)。
  • 使用缓存存储重复请求的结果,降低 API 调用成本。

现在,你已经可以轻松将大模型能力集成到自己的 Spring Boot 应用中!🚀


重要提醒
大模型 API 通常需要付费(按 token 计费),请理性使用,并遵守各平台的使用政策。本文示例仅用于学习,实际项目中请仔细阅读官方文档获取最新接口规范。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 0:23:57

基于Vue的问诊平台管理系统0jbb3(程序 + 源码 + 数据库 + 调试部署 + 开发环境配置),配套论文文档字数达万字以上,文末可获取,系统界面展示置于文末

系统程序文件列表 系统功能 患者,医生,服务评价,问诊查询,回复查询,科室分类 开题报告内容 基于Vue的问诊平台管理系统开题报告 一、选题背景与意义 &#xff08;一&#xff09;选题背景 随着互联网技术的飞速发展和人们健康意识的提升&#xff0c;线上问诊作为一种便捷、…

作者头像 李华
网站建设 2026/4/5 3:20:48

【干货收藏】0基础网络安全学习指南:大学生高薪就业的必备攻略

最近我的后台简直要被大学生们的私信淹没啦&#xff0c;全是关于网络安全转行的问题。看来大家对未来的职业规划都挺上心的&#xff0c;我特别欣慰&#xff01;今天咱就敞开了好好唠唠&#xff0c;给各位大学生朋友指条明路。 一、现状剖析&#xff1a;网络安全——大学生就业…

作者头像 李华
网站建设 2026/4/18 7:01:38

ERP 不是万能的,把它当 WMS 用,迟早要出问题

在很多企业的仓库管理中&#xff0c;一个常见的现象是&#xff1a;ERP 系统里的库存账面上完全正确&#xff0c;可仓库现场却依然混乱。订单拣货出现错误货物摆放杂乱员工操作经常出偏差这时很多管理者会本能地怀疑&#xff1a;“是不是我们的 ERP 系统不够好&#xff1f;”ERP…

作者头像 李华
网站建设 2026/4/18 2:05:17

ByteDance AI战略:前端生态的颠覆者

在AI浪潮席卷全球的当下&#xff0c;科技巨头的竞争已从单一模型能力比拼升级为全栈生态角逐。字节跳动作为后起之秀&#xff0c;凭借其在C端流量、数据规模与工程化能力的积淀&#xff0c;构建了覆盖基础模型、核心算法、多业务场景落地及商业化闭环的完整AI战略体系。本文将从…

作者头像 李华