整理时间:2026-10-09
适用版本:Spring AI 1.1.0 / Spring AI Alibaba 1.1.2.x(
spring-ai-alibaba-starter-dashscope)
一、整体定位
ChatModel API 的作用:把"发一段自然语言给模型、拿回一段补全文本"这件事标准化。
- 它建立在 Generic Model API 之上,提供 Chat 特有的抽象;
- 通过
Prompt(输入封装)与ChatResponse(输出封装)统一与各类 AI 模型的通信; - 屏蔽请求拼装与响应解析的复杂度,换模型只需换 Starter + 改配置,业务代码基本不动。
一句话记忆:「ChatModel 吃 Prompt,吐 ChatResponse」。
二、Generic Model API(地基)
java
public interface Model<TReq extends ModelRequest<?>, TRes extends ModelResponse<?>> {
TRes call(TReq request);
}
public interface StreamingModel<TReq extends ModelRequest<?>, TResChunk extends ModelResponse<?>> {
Flux<TResChunk> stream(TReq request);
}
四个配套抽象:
| 接口 | 职责 | 关键方法 |
|---|---|---|
ModelRequest<T> |
封装请求 | T getInstructions()(输入)、ModelOptions getOptions()(参数) |
ModelOptions |
可定制选项 | 标记接口,无方法 |
ModelResponse<T extends ModelResult<?>> |
封装响应 | getResult()、getResults()、getMetadata() |
ModelResult<T> |
单个结果 | T getOutput()、getMetadata() |
泛型是这套 API 的灵魂:
Model<Prompt, ChatResponse>就是 ChatModel 的精确描述。
三、Chat Model API
3.1 两个核心接口
java
public interface ChatModel extends Model<Prompt, ChatResponse>, StreamingChatModel {
default String call(String message) { ... } // 便捷版
@Override ChatResponse call(Prompt prompt); // 正式版
}
public interface StreamingChatModel extends StreamingModel<Prompt, ChatResponse> {
default Flux<String> stream(String message) { ... }
@Override Flux<ChatResponse> stream(Prompt prompt);
}
call(String)/stream(String):快速尝鲜用,返回纯文本,拿不到元数据和 token 用量。call(Prompt)/stream(Prompt):**生产使用」,可携带 System/多轮消息 + 运行时选项。
3.2 Prompt
java
public class Prompt implements ModelRequest<List<Message>> {
private final List<Message> messages;
private ChatOptions modelOptions;
// getInstructions() → messages;getOptions() → modelOptions
}
Prompt = 消息列表 + 可选 ChatOptions 。多轮对话就是把历史一条条塞进 messages。
3.3 Message 体系
java
public interface Content { String getText(); Map<String, Object> getMetadata(); }
public interface Message extends Content { MessageType getMessageType(); }
public interface MediaContent extends Content { Collection<Media> getMedia(); } // 多模态
| 实现类 | 角色 | 场景 |
|---|---|---|
SystemMessage |
system | 人设、规则、输出格式约束 |
UserMessage |
user | 用户输入;对无角色概念的模型,作为标准类别兜底 |
AssistantMessage |
assistant | 模型回复,也是流式输出的载体 |
FunctionMessage |
function | 函数调用结果(旧式) |
ToolResponseMessage |
tool | 工具执行结果(Agent 场景) |
MessageType不是数据格式,而是这条消息在对话中扮演的角色。
3.4 ChatOptions(可移植选项)
java
public interface ChatOptions extends ModelOptions {
String getModel();
Float getFrequencyPenalty(); // -2.0~2.0,降低重复 token
Integer getMaxTokens(); // 最大生成 token
Float getPresencePenalty(); // -2.0~2.0,鼓励谈新主题
List<String> getStopSequences();// 停止序列
Float getTemperature(); // 0.0~2.0,采样温度
Integer getTopK(); // Top-K 采样
Float getTopP(); // Top-P 核采样
ChatOptions copy();
}
各厂商实现可追加私有选项(如 OpenAI 的 logitBias、seed、user),这就是"统一接口 + 厂商扩展"的设计。
3.5 选项合并流程(重要)
① 启动配置 ChatModel 初始化时设置 defaultOptions(全局默认)
↓
② 运行时配置 Prompt 里携带的 ChatOptions(本次请求)
↓
③ 合并 merge:运行时选项 优先 于 启动选项
↓
④ 转换输入 转成厂商原生的请求格式(如 DashScope 的 payload)
↓
⑤ 转换输出 厂商响应 → 标准化 ChatResponse
意义 :全局一套默认参数,个别请求可临时微调(defaultOptions + Prompt(messages, runtimeOptions))。本项目正是这样:全局 application.yml 配 enable-thinking,每次调用在 Prompt 里单独传 temperature(0.7)。
3.6 ChatResponse / Generation
java
public class ChatResponse implements ModelResponse<Generation> {
private final ChatResponseMetadata chatResponseMetadata; // token 用量、速率限制等
private final List<Generation> generations; // n 个候选结果
}
public class Generation implements ModelResult<AssistantMessage> {
private final AssistantMessage assistantMessage;
private ChatGenerationMetadata chatGenerationMetadata; // 结束原因等
}
取值链路(必须记牢):
java
String text = chatResponse.getResult() // Generation(第一个候选)
.getOutput() // AssistantMessage
.getText(); // 文本
getResults()拿全部候选(对应 n>1),getResult()是getResults().get(0)的快捷方式。
四、支持的模型提供商
全部走统一的 ChatModel / StreamingChatModel 接口:
| 提供商 | 流式 | 多模态 | 函数调用 |
|---|---|---|---|
| OpenAI Chat Completion | ✓ | ✓ | ✓ |
| Azure OpenAI | ✓ | --- | ✓ |
| Alibaba DashScope | ✓ | --- | ✓ |
| Ollama | ✓ | ✓ | ✓ |
| Hugging Face | ✗ | --- | --- |
| Google Vertex AI Gemini | ✓ | ✓ | ✓ |
| Amazon Bedrock | --- | --- | --- |
| Mistral AI | ✓ | --- | ✓ |
| Anthropic | ✓ | --- | ✓ |
五、DashScopeChatModel(通义千问)
5.1 前置条件
bash
export AI_DASHSCOPE_API_KEY=your_api_key # 阿里云百炼申请
xml
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
<version>1.1.2.1</version>
</dependency>
5.2 创建与调用
java
DashScopeApi dashScopeApi = DashScopeApi.builder()
.apiKey(System.getenv("AI_DASHSCOPE_API_KEY"))
.build();
ChatModel chatModel = DashScopeChatModel.builder()
.dashScopeApi(dashScopeApi)
.build();
// 简化调用
String r1 = chatModel.call("介绍一下Spring框架");
// 正式调用
Prompt prompt = new Prompt(new UserMessage("解释什么是微服务架构"));
ChatResponse response = chatModel.call(prompt);
String answer = response.getResult().getOutput().getText();
在 Spring Boot 中不需要手写 builder :引入 starter 后自动装配
DashScopeChatModel,直接@Autowired/构造器注入即可(本项目就是构造器注入方式)。
5.3 启动选项 vs 运行时选项
java
// 启动选项:全局默认
DashScopeChatOptions options = DashScopeChatOptions.builder()
.withModel("qwen-plus")
.withTemperature(0.7)
.withMaxToken(2000)
.withTopP(0.9)
.build();
ChatModel chatModel = DashScopeChatModel.builder()
.dashScopeApi(dashScopeApi).defaultOptions(options).build();
// 运行时选项:覆盖默认值
DashScopeChatOptions runtimeOptions = DashScopeChatOptions.builder()
.withTemperature(0.3) // 更确定、更适合评分/抽取
.withMaxToken(500)
.build();
Prompt prompt = new Prompt(new UserMessage("用一句话总结Java的特点"), runtimeOptions);
ChatResponse response = chatModel.call(prompt);
5.4 流式响应
java
Flux<ChatResponse> responseStream = chatModel.stream(
new Prompt("详细解释Spring Boot的自动配置原理"));
responseStream.subscribe(
chatResponse -> System.out.print(chatResponse.getResult().getOutput().getText()),
error -> System.err.println("错误: " + error.getMessage()),
() -> System.out.println("\n流式响应完成")
);
5.5 多轮对话
java
List<Message> messages = List.of(
new SystemMessage("你是一个Java专家"),
new UserMessage("什么是Spring Boot?"),
new AssistantMessage("Spring Boot是..."), // 历史回复要显式回填
new UserMessage("它有什么优势?")
);
ChatResponse response = chatModel.call(new Prompt(messages));
ChatModel 是无状态 的,上下文靠你自己维护消息列表;需要自动记忆请用
ChatMemory或 ReactAgent 的Saver。
5.6 函数调用(Function Calling)
java
ToolCallback weatherFunction = FunctionToolCallback.builder("getWeather", (String city) -> "晴朗,25°C")
.description("获取指定城市的天气") // 描述决定模型何时调用,必须写准
.inputType(String.class)
.build();
DashScopeChatOptions options = DashScopeChatOptions.builder()
.withToolCallbacks(List.of(weatherFunction))
.build();
ChatResponse response = chatModel.call(new Prompt("北京的天气怎么样?", options));
5.7 支持的模型
| 模型 | 特点 |
|---|---|
qwen-turbo |
速度快、成本低,适合高频短任务 |
qwen-plus |
增强版,综合性价比高 |
qwen-max |
旗舰版,复杂推理最强 |
qwen-max-longcontext |
长文本场景 |
选型建议 :出题/创作类用 plus;简历评分、答案评估这类需要稳定判定 + 长 JSON 输出的场景,建议 qwen-max + 低温度(0.2~0.3)。
5.8 与 ReactAgent 集成
java
ReactAgent agent = ReactAgent.builder()
.name("my_agent")
.model(chatModel) // 复用同一个 ChatModel 实例
.systemPrompt("你是一个有帮助的AI助手")
.build();
AssistantMessage response = agent.call("帮我分析这个问题");
六、对照本项目(xs-interview-agent)
MockInterviewService 是这套 API 的标准用法范本:
java
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage(resumeAnalysisSystemPromptResource)); // system 角色
messages.add(new UserMessage(promptTemplate.render(...))); // user 角色
Prompt prompt = new Prompt(messages, // 运行时选项
DashScopeChatOptions.builder().temperature(0.7).build());
String response = chatModel.call(prompt).getResult().getOutput().getText(); // 标准取值链路
对照笔记可做的三处优化:
-
温度分场景 :出题保持 0.7,评分与评估改 0.2(
new Prompt(messages, lowTempOptions)),稳定性明显提升。 -
别丢
ChatResponse:当前链式取值直接丢弃了中间对象,等于丢弃ChatResponseMetadata(token 消耗、finishReason)。建议先接住再做日志/成本统计:javaChatResponse cr = chatModel.call(prompt); log.info("tokens={}", cr.getMetadata().getUsage()); String text = cr.getResult().getOutput().getText(); -
长任务改流式 :
chatModel.stream(prompt)+ SSE 推送到interview.html,解决评估阶段长时间白屏;或用outputType/BeanOutputConverter让框架帮你做结构化输出,替掉手写的JsonNode解析与 JSON 去围栏逻辑。
七、速查卡
java
// 1. 注入(Spring Boot 自动装配,推荐)
private final ChatModel chatModel; // 构造器注入
// 2. 极简
String text = chatModel.call("你好");
// 3. 系统提示 + 用户消息 + 运行时参数
List<Message> msgs = List.of(new SystemMessage("..."), new UserMessage("..."));
Prompt prompt = new Prompt(msgs, DashScopeChatOptions.builder()
.withModel("qwen-plus").withTemperature(0.2).withMaxToken(4096).build());
// 4. 取值
String out = chatModel.call(prompt).getResult().getOutput().getText();
Flux<ChatResponse> flux = chatModel.stream(prompt);
取值链路 :ChatResponse → getResult() → Generation → getOutput() → AssistantMessage → getText()
合并优先级 :运行时 Prompt 的 ChatOptions 覆盖 启动时 defaultOptions。