Spring Boot 4 + Spring AI Ollama 集成踩坑实录
背景:Spring Boot 4.1.0 + Spring AI 2.0.0-RC2 + Ollama(deepseek-r1:1.5b),实现一个简单的流式聊天接口。搭建过程中连续踩了两个坑,在此记录,希望帮到有同样遭遇的同学。
环境
| 组件 | 版本 |
|---|---|
| Java | 21 |
| Spring Boot | 4.1.0 |
| Spring AI | 2.0.0-RC2 |
| Ollama | deepseek-r1:1.5b(部署在局域网 172.16.29.3:11434) |
坑一:Spring AI 版本与 Spring Boot 4 不兼容
报错信息
BeanDefinitionStoreException: Failed to process import candidates for configuration class
[org.springframework.ai.autoconfigure.ollama.OllamaAutoConfiguration]:
Type org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration not present原因
Spring AI 的 1.x 版本(如 1.0.0-M6、1.1.x)是基于 Spring Boot 3.x 构建的,而 Spring Boot 4.x 对模块进行了大幅重构,RestClientAutoConfiguration 的包路径和所属模块都发生了变化。
更关键的是,从 Spring AI 2.0 开始,Ollama 的 starter artifact 名字也改了:
| Spring AI 版本 | Artifact 名 |
|---|---|
| 1.x(Spring Boot 3) | spring-ai-ollama-spring-boot-starter |
| 2.x(Spring Boot 4) | spring-ai-starter-model-ollama |
解决方案
如果你的 Spring Boot 版本是 4.x,必须使用 Spring AI 2.0 系列的依赖:
<properties>
<spring-ai.version>2.0.0-RC2</spring-ai.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-ollama</artifactId>
<version>${spring-ai.version}</version>
</dependency>
</dependencies>版本兼容对照
| Spring Boot | Spring AI | Artifact |
|---|---|---|
| 3.x | 1.0.x / 1.1.x | spring-ai-ollama-spring-boot-starter |
| 4.x | 2.0.x | spring-ai-starter-model-ollama |
提示:Spring AI 2.0.0 GA 版已于 2026 年 5 月底发布,建议优先使用 GA 版本。截至 2026 年 6 月,最新的预发布版本为 RC2。
坑二:系统 HTTP 代理导致 Ollama 流式响应解析失败
报错信息
WebClientResponseException: 200 OK from POST http://172.16.29.3:11434/api/chat,
but response failed with cause: java.lang.NumberFormatException: Empty chunk size
Caused by: java.lang.NumberFormatException: Empty chunk size
at io.netty.handler.codec.http.HttpObjectDecoder.getChunkSize(HttpObjectDecoder.java:1047)应用启动完全正常,Tomcat 监听 8080 端口也没问题,但只要一调用 Ollama 的聊天接口就报错。
排查过程
仔细看堆栈信息,发现一个关键线索:
at io.netty.handler.proxy.HttpProxyHandler$HttpClientCodecWrapper.channelRead(HttpProxyHandler.java:304)HttpProxyHandler 出现在 Netty 的 pipeline 中!这说明 Reactor Netty 的 WebClient 检测到了系统代理,并通过代理转发了对 Ollama 的请求。
Ollama 的流式接口(/api/chat?stream=true)使用 chunked transfer encoding 返回 NDJSON 格式的数据。HTTP 代理在转发这类流式响应时,可能会重新编码 chunked 数据,导致 Netty 的 HttpObjectDecoder 在解析 chunk size 时遇到了空行(\r\n),从而抛出 NumberFormatException: Empty chunk size。
为什么会被代理?
Reactor Netty 的 HttpClient 会自动读取 Java 系统属性或操作系统级别的代理配置(如 macOS 的系统代理、VPN、Charles/mitmproxy 等),然后自动添加 HttpProxyHandler。这在你访问外网时是好事,但访问局域网地址时就成了干扰。
解决方案
方法一:JVM 启动参数排除代理(推荐)
在启动参数中添加 nonProxyHosts,让局域网地址绕过代理:
# IntelliJ IDEA: Run Configuration → VM options
-Dhttp.nonProxyHosts=172.16.29.3
-Dhttps.nonProxyHosts=172.16.29.3也可以使用通配符:
-Dhttp.nonProxyHosts=172.16.29.*|192.168.*|localhost|127.0.0.1
-Dhttps.nonProxyHosts=172.16.29.*|192.168.*|localhost|127.0.0.1方法二:代码中配置(灵活但侵入性强)
如果你不想改 JVM 参数,也可以在 Spring 配置类中自定义 WebClient.Builder,让 Reactor Netty 跳过代理:
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;
import java.net.InetSocketAddress;
import java.net.ProxySelector;
@Configuration
public class ProxyBypassConfig {
@Bean
public WebClient.Builder webClientBuilder() {
// 创建一个不使用代理的 HttpClient
HttpClient httpClient = HttpClient.create()
.proxy(proxy -> proxy
.type(reactor.netty.transport.ProxyProvider.Proxy.HTTP)
.nonProxyHosts("172.16.29.*")
);
return WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(httpClient));
}
}方法三:临时关闭系统代理
如果你只是在本地开发测试,最快的方式是临时关闭 VPN / 系统代理 / 抓包工具。
验证 Ollama 服务本身是否正常
排查时可以用 curl 直接测试 Ollama(curl 默认不走系统代理):
# 非流式测试
curl http://172.16.29.3:11434/api/chat \
-d '{"model":"deepseek-r1:1.5b","messages":[{"role":"user","content":"你好"}],"stream":false}'
# 流式测试
curl http://172.16.29.3:11434/api/chat \
-d '{"model":"deepseek-r1:1.5b","messages":[{"role":"user","content":"你好"}],"stream":true}'如果 curl 能正常返回,说明 Ollama 没问题,问题出在代理。
最终配置参考
pom.xml(关键依赖)
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>4.1.0</version>
</parent>
<properties>
<java.version>21</java.version>
<spring-ai.version>2.0.0-RC2</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-starter-model-ollama</artifactId>
<version>${spring-ai.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>application.yaml
spring:
application:
name: ai-demo
ai:
ollama:
base-url: http://172.16.29.3:11434
chat:
model: deepseek-r1:1.5bChatController(流式聊天接口)
@RequiredArgsConstructor
@RestController
@RequestMapping("/ai")
public class ChatController {
private final ChatClient chatClient;
@RequestMapping(value = "/chat", produces = "text/html;charset=UTF-8")
public Flux<String> chat(@RequestParam(defaultValue = "讲个笑话") String prompt) {
return chatClient
.prompt(prompt)
.stream()
.content();
}
}IntelliJ VM Options
-Dhttp.nonProxyHosts=172.16.29.3
-Dhttps.nonProxyHosts=172.16.29.3总结
| 坑 | 症状 | 根因 | 解法 |
|---|---|---|---|
| 版本不兼容 | 启动失败,RestClientAutoConfiguration not present | Spring AI 1.x 不兼容 Spring Boot 4.x,且 artifact 改名 | 使用 Spring AI 2.0 + spring-ai-starter-model-ollama |
| 代理干扰 | 运行时报 Empty chunk size | 系统 HTTP 代理破坏了 Ollama 流式响应的 chunked 编码 | JVM 参数 -Dhttp.nonProxyHosts 排除局域网地址 |
一句话总结:Spring Boot 4 必须配 Spring AI 2.0,局域网 Ollama 别让代理劫了。
Written on 2026-06-12