跟著這篇走完,你會在本地把 Spring Boot 和 Ollama 接起來:建工程、引 starter、配 base-url、寫一個 ChatClient 接口,再跑一次同步對話和一次流式輸出。整個過程 6 步,每步都有一條命令能驗證自己做對了沒有。文中 localhost:11434 是 Ollama 的預設監聽地址,模型固定用 qwen3:8b;如果你換了端口或換了 tag,把示例值替換掉即可。還沒裝過 Ollama 的話,先去從零跑通 Ollama + Qwen3 本地對話把服務跑起來再回來。

前置條件
| 項 | 要求 | 說明 |
|---|---|---|
| JDK | 17 或更高 | Spring Boot 3.5 要求 Java 17+;本文按站點基線 JDK 17 寫 |
| Maven | 3.9 或更高 | 構建和啟動都用它,低版本對 BOM import 支持不完整 |
| Spring Boot | 3.5.15 | 與站內其他 Spring AI 文章保持同一基線,避免版本行為不一致 |
| Ollama | 0.34.4,已拉好 qwen3:8b |
服務必須在跑、模型必須在本地,見前置文章《從零跑通 Ollama + Qwen3 本地對話》 |
| 記憶體 | 16 GB 以上 | qwen3:8b 按預設 Q4_K_M 量化後約 5 GB 常駐,再加上 JVM 本身 |
先跑這條確認 JDK 和 Maven 都在。
java -version && mvn -v
看到 openjdk version "17..." 和 Apache Maven 3.9.x 就滿足前兩項。命令報 command not found 說明環境變數沒配好,先解決再往下走。
第一步:確認 Ollama 在跑、模型已拉
Spring AI 只是 Ollama 的客戶端,模型在不在、服務通不通跟 Java 程式碼無關。先做一次「服務端體檢」,省得後面把 Java 程式碼來回改。
curl http://localhost:11434/api/version
返回 {"version":"0.34.4"} 說明服務在監聽 11434。返回 curl: (7) Failed to connect to localhost port 11434 是服務沒起,回到前置文章的第一步。
再確認模型真的在本地。
ollama list
輸出裡有 qwen3:8b 一行就算好。列表裡沒有它,先 ollama pull qwen3:8b 再回來;這一步跳過的話,後面 Spring 啟動不報錯、一調用就報 model not found,容易繞彎路。
第二步:創建 Spring Boot 工程
用 start.spring.io 生成:Project 選 Maven,Language 選 Java,Spring Boot 選 3.5.15,Java 選 17,依賴只勾 Spring Web。點 GENERATE 下載 zip,解壓後得到一個標準工程目錄。
工程裡確認有這兩個文件再繼續。
ls pom.xml src/main/java
能看到 pom.xml 和 src/main/java 目錄就說明骨架完整。後面所有程式碼都寫在 src/main/java 下,預設包名是你在生成頁填的 Group + Artifact(本文示例用 com.example.ai)。
第三步:加 Spring AI Ollama 依賴
Spring AI 1.x 起,Ollama 的 starter 名叫 spring-ai-starter-model-ollama(舊名 spring-ai-ollama-spring-boot-starter 是 0.8 版本線的,別混用)。版本統一交給 spring-ai-bom 管,不要在單個依賴上寫版本號。
打開 pom.xml,在 <dependencyManagement> 里加 BOM:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>1.1.8</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
再在 <dependencies> 里加 starter:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-ollama</artifactId>
</dependency>
驗證依賴有沒有真正拉進來。
mvn dependency:tree | grep spring-ai
能看到 spring-ai-ollama、spring-ai-core 等模塊就對了。列表裡只有你手動寫的那個依賴而沒有 spring-ai-core,多半是 BOM 沒生效——檢查 <dependencyManagement> 是不是寫進了父級而不是工程自己的 pom.xml。
第四步:寫 application.yml 設定
Spring AI 對 Ollama 的連接前綴是 spring.ai.ollama。base-url 預設就是 http://localhost:11434,不寫也行,但顯式寫出來能讓後來的排查少一層猜測。
在 src/main/resources/application.yml 寫入:
spring:
ai:
ollama:
base-url: http://localhost:11434
chat:
options:
model: qwen3:8b
temperature: 0.7
model 的值要和 ollama list 裡那一行完全一致(倉庫名:tag)。這裡寫錯的話,應用能正常啟動,一調用就報 model not found。設定鍵名用中劃線,options 是複數,這兩處拼錯會導致屬性綁定不到、模型回退到預設的 mistral。
第五步:寫一個 ChatClient 接口
Spring AI 1.x 推薦用 ChatClient,它由 ChatClient.Builder 構建,構造器注入即可,不需要手動 new。創建一個 ChatController:
package com.example.ai;
import java.util.Map;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ChatController {
private final ChatClient chatClient;
public ChatController(ChatClient.Builder builder) {
this.chatClient = builder.build();
}
@GetMapping("/ai/chat")
public Map<String, String> chat(@RequestParam(defaultValue = "用一句话介绍 Spring Boot") String message) {
String reply = chatClient.prompt()
.user(message)
.call()
.content();
return Map.of("reply", reply);
}
}
鏈路是:prompt() 開一輪 → user() 放用戶消息 → call() 同步拿到響應 → content() 取文本。ChatClient.Builder 是 Spring AI 自動設定註冊的 Bean,Ollama starter 生效後它會自動綁定到 OllamaChatModel。
驗證程式碼能編譯。
mvn -q compile
沒有報錯、退出碼為 0 就過了。這一步如果拋 No qualifying bean of type ChatModel,說明自動設定沒生效,優先檢查第三步的依賴有沒有進 BOM。
第六步:啟動並跑通第一次對話
啟動應用。
mvn spring-boot:run
看到 Started ... in X seconds 就算起來了。日誌裡如果出現 CONNECTION REFUSED 或 model not found 的警告,先別慌——Spring AI 啟動時可能預檢,但這不必然阻塞;真正的判定以調用為準。
另開一個終端發起請求。
curl "http://localhost:8080/ai/chat?message=用一句话解释什么是依赖注入"
第一次調用要等模型權重加載進記憶體,會卡幾秒到幾十秒,屬正常現象。返回 {"reply":"依赖注入是..."} 且 reply 非空,就算跑通了。reply 為空字符串或 null,看應用日誌裡有沒有模型加載失敗、顯存不足的信息。
核心概念
下面這張圖是整條調用鏈路的走向,從左到右就是一次請求的完整路徑。

| 概念 | 是什麼 | 類比 |
|---|---|---|
| ChatModel | Spring AI 對各家模型能力的統一抽象,Ollama 的實現在 OllamaChatModel |
像 JDBC,一套接口接不同驅動 |
| ChatClient | 面向應用的鏈式門面,封裝 prompt / 參數 / 響應解析 | 像 RestClient 之於 HTTP,把底層細節藏起來 |
| base-url | Ollama 服務地址,預設 http://localhost:11434 |
像數據庫連接串,指錯就全連不上 |
| BOM | spring-ai-bom 統一管理 Spring AI 各模塊版本 |
像 Spring Boot BOM 管 starter 版本,避免內部打架 |
| stream() | ChatClient 的流式方法,返回 Flux<String> 逐塊推內容 |
像 curl -N 實時打印,而不是等全部生成完 |
| 自動拉模型 | spring.ai.ollama.init.pull-model-strategy=always 啟動時自動 pull |
像容器啟動自動拉鏡像,生產環境不建議開 |
常見問題
Connection refused: POST http://localhost:11434/api/chat
現象:應用能啟動,一調用接口就拋 ResourceAccessException: I/O error on POST request ... Connection refused。
原因:Spring AI 連不上 Ollama 的 11434 端口。要麼 Ollama 服務沒起,要麼容器/遠程場景下 base-url 寫的是別人機器上的地址。
model "qwen3:9b" not found, try pulling it first
現象:連接是通的,Ollama 回一句 model not found 讓你先 pull。
原因:本地沒這個模型,或 application.yml 裡 model 拼錯(tag 寫錯、倉庫名寫錯)。設定文件回退到預設 mistral 也會這樣,因為你根本沒拉過它。
No qualifying bean of type 'ChatModel'
現象:啟動或注入 ChatClient.Builder 時拋 bean 找不到。
原因:Ollama 自動設定沒生效。常見是 starter 沒引、版本沒走 BOM,或 spring.ai.ollama.chat.options.* 鍵名拼錯導致裝配條件不滿足。
多輪對話到後面報 400,或回答丟掉開頭的內容
現象:單輪沒問題,消息越長越容易 400,或模型開始忘掉早先的設定。
原因:num-ctx 預設只有 2048,歷史加提示詞塞滿後被截斷。本地模型上下文窗口再大,也受設定裡的 num-ctx 限制。
想用 stream() 流式輸出,編譯或運行時說不支持
現象:寫了 chatClient.prompt().user(...).stream().content(),但 IDE 報方法不存在,或運行時行為例外。
原因:Spring AI 的流式只支持 Reactive 棧,命令式工程(只引了 spring-boot-starter-web)預設沒有 Flux。要加 spring-boot-starter-webflux 依賴才能用。
