Models 总览与统一抽象
本教程共 45 篇 · 第 10 篇 · 更新于 2026-08-16 · 约 6 分钟阅读
本节目标:看懂 Spring AI 的模型 API 分层,理解五大模型接口的职责,学会用统一的 ChatOptions 控制不同厂商的模型,掌握跨厂商切换与选型的基本思路。
10.1 为什么需要统一抽象
接入大模型厂商,绕不开一个问题:每家 API 长得都不一样。OpenAI 用 messages 数组,Anthropic 用 system + messages,Ollama 又是另一套参数。业务代码如果直接调厂商接口,换一家就要重写一遍。
Spring AI 的思路和 JDBC 一样。它定义一套通用接口,各家厂商实现这套接口。业务代码只依赖接口,不依赖具体厂商。
这套抽象叫 Model API。官方文档明确说:它是”跨 AI 供应商的可移植 Model API”,覆盖聊天、文生图、音频转录、语音合成、嵌入五类模型,同时提供同步和流式两种调用方式。
10.2 Model API 的三层结构
Spring AI 的模型接口分三层,从通用到具体:
// 第一层:通用模型接口
public interface Model<T extends ModelRequest<?>, R extends ModelResponse<?>> {
R call(T request);
}
// 第二层:模型大类接口
public interface ChatModel extends Model<Prompt, ChatResponse>, StreamingChatModel {
// ...
}
// 第三层:厂商实现
public class OpenAiChatModel implements ChatModel, StreamingChatModel {
// ...
}
第一层 Model<T, R> 只干一件事:接收请求,返回响应。第二层按模型类型拆分,比如 ChatModel、EmbeddingModel。第三层是各厂商的实现,OpenAiChatModel、AnthropicChatModel、DeepSeekChatModel 都在这一层。
分层的好处是依赖方向固定。你的代码依赖第二层的接口,具体是哪个厂商的实现,由 Spring 容器注入。
10.3 五大模型接口
Spring AI 2.0 按能力把模型分成五类:
| 接口 | 能力 | 典型厂商实现 |
|---|---|---|
| ChatModel / StreamingChatModel | 对话补全,文本生成 | OpenAI、Anthropic、DeepSeek、Ollama |
| EmbeddingModel | 文本转向量,供检索使用 | OpenAI、Ollama、Google |
| ImageModel | 文生图 | OpenAI、Stability |
| AudioModel | 语音转文字、文字转语音 | OpenAI、ElevenLabs |
| ModerationModel | 内容审核,判断文本是否有害 | OpenAI、Mistral |
五类接口都遵循同一套约定:请求封装成 ModelRequest,响应封装成 ModelResponse,参数封装成 ModelOptions。学会一个,其他触类旁通。
其中 ChatModel 是核心,本教程后面大部分章节都围绕它展开。同一个应用可以同时配置多个厂商的模型,用 spring.ai.model.chat 之类的开关选择启用哪个,具体见第 16 章。
10.4 ChatModel 接口
ChatModel 的定义很简洁:
public interface ChatModel extends Model<Prompt, ChatResponse>, StreamingChatModel {
default String call(String message) { ... }
ChatResponse call(Prompt prompt);
}
public interface StreamingChatModel extends StreamingModel<Prompt, ChatResponse> {
default Flux<String> stream(String message) { ... }
Flux<ChatResponse> stream(Prompt prompt);
}
注意两点。call(String) 是默认方法,适合快速验证,底层会帮你包一层 Prompt。生产代码通常用 call(Prompt),因为要传多轮消息和参数。
ChatModel 同时继承了 StreamingChatModel,所以同一个对象既能同步调用,也能流式调用。流式返回的是 Reactor 的 Flux<ChatResponse>,边生成边推送。
Note流式接口在 2.0 里是
ChatModel的一部分。1.x 时代需要单独判断模型是否实现了StreamingChatModel,2.0 直接统一了。
10.5 请求与响应:Prompt 和 ChatResponse
ChatModel 的请求类型是 Prompt,响应类型是 ChatResponse。
Prompt 封装两样东西:消息列表和可选的模型参数。
public class Prompt implements ModelRequest<List<Message>> {
private final List<Message> messages;
private ChatOptions modelOptions;
}
Message 是消息接口,按角色区分。SystemMessage 放系统提示词,UserMessage 放用户输入,AssistantMessage 放模型回复。多轮对话就是这些消息按顺序排成的列表。
ChatResponse 封装模型输出。它包含多个 Generation,每个 Generation 里有一条 AssistantMessage 和元数据。
ChatResponse response = chatModel.call(new Prompt("你好"));
String text = response.getResult().getOutput().getText();
getResult() 取第一个 Generation,getOutput() 取里面的 AssistantMessage,getText() 拿文本内容。这条链路是 ChatModel 最常用的取数路径。
10.6 ChatOptions:可移植的参数
每个厂商都有专属参数,比如 OpenAI 的 logitBias。但大部分参数是通用的:温度、最大 token 数、停止序列。Spring AI 把通用参数抽成 ChatOptions 接口:
public interface ChatOptions extends ModelOptions {
String getModel();
Double getTemperature();
Double getTopP();
Integer getTopK();
Integer getMaxTokens();
List<String> getStopSequences();
Double getFrequencyPenalty();
Double getPresencePenalty();
ChatOptions.Builder<?> mutate();
}
用 ChatOptions.builder() 创建实例:
ChatOptions options = ChatOptions.builder()
.model("gpt-4o")
.temperature(0.7)
.maxTokens(500)
.build();
ChatResponse response = chatModel.call(new Prompt("讲个笑话", options));
这套参数是跨厂商的。同一份 ChatOptions,换一个 ChatModel 实现照样能用。厂商专属参数则放在各自的 Options 类里,比如 OpenAiChatOptions,用法不变。
10.7 两层配置机制
模型参数有两个设置时机,官方文档叫”启动配置”和”运行时配置”。
启动配置在 application.properties 里写,是全局默认值。运行时配置通过 Prompt 携带,只影响当前这次请求。
规则只有一条:运行时配置完全覆盖启动配置。拿温度举例,属性里配了 0.8,某次请求在 Prompt 里传 0.2,这次就用 0.2。
# 启动配置:全局默认
spring.ai.openai.chat.model=gpt-4o
spring.ai.openai.chat.temperature=0.8
// 运行时配置:仅本次请求生效,完全覆盖上面的默认值
ChatOptions options = ChatOptions.builder()
.model("gpt-4o")
.temperature(0.2)
.build();
chatModel.call(new Prompt("写一段代码", options));
Tip直接调 ChatModel 时,Prompt 里的 options 必须是完整的。想只改一个参数,用
chatModel.getOptions().mutate()先拿到默认值再改。走 ChatClient 则没这个限制,它会在内部帮你合并。
10.8 跨厂商一致性
统一抽象带来的直接好处是切换厂商成本极低。对比官方文档的聊天模型能力表,各厂商差异主要集中在多模态输入和 API 兼容性上:
| 厂商 | 多模态输入 | 特点 |
|---|---|---|
| OpenAI | 文本、图片、音频 | 输入输出都支持音频,能力最全 |
| Anthropic Claude | 文本、PDF、图片 | 长文档理解强,支持思考模式 |
| DeepSeek | 文本 | OpenAI 兼容,国产性价比高 |
| Ollama | 文本、图片 | 本地部署,数据不出机器 |
| Google GenAI | 文本、PDF、图片、音频、视频 | 多模态覆盖最广 |
选型没有标准答案,但有几条实用建议。
按部署位置分。数据敏感、需要离线运行,选 Ollama 本地部署。追求效果和生态,选 OpenAI 或 Claude。
按功能需求分。要做语音对话,OpenAI 的 gpt-audio 支持音频输入输出。要处理 PDF 合同,Claude 原生支持 PDF 输入。只要文本对话,DeepSeek 这类 OpenAI 兼容厂商足够。
按成本分。国产模型价格优势明显,本地小模型免费但效果有限。建议先用云厂商跑通功能,再评估要不要换本地模型。
最后一条建议:别一开始就上全套。先用一个厂商跑通功能,再按需增加第二个。抽象层的好处是切换成本低,但每多接一个厂商,就多一份配置、多一组测试。接入两个以内是性价比最高的状态。
10.9 小结
Model API 是 Spring AI 的地基。五类模型接口共用一套请求响应模型,ChatOptions 承载跨厂商通用参数,两层配置机制兼顾全局默认和单次覆盖。下一章开始逐个接入厂商,先从 OpenAI 讲起。