Spring AI Ollama 连接超时问题排查与解决:OkHttp 读超时配置全指南
摘要: Spring AI Ollama 集成时出现 HTTP 连接超时问题,表现为调用聊天接口时在10秒左右报错。根本原因是存在两层独立超时机制:模型层超时(spring.ai.ollama.chat.options.timeout)仅控制服务端生成时间,而底层 OkHttp 客户端的默认读超时(10秒)会先触发中断。解决方案包括两种:1)通过 okhttp.read-timeout 全局配置延
Spring AI Ollama 连接本地模型超时问题完全解决指南
一、问题现象
在 Spring Boot 3.2.5 项目中使用 spring-ai-ollama-spring-boot-starter(版本 1.0.0-M6)连接本地 Ollama 部署的 qwen2.5:7b-instruct 模型时,调用聊天接口(例如 RAG 问答)会在约 10 秒后抛出以下异常:
org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://localhost:11434/api/chat": timeout
at org.springframework.web.client.DefaultRestClient...
Caused by: java.net.SocketTimeoutException: timeout
at okio.SocketAsyncTimeout.newTimeoutException(JvmOkio.kt:146)
at okhttp3.internal.http1.Http1ExchangeCodec.readResponseHeaders(...)
尽管在 application.yml 中已经配置了 spring.ai.ollama.chat.options.timeout: 120s,超时仍然准时在 10 秒左右发生,导致模型生成未完成就被中断。
二、问题场景
- 本地 Ollama 模型响应慢:使用 7B 或更大参数量的模型(如
qwen2.5:7b-instruct),或者提问复杂度较高时,Ollama 服务端需要较长时间(可能十几秒甚至几十秒)才能返回第一个 token 或完整响应。 - 只配置了服务端超时,未配置客户端 HTTP 超时:开发者往往认为
spring.ai.ollama.chat.options.timeout就足够控制整个请求的超时,但实际它只控制发送给 Ollama API 的timeout参数(告诉服务端最多生成多久),并不影响 Java 客户端等待响应的时长。 - 底层 HTTP 客户端为 OkHttp:Spring AI Ollama 在无自定义配置时,默认通过
OkHttp3ClientHttpRequestFactory使用 OkHttp 发起请求。OkHttp 的默认读超时为 10 秒,这就是超时发生在 10 秒的根本原因。
三、根因分析
1. 两层超时机制相互独立
-
模型层超时(
chat.options.timeout)
该值会被序列化到POST /api/chat请求体中的options.timeout字段,用于告知 Ollama 服务端允许的最长生成时间。服务端如果超时,会主动中断生成并返回错误。 -
HTTP 客户端层超时(OkHttp 读超时)
这是 Java 应用等待服务器返回响应的最大时间。如果服务端处理慢(比如模型生成耗时较长),客户端会在达到读超时后直接抛出SocketTimeoutException,无论服务端是否仍在正常工作。
OkHttp 默认readTimeout = 10_000ms(10 秒)。
只有 HTTP 读超时 > 模型生成所需时间时,请求才能正常完成。 反之,即使服务端允许生成更久,客户端也会先断开连接。
2. 常见配置为何不生效?
-
spring.restclient.read-timeout无效spring.restclient属性通过RestClientCustomizer全局修改RestClient.Builder,但 Spring AI Ollama 自动配置内部是独立创建RestClient的,并未应用全局定制器,因此该配置无法传递到 Ollama 所用客户端。 -
SimpleClientHttpRequestFactory无效
实际堆栈中显示底层为okhttp3.OkHttpClient,而非 JDK 默认的HttpURLConnection(对应SimpleClientHttpRequestFactory)。配置后者当然不起作用。 -
spring.okhttp.read-timeout无效(或直接启动报错)
Spring Boot 对 OkHttp 的属性前缀是spring.okhttp,而非okhttp。即使写成正确前缀,Ollama 自动配置也可能没有使用 Spring 管理的OkHttpClientBean,而是直接创建了一个默认OkHttpClient,因此全局配置同样不生效。
此外,若在 YAML 中不慎写出两个顶级 spring: 键,会触发 DuplicateKeyException 导致启动失败。
4. 自定义 Bean 时的常见坑
直接创建 OllamaApi Bean 时,需注意其构造函数签名在 1.0.0-M6 版本中为:
public OllamaApi(String baseUrl,
RestClient.Builder restClientBuilder,
WebClient.Builder webClientBuilder)
而不是 (String, RestClient)。错误地调用构造函数会导致编译失败。
四、最终解决方案
自定义 OllamaApi Bean,显式控制 OkHttp 超时
直接通过配置类覆盖 OllamaApi Bean,创建一个具有足够长读超时的 OkHttpClient,并将其通过 RestClient.Builder 注入到 OllamaApi 中。此方案完全绕过 Spring 的全局 OkHttp 配置,从根源上解决问题。
步骤:
- 在项目中新增配置类
OllamaTimeoutConfig.java。 - 使用
@Value注入spring.ai.ollama.base-url。 - 构建自定义超时的
OkHttpClient。 - 创建
RestClient.Builder并设置OkHttp3ClientHttpRequestFactory(虽然已过时,但功能正常,可忽略警告)。 - 提供空
WebClient.Builder实例。 - 调用正确的
OllamaApi三参数构造器并返回 Bean。
完整代码:
package com.badao.ai.config;
import okhttp3.OkHttpClient;
import org.springframework.ai.ollama.api.OllamaApi;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
import org.springframework.web.client.RestClient;
import org.springframework.web.reactive.function.client.WebClient;
import java.time.Duration;
@Configuration
public class OllamaTimeoutConfig {
@Value("${spring.ai.ollama.base-url}")
private String baseUrl;
@Bean
public OllamaApi ollamaApi() {
// 1. 自定义 OkHttpClient 超时
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(Duration.ofSeconds(30)) // 连接超时
.readTimeout(Duration.ofMinutes(3)) // 读超时 3 分钟,大于模型 timeout
.writeTimeout(Duration.ofSeconds(60)) // 写超时
.build();
// 2. 创建 OkHttp3ClientHttpRequestFactory(已过时但可用)
OkHttp3ClientHttpRequestFactory factory =
new OkHttp3ClientHttpRequestFactory(okHttpClient);
// 3. 构建 RestClient.Builder,注入自定义 factory
RestClient.Builder restClientBuilder = RestClient.builder()
.baseUrl(baseUrl)
.requestFactory(factory);
// 4. 提供 WebClient.Builder(必须,传默认空 builder 即可)
WebClient.Builder webClientBuilder = WebClient.builder();
// 5. 调用 OllamaApi 实际构造函数
return new OllamaApi(baseUrl, restClientBuilder, webClientBuilder);
}
}
YAML 配置精简:
既然已经通过代码完全掌控了 HTTP 客户端超时,就可以移除 application.yml 中的 spring.restclient、spring.okhttp 等无关超时配置,保持清晰:
server:
port: 885
logging:
level:
com.badao: debug
org.springframework.ai: debug
spring:
ai:
ollama:
base-url: http://localhost:11434
chat:
options:
model: qwen2.5:7b-instruct
temperature: 0.5
timeout: 120s # 服务端模型生成超时,依然建议保留
embedding:
options:
model: nomic-embed-text
timeout: 120s
servlet:
multipart:
max-file-size: 10MB
max-request-size: 10MB
关键要点
- 读超时必须大于模型超时:这里
readTimeout = 3 分钟,而chat.options.timeout = 2 分钟,留有充足缓冲。 OkHttp3ClientHttpRequestFactory过时警告:不影响功能,可忽略。如需消除,需整体切换到其他 HTTP 客户端(如 JDK HttpClient),但会增加配置复杂度,不值得。- 不要添加额外的 YAML OkHttp 配置,避免干扰。
五、验证效果
- 重新编译并启动应用。
- 发送之前会导致超时的 RAG 请求。
- 观察日志,不再出现
Read timed out或SocketTimeoutException。 - 模型正常返回生成结果,即使耗时超过 10 秒、甚至 1 分钟,也能顺利完成。
六、总结
本次问题的本质是 Spring AI Ollama 使用的底层 OkHttp 读超时默认过短,且 YAML 配置中的服务端超时选项无法控制客户端行为,加上 Spring Boot 全局 OkHttp 属性与 Ollama 自动配置并不互通,导致常规配置尝试全部失效。
最终通过自定义 OllamaApi Bean 直接构建带超时的 OkHttpClient,并依其正确的构造函数注入,彻底解决了超时问题。该方案稳定可靠,推荐遇到同类问题的开发者采用。
更多推荐

所有评论(0)