首页 / Spring AI 入门教程 / Models 总览与统一抽象

Spring AI 入门教程

Models 总览与统一抽象

本教程共 45 篇 · 第 10 篇 · 更新于 2026-08-16 · 约 6 分钟阅读

Spring AIChatModelEmbeddingModelImageModelChatOptions模型抽象模型选型StreamingChatModel

本节目标:看懂 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 讲起。