第3天 | Spring AI Alibaba 第一个 AI 应用:ChatModel 基础使用
系列导读:本文是《Spring AI Alibaba 30 天技术博客》系列的第 3 篇。在了解了 Spring AI Alibaba 的整体架构和 Model 体系之后,今天我们将动手写第一个真正的 AI 应用——使用 ChatModel 完成与通义千问的对话交互。
📋 目录
- 1. 本章目标
- 2. 创建 Spring Boot 项目
- 3. 最小可用的 ChatModel 调用
- 4. ChatModel 接口详解
- 5. Prompt 构建完整指南
- 6. ChatOptions 参数配置
- 7. 响应解析:从 ChatResponse 中提取信息
- 8. 完整实战案例:智能翻译助手
- 9. 常见错误排查
- 10. 最佳实践总结
- 11. 总结
1. 本章目标
读完本章,你将能够:
- ✅ 从零搭建一个可运行的 Spring AI Alibaba 项目
- ✅ 使用 ChatModel 完成基本的对话调用
- ✅ 理解 Prompt、Message、ChatResponse 的核心概念
- ✅ 掌握同步、异步、流式三种调用方式
- ✅ 灵活配置模型参数(temperature、maxTokens 等)
- ✅ 构建一个完整的”智能翻译助手”Web 应用
- ✅ 排查常见的 API 调用错误
2. 创建 Spring Boot 项目
我们使用 Spring Boot 3.3+ 配合 Spring AI Alibaba 1.0.0+。推荐使用 start.aliyun.com 初始化项目。
<!-- pom.xml 核心依赖 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.5</version>
</parent>
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring AI Alibaba Starter -->
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter</artifactId>
<version>1.0.0-M5.1</version>
</dependency>
<!-- Lombok(可选,简化代码) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
版本提示:Spring AI Alibaba 的版本迭代较快,请前往 GitHub Releases 确认最新版本。本文基于
1.0.0-M5.1编写。
3. 最小可用的 ChatModel 调用
3.1 配置文件
在 application.yml 中配置通义千问的 API Key:
spring:
ai:
dashscope:
api-key: ${DASHSCOPE_API_KEY:sk-your-api-key-here}
chat:
options:
model: qwen-plus
temperature: 0.7
max-tokens: 2048
安全提醒:切勿将 API Key 硬编码在代码中!使用环境变量或 Spring Cloud Config 等配置中心管理。
3.2 最简代码
只需三行核心代码,就能完成一次 AI 对话:
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component
public class MinimalChatRunner implements CommandLineRunner {
private final ChatModel chatModel;
public MinimalChatRunner(ChatModel chatModel) {
this.chatModel = chatModel;
}
@Override
public void run(String... args) {
// 一行代码完成 AI 对话
String response = chatModel.call("请用一句话解释什么是 Spring AI?");
System.out.println("AI 回复:" + response);
}
}
3.3 运行结果
AI 回复:Spring AI 是一个基于 Spring 框架的 AI 集成库,它提供了统一的编程模型,
让开发者可以轻松地将各种 AI 模型(如 OpenAI、通义千问等)集成到 Spring Boot 应用中,
实现自然语言处理、图像生成等 AI 能力。
这三行代码背后,Spring AI Alibaba 自动完成了以下工作:
- 将字符串包装为
Prompt对象 - 将
Prompt序列化为 DashScope API 所需的 JSON 格式 - 发起 HTTP 请求到通义千问服务
- 解析响应,提取回复文本
- 返回结果
4. ChatModel 接口详解
ChatModel 是 Spring AI 中最核心的接口,定义了三种调用方式:
public interface ChatModel {
// 同步调用:阻塞等待完整响应
String call(String prompt);
// 同步调用(完整版):返回 ChatResponse,包含更多元数据
ChatResponse call(Prompt prompt);
// 流式调用:返回 Flux<ChatResponse>,逐字输出
Flux<ChatResponse> stream(Prompt prompt);
// 异步调用:返回 CompletableFuture<ChatResponse>
default CompletableFuture<ChatResponse> async(Prompt prompt) {
// 默认实现...
}
}
4.1 call():同步调用
// 方式一:简单字符串(适合快速测试)
String result = chatModel.call("你好,介绍一下你自己");
// 方式二:Prompt 对象(生产推荐)
Prompt prompt = new Prompt("你好,介绍一下你自己");
ChatResponse response = chatModel.call(prompt);
String result = response.getResult().getOutput().getText();
适用场景:简单的问答、翻译、摘要等,响应时间在 1~5 秒内可接受的情况。
注意事项:
- 同步调用会阻塞当前线程,直到收到完整响应
- 如果模型响应较慢(如生成长文),可能导致 HTTP 超时
- 生产环境中建议配合
@Async或消息队列使用
4.2 stream():流式调用
流式调用是提升用户体验的关键技术。用户在模型生成过程中就能看到文字逐字出现,而不是等待数秒后一次性显示全部内容。
import org.springframework.ai.chat.model.ChatResponse;
import reactor.core.publisher.Flux;
// 流式调用示例
public void streamChat(String question) {
Prompt prompt = new Prompt(question);
Flux<ChatResponse> responseFlux = chatModel.stream(prompt);
responseFlux
.map(response -> response.getResult().getOutput().getText())
.filter(text -> text != null && !text.isEmpty())
.doOnNext(chunk -> System.out.print(chunk)) // 逐字打印
.doOnError(error -> System.err.println("流式调用出错:" + error.getMessage()))
.doOnComplete(() -> System.out.println("\n[生成完成]"))
.blockLast(); // 等待流完成
}
在 WebFlux 中直接使用:
@RestController
@RequestMapping("/api/chat")
public class ChatController {
private final ChatModel chatModel;
public ChatController(ChatModel chatModel) {
this.chatModel = chatModel;
}
// 返回 Server-Sent Events (SSE),前端可直接用 EventSource 接收
@GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> streamChat(@RequestParam String message) {
return chatModel.stream(new Prompt(message))
.map(response -> response.getResult().getOutput().getText())
.filter(text -> text != null && !text.isEmpty());
}
}
适用场景:
- 聊天界面需要实时显示生成过程
- 生成长文本(文章、代码等),用户希望尽早看到开头
- 需要实时进度反馈的场景
4.3 async():异步调用
import java.util.concurrent.CompletableFuture;
public CompletableFuture<String> asyncChat(String question) {
Prompt prompt = new Prompt(question);
return chatModel.async(prompt)
.thenApply(response -> response.getResult().getOutput().getText());
}
// 使用示例
asyncChat("请写一首关于春天的诗")
.thenAccept(poem -> System.out.println("异步回复:" + poem))
.exceptionally(ex -> {
System.err.println("异步调用失败:" + ex.getMessage());
return null;
});
适用场景:
- 需要并发调用多个 AI 请求
- 不阻塞主线程的后台任务
- 批量处理场景
5. Prompt 构建完整指南
Prompt 是 AI 应用的灵魂。在 Spring AI 中,Prompt 对象是构建请求的核心载体。
5.1 简单文本 Prompt
// 最简单的方式
Prompt prompt = new Prompt("请列出 Java 17 的 5 个新特性");
5.2 多角色消息 Prompt
真实的对话场景中,我们需要区分不同角色的消息:
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.messages.Message;
List<Message> messages = List.of(
// 系统消息:设定 AI 的角色和行为准则
new SystemMessage("你是一位资深的 Java 技术专家,擅长用通俗易懂的方式解释技术概念。"),
// 历史对话:模拟多轮对话上下文
new UserMessage("什么是函数式编程?"),
new AssistantMessage("函数式编程是一种编程范式,它将计算视为数学函数的求值..."),
// 当前用户输入
new UserMessage("那它和面向对象编程有什么区别?")
);
Prompt prompt = new Prompt(messages);
ChatResponse response = chatModel.call(prompt);
5.3 带系统提示的对话
这是最常见的生产模式——通过 SystemMessage 设定 AI 的角色、语气、输出格式等:
public String translateWithRole(String text, String targetLang) {
List<Message> messages = List.of(
new SystemMessage(String.format("""
你是一位专业的翻译专家。请遵守以下规则:
1. 仅输出翻译结果,不要解释
2. 保持原文的语气和风格
3. 专业术语使用业界通用译法
4. 目标语言:%s
""", targetLang)),
new UserMessage(text)
);
return chatModel.call(new Prompt(messages));
}
5.4 带参数的 Prompt
Spring AI 支持使用 PromptTemplate 进行参数化模板填充,这在需要动态替换内容的场景中非常有用:
import org.springframework.ai.chat.prompt.PromptTemplate;
import java.util.Map;
// 模板字符串,使用 {variableName} 占位
String templateText = """
请分析以下代码的问题,并给出修复建议:
语言:{language}
代码:
```
{code}
```
请从以下维度分析:
1. 性能问题
2. 安全隐患
3. 可读性改进
""";
PromptTemplate promptTemplate = new PromptTemplate(templateText);
Prompt prompt = promptTemplate.create(Map.of(
"language", "Java",
"code", """
public class UserService {
public User findUserById(Long id) {
String sql = "SELECT * FROM users WHERE id = " + id;
return jdbcTemplate.queryForObject(sql, User.class);
}
}
"""
));
ChatResponse response = chatModel.call(prompt);
模板引擎:除了简单的
{variable}替换,Spring AI 还支持更复杂的模板语法。我们将在第4天详细讲解 Prompt 工程与模板引擎。
6. ChatOptions 参数配置
模型参数直接影响 AI 的输出质量。理解并正确配置这些参数是写出好应用的关键。
6.1 基础参数
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
model | String | qwen-plus | 使用的模型名称 |
temperature | Double | 0.7 | 创造性程度。0=确定性输出,1=高度随机 |
maxTokens | Integer | 2048 | 最大输出 token 数 |
topP | Double | 0.8 | 核采样阈值,控制输出多样性 |
topK | Integer | 50 | 采样时考虑的 Top-K 候选数 |
stopSequences | List<String> | [] | 遇到这些序列时停止生成 |
presencePenalty | Double | 0.0 | 降低重复话题的倾向(-2.0 ~ 2.0) |
frequencyPenalty | Double | 0.0 | 降低重复词汇的倾向(-2.0 ~ 2.0) |
6.2 通过配置类设置
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AIConfig {
@Bean
public DashScopeChatOptions chatOptions() {
return DashScopeChatOptions.builder()
.withModel("qwen-plus")
.withTemperature(0.7)
.withMaxTokens(4096)
.withTopP(0.8)
.withTopK(50)
.build();
}
}
6.3 运行时动态覆盖
有时不同请求需要不同的参数。例如:创意写作需要高 temperature,代码生成需要低 temperature。Spring AI 允许在每次调用时覆盖默认配置:
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
// 创意写作模式:高创造性
public String creativeWriting(String topic) {
ChatOptions options = DashScopeChatOptions.builder()
.withModel("qwen-plus")
.withTemperature(0.9) // 高创造性
.withTopP(0.95)
.withMaxTokens(4096)
.build();
Prompt prompt = new Prompt(
new UserMessage("请以「" + topic + "」为主题,写一篇散文"),
options // 运行时覆盖配置
);
return chatModel.call(prompt);
}
// 代码生成模式:高精确性
public String codeGeneration(String description) {
ChatOptions options = DashScopeChatOptions.builder()
.withModel("qwen-plus")
.withTemperature(0.1) // 低创造性,高精确性
.withTopP(0.5)
.withMaxTokens(8192) // 代码可能很长
.build();
Prompt prompt = new Prompt(
new UserMessage("请实现以下功能:\n" + description),
options
);
return chatModel.call(prompt);
}
7. 响应解析:从 ChatResponse 中提取信息
完整的 ChatResponse 包含丰富的元数据,不只是回复文本那么简单。
Prompt prompt = new Prompt("请解释什么是微服务");
ChatResponse response = chatModel.call(prompt);
// === 1. 获取回复文本 ===
String text = response.getResult().getOutput().getText();
System.out.println("回复:" + text);
// === 2. 获取 Token 用量 ===
Usage usage = response.getMetadata().getUsage();
System.out.println("Prompt Tokens: " + usage.getPromptTokens());
System.out.println("Completion Tokens: " + usage.getCompletionTokens());
System.out.println("Total Tokens: " + usage.getTotalTokens());
// === 3. 获取 Finish Reason ===
String finishReason = response.getResult().getMetadata().getFinishReason();
System.out.println("结束原因:" + finishReason);
// 可能的值:
// - "stop":正常完成
// - "length":达到了 maxTokens 限制
// - "content_filter":触发了内容安全过滤
// === 4. 获取模型信息 ===
String model = response.getMetadata().getModel();
System.out.println("使用模型:" + model);
// === 5. 获取 ID ===
String id = response.getMetadata().getId();
System.out.println("请求 ID:" + id);
7.1 获取回复文本
最常见的操作——直接获取 AI 的回复内容:
String result = chatModel.call("你好");
// 等价于:
ChatResponse response = chatModel.call(new Prompt("你好"));
String result2 = response.getResult().getOutput().getText();
7.2 获取 Token 用量
Token 用量监控对于成本控制至关重要:
import org.springframework.ai.chat.metadata.Usage;
public void logUsage(Prompt prompt, ChatResponse response) {
Usage usage = response.getMetadata().getUsage();
// 记录到日志系统
log.info("AI 调用 - PromptTokens: {}, CompletionTokens: {}, TotalTokens: {}",
usage.getPromptTokens(),
usage.getCompletionTokens(),
usage.getTotalTokens()
);
// 可以用于计费统计
// double cost = calculateCost(usage.getTotalTokens());
}
7.3 获取 Finish Reason
判断 AI 是否完整回答了你的问题:
String finishReason = response.getResult().getMetadata().getFinishReason();
switch (finishReason) {
case "stop" -> System.out.println("正常完成");
case "length" -> {
System.out.println("回答被截断!考虑增加 maxTokens 参数");
// 可以继续发送请求让 AI 补充
}
case "content_filter" -> {
System.out.println("触发了内容安全过滤");
// 记录并处理
}
default -> System.out.println("未知结束原因:" + finishReason);
}
8. 完整实战案例:智能翻译助手
让我们把前面学到的所有知识整合起来,构建一个功能完整的智能翻译 Web 应用。
8.1 项目结构
src/main/java/com/example/translator/
├── TranslatorApplication.java # 启动类
├── config/
│ └── AIConfig.java # AI 配置
├── service/
│ └── TranslationService.java # 翻译业务逻辑
├── controller/
│ └── TranslationController.java # REST API
└── dto/
├── TranslationRequest.java # 请求 DTO
└── TranslationResponse.java # 响应 DTO
8.2 配置类
package com.example.translator.config;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AIConfig {
/**
* 翻译场景的专用配置
* 翻译任务需要精确性,设置较低的 temperature
*/
@Bean("translationOptions")
public DashScopeChatOptions translationOptions() {
return DashScopeChatOptions.builder()
.withModel("qwen-plus")
.withTemperature(0.2) // 翻译需要精确,低创造性
.withTopP(0.5)
.withMaxTokens(4096)
.build();
}
}
8.3 Service 层
package com.example.translator.service;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
@Service
public class TranslationService {
private final ChatModel chatModel;
private final DashScopeChatOptions translationOptions;
// 支持的语言对
private static final Map<String, String> LANG_PAIRS = Map.of(
"zh-en", "中文 -> 英文",
"en-zh", "英文 -> 中文",
"zh-ja", "中文 -> 日文",
"ja-zh", "日文 -> 中文",
"zh-ko", "中文 -> 韩文",
"en-ja", "英文 -> 日文"
);
public TranslationService(
ChatModel chatModel,
@Qualifier("translationOptions") DashScopeChatOptions translationOptions) {
this.chatModel = chatModel;
this.translationOptions = translationOptions;
}
/**
* 执行翻译
*/
public TranslationResult translate(String text, String langPair) {
if (!LANG_PAIRS.containsKey(langPair)) {
throw new IllegalArgumentException("不支持的语言对:" + langPair);
}
String langDirection = LANG_PAIRS.get(langPair);
String[] langs = langPair.split("-");
String targetLangName = getLangName(langs[1]);
// 构建系统提示
SystemMessage systemMessage = new SystemMessage(buildSystemPrompt(langDirection, targetLangName));
// 构建用户消息
UserMessage userMessage = new UserMessage(text);
// 构建 Prompt
Prompt prompt = new Prompt(
List.of(systemMessage, userMessage),
translationOptions
);
// 调用 AI
ChatResponse response = chatModel.call(prompt);
// 提取结果
String translatedText = response.getResult().getOutput().getText();
int promptTokens = response.getMetadata().getUsage().getPromptTokens();
int completionTokens = response.getMetadata().getUsage().getCompletionTokens();
return new TranslationResult(
text,
translatedText,
langDirection,
promptTokens,
completionTokens
);
}
/**
* 构建系统提示词
*/
private String buildSystemPrompt(String langDirection, String targetLangName) {
return """
你是一位专业的翻译专家,精通 %s 的互译。请遵守以下规则:
1. 仅输出翻译结果,不要添加任何解释或额外内容
2. 保持原文的语气、风格和情感
3. 专有名词、品牌名、技术术语保留原文或使用业界通用译法
4. 如果原文有多个段落,逐段翻译
5. 如果遇到无法确定的内容,使用 [?] 标记
6. 不要对原文内容进行评判或补充说明
当前翻译方向:%s
请确保翻译准确、流畅、自然。
""".formatted(langDirection, targetLangName);
}
private String getLangName(String code) {
return Map.of(
"zh", "中文",
"en", "英文",
"ja", "日文",
"ko", "韩文"
).getOrDefault(code, code);
}
/**
* 翻译结果 DTO
*/
public record TranslationResult(
String originalText,
String translatedText,
String langDirection,
int promptTokens,
int completionTokens
) {}
}
8.4 Controller 层
package com.example.translator.controller;
import com.example.translator.service.TranslationService;
import com.example.translator.service.TranslationService.TranslationResult;
import jakarta.validation.constraints.NotBlank;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
@RestController
@RequestMapping("/api/translate")
public class TranslationController {
private final TranslationService translationService;
public TranslationController(TranslationService translationService) {
this.translationService = translationService;
}
/**
* 翻译接口
* POST /api/translate
* Body: { "text": "你好世界", "langPair": "zh-en" }
*/
@PostMapping
public ResponseEntity<Map<String, Object>> translate(
@RequestBody TranslationRequest request) {
TranslationResult result = translationService.translate(
request.text(),
request.langPair()
);
return ResponseEntity.ok(Map.of(
"success", true,
"data", Map.of(
"original", result.originalText(),
"translated", result.translatedText(),
"direction", result.langDirection(),
"tokens", Map.of(
"prompt", result.promptTokens(),
"completion", result.completionTokens(),
"total", result.promptTokens() + result.completionTokens()
)
)
));
}
/**
* 获取支持的语言对
* GET /api/translate/languages
*/
@GetMapping("/languages")
public ResponseEntity<Map<String, String>> getLanguages() {
return ResponseEntity.ok(Map.of(
"zh-en", "中文 → 英文",
"en-zh", "英文 → 中文",
"zh-ja", "中文 → 日文",
"ja-zh", "日文 → 中文",
"zh-ko", "中文 → 韩文",
"en-ja", "英文 → 日文"
));
}
/**
* 请求 DTO
*/
public record TranslationRequest(
@NotBlank(message = "翻译文本不能为空") String text,
@NotBlank(message = "语言对不能为空") String langPair
) {}
}
8.5 测试验证
# 1. 查看支持的语言
curl http://localhost:8080/api/translate/languages
# 2. 执行翻译
curl -X POST http://localhost:8080/api/translate \
-H "Content-Type: application/json" \
-d '{
"text": "人工智能正在改变世界",
"langPair": "zh-en"
}'
# 响应:
# {
# "success": true,
# "data": {
# "original": "人工智能正在改变世界",
# "translated": "Artificial intelligence is changing the world.",
# "direction": "中文 -> 英文",
# "tokens": {
# "prompt": 45,
# "completion": 12,
# "total": 57
# }
# }
# }
9. 常见错误排查
错误 1:API Key 无效
com.alibaba.dashscope.exception.ApiException: Invalid API-key provided.
解决方案:
- 确认环境变量
DASHSCOPE_API_KEY已正确设置 - 前往 DashScope 控制台 确认 Key 状态
- 检查
application.yml中的配置路径是否正确
错误 2:模型不存在
Model not found: qwen-turbo-pro
解决方案:
- 确认模型名称拼写正确(常见模型:
qwen-turbo、qwen-plus、qwen-max) - 确认你的账户有权限访问该模型
- 参考 DashScope 模型列表
错误 3:Token 超限
This model's maximum context length is 8192 tokens.
解决方案:
- 减少 Prompt 中的输入内容
- 如果对话历史过长,进行摘要或截断
- 切换到支持更大上下文的模型(如
qwen-max支持 32768 tokens)
错误 4:超时
java.net.SocketTimeoutException: Read timed out
解决方案:
# 在 application.yml 中增加超时配置
spring:
ai:
dashscope:
timeout:
connect: 30s
read: 120s
错误 5:Finish Reason 为 “length”
这说明回答被截断了。解决方案:
- 增加
maxTokens参数 - 使用流式调用,并在截断处继续生成(发送包含已生成内容的 Prompt)
10. 最佳实践总结
🎯 调用方式选择
| 场景 | 推荐方式 | 原因 |
|---|---|---|
| 简单问答、后台批处理 | call() | 实现简单,逻辑清晰 |
| 聊天界面、长文生成 | stream() | 用户体验好,减少等待感 |
| 并发处理、异步任务 | async() | 不阻塞主线程 |
| 实时推荐、低延迟场景 | stream() + 缓存 | 结合缓存减少实际调用 |
🎯 Prompt 设计原则
- 角色明确:始终使用 SystemMessage 设定 AI 角色
- 规则具体:规则越具体,输出越稳定(”仅输出 JSON” 比 “简洁回答” 好)
- 格式固定:输出格式要求用明确的格式说明(JSON Schema、Markdown 等)
- 上下文管理:控制对话历史长度,避免超过模型上下文窗口
🎯 参数调优建议
| 场景 | temperature | topP | maxTokens |
|---|---|---|---|
| 代码生成 | 0.1~0.2 | 0.3~0.5 | 4096~8192 |
| 翻译 | 0.2~0.3 | 0.5~0.7 | 2048~4096 |
| 数据分析 | 0.1~0.3 | 0.5~0.7 | 2048~4096 |
| 创意写作 | 0.7~0.9 | 0.8~0.95 | 4096~8192 |
| 头脑风暴 | 0.8~1.0 | 0.9~1.0 | 2048~4096 |
| 聊天对话 | 0.6~0.8 | 0.7~0.9 | 2048 |
🎯 生产环境建议
- 使用 @Qualifier 区分多个 ChatModel Bean(当你配置了多个模型时)
- 记录每次调用的 Token 用量,用于成本核算
- 设置合理的超时时间,避免无限等待
- 实现重试机制(我们将在后续章节详细介绍)
- 监控 API 响应时间和错误率
11. 总结
今天我们完成了 Spring AI Alibaba 的第一个完整应用。我们从最小化的三行代码出发,逐步深入到:
- ✅ ChatModel 的三种调用方式(同步、异步、流式)
- ✅ Prompt 的多种构建方式(简单文本、多角色消息、参数化模板)
- ✅ ChatOptions 参数配置(全局配置 + 运行时覆盖)
- ✅ ChatResponse 元数据提取(Token 用量、Finish Reason)
- ✅ 完整的智能翻译助手实战项目
核心要点回顾:
- 一行代码即可开始:
chatModel.call("你的问题")是最简单的入口- 生产使用 Prompt 对象:带 SystemMessage 的 Prompt 能获得更稳定的输出
- 流式调用是用户体验的关键:
stream()返回Flux<ChatResponse>,逐字输出- 参数决定输出质量:不同场景需要不同的 temperature 和 maxTokens
- Token 用量需要监控:
response.getMetadata().getUsage()获取用量数据
在下一篇文章中,我们将深入探讨 Prompt 工程与模板引擎,学习如何设计高质量的 Prompt、使用 PromptTemplate 进行参数化模板填充,以及构建可复用的 Prompt 组件。