通义千问1.5-1.8B-Chat-GPTQ-Int4 Java集成开发SpringBoot项目调用指南如果你是一名Java开发者想把大模型的能力快速集成到自己的SpringBoot应用里可能会觉得有点无从下手。模型服务通常是用Python写的各种依赖和配置看着就头疼怎么在Java项目里优雅地调用呢别担心这篇文章就是为你准备的。咱们不聊复杂的模型原理也不折腾Python环境就聚焦一件事怎么在一个标准的SpringBoot项目里像调用普通REST服务一样方便地使用通义千问1.5-1.8B-Chat-GPTQ-Int4这个模型。我会手把手带你走一遍从零集成的完整流程提供可以直接复制粘贴的代码让你半小时内就能跑起来。1. 开始之前你需要准备什么在动手写代码之前咱们先确保几件事这样后面会顺利很多。首先你得有一个已经部署好的通义千问模型服务。这个服务应该提供了一个HTTP接口比如http://你的服务器地址:端口/v1/chat/completions。至于怎么部署你可以用官方提供的镜像或者自己用Python框架搭一个这部分不是今天讨论的重点我们假设服务已经在那儿了能正常响应。其次你的开发环境需要准备好。我假设你已经在用IntelliJ IDEA或者Eclipse本地装好了JDK 8或以上版本Maven也用得挺熟。SpringBoot的版本我用的是比较主流的2.7.x但2.5.x到3.x的版本基本都兼容。最后明确一下我们的目标。今天不是要重新发明轮子去实现模型推理而是学会如何作为一个“客户端”去消费已经存在的模型服务。这就像你的应用要调用微信支付接口一样重点是学会怎么组请求、发请求、处理响应。2. 项目搭建与核心依赖咱们从创建一个最基础的SpringBoot项目开始。你可以用Spring Initializr在线生成也可以用IDE的创建向导。项目创建时记得勾选Spring Web依赖因为我们需要它来提供RESTful的客户端能力。创建好后打开pom.xml文件我们需要添加几个关键的依赖。除了SpringBoot自带的主要会用到两个库来处理HTTP请求和JSON。?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd modelVersion4.0.0/modelVersion parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version2.7.18/version !-- 你可以根据情况调整版本 -- relativePath/ /parent groupIdcom.example/groupId artifactIdqwen-springboot-demo/artifactId version0.0.1-SNAPSHOT/version nameqwen-springboot-demo/name descriptionDemo project for integrating Qwen model/description properties java.version1.8/java.version /properties dependencies !-- Spring Boot Web Starter (包含RestTemplate等) -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency !-- 用于简化HTTP客户端调用比RestTemplate更现代 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-webflux/artifactId /dependency !-- Lombok减少Getter/Setter等样板代码 -- dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency !-- 测试依赖 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-test/artifactId scopetest/scope /dependency /dependencies build plugins plugin groupIdorg.springframework.boot/groupId artifactIdspring-boot-maven-plugin/artifactId configuration excludes exclude groupIdorg.projectlombok/groupId artifactIdlombok/artifactId /exclude /excludes /configuration /plugin /plugins /build /project这里我引入了WebFlux的依赖主要是为了使用WebClient。WebClient是Spring 5以后推荐的非阻塞式HTTP客户端功能强大且灵活比传统的RestTemplate更好用。当然如果你对RestTemplate更熟悉用它也完全没问题逻辑是相通的。依赖加好之后执行一下mvn clean compile确保项目能正常构建。3. 定义数据模型请求与响应调用任何API第一步都是搞清楚它要什么、返回什么。对于通义千问的Chat接口我们需要定义两个核心的Java类一个用来组装请求参数另一个用来解析返回的结果。我查阅了类似模型的常见接口规范一个典型的Chat请求体通常包含消息列表、模型名称和一些生成参数。响应体则包含模型返回的消息内容和其他元信息。下面我们来创建这些类。首先在src/main/java/com/example/demo/model目录下如果没有就创建创建请求和响应的模型类。请求模型ChatRequest.javapackage com.example.demo.model; import lombok.Data; import java.util.List; Data public class ChatRequest { /** * 模型名称例如qwen1.5-1.8b-chat-gptq-int4 */ private String model; /** * 对话消息列表 */ private ListMessage messages; /** * 生成文本的最大token数 */ private Integer max_tokens; /** * 采样温度控制随机性。值越高越随机越低越确定。 */ private Double temperature; /** * 核采样参数仅保留概率累积和达到此值的token。 */ private Double top_p; Data public static class Message { /** * 角色如system, user, assistant */ private String role; /** * 消息内容 */ private String content; } }响应模型ChatResponse.javapackage com.example.demo.model; import lombok.Data; import java.util.List; Data public class ChatResponse { /** * 响应ID */ private String id; /** * 对象类型通常是 chat.completion */ private String object; /** * 创建时间戳 */ private Long created; /** * 模型名称 */ private String model; /** * 模型返回的选择列表 */ private ListChoice choices; /** * 使用情况统计 */ private Usage usage; Data public static class Choice { /** * 当前选择的索引 */ private Integer index; /** * 返回的消息 */ private Message message; /** * 结束原因如stop, length */ private String finish_reason; } Data public static class Message { private String role; private String content; } Data public static class Usage { /** * 提示词消耗的token数 */ private Integer prompt_tokens; /** * 补全内容消耗的token数 */ private Integer completion_tokens; /** * 总token数 */ private Integer total_tokens; } }这里我用到了Lombok的Data注解它会自动生成getter、setter、toString等方法让代码非常简洁。这些类的字段名故意保持了和常见API规范如OpenAI格式的一致这样大概率能和你部署的模型服务匹配。如果不匹配稍后调整一下字段名即可。4. 构建HTTP客户端与服务层数据模型准备好了接下来就是干活的核心部分发送HTTP请求。我们将创建一个服务类把所有调用模型的逻辑封装在里面。我选择使用WebClient因为它支持响应式编程流式处理响应也很方便。我们先在配置类里把它初始化成一个Spring Bean。创建一个配置类WebClientConfig.javapackage com.example.demo.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.reactive.function.client.WebClient; Configuration public class WebClientConfig { Bean public WebClient webClient() { // 这里可以配置一些默认设置如超时时间、默认头信息等 return WebClient.builder() .codecs(configurer - configurer.defaultCodecs().maxInMemorySize(16 * 1024 * 1024)) // 设置最大内存缓冲区为16MB应对长文本 .build(); } }然后创建我们的核心服务类QwenAIService.javapackage com.example.demo.service; import com.example.demo.model.ChatRequest; import com.example.demo.model.ChatResponse; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.stereotype.Service; import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.reactive.function.client.WebClientResponseException; import reactor.core.publisher.Mono; import javax.annotation.PostConstruct; import java.util.Collections; Slf4j Service public class QwenAIService { Value(${qwen.api.base-url:http://localhost:8000}) private String apiBaseUrl; Value(${qwen.api.key:}) private String apiKey; Autowired private WebClient webClient; private WebClient client; PostConstruct public void init() { // 构建带有基础URL和默认请求头的WebClient实例 this.client webClient.mutate() .baseUrl(apiBaseUrl) .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE) .build(); } /** * 发送单轮对话请求同步阻塞方式适合大多数场景 */ public String chatCompletionSync(String userMessage) { ChatRequest request buildDefaultRequest(userMessage); try { ChatResponse response client.post() .uri(/v1/chat/completions) // 根据你的模型服务路径调整 .bodyValue(request) .retrieve() .bodyToMono(ChatResponse.class) .block(); // 同步阻塞等待结果 return extractContentFromResponse(response); } catch (WebClientResponseException e) { log.error(调用模型API失败状态码{} 响应体{}, e.getStatusCode(), e.getResponseBodyAsString()); throw new RuntimeException(模型服务调用异常: e.getMessage(), e); } catch (Exception e) { log.error(调用模型API发生未知异常, e); throw new RuntimeException(服务调用失败, e); } } /** * 发送单轮对话请求异步非阻塞方式适合高并发 */ public MonoString chatCompletionAsync(String userMessage) { ChatRequest request buildDefaultRequest(userMessage); return client.post() .uri(/v1/chat/completions) .bodyValue(request) .retrieve() .bodyToMono(ChatResponse.class) .map(this::extractContentFromResponse) .onErrorResume(WebClientResponseException.class, e - { log.error(异步调用失败状态码{}, e.getStatusCode()); return Mono.error(new RuntimeException(异步调用异常: e.getMessage())); }); } /** * 构建一个默认的请求对象 */ private ChatRequest buildDefaultRequest(String userMessage) { ChatRequest request new ChatRequest(); request.setModel(qwen1.5-1.8b-chat-gptq-int4); // 模型名称根据实际情况修改 request.setMessages(Collections.singletonList( new ChatRequest.Message(user, userMessage) )); request.setMaxTokens(512); // 限制生成长度 request.setTemperature(0.7); // 设置随机性 request.setTopP(0.9); return request; } /** * 从响应体中提取助手的回复内容 */ private String extractContentFromResponse(ChatResponse response) { if (response null || response.getChoices() null || response.getChoices().isEmpty()) { return 模型未返回有效内容。; } // 通常取第一个选择的内容 return response.getChoices().get(0).getMessage().getContent(); } }这个服务类做了几件关键的事读取配置通过Value注解从application.properties读取模型服务的地址和API密钥如果需要。初始化客户端在init方法里配置了WebClient的基础URL和默认请求头。提供两种调用方式chatCompletionSync是同步方法会一直等到拿到结果代码写起来直观。chatCompletionAsync返回一个MonoString是非阻塞的适合在响应式编程栈里使用。异常处理专门捕获了WebClientResponseException这是HTTP请求出错时抛出的异常我们可以在这里记录详细的错误信息状态码、响应体方便排查问题。结果解析extractContentFromResponse方法负责从复杂的响应对象里把模型生成的文本内容“挖”出来。别忘了在src/main/resources/application.properties里加上配置# 通义千问模型服务的地址 qwen.api.base-urlhttp://你的服务器IP:端口 # 如果需要API密钥的话 # qwen.api.keyyour-api-key-here # 可选配置日志级别方便调试 logging.level.com.example.demo.serviceDEBUG5. 创建控制器与测试接口服务层写好了我们还需要一个控制器Controller来暴露一个HTTP接口方便我们测试也展示了如何在实际业务中调用这个服务。创建ChatController.javapackage com.example.demo.controller; import com.example.demo.service.QwenAIService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import reactor.core.publisher.Mono; RestController RequestMapping(/api/chat) public class ChatController { Autowired private QwenAIService qwenAIService; /** * 同步对话接口 */ PostMapping(/sync) public String chatSync(RequestBody ChatRequest request) { // 这里为了简单假设request里只有一条用户消息。实际可以解析复杂的消息列表。 String userMessage request.getMessages().get(0).getContent(); return qwenAIService.chatCompletionSync(userMessage); } /** * 异步对话接口 */ PostMapping(/async) public MonoString chatAsync(RequestBody ChatRequest request) { String userMessage request.getMessages().get(0).getContent(); return qwenAIService.chatCompletionAsync(userMessage); } /** * 一个简单的GET接口用于快速测试 */ GetMapping(/test) public String testChat(RequestParam(defaultValue 你好请介绍一下你自己。) String message) { return qwenAIService.chatCompletionSync(message); } }控制器提供了三个接口POST /api/chat/sync接收一个完整的ChatRequest对象进行同步对话。POST /api/chat/async异步对话接口返回MonoString。GET /api/chat/test一个最简单的测试接口通过URL参数传递问题方便用浏览器直接测试。6. 运行测试与常见问题现在所有代码都写完了。启动你的SpringBoot应用运行DemoApplication里的main方法。打开浏览器或者用Postman这样的工具访问http://localhost:8080/api/chat/test?messageJava是一门什么样的语言。如果一切配置正确你应该很快就能看到模型返回的回答了。如果没成功别着急咱们来排查一下。以下是几个最常见的坑连接被拒绝 (Connection refused)这通常意味着qwen.api.base-url配置错了或者模型服务根本没启动。请确保模型服务正在运行并且IP和端口号正确无误。你可以在命令行用curl http://你的IP:端口/v1/chat/completions先测试一下服务本身是否正常。404 Not FoundURL路径不对。检查控制器里和服务类里设置的URI路径如/v1/chat/completions是否和模型服务提供的接口路径完全一致。400/422 Bad Request请求参数不对。检查ChatRequest类的字段名是否和模型服务要求的字段名匹配比如对方要求max_tokens你写成了maxTokens。查看服务返回的错误信息里面往往有具体提示。500 Internal Server Error模型服务内部出错。查看你的SpringBoot应用日志和模型服务的日志找到根本原因。超时 (Timeout)如果模型推理时间很长WebClient默认的超时时间可能不够。你需要在WebClientConfig中配置更长的超时时间。调试时强烈建议把服务的日志级别调到DEBUG这样能看到详细的HTTP请求和响应信息。7. 总结与后续建议走完这一遍你应该已经成功在SpringBoot项目里集成了通义千问模型。整个过程其实和集成其他任何外部REST服务没有本质区别定义数据模型、配置HTTP客户端、发送请求、处理响应和异常。用下来的感觉是只要模型服务部署好了Java这边集成起来还是挺顺畅的。WebClient用熟了之后非常强大异步调用对于提升应用并发能力很有帮助。代码里我做了比较完整的异常处理和日志记录这在生产环境里是必须的能帮你快速定位是网络问题、参数问题还是模型服务本身的问题。如果你想更进一步可以考虑这些方向一是把模型服务的地址、密钥等配置放到Nacos、Apollo这样的配置中心实现动态更新二是加入熔断、降级和重试机制可以用Resilience4j或Sentinel防止模型服务不稳定拖垮你的应用三是如果响应是流式的streaming可以用WebClient来处理数据流实现打字机效果。最关键的一点是记得根据你实际部署的模型服务的具体API文档微调请求和响应的数据模型。不同的部署方式接口细节可能会有微小差异。好了代码都在上面复制过去改改配置就能跑起来快去试试吧。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。