一、为什么需要 Spring AI
直接在 Java 项目中调用大模型,通常要处理 HTTP 请求、身份认证、请求参数、响应解析、流式传输以及不同模型厂商之间的协议差异。当应用从一个模型切换到另一个模型时,这些差异还会进入业务代码。
Spring AI 的作用,是借鉴 Spring 生态一贯的抽象设计,为 AI 应用提供相对统一的编程模型。开发者可以更多地面向 `ChatModel`、`ChatClient`、`Prompt` 等 Spring AI 抽象编程,而不是让业务代码直接依赖某一家模型厂商的原始 SDK。
Spring AI 并不是一个大模型,也不会替我们训练模型。它更像连接 Java 应用与大模型服务之间的工程化适配层。
二、本文学习目标
学完本文,你应该能够回答以下问题:
-
Spring AI 的聊天模型 API 解决了什么问题?
-
`ChatModel` 和 `ChatClient` 有什么区别?
-
`Message`、`Prompt`、`Generation` 和 `ChatResponse` 分别表示什么?
-
为什么调用一次聊天接口,并不等于实现了多轮对话?
-
同步调用和流式调用在接口层面有什么区别?
三、核心对象之间的关系

3.1 Message:带有角色的消息

例如:
java
```java
SystemMessage systemMessage =
new SystemMessage("你是一名专业的 Java 教师");
UserMessage userMessage =
new UserMessage("请解释什么是依赖注入");
注意:System Message 是对模型的指令和引导,但不能代替权限校验、数据脱敏、输入检查和输出治理。
3.2 Prompt:一次模型请求的输入载体
`Prompt` 用于组织一次模型调用所需的信息。它可以包含一条或多条消息,也可以携带本次请求的模型参数。
java
```java
Prompt prompt = new Prompt(
List.of(systemMessage, userMessage)
);
可以把 `Prompt` 理解为一次模型请求的完整上下文,而不是简单的"提示词字符串"。
3.3 Generation:模型生成的一条候选结果
模型可能返回一个或多个候选答案,Spring AI 使用 `Generation` 表示其中一条生成结果。生成的文本通常位于输出消息中。
java
Generation generation = response.getResult();
String text = generation != null
? generation.getOutput().getText()
: "";
不同 Spring AI 版本中,读取文本的方法可能是 `getText()` 或旧版的 `getContent()`。同一篇文章必须使用与项目依赖一致的 API,不能混用不同版本的写法。
3.4 ChatResponse:完整的模型响应
ChatResponse` 不只包含最终文本,还可能包含:
-
一个或多个生成结果;
-
模型响应元数据;
-
Token 使用量;
-
结束原因;
-
模型供应商提供的其他信息。
如果业务只需要字符串,可以使用便捷方法;如果需要统计 Token、记录模型信息或者分析结束原因,就应保留完整的 `ChatResponse`。
四、ChatModel:底层聊天模型抽象
ChatModel 是 Spring AI 聊天模型体系中的核心接口。它统一了同步调用和流式调用的入口,让上层代码不必直接面向某个厂商的模型客户端。
本文使用版本中的接口结构如下:
java
public interface ChatModel
extends Model<Prompt, ChatResponse>, StreamingChatModel {
default String call(String message) {
Prompt prompt = new Prompt(new UserMessage(message));
Generation generation = call(prompt).getResult();
return (generation != null)
? generation.getOutput().getText()
: "";
}
default String call(Message... messages) {
Prompt prompt = new Prompt(Arrays.asList(messages));
Generation generation = call(prompt).getResult();
return (generation != null)
? generation.getOutput().getText()
: "";
}
@Override
ChatResponse call(Prompt prompt);
default ChatOptions getDefaultOptions() {
return ChatOptions.builder().build();
}
default Flux<ChatResponse> stream(Prompt prompt) {
throw new UnsupportedOperationException(
"streaming is not supported"
);
}
}
4.1 call(String message) 做了什么?
该方法适合最简单的单轮调用:
String answer = chatModel.call("请介绍一下 Spring AI");
从源码可以看出,它在内部完成了以下转换:
bash
String
→ UserMessage
→ Prompt
→ call(Prompt)
→ ChatResponse
→ Generation
→ 文本
因此,`call(String)` 是便捷入口,真正的核心同步方法仍然是 `call(Prompt)`。
4.2 call(Message... messages) 有什么用
这个重载可以一次传入多条不同角色的消息:
java
String answer = chatModel.call(
new SystemMessage("你是一名专业的 Java 教师"),
new UserMessage("请解释 Spring Bean 的生命周期")
);
它比单字符串调用更加灵活,但最终仍只返回文本。如果需要完整元数据,应使用 call(Prompt)。
4.3 call(Prompt prompt) 为什么最重要
java
ChatResponse response = chatModel.call(prompt);
具体模型实现必须实现这个方法。使用它可以:
-
发送多条消息;
-
设置本次调用的模型参数;
-
读取完整的 `ChatResponse`;
-
获取生成结果之外的元数据。
4.4 声明流式能力,不等于所有模型都支持流式输出
`ChatModel` 同时继承 `StreamingChatModel`,但接口中的默认 `stream()` 实现会直接抛出异常:
java
throw new UnsupportedOperationException(
"streaming is not supported"
);
这说明 Spring AI 在接口层面统一了流式调用入口,但具体实现仍需满足两个条件:
-
对应的 `ChatModel` 实现重写了流式方法;
-
底层模型服务本身支持流式响应。
五、ChatClient:面向业务的高层客户端
`ChatClient` 构建在 `ChatModel` 之上,提供类似 `WebClient` 或 `RestClient` 的链式调用体验。
java
String answer = chatClient.prompt()
.user("请介绍一下 Spring AI")
.call()
.content();
相比直接操作 `ChatModel`,`ChatClient` 更适合在业务代码中使用,因为它可以更自然地组织:
System Message 和 User Message;
提示词模板参数;
同步和流式调用;
结构化输出;
Advisor 等增强能力。
二者的层级关系是:
六、ChatClient 与 ChatModel 如何选择

七、一次调用为什么不等于多轮聊天
下面的代码每次只发送当前用户输入:
java
chatClient.prompt()
.user(message)
.call()
.content();
当第二次 HTTP 请求到来时,模型并不知道第一次请求发生过什么。因此,这只是单轮调用,而不是真正具有上下文的多轮聊天。
多轮对话需要显式保存和重新发送历史消息,或者使用 Spring AI 的 Chat Memory、Advisor 等机制。后续会单独用一篇文章讲解。
八、常见问题
8.1 Spring AI 会自动训练模型吗?
不会。Spring AI 主要解决应用集成和工程化问题,模型能力来自 DeepSeek、OpenAI、Ollama 等底层模型服务。
8.2 换模型以后业务代码完全不用改吗?
基础调用通常可以保持相对稳定,但不同模型支持的参数、多模态能力、工具调用能力和返回元数据并不完全相同。统一抽象降低了切换成本,并不意味着所有模型功能完全一致。
九、本文总结
本文需要记住五点:
-
Spring AI 是 Java 应用与大模型服务之间的工程化抽象层。
-
`Message` 表示带角色的消息,`Prompt` 表示一次模型请求的完整输入。
-
`ChatModel` 是底层模型抽象,统一同步和流式调用入口。
-
`ChatClient` 构建在 `ChatModel` 之上,更适合大多数业务开发。
-
单次调用默认没有跨请求记忆,多轮聊天需要额外维护会话上下文。
下一篇将搭建一个完整的 Spring Boot 项目,并通过 `ChatClient` 调用 DeepSeek。