Spring AI Alibaba 报错合集:我踩过的那些坑

0 阅读7分钟

Spring AI Alibaba 报错合集:我踩过的那些坑

说实话,Spring AI 入门文档写得挺顺的,但真正跑起来报错的时候,那个体验落差能让你怀疑人生。

这不是一篇教你"如何优雅使用 Spring AI"的文章。这是我的踩坑实录,每一个坑都是真实付出过时间代价的。有些错误重复踩过三四次才记住,写下来算是给自己提个醒,顺便帮后来者少走点弯路。


1. JDK 17 以下,报错 Unsupported class file major version XX

报错信息:

java.lang UnsupportedClassVersionError: class file version XX.0 
does not match Java version requirement (class file version must be one of '65')

出现场景:

项目跑起来,直接崩,或者启动时看到 UnsupportedClassVersionError

根因:

Spring AI 基于 Spring Boot 3.x 开发,而 Spring Boot 3.x 要求最低 JDK 17。JDK 8、11、14、16 全都不行。

解决:

Alibaba DragonwellAdoptium 下载安装 JDK 17 或 21,然后:

# 确认当前 Java 版本
java -version

# 如果用的是 IDEA,在 File > Project Structure > Project 
# SDK 里手动改成本地装好的 JDK 17+

这条没什么技巧,就是装 JDK,没别的办法。踩过三次之后我终于把环境变量里的 JAVA_HOME 永久改成了 JDK 21。


2. pom.xml 里的依赖拉不下来,报 Could not resolve dependencies

报错信息:

Could not resolve dependencies for project xxx:chatbot:jar:0.0.1-SNAPSHOT: 
Could not find artifact org.springframework.ai:spring-ai-starter-model-zhipuai:jar:1.1.2

出现场景:

pom.xml 写好了,一 mvn compile,报找不到依赖。

根因:

Spring AI 的包还没进 Maven 中央仓库,spring-ai-starter-model-zhipuai 这类 artifact 都在 Spring 的 Milestone 仓库里。

解决:

在 pom.xml 里补上仓库配置:

<repositories>
    <repository>
        <id>spring-milestones</id>
        <name>Spring Milestones</name>
        <url>https://repo.spring.io/milestone</url>
        <snapshots><enabled>false</enabled></snapshots>
    </repository>
    <repository>
        <id>sonatype-snapshots</id>
        <name>Sonatype Snapshot Repository</name>
        <url>https://oss.sonatype.org/content/repositories/snapshots</url>
        <releases><enabled>false</enabled></releases>
        <snapshots><enabled>true</enabled></snapshots>
    </repository>
</repositories>

这条我第一次踩的时候,百度了半小时没解决,后来发现就是仓库没配。国内网络可能还访问不了国外仓库,要配一下阿里云镜像:

<mirrors>
    <mirror>
        <id>aliyunmaven</id>
        <mirrorOf>*</mirrorOf>
        <name>Aliyun Maven</name>
        <url>https://maven.aliyun.com/repository/public</url>
    </mirror>
</mirrors>

不过注意:sonatype-snapshots 这个仓库如果也被镜像覆盖,snapshot 版本可能拉不到。那就改成:

<mirror>
    <id>aliyunmaven</id>
    <mirrorOf>spring-milestones,central</mirrorOf>
    <name>Aliyun Maven</name>
    <url>https://maven.aliyun.com/repository/public</url>
</mirror>

只镜像 centralspring-milestones,放过 sonatype。


3. API Key 报错 401 UnauthorizedInvalid API key

报错信息:

[ERROR] org.springframework.ai.zhipuai.ZhiPuAiApiException: 
Invalid API key. Please check your API key.

出现场景:

项目启动没问题,接口也调了,但每次请求都返回 401。

根因:

就三个可能:Key 写错了、Key 没生效、环境变量没读到。

排查顺序:

第一步,先看 application.yml 里有没有写死 Key:

spring:
  ai:
    zhipuai:
      api-key: ${ZHIPUAI_API_KEY:your-api-key-here}  # 这里

如果冒号后面那个 your-api-key-here 就是你环境变量的默认值,而你环境变量没配,就会用这个假 Key 去请求。

第二步,确认环境变量名对不对:

# Windows PowerShell
echo $env:ZHIPUAI_API_KEY

# macOS / Linux
echo $ZHIPUAI_API_KEY

输出为空或者空的,就说明环境变量没设上。

第三步,确认 Key 本身没问题。登录 open.bigmodel.cn,进 API Key 管理页面,确认 Key 没被禁用、没过期、额度还有。


4. 模型名写错,报 model not found

报错信息:

[ERROR] ZhiPuAiApiException: model [glm-4.7-flash] not found or not available

出现场景:

配置写好了,Key 也没问题,但就是跑不通。

根因:

模型名大小写敏感,且智谱的模型名格式要求严格。

踩坑记录:

  • 写成 GLM-4(全大写)→ 报错
  • 写成 glm-4-flash(混了glm-4和4.7)→ 报错
  • 写成 glm-4.7-flash(实际想用但当前账号没权限)→ 报错
  • 写成 glm-4 → 成功

正确写法(对照表):

你想用的模型正确写法
GLM-4 最新版glm-4
GLM-4 Flashglm-4-flash
GLM-4.7 Flashglm-4.7-flash
GLM-4V(多模态)glm-4v

建议先在 open.bigmodel.cn 的体验中心测试一下,确认模型能跑再写到配置里。


5. 同时引入多个 Starter,启动报 NoUniqueBeanDefinitionException

报错信息:

NoUniqueBeanDefinitionException: No qualifying bean of type 
'org.springframework.ai.chat.client.ChatClient$Builder' available

出现场景:

同时引了 spring-ai-starter-model-zhipuaispring-ai-starter-model-dashscope,或者同时引了 spring-ai-alibaba-starter,然后启动直接崩。

根因:

每个 Starter 都会自动装配自己的 ChatClient.Builder 实现,同时引入多个 Spring AI 扩展的 Starter,就会产生冲突——Spring 不知道该用哪个 Builder。

踩坑场景还原:

<!-- 这样写会报错 -->
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-model-zhipuai</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba.cloud.ai</groupId>
    <artifactId>spring-ai-alibaba-starter</artifactId>
</dependency>

解决:

按需只选一个。如果当前用智谱,只保留 zhipuai 的 starter;如果后续要换通义,到时候再改。

如果你确实需要同时支持多个模型,可以手动指定使用哪个 Builder:

// 在 @Configuration 类里显式注入需要的 Builder
@Configuration
public class ChatClientConfig {
    
    @Bean
    public ChatClient zhipuChatClient(ChatClient.Builder builder) {
        return builder.defaultSystem("你是一个助手").build();
    }
}

6. ChatMemory 不生效,连续对话记不住上下文

报错信息:

不报错,但连续问问题模型"失忆"了。上一轮说"我叫张三",下一轮问"我叫什么",模型回答"你没有告诉我你的名字"。

踩坑过程:

兴冲冲加了 MessageChatMemoryAdvisor,以为完事了:

// 这是错误的用法,实际每次请求都会创建新的 Memory 实例
.defaultAdvisors(new MessageChatMemoryAdvisor(new InMemoryChatMemory()))

这样写 ChatMemory 是局部变量,请求结束后就没了,每次对话都是全新的。

正确写法:

把 ChatMemory 提出来作为类成员变量:

private final ChatMemory chatMemory = MessageWindowChatMemory.builder()
        .maxMessages(50)
        .build();

public ChatController(ChatClient.Builder chatClientBuilder) {
    this.chatClient = chatClientBuilder
            .defaultSystem(DEFAULT_PROMPT)
            .defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build())
            .defaultAdvisors(new SimpleLoggerAdvisor())
            .build();
}

另外,如果你的应用是多实例部署,每个实例的 ChatMemory 是独立的——A 实例记住的上下文,B 实例不知道。这是分布式场景下的额外坑,需要引入 Redis 等外部存储做 Memory 持久化。


7. 启动成功但接口没响应,一直转圈

报错信息:

无报错,但请求发出去之后一直 pending,30 秒后超时。

踩坑排查过程:

  • 网络通不通?curl http://localhost:8080/chat/simple?query=hi 直接返回,说明本地没问题
  • API Key 有没有额度?没额度不会马上报错,有些平台会静默超时
  • 模型名有没有写错?写错有时候不是报 404,而是静默超时

最后发现:

公司网络限制了外网访问,Java 应用能连 GitHub 拉依赖,但连不上 open.bigmodel.cn,请求发不出去。

解决:

# 测试网络连通性
ping open.bigmodel.cn
curl -v https://open.bigmodel.cn/api/paas/v4

# 如果 ping 不通但能拉依赖,说明是 DNS 污染或者白名单问题
# 可以尝试在 application.yml 里指定 base-url(部分 starter 支持)

在国内用智谱模型,基本不存在这个问题。但如果你用的是通义千问或者 OpenAI,而且走的代理,一定注意不要在代码里设全局代理http.proxyHost),否则可能导致请求头里的 API Key 被意外转发到不该去的地方。


8. @GetMapping 传中文参数变乱码

报错信息:

不报错,但 query 参数传中文,返回的结果像是随机抽的,完全不对。

踩坑过程:

// 以为是模型的问题,结果是编码问题
http://localhost:8080/chat/simple?query=你好

用 Postman 调没问题,用浏览器地址栏直接输就出问题。

根因:

Tomcat 默认 URL 参数编码是 ISO-8859-1,Spring Boot 3.x 虽然默认改成了 UTF-8,但某些版本或配置下仍然有问题。

解决:

application.yml 里显式指定:

server:
  port: 8080
  servlet:
    encoding:
      charset: UTF-8
      enabled: true
      force: true

或者不用 @GetMapping 的 query 参数,改用 @RequestBody 接收 JSON:

@PostMapping("/simple")
public String simpleChat(@RequestBody Map<String, String> request) {
    String query = request.get("query");
    return chatClient.prompt(query).call().content();
}

// 请求体:
// { "query": "你好" }

POST + JSON 彻底绕开 URL 编码问题,推荐这种方式。


9. spring-ai-alibaba 版本升级后 API 变了

报错信息:

升级了 spring-ai-alibaba.version,然后编译报错,很多类找不到或者方法签名变了。

踩坑场景:

1.0.0-M5.1 升级到 1.1.2.2,发现:

  • DashScopeChatOptions 包名变了
  • InMemoryChatMemory 改成了 MessageWindowChatMemory
  • ChatClient.Builder 的配置方法名也有调整

根因:

Spring AI 和 Spring AI Alibaba 都还在快速迭代,版本之间的 API 兼容性没有保证。里程碑版本尤其明显——1.0.0-M11.0.0-M6 之间 API 差距能让人崩溃。

建议:

  • 锁定 BOM 版本,不要用 LATEST 或者不写版本号
  • 升级前先看 Changelog,确认 breaking changes
  • 如果是生产项目,锁定 minor 版本,只做 patch 升级
<properties>
    <spring-ai.version>1.1.2</spring-ai.version>  <!-- 锁定到 1.1.x,不要写 1.x -->
    <spring-ai-alibaba.version>1.1.2.2</spring-ai-alibaba.version>
</properties>

总结:踩坑规律

写完回头看,这些坑有规律:

  1. 环境类:JDK 版本、仓库配置、网络连通性——这类问题只要你第一次搭好环境,后面基本不会再踩
  2. 配置类:API Key、模型名、编码——这类问题有标准解法,踩一次记住就好
  3. 理解类:ChatMemory 实例作用域、多 Starter 冲突、版本兼容性——这类需要真正理解 Spring AI 的设计思想,踩了印象最深

前两类靠细心,第三类靠多读文档多看源码。Spring AI 的文档虽然有些不完整,但源码注释写得挺清楚的,IDE 里 Ctrl+点击 进去看,比百度有效率得多。

有问题欢迎评论区见,说说你踩过哪个最离谱的坑。


🎯 收藏+关注,持续更新

如果觉得有帮助,请:

  1. 收藏本文 —— 方便后续查阅,随时回顾核心概念
  2. 📱 关注同名公众号 —— 点击菜单「获取源码」获取完整代码(Gitee 仓库)
  3. 🔗 分享给同事 —— 一起学习 Spring AI Alibaba,少走弯路

系列更新不迷路,下篇推荐:暂无!后续更新都会以一个实战项目为主