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

这篇帮到你了吗?

刚解决了一个棘手的报错?花两分钟记录下来,帮助下一个遇到同样问题的开发者。

贡献一条解法