SpringAI系列---【请求自己公司自己部署的模型时,springAI框架报500,curl直接访问没问题】
1.问题
我在对接自己公司部署的模型时,使用curl直接访问模型接口没问题,但是使用springAI就不行了。报下面的错误:
2025-08-12T22:10:02.402+08:00 INFO 17620 --- [spring-Ai] [nio-8080-exec-2] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2025-08-12T22:10:02.403+08:00 INFO 17620 --- [spring-Ai] [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2025-08-12T22:10:02.405+08:00 INFO 17620 --- [spring-Ai] [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : Completed initialization in 2 ms
2025-08-12T22:10:19.562+08:00 DEBUG 17620 --- [spring-Ai] [nio-8080-exec-2] o.s.w.r.f.client.ExchangeFunctions : [394adf46] HTTP POST http:/xx.test:8080/apis/aip-v2/chat/comletions
2025-08-12T22:10:19.989+08:00 DEBUG 17620 --- [spring-Ai] [onPool-worker-1] o.s.w.r.f.client.ExchangeFunctions : [394adf46] [36960f7] Response 500 INTERNAL_SERVER_ERROR
2025-08-12T22:10:28.991+08:00 ERROR 17620 --- [spring-Ai] [onPool-worker-1] o.s.ai.chat.model.MessageAggregator : Aggregation Error
org.springframework.web.reactive.function.client.WebClientResponseException$InternalServerError: 500 Internal Server Error from POST http:/xx.test:8080/apis/aip-v2/chat/comletions
at org.springframework.web.reactive.function.client.WebClientResponseException.create(WebClientResponseException.java:332) ~[spring-webflux-6.2.3.jar:6.2.3]
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Error has been observed at the following site(s):
*__checkpoint ⇢ 500 INTERNAL_SERVER_ERROR from POST http:/xx.test:8080/apis/aip-v2/chat/comletions [DefaultWebClient]
Original Stack Trace:
at org.springframework.web.reactive.function.client.WebClientResponseException.create(WebClientResponseException.java:332) ~[spring-webflux-6.2.3.jar:6.2.3]
at org.springframework.web.reactive.function.client.DefaultClientResponse.lambda$createException$1(DefaultClientResponse.java:214) ~[spring-webflux-6.2.3.jar:6.2.3]
at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:106) ~[reactor-core-3.7.3.jar:3.7.3]
at reactor.core.publisher.FluxOnErrorReturn$ReturnSubscriber.onNext(FluxOnErrorReturn.java:162) ~[reactor-core-3.7.3.jar:3.7.3]
at reactor.core.publisher.FluxDefaultIfEmpty$DefaultIfEmptySubscriber.onNext(FluxDefaultIfEmpty.java:122) ~[reactor-core-3.7.3.jar:3.7.3]
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:129) ~[reactor-core-3.7.3.jar:3.7.3]
at reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.onNext(FluxContextWrite.java:107) ~[reactor-core-3.7.3.jar:3.7.3]
at reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.onNext(FluxMapFuseable.java:299) ~[reactor-core-3.7.3.jar:3.7.3]
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableConditionalSubscriber.onNext(FluxFilterFuseable.java:337) ~[reactor-core-3.7.3.jar:3.7.3]
at reactor.core.publisher.Operators$BaseFluxToMonoOperator.completePossiblyEmpty(Operators.java:2097) ~[reactor-core-3.7.3.jar:3.7.3]
at reactor.core.publisher.MonoCollect$CollectSubscriber.onComplete(MonoCollect.java:145) ~[reactor-core-3.7.3.jar:3.7.3]
at reactor.core.publisher.FluxPublish$PublishSubscriber.checkTerminated(FluxPublish.java:634) ~[reactor-core-3.7.3.jar:3.7.3]
at reactor.core.publisher.FluxPublish$PublishSubscriber.drain(FluxPublish.java:494) ~[reactor-core-3.7.3.jar:3.7.3]
at reactor.core.publisher.FluxPublish$PublishSubscriber.onComplete(FluxPublish.java:355) ~[reactor-core-3.7.3.jar:3.7.3]
at reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.onComplete(FluxContextWrite.java:126) ~[reactor-core-3.7.3.jar:3.7.3]
at reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.onComplete(FluxMapFuseable.java:350) ~[reactor-core-3.7.3.jar:3.7.3]
at reactor.core.publisher.FluxFlattenIterable$FlattenIterableSubscriber.drainAsync(FluxFlattenIterable.java:371) ~[reactor-core-3.7.3.jar:3.7.3]
at reactor.core.publisher.FluxFlattenIterable$FlattenIterableSubscriber.drain(FluxFlattenIterable.java:724) ~[reactor-core-3.7.3.jar:3.7.3]
at reactor.core.publisher.FluxFlattenIterable$FlattenIterableSubscriber.onComplete(FluxFlattenIterable.java:273) ~[reactor-core-3.7.3.jar:3.7.3]
at reactor.adapter.JdkFlowAdapter$SubscriberToRS.onComplete(JdkFlowAdapter.java:160) ~[reactor-core-3.7.3.jar:3.7.3]
at java.net.http/jdk.internal.net.http.ResponseSubscribers$PublishingBodySubscriber.complete(ResponseSubscribers.java:933) ~[java.net.http:na]
at java.net.http/jdk.internal.net.http.ResponseSubscribers$PublishingBodySubscriber.lambda$new$1(ResponseSubscribers.java:864) ~[java.net.http:na]
at java.base/java.util.concurrent.CompletableFuture$UniAccept.tryFire$$$capture(CompletableFuture.java:718) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture$UniAccept.tryFire(CompletableFuture.java) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:510) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:2147) ~[na:na]
at java.net.http/jdk.internal.net.http.ResponseSubscribers$PublishingBodySubscriber.lambda$subscribe$3(ResponseSubscribers.java:961) ~[java.net.http:na]
at java.base/java.util.concurrent.CompletableFuture.uniAcceptNow(CompletableFuture.java:757) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture.uniAcceptStage(CompletableFuture.java:735) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture.thenAccept(CompletableFuture.java:2182) ~[na:na]
at java.net.http/jdk.internal.net.http.ResponseSubscribers$PublishingBodySubscriber.subscribe(ResponseSubscribers.java:957) ~[java.net.http:na]
at reactor.adapter.JdkFlowAdapter$FlowPublisherAsFlux.subscribe(JdkFlowAdapter.java:68) ~[reactor-core-3.7.3.jar:3.7.3]
at reactor.core.publisher.InternalFluxOperator.subscribe(InternalFluxOperator.java:68) ~[reactor-core-3.7.3.jar:3.7.3]
at reactor.core.publisher.FluxPublish.connect(FluxPublish.java:106) ~[reactor-core-3.7.3.jar:3.7.3]
at reactor.core.publisher.FluxAutoConnect.subscribe(FluxAutoConnect.java:62) ~[reactor-core-3.7.3.jar:3.7.3]
at reactor.core.publisher.Flux.subscribe(Flux.java:8891) ~[reactor-core-3.7.3.jar:3.7.3]
at org.springframework.http.client.reactive.AbstractClientHttpResponse$SingleSubscriberPublisher.subscribe(AbstractClientHttpResponse.java:112) ~[spring-web-6.2.3.jar:6.2.3]
at reactor.core.publisher.FluxSource.subscribe(FluxSource.java:71) ~[reactor-core-3.7.3.jar:3.7.3]
at reactor.core.publisher.Flux.subscribe(Flux.java:8891) ~[reactor-core-3.7.3.jar:3.7.3]
at reactor.core.publisher.MonoFlatMapMany$FlatMapManyMain.onNext(MonoFlatMapMany.java:196) ~[reactor-core-3.7.3.jar:3.7.3]
at reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.onNext(FluxContextWrite.java:107) ~[reactor-core-3.7.3.jar:3.7.3]
at reactor.core.publisher.FluxDoFinally$DoFinallySubscriber.onNext(FluxDoFinally.java:113) ~[reactor-core-3.7.3.jar:3.7.3]
at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.onNext(MonoPeekTerminal.java:180) ~[reactor-core-3.7.3.jar:3.7.3]
at reactor.core.publisher.FluxPeekFuseable$PeekConditionalSubscriber.onNext(FluxPeekFuseable.java:854) ~[reactor-core-3.7.3.jar:3.7.3]
at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onNext(FluxSwitchIfEmpty.java:74) ~[reactor-core-3.7.3.jar:3.7.3]
at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:200) ~[reactor-core-3.7.3.jar:3.7.3]
at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:122) ~[reactor-core-3.7.3.jar:3.7.3]
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79) ~[reactor-core-3.7.3.jar:3.7.3]
at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:200) ~[reactor-core-3.7.3.jar:3.7.3]
at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:200) ~[reactor-core-3.7.3.jar:3.7.3]
at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.complete(MonoIgnoreThen.java:294) ~[reactor-core-3.7.3.jar:3.7.3]
at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onNext(MonoIgnoreThen.java:188) ~[reactor-core-3.7.3.jar:3.7.3]
at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:122) ~[reactor-core-3.7.3.jar:3.7.3]
at reactor.core.publisher.MonoCompletionStage$MonoCompletionStageSubscription.apply(MonoCompletionStage.java:121) ~[reactor-core-3.7.3.jar:3.7.3]
at reactor.core.publisher.MonoCompletionStage$MonoCompletionStageSubscription.apply(MonoCompletionStage.java:67) ~[reactor-core-3.7.3.jar:3.7.3]
at java.base/java.util.concurrent.CompletableFuture.uniHandle(CompletableFuture.java:934) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture$UniHandle.tryFire(CompletableFuture.java:911) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:510) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture.postFire(CompletableFuture.java:614) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:844) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture$Completion.exec(CompletableFuture.java:483) ~[na:na]
at java.base/java.util.concurrent.ForkJoinTask.doExec$$$capture(ForkJoinTask.java:373) ~[na:na]
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java) ~[na:na]
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182) ~[na:na]
at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655) ~[na:na]
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622) ~[na:na]
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165) ~[na:na]
2.解决方案
我先用curl命令验证模型接口没问题,首先排除大模型的问题,然后查看curl命令的入参和响应是否符合openAI的规范,确认符合规范后,我就重点放在了springAI框架上,经过一路打断点,发现请求的参数都没问题,和curl的参数一致,那么至此就确定了是http客户端接收响应有问题。经过咨询chatgpt之后,发现,springAI框架调用http默认使用的RestClient和WebClient,并且默认使用的是HTTP/2协议,而curl默认的是HTTP/1.1,因为 HTTP/2 需要用到 libcurl 编译时启用 nghttp2 或 hyper 支持,而不是所有系统上的 curl 都有这个功能,所以不好用curl验证大模型是否支持HTTP/2协议(curl发送HTTP/2协议的请求待完善)。至此,问题的关键已找到,最简单的方法是把springAI的httpClient改成支持发生HTTP/1.1即可。
@Configuration
public class HttpClientConfiguration {
private HttpClient client() {
return HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_1_1)
.build();
}
/**
* 非流式请求
*/
@Bean
@Primary
public RestClient.Builder restClientBuilder() {
return RestClient.builder()
.requestFactory(new JdkClientHttpRequestFactory(client()));
}
/**
* 流式请求
*/
@Bean
@Primary
public WebClient.Builder webClientBuilder() {
return WebClient.builder()
.clientConnector(new JdkClientHttpConnector(client()));
}
}
#如上所示,流式和非流式的Client可以都自定义一下,万无一失。
3.配置文件
spring:
application:
name: spring-ai-promote
ai:
openai:
#去掉v1,springai会自动加。加上的话在运行时会报404 NOT_FOUND from POST https://dashscope.aliyuncs.com/compatible-mode/v1/v1/chat/completions
baseurl: https://dashscope.aliyuncs.com/compatible-mode
# 为了防止泄密,这里建议使用环境变量的方式,将 API Key 配置在环境变量中,实际这里最后在发起http请求后,把这个加在了请求头Authorization: Bearer sk-xxx
api-key: ${OPENAI_API_KEY}
chat:
#默认是/v1/chat/completions,如果你公司的自建模型不是,就设置一下
completions-path: /v1/chat/completions
options:
#这个模型支持非思考模式,适用于快速响应的场景
model: qwen-max
4.pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.4.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.fast.ai</groupId>
<artifactId>spring-ai-promote</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-ai-promote</name>
<description>spring-ai-promote</description>
<properties>
<java.version>17</java.version>
<spring-ai.version>1.0.0-M6</spring-ai.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-ollama-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>3.5.10.1</version>
</dependency>
<!-- lombok:注意,不要在创建项目时勾选,脚手架里那个版本有问题,这里建议手动引入 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.28</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>${spring-ai.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
愿你走出半生,归来仍是少年!
浙公网安备 33010602011771号