StackTraces
Spring AI從零跑通

從零跑通 Spring AI + Ollama 本地對話:6 步,外加 5 個容易卡住的地方

@debug_master2026-09-30

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

Spring AI 接 Ollama:從零跑通的六個步驟

前置條件

項 要求 說明
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,看應用日誌裡有沒有模型加載失敗、顯存不足的信息。

核心概念

下面這張圖是整條調用鏈路的走向,從左到右就是一次請求的完整路徑。

Spring AI 接 Ollama 調用鏈路架構圖

概念 是什麼 類比
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 寫的是別人機器上的地址。

相關文章:Spring AI 接 Ollama 報 Connection refused

model "qwen3:9b" not found, try pulling it first

現象:連接是通的,Ollama 回一句 model not found 讓你先 pull。

原因:本地沒這個模型,或 application.yml 裡 model 拼錯(tag 寫錯、倉庫名寫錯)。設定文件回退到預設 mistral 也會這樣,因為你根本沒拉過它。

相關文章:Spring AI 接 Ollama 報 model not found

No qualifying bean of type 'ChatModel'

現象:啟動或注入 ChatClient.Builder 時拋 bean 找不到。

原因:Ollama 自動設定沒生效。常見是 starter 沒引、版本沒走 BOM,或 spring.ai.ollama.chat.options.* 鍵名拼錯導致裝配條件不滿足。

相關文章:Spring AI 報 No qualifying bean of type ChatModel

多輪對話到後面報 400,或回答丟掉開頭的內容

現象:單輪沒問題,消息越長越容易 400,或模型開始忘掉早先的設定。

原因:num-ctx 預設只有 2048,歷史加提示詞塞滿後被截斷。本地模型上下文窗口再大,也受設定裡的 num-ctx 限制。

相關文章:Spring AI 報 400 context_length_exceeded

想用 stream() 流式輸出,編譯或運行時說不支持

現象:寫了 chatClient.prompt().user(...).stream().content(),但 IDE 報方法不存在,或運行時行為例外。

原因:Spring AI 的流式只支持 Reactive 棧,命令式工程(只引了 spring-boot-starter-web)預設沒有 Flux。要加 spring-boot-starter-webflux 依賴才能用。

相關文章:Spring AI 流式輸出:stream 與 SseEmitter

下一步

給本地模型加工具調用

qwen3:8b 支持 function calling,用 @Tool 註解就能讓模型主動調你的方法,和接 MCP 是同一套鏈路。

Spring AI 工具調用不生效

讓對話記住上下文

ChatClient 預設每次都是新會話。接 ChatMemory 和 MessageChatMemoryAdvisor,按 conversation-id 存歷史,才能做真正的多輪對話。

Spring AI 聊天記憶 conversation-id required

把流式輸出接到 Web 層

Flux<String> 只是開始,前端要消費還得處理 SSE 的連接生命週期、超時和斷線重連。

Spring AI 流式輸出:stream 與 SseEmitter

卡在哪一步了?

從零跑通的過程中撞到報錯?把命令和輸出記下來,幫助下一個剛起步的人。

貢獻一條解法