Spring AI 凭什么能"一套代码换任意大模型"?
用 Java 做 AI 应用的人越来越多,但多数人还在为不同厂商的 API 疲于适配。Spring AI 用一层抽象把 OpenAI、Ollama、Azure 全部统一,业务代码零改动切换模型。这篇拆解它的核心设计。
Java 开发者做 AI 应用有个绕不开的尴尬:今天用 OpenAI,明天想换本地 Ollama 省成本,后天客户要求上 Azure。每换一家,API 调用、鉴权、返回结构全不一样,业务代码得重写一遍。
Spring AI 就是来填这个坑的。它的核心思路一句话:复刻 Spring 对数据库的玩法——用一层抽象,把”具体哪家模型”和”你的业务代码”彻底解耦。正如 JPA 让你不用关心背后是 MySQL 还是 PostgreSQL,Spring AI 让你不用关心背后是 GPT 还是 llama3。
抽象层长什么样
应用层 ChatClient 统一 API
│
Spring AI 抽象层 ChatModel / EmbeddingModel / VectorStore
│
具体实现(Starter) OpenAI / Ollama / Azure / ...
│
底层模型服务 OpenAI API / Ollama 本地 / Azure OpenAI
关键在中间那层 ChatModel 抽象。你写业务代码时只认 ChatClient,具体是谁来实现,由引入的 starter 和配置决定。
切模型只需改配置
这是最实用的部分。先引入两个 starter(只引你需要的):
<!-- OpenAI -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
<!-- 本地 Ollama -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-ollama-spring-boot-starter</artifactId>
</dependency>
切到 OpenAI:
spring:
ai:
openai:
api-key: ${OPENAI_API_KEY}
model: gpt-4
temperature: 0.7
切到本地 Ollama:
spring:
ai:
ollama:
base-url: http://localhost:11434
model: llama3
temperature: 0.7
业务代码一行都不用动:
@Service
public class UnifiedChatService {
private final ChatClient chatClient;
// 注入统一的 Builder,具体实现由配置决定
public UnifiedChatService(ChatClient.Builder chatClientBuilder) {
this.chatClient = chatClientBuilder.build();
}
// 完全不关心底层是 OpenAI 还是 Ollama
public String chat(String message) {
return chatClient.prompt()
.user(message)
.call()
.content();
}
}
从云端大模型迁到本地模型,改个 yml 就行。对企业来说,这意味着”厂商锁定”的顾虑基本消失。
ChatClient 的设计哲学:AI 世界的 JdbcClient
官方把 ChatClient 类比为 JDBC 层的 JdbcClient——高级抽象、方便使用;而 ChatModel 是底层核心、负责协议适配。这个类比很准。
它用建造者模式提供链式调用,读起来很顺:
String response = chatClient.prompt()
.system("You are a helpful assistant")
.user("What is Spring AI?")
.options(ChatOptions.builder().temperature(0.8).build())
.call()
.content();
几个我觉得真正提升开发体验的点:
结构化输出:直接把 LLM 返回的 JSON 映射成 Java 对象,不用自己解析。
public record ActorFilms(String actor, List<String> movies) {}
ActorFilms result = chatClient.prompt()
.user("Generate the filmography for Tom Hanks")
.call()
.entity(ActorFilms.class); // 自动 JSON 解析 + 类型转换
顾问链(Advisor Chain):这是我最想推荐的。它用责任链模式在请求/响应前后做拦截增强,日志、记忆、RAG、工具调用全是 Advisor,可以像搭积木一样组合:
ChatClient client = ChatClient.builder(chatModel)
.defaultAdvisors(loggerAdvisor, memoryAdvisor, ragAdvisor, toolAdvisor)
.build();
比如加一个 QuestionAnswerAdvisor 就把 RAG 接进来了,业务代码完全无感。从 1.1.0 开始还有递归顾问,能做”输出不达标就自动重试”的迭代工作流。
为什么这件事对 Java 开发者重要
Python 生态里换模型也不算难,但 Java 后端的特点是企业级、长生命周期、怕绑定。Spring AI 把”可移植性”做成默认值,配合 Spring Boot 的 starter 自动配置,样板代码极少。
我目前用它在做两件事:一是把内部知识库问答从 OpenAI 切到本地模型,成本直接归零;二是用 Advisor 链把日志、记忆、RAG 串成一条流水线,比自己拼 HTTP 调用清爽太多。
如果你的技术栈是 Java,又想碰 AI,Spring AI 是目前最省心的入口。欢迎在关于页找我交流。
关注我