一句話先說結論:Spring AI 是快速迭代的框架,1.0 前後踩了幾乎所有“命名遷移”的坑——舊
ChatClient的功能挪進了ChatModel,EmbeddingClient/ImageClient這類*Client統一改成*Model,starter 的 artifact 名也標準化了。升級時最容易翻車的是照著舊博客抄程式碼,結果類名、包名、設定鍵全對不上。升級前先讀官方 upgrade notes,再用 BOM + OpenRewrite 自動遷移。
背景
Spring AI 從 0.7/0.8 一路發到 1.0(2025-05 GA),每個 milestone 都帶著 breaking change。早期很多教程、博客裡的程式碼是 0.8 時代的,直接照搬到 1.x 項目裡會到處編譯不過。理解那條主線——“把模型訪問能力從 *Client 歸到 *Model”,就能抓住大半變化。
現象
升級後最常見的幾類報錯:
// 类找不到
Cannot resolve symbol 'ChatClient'
// 或者方法名变了
Cannot resolve method 'getGenerationTokens'
// 或者配置键不生效,模型 Bean 没注册
Unsupported model provider: 'openai'
更隱蔽的是:程式碼能編譯、啟動也不報錯,但某些設定項(比如 .options 前綴下的 model)悄悄失效,導致運行時走了預設值,行為不對。
如果舊程式碼的方法在升級後直接沒了,運行時拋的是 NoSuchMethodError,例如還是按老名調 getGenerationTokens():
java.lang.NoSuchMethodError: 'java.lang.Long org.springframework.ai.chat.metadata.Usage.getGenerationTokens()'
at com.example.service.ChatService.ask(ChatService.java:27)
at com.example.controller.ChatController.chat(ChatController.java:42)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:256)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:190)
它是編譯過了、運行才炸的標誌,說明調用點還停留在舊版本的簽名上,只是編譯期和運行期各拿了一個版本的 class。
根因分析
變化 1:Client → Model 的角色遷移
這是最核心的一條。1.0.0-M1 起,舊的 ChatClient 被拆了:
- 模型訪問能力(
call/stream)挪進了ChatModel。 - 新的
ChatClient持有一個ChatModel實例,主打 fluent API(鏈式prompt().user().call())。
同類命名統一也在發生:EmbeddingClient → EmbeddingModel、ImageClient → ImageModel。所以舊程式碼裡凡是 *Client 當模型用的,升級後基本都要改成 *Model。
變化 2:artifact 名標準化
pre-1.0 的 spring-ai-openai-spring-boot-starter 這種長名字,1.0 起統一成 spring-ai-starter-model-openai。memory 相關還加了 repository 後綴:
spring-ai-openai-spring-boot-starter → spring-ai-starter-model-openai
spring-ai-model-chat-memory-jdbc → spring-ai-model-chat-memory-repository-jdbc
spring-ai-elasticsearch-store-spring-boot-starter → spring-ai-starter-vector-store-elasticsearch
只換 starter 名字、不碰內部模塊,就會因為 artifact 找不到而構建失敗。
變化 3:包名和模塊拆分
spring-ai-core 這個大雜燴被拆成了 spring-ai-commons / spring-ai-model / spring-ai-vector-store / spring-ai-client-chat 等。一些類也搬了包:
org.springframework.ai.model.Content → org.springframework.ai.content.Content
org.springframework.ai.transformer.xxx → org.springframework.ai.chat.transformer.xxx
變化 4:方法名和設定鍵
Usage.getGenerationTokens()→getCompletionTokens(),token 計數Long→Integer。- 到 1.1/2.0,設定屬性去掉了
.options這一層:spring.ai.openai.chat.options.model→spring.ai.openai.chat.model(2.0.0-M6 起)。
解決方案
用 BOM 統一版本,不手動寫版本號
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>1.1.7</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
用 BOM 後,starter 和內部模塊版本由 BOM 拉平,避免“版本號各自為政”導致的 ClassNotFoundException。
有官方的 OpenRewrite recipe 可自動化遷移
Spring AI 提供了 OpenRewrite 遷移 recipe(Arconia Spring AI Migrations),能自動改大部分類名/包名/方法名:
# 参考 https://github.com/arconia-io/arconia-migrations
大項目手工改容易漏,建議先跑 recipe 再人工核對剩餘 diff。
升級動作清單
- 查 upgrade notes 對應版本段。
- 升 BOM 版本,改 starter 為標準命名。
*Client→*Model,getGenerationTokens()→getCompletionTokens()。- 檢查包名是否遷移(IDE 的 import 會提示)。
- 檢查設定鍵是否去掉了
.options層。 - 跑一遍測試/壓測確認行為沒變,而不只是編譯通過。
小結
- Spring AI 升級的核心詞是“改名”:
*Client→*Model、artifact 標準化、包名重排、設定鍵去.options。 - 別照抄舊博客,先對照 upgrade notes。
- 用 BOM 管版本 + OpenRewrite 自動化,能省一大半手工活。
- 編譯過了還不夠,設定鍵靜默失效這種要跑功能驗證才抓得到。
