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

使用 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 计费),请理性使用,并遵守各平台的使用政策。本文示例仅用于学习,实际项目中请仔细阅读官方文档获取最新接口规范。

Read more

OpenClaw之Memory配置成本地模式,Ubuntu+CUDA+cuDNN+llama.cpp

文章目录 * 背景:Memory不生效的问题 * OpenClaw的Memory配置 * Ubuntu24.04安装CUDA和cuDNN * 编译llama.cpp * 验证方案1: * 验证方案2:下载并运行Llama-2 7B模型 * 安装node-llama-cpp * 验证Memory * sqlite-vec unavailable * 踩过的坑 * 安装node-llama-cpp的一些提示 * 安装node-llama-cpp的前置条件 * Using `node-llama-cpp` With Vulkan 承接上文:Windows11基于WSL2首次运行Openclaw,并对接飞书应用,我已经在电脑上安装了OpenClaw,接下来解决Memory问题。走了很多弯路,下面主要讲我总结的正确的安装过程。 总结来说:针对Memory不生效的问题,又不想用OpenAI或Gemini,或者只想单纯的节省token,可以按照如下的方式,设置为local模式: * 修改openclaw.json配置 * 安装CUDA和cu

【大作业-46】基于YOLO12的无人机(航拍)视角的目标检测系统

【大作业-46】基于YOLO12的无人机(航拍)视角的目标检测系统

基于YOLO12的无人机(航拍)视角的目标检测系统 🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳 【大作业-46】基于yolo12的航拍(无人机)视角目标检测与追踪系统 🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳 各位小伙伴大家好,今天我们为大家带来的是基于无人机视角下的目标检测,主要是对常规的行人、车辆这些目标进行检测,并且接着这个机会我们对yolo12的新模块进行一下说明,和之前的内容一样,我们的教程中包含了标注好的数据集、训练好的yolov5、yolov8、yolo11以及yolo12的模型,还有一个配套的图形化界面。本次的数据集包含的类别如下: 0: pedestrian 行人 1: people 人 2: bicycle 自行车 3: car 汽车 4: van 货车 5: truck 卡车 6: tricycle 三轮车 7: awning-tricycle 遮阳篷三轮车 8: bus 公交车 9: motor 摩托车 以下是部分数据示例。

机器人灵巧手:技术演进、市场格局与未来前景

机器人灵巧手:技术演进、市场格局与未来前景

机器人灵巧手:技术演进、市场格局与未来前景 机器人灵巧手作为具身智能的”最后一厘米”,正经历从实验室技术到产业化落地的关键转折点。2025年,全球灵巧手市场规模已达63.39亿元,中国市场规模更高达501.33亿元,年复合增长率超过300%。随着特斯拉Optimus Gen3等产品的量产计划推进,灵巧手技术正向”全感知”和”自适应”方向发展,逐步突破”性能、成本、可靠性”的”不可能三角”。从驱动系统看,空心杯电机和微型丝杠+腱绳传动方案成为主流;感知系统则通过触觉传感器与AI视觉融合实现突破。产业链国产化率已达70%以上,核心部件如空心杯电机、谐波减速器、传感器等均实现自主可控。未来5-10年,灵巧手有望从工业制造向家庭服务、医疗康养、特种作业等多元场景扩展,2030年全球市场规模预计达450亿元,2035年销量将突破百万只,迎来百亿级市场。 一、技术发展路径与核心模块创新 灵巧手技术发展经历了三个主要阶段:1970-1990年的基础结构阶段,1990-2020年的系统集成阶段,以及2020年至今的”全感知”和”自适应”