StackTraces
Spring AI已驗證

Spring AI 報 No qualifying bean of type ChatModel

@debug_master12 天前更新閱讀 6 min00

No qualifying bean of type 'ChatModel'、Unsupported model provider: 'openai'、No beans of 'OpenAiChatModel' type found,這三條報錯指向同一件事:容器裡沒有裝配好的 ChatModel 實現。要麼壓根沒引入對應廠商的 starter,要麼 application.yml 裡的 api-key / model 沒配好,要麼版本沒走 BOM 管理導致內部模塊對不上。按依賴、設定、自動設定三步查,常見成因基本都能定位。

Issue & Env(案發現場與環境)

  • 業務場景:Spring Boot 裡用 Spring AI 調模型,注入 ChatModel 或 ChatClient 時啟動失敗;或者啟動能過,一調 ChatClient 才拋 Unsupported model provider。
  • 環境:Spring AI 1.1.8,Spring Boot 3.5.15,JDK 17。用 OpenAI 時依賴應為 spring-ai-starter-model-openai,設定項在 spring.ai.openai.* 下。
  • 一個反直覺的點:這類故障經常只差一個拼寫或一條依賴,可報錯卻指向 bean 找不到。真正的原因在依賴座標和設定文件裡,跟你的注入語法、跟 @Autowired 寫法都無關。所以看到 bean 找不到就先別改程式碼,先看依賴和設定。

StackTrace(堆疊日誌)

啟動或注入時常見的三種報錯,原文如下:

org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type 'org.springframework.ai.chat.model.ChatModel'
java.lang.IllegalArgumentException: Unsupported model provider: 'openai'
Could not autowire. No beans of 'OpenAiChatModel' type found.

三者表象不同,但都指向同一件事:容器里根本沒有 ChatModel 的實現 Bean。

第一個例外往裡追,完整堆疊是這樣的:

org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type 'org.springframework.ai.chat.model.ChatModel' available:
expected at least 1 bean which qualifies as autowire candidate.
Dependency annotations: {}
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1804)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1363)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1318)
    at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:911)
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:788)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:542)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1355)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1197)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:535)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:338)

DefaultListableBeanFactory 這一串 resolveDependency → createBean 鏈路,就是 Spring 容器在給某個構造器注入 ChatModel 時發現候選為空的全過程。

判斷技巧:棧裡看不到任何 OpenAiAutoConfiguration(或其他廠商 *AutoConfiguration)相關的幀,基本就坐實了自動設定沒生效。自動設定跑過但內部出錯,棧裡會帶上廠商設定類的名字;棧裡從頭到尾只有 DefaultListableBeanFactory 的通用解析鏈路,說明設定類根本沒被加載。

Reproduce(復現程式碼)

最小復現有兩種,都能穩定得到上面的報錯。

第一種,只引 starter、完全不配 spring.ai.*:

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
# application.yml 里没有任何 spring.ai 配置
spring:
  application:
    name: demo

依賴在、設定空,OpenAiAutoConfiguration 因為拿不到 api-key 而不滿足裝配條件,ChatModel 就不註冊。

第二種,設定寫了但 key 拼錯成下劃線:

spring:
  ai:
    openai:
      api_key: ${OPENAI_API_KEY}   # 错:应为 api-key
      chat:
        options:
          model: gpt-4o-mini

api_key 這個鍵 Spring AI 不認,等價於 api-key 沒配,於是回到第一種情況。

Root Cause(根因分析)

Spring AI 採用「廠商即模塊」的設計:用 OpenAI 就引 OpenAI 的 starter,用 Ollama 就引 Ollama 的 starter。starter 自帶自動設定類(如 OpenAiAutoConfiguration),由它在容器裡註冊 ChatModel、ChatClient。鏈路是:加依賴 → 配屬性 → 自動設定註冊 Bean → 程式碼裡注入。任何一環斷了,注入時就報 bean 找不到。下面四個坑覆蓋了絕大多數斷點。

坑 1:沒引入廠商 starter

沒 starter 就沒有自動設定入口。選錯廠商也一樣:配的是 Ollama 卻只引了 OpenAI 的 starter,或者反過來,ChatModel 同樣註冊不上(Ollama 側連不上時另有報錯形態,見 Spring AI Ollama 連接被拒)。以 OpenAI 為例,Spring AI 1.x 起 artifact 名是 spring-ai-starter-model-openai:

<!-- Spring AI 1.x 起的命名 -->
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>

舊名是 spring-ai-openai-spring-boot-starter(0.8 版本線)。不同版本之間 artifact 名不一樣,升級時這類改名見 Spring AI 版本升級的破壞性變更。先確認你引的那個 starter 是不是當前版本對應的名字,名字錯了 Maven 未必報錯,但自動設定一定不加載。

坑 2:版本沒走 BOM,內部模塊版本對不上

Spring AI 迭代快,手動給單個依賴寫版本,很容易出現「你寫的版本和內部拉到的模塊版本不一致」,輕則 ClassNotFoundException,重則自動設定類條件判斷失敗、bean 不註冊。正確做法是用 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>

用 Milestone / Snapshot 版本還要額外配 Spring 倉庫:

<repositories>
    <repository>
        <id>spring-milestones</id>
        <url>https://repo.spring.io/milestone</url>
    </repository>
</repositories>

坑 3:設定屬性沒寫對

只引 starter 還不夠,spring.ai.* 設定也要對:

spring:
  ai:
    openai:
      api-key: ${OPENAI_API_KEY}
      chat:
        options:
          model: gpt-4o-mini
          temperature: 0.2

兩個高頻拼寫錯誤:api-key 寫成 api_key(中劃線 vs 下劃線),模型名寫錯(比如實際是 gpt-4o-mini,寫成了 gpt-4-mini)。這類錯往往導致 OpenAiChatModel 構造失敗後靜默跳過 bean 註冊,日誌裡不算顯眼,特別難查。key 完全沒配時的報錯形態見 Spring AI 報 api-key must be set。

坑 4:手動聲明 ChatClient 沒綁定 ChatModel

繞過自動設定自己寫 @Bean ChatClient 時,必須注入底層 ChatModel:

@Bean
public ChatClient chatClient(ChatModel chatModel) {
    return ChatClient.builder()
        .model(chatModel)          // 必须显式绑定
        .build();
}

ChatClient.builder().build() 不帶 model,內部會嘗試從上下文字典找 ChatModel,初始化順序不對就失敗。這種寫法只適合在測試裡手動塞 model。同樣的漏綁還會讓工具調用靜默失效,見 Spring AI 工具調用不生效。

The Fix(解決方案)

1. 依賴:對齊 starter 名與 BOM

確認引入的是當前版本對應的廠商 starter(OpenAI 用 spring-ai-starter-model-openai),並且版本走 spring-ai-bom(1.1.8)的 dependencyManagement,不給單模塊寫版本號。這步做完,先跑一次 mvn dependency:tree,確認沒有出現兩個不同版本的 spring-ai-core。

2. 設定:核對鍵名與模型名

spring.ai.openai.api-key 用中劃線,chat.options.model 的值必須是廠商真實存在的模型名。核對方法:把 yml 裡的鍵名和上面的正確示例逐字符比一遍,_ 與 - 是兩回事。

3. 自動設定:確認它有沒有生效

啟動時加 --debug,在輸出的 CONDITIONS EVALUATION REPORT 裡搜 OpenAiAutoConfiguration:

java -jar app.jar --debug

在報告裡找到它,看是哪一種:

  • matched:設定類已生效,問題回到坑 3(屬性綁定)。
  • did not match:條件不滿足,報告裡會緊跟一行 Did not match because ...,直接給出缺什麼。
  • excluded:被排除列表擋掉了,查 spring.autoconfigure.exclude。
  • 整個報告裡搜不到這個類:說明它沒進 classpath,回到坑 1(starter 沒引對)。

想用程式碼確認 bean 是否真的在容器裡:

String[] names = context.getBeanNamesForType(ChatModel.class);
System.out.println(Arrays.toString(names));   // 空数组说明自动配置没生效

一個真實的自定義設定坑

如果你在 @Configuration 裡用 @Value 讀 api-key,發現注入進來是 null,甚至日誌打了 Cannot enhance @Configuration bean definition since its singleton instance has been created too early,這是 Spring AI 的設定類初始化得太早,早於屬性綁定。解決是把這段設定改用 @ConfigurationProperties + 構造器注入,而不是 @Value 字段注入。

小結

  • 報 bean 找不到,別先改注入語法,先看依賴和自動設定。
  • 三件套:正確的廠商 starter + BOM 版本管理 + 正確拼寫的 spring.ai.* 設定。
  • 棧裡沒有廠商 *AutoConfiguration 幀,就是自動設定沒加載,基本不用再往下讀堆疊。
  • --debug 看 CONDITIONS EVALUATION REPORT 裡搜設定類名,did not match 會直接告訴你缺什麼;context.getBeanNamesForType(ChatModel.class) 返回空陣列是同一結論的程式碼版驗證。
  • 手寫 ChatClient Bean 必須注入 ChatModel;自定義設定類別用 @Value 讀 api-key,改用 @ConfigurationProperties。

References(參考來源)

最後更新於 2026-09-29

這篇幫到你了嗎?

剛解決了一個棘手的報錯?花兩分鐘記錄下來,幫助下一個遇到同樣問題的開發者。

貢獻一條解法