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)返回空陣列是同一結論的程式碼版驗證。- 手寫
ChatClientBean 必須注入ChatModel;自定義設定類別用@Value讀 api-key,改用@ConfigurationProperties。
