2026 Spring AI 核心概念详解:ChatClient、Prompt、Model 三剑客深度解析
Spring AI 核心概念详解:ChatClient、Prompt、Model 三剑客深度解析
作者:架构源启-12年OTA公司资深程序员
技术栈:Spring Boot 3.5.9 + Spring AI 1.1.4
前置知识:可查看第一篇《2026 Java 程序员新标配:Spring AI 最新版本1.1.4 从零搭建 + 避坑指南(收藏版)》

📖 前言
在上一篇文章中,我们成功搭建了第一个 Spring AI 应用。但你可能会有这样的疑问:
- ❓ ChatClient 到底是什么?它和 RestTemplate 有什么区别?
- ❓ Prompt 只是简单的字符串吗?如何写出高质量的提示词?
- ❓ Model 抽象层有什么作用?为什么要统一接口?
- ❓ 如何管理多轮对话的上下文?
- ❓ 如何让 AI 返回结构化的 JSON 数据?
如果你也有这些疑问,那么这篇文章就是为你准备的!
本文将深入解析 Spring AI 的三大核心概念,通过大量代码示例和实战案例,带你真正理解 Spring AI 的设计哲学和使用技巧。
本文你将学到
✅ ChatClient 的设计原理与高级用法
✅ Prompt 工程完整指南(从基础到进阶)
✅ Model 抽象层与多模型切换策略(含 DeepSeek-V4-Pro)
✅ 消息类型详解与上下文管理
✅ 结构化输出最佳实践
✅ 实战:构建智能客服机器人
学习建议
- 💡 边读边敲代码,实践出真知
- 💡 重点关注"设计思想"部分,理解为什么这样设计
- 💡 收藏本文,作为日常开发的参考手册
准备好了吗?让我们开始吧!🚀
🎯 一、ChatClient:Spring AI 的核心入口
1.1 ChatClient 是什么?
ChatClient 是 Spring AI 提供的统一聊天接口,类似于 Spring Data 的 Repository 或 Spring MVC 的 RestTemplate。
传统方式 vs Spring AI:
// ❌ 传统方式:手动调用 HTTP API
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "Bearer " + apiKey);
Map<String, Object> body = new HashMap<>();
body.put("model", "deepseek-v4-flash");
body.put("messages", List.of(
Map.of("role", "user", "content", "你好")
));
ResponseEntity<Map> response = restTemplate.postForEntity(
"https://api.deepseek.com/chat/completions",
new HttpEntity<>(body, headers),
Map.class
);
String content = ((List<Map>) response.getBody().get("choices"))
.get(0)
.get("message")
.get("content")
.toString();
// ✅ Spring AI 方式:简洁优雅
String content = chatClient.prompt()
.user("你好")
.call()
.content();
对比优势:
- 🟢 代码量减少 80%
- 🟢 无需关心 HTTP 细节
- 🟢 自动处理序列化/反序列化
- 🟢 内置错误处理和重试
- 🟢 支持流式输出
- 🟢 模型无关(可轻松切换)
1.2 ChatClient 的初始化方式
方式一:构造函数注入(推荐)
@RestController
@RequestMapping("/chat")
public class ChatController {
private final ChatClient chatClient;
// Spring 自动注入 ChatClient.Builder
public ChatController(ChatClient.Builder builder) {
this.chatClient = builder
.defaultSystem("你是专业的酒店客服助手")
.defaultOptions(OpenAiChatOptions.builder()
.model("deepseek-v4-flash")
.temperature(0.7)
.maxTokens(2048)
.build())
.build();
}
}
优点:
- ✅ 不可变性(final 字段)
- ✅ 便于单元测试
- ✅ 符合 Spring 最佳实践
- ✅ 启动时完成配置,性能更好
方式二:自动注入 ChatClient
@RestController
public class ChatController {
@Autowired
private ChatClient chatClient; // 直接使用
@GetMapping("/chat")
public String chat(String message) {
return chatClient.prompt()
.user(message)
.call()
.content();
}
}
适用场景:使用默认配置,无需自定义
方式三:编程式创建
@Configuration
public class AiConfig {
@Bean
public ChatClient customChatClient(ChatClient.Builder builder) {
return builder
.defaultSystem("""
你是小智,酒店智能助手。
职责:退房、续住、查询、打扫、预订。
要求:友好、专业、简洁。
""")
.defaultOptions(OpenAiChatOptions.builder()
.model("deepseek-v4-flash")
.temperature(0.7)
.maxTokens(1024)
.topP(0.9)
.frequencyPenalty(0.0)
.presencePenalty(0.0)
.build())
.build();
}
}
适用场景:需要多个不同配置的 ChatClient
1.3 ChatClient 的核心方法
// 1. 创建提示词构建器
PromptBuilder promptBuilder = chatClient.prompt();
// 2. 设置系统提示词
promptBuilder.system("你是专业的翻译助手");
// 3. 设置用户消息
promptBuilder.user("Hello, how are you?");
// 4. 添加历史消息
promptBuilder.messages(historyMessages);
// 5. 设置选项(覆盖默认值)
promptBuilder.options(OpenAiChatOptions.builder()
.temperature(0.9)
.build());
// 6. 同步调用(等待完整响应)
ChatResponse response = promptBuilder.call();
// 7. 流式调用(实时返回)
Flux<String> stream = promptBuilder.stream().content();
// 8. 提取内容
String content = response.getResult().getOutput().getContent();
// 9. 转换为实体对象
IntentResponse intent = response.entity(IntentResponse.class);
1.4 ChatClient 的设计思想
建造者模式(Builder Pattern):
chatClient.prompt() // 1. 创建构建器
.system("角色设定") // 2. 配置系统提示
.user("用户问题") // 3. 配置用户消息
.options(options) // 4. 配置选项
.call(); // 5. 执行调用
优势:
- 🎯 链式调用,代码可读性强
- 🎯 灵活配置,可选参数
- 🎯 不可变对象,线程安全
- 🎯 易于扩展新功能
适配器模式(Adapter Pattern):
ChatClient (统一接口)
↓
OpenAiChatModel (OpenAI 适配器)
ZhipuAiChatModel (智谱适配器)
GeminiChatModel (Gemini 适配器)
↓
各自的 HTTP API
优势:
- 🎯 模型无关,轻松切换
- 🎯 新增模型无需修改业务代码
- 🎯 统一的错误处理
💡 二、Prompt 工程:让 AI 更懂你
2.1 什么是 Prompt?
Prompt(提示词)是你与 AI 交流的指令和上下文。好的 Prompt 能让 AI 输出更准确、更有用的结果。
Prompt 的组成:
┌─────────────────────────────────┐
│ System Prompt │ ← 角色设定、行为准则
│ "你是专业的酒店客服助手..." │
├─────────────────────────────────┤
│ Context / History │ ← 对话历史、背景信息
│ User: 我想退房 │
│ AI: 好的,请问房间号是多少? │
├─────────────────────────────────┤
│ User Message │ ← 当前问题
│ "房间号是 1201" │
├─────────────────────────────────┤
│ Examples (Few-shot) │ ← 示例(可选)
│ 例1: ... → ... │
│ 例2: ... → ... │
└─────────────────────────────────┘
2.2 System Prompt 最佳实践
基础模板
String systemPrompt = """
# 角色定义
你是{role},名叫{name}。
# 职责范围
你的职责是:
1. {duty1}
2. {duty2}
3. {duty3}
# 回答规范
- 语气:{tone}
- 长度:{length}
- 格式:{format}
# 限制条件
- {constraint1}
- {constraint2}
# 特殊情况处理
如果遇到{scenario},请{action}。
""";
实战案例:酒店客服助手
@GetMapping("/hotel-assistant")
public String hotelAssistant(@RequestParam String message) {
String systemPrompt = """
# 角色定义
你是小智,XX 酒店的智能客服助手。
# 职责范围
你可以处理以下业务:
1. 查询订单状态
2. 办理退房手续
3. 申请续住服务
4. 预约房间打扫
5. 酒店设施咨询
# 回答规范
- 语气:友好、专业、热情
- 长度:简洁明了,不超过 100 字
- 格式:分点说明,重点突出
# 限制条件
- 只能回答酒店相关问题
- 不提供价格优惠承诺
- 不泄露其他客人信息
# 特殊情况处理
- 如果无法回答,礼貌告知并转人工客服
- 如果客人情绪激动,先安抚再解决问题
- 如果需要具体信息(如房间号),主动询问
# 示例对话
客人:我想退房
你:好的,我可以帮您办理退房。请问您的房间号是多少?
客人:房间号是 1201
你:收到,1201 房间的退房手续已办理。祝您旅途愉快!如有需要,欢迎再次光临。
""";
return chatClient.prompt()
.system(systemPrompt)
.user(message)
.call()
.content();
}
测试效果:
输入:我要续住两天
输出:好的,我可以帮您办理续住。请问您的房间号是多少?
续住两晚的费用是 XXX 元,您确认要办理吗?
2.3 Few-shot Learning(少样本学习)
通过提供示例,让 AI 学习特定的输出格式或风格。
@GetMapping("/sentiment-analysis")
public String sentimentAnalysis(@RequestParam String review) {
String systemPrompt = """
分析酒店评论的情感倾向,返回 JSON 格式。
示例1:
输入:"房间很干净,服务也很好,下次还会来"
输出:{"sentiment": "positive", "score": 0.9, "keywords": ["干净", "服务好"]}
示例2:
输入:"前台态度很差,房间还有异味"
输出:{"sentiment": "negative", "score": 0.2, "keywords": ["态度差", "异味"]}
示例3:
输入:"位置不错,但设施有点旧"
输出:{"sentiment": "neutral", "score": 0.5, "keywords": ["位置好", "设施旧"]}
现在请分析以下评论:
""";
return chatClient.prompt()
.system(systemPrompt)
.user(review)
.call()
.content();
}
测试:
输入:早餐种类丰富,但电梯太慢了
输出:{"sentiment": "neutral", "score": 0.6, "keywords": ["早餐丰富", "电梯慢"]}
2.4 Chain of Thought(思维链)
引导 AI 逐步推理,提高复杂问题的准确性。
@GetMapping("/complex-reasoning")
public String complexReasoning(@RequestParam String question) {
String systemPrompt = """
请按照以下步骤思考问题:
步骤1:理解问题,提取关键信息
步骤2:分析可能的解决方案
步骤3:评估每个方案的优缺点
步骤4:给出最终建议和理由
请按上述步骤详细回答。
""";
return chatClient.prompt()
.system(systemPrompt)
.user(question)
.call()
.content();
}
测试:
输入:我预算 500 元/晚,想要市中心、有健身房、评分 4.5 以上的酒店,推荐哪家?
输出:
步骤1:理解问题
- 预算:500 元/晚
- 位置:市中心
- 设施:健身房
- 评分:4.5 以上
步骤2:分析可能的解决方案
根据您的需求,我筛选出以下候选酒店:
1. XX 国际酒店 - 480 元/晚,评分 4.7,市中心,有健身房
2. YY 商务酒店 - 450 元/晚,评分 4.6,市中心,有健身房
3. ZZ 精品酒店 - 520 元/晚,评分 4.8,市中心,有健身房
步骤3:评估优缺点
- XX 国际酒店:性价比高,但房间较小
- YY 商务酒店:价格最低,但设施较旧
- ZZ 精品酒店:评分最高,但略超预算
步骤4:最终建议
推荐 XX 国际酒店,理由:
1. 符合所有条件
2. 在预算范围内
3. 评分优秀
4. 性价比最高
2.5 Prompt 模板化
使用占位符动态生成 Prompt。
@Service
public class PromptTemplateService {
private final ChatClient chatClient;
public String generateEmail(String recipientName, String purpose, String tone) {
String template = """
请帮我写一封邮件。
收件人:{recipientName}
目的:{purpose}
语气:{tone}
要求:
- 包含称呼和落款
- 正文简洁明了
- 不超过 200 字
""";
String prompt = template
.replace("{recipientName}", recipientName)
.replace("{purpose}", purpose)
.replace("{tone}", tone);
return chatClient.prompt()
.user(prompt)
.call()
.content();
}
}
使用:
String email = promptTemplateService.generateEmail(
"张经理",
"申请项目延期一周",
"正式、诚恳"
);
输出:
尊敬的张经理:
您好!
我是项目负责人李明。由于近期遇到一些技术难题,
为确保项目质量,特申请将项目截止日期延长一周。
我们会加倍努力,确保在新期限内高质量完成任务。
感谢您的理解与支持!
此致
敬礼
李明
2026-05-04
2.6 Prompt 优化技巧
技巧1:明确具体
// ❌ 模糊
"user": "介绍一下酒店"
// ✅ 具体
"user": "请介绍 XX 酒店的位置、设施、特色服务,每点不超过 50 字"
技巧2:指定格式
// ❌ 无格式要求
"user": "列出酒店的优势"
// ✅ 指定格式
"user": "请用 Markdown 表格列出酒店的 5 大优势,包含列:优势、说明、评分"
技巧3:提供上下文
// ❌ 缺少上下文
"user": "怎么办理?"
// ✅ 提供上下文
"user": "我想办理退房,房间号 1201,明天离开,请问流程是什么?"
技巧4:设定约束
// ❌ 无约束
"user": "写一段酒店介绍"
// ✅ 设定约束
"user": "写一段酒店介绍,要求:
- 不超过 100 字
- 突出位置和性价比
- 语气热情
- 适合发朋友圈"
技巧5:迭代优化
// 第一轮:获取初稿
String draft = chatClient.prompt()
.user("写一篇酒店推广文案")
.call()
.content();
// 第二轮:优化
String optimized = chatClient.prompt()
.system("你是专业的文案策划师")
.user("""
请优化以下文案,要求:
- 更有吸引力
- 加入 emoji
- 适合小红书平台
原文:
{draft}
""".replace("{draft}", draft))
.call()
.content();
🔧 三、Model 抽象层:模型无关的设计
3.1 为什么需要 Model 抽象?
问题场景:
假设你的应用使用了 OpenAI 的 GPT-4,但后来发现:
- 成本太高,想切换到智谱 GLM-4
- 或者需要同时支持多个模型
- 或者某些功能只有特定模型支持
如果没有抽象层,你需要修改大量代码。
Spring AI 的解决方案:
业务代码
↓
ChatClient (统一接口)
↓
ChatModel (抽象接口)
↓
┌───────┬───────┬────────┐
│OpenAI │ 智谱 │ Gemini │ ← 具体实现
└───────┴───────┴────────┘
优势:
- 🎯 业务代码无需修改
- 🎯 轻松切换模型
- 🎯 支持多模型并行
- 🎯 便于测试(可 Mock)
3.2 ChatModel 接口
public interface ChatModel {
// 同步调用
ChatResponse call(Prompt prompt);
// 流式调用
Flux<ChatResponse> stream(Prompt prompt);
}
具体实现:
OpenAiChatModel:OpenAI 系列模型(GPT-4o/GPT-4o-mini)ZhipuAiChatModel:智谱 AI 模型(GLM-4/GLM-4-Flash)GeminiChatModel:Google Gemini 模型(gemini-1.5/gemini-2.0)DeepSeekChatModel:DeepSeek 模型(DeepSeek-V4-Pro/DeepSeek-R1)AzureOpenAiChatModel:Azure OpenAI
3.3 多模型配置
配置文件
spring:
ai:
# OpenAI 配置
openai:
api-key: ${OPENAI_API_KEY}
base-url: https://api.openai.com
chat:
options:
model: gpt-5.5
temperature: 0.7
# DeepSeek 配置(推荐 - 性价比高)
deepseek:
api-key: ${DEEPSEEK_API_KEY}
base-url: https://api.deepseek.com
chat:
options:
model: deepseek-v4-flash # DeepSeek-V4-Pro
temperature: 0.7
max-tokens: 8192
# 智谱 AI 配置
zhipuai:
api-key: ${ZHIPU_API_KEY}
chat:
options:
model: glm-4-flash
temperature: 0.7
# Gemini 配置
gemini:
api-key: ${GEMINI_API_KEY}
chat:
options:
model: gemini-3-flash-preview
temperature: 0.7
注入多个 ChatClient
@Configuration
public class MultiModelConfig {
@Bean("openAiChatClient")
public ChatClient openAiChatClient(ChatClient.Builder builder) {
return builder
.defaultOptions(OpenAiChatOptions.builder()
.model("gpt-4o")
.temperature(0.7)
.maxTokens(2048)
.build())
.build();
}
@Bean("deepseekChatClient")
public ChatClient deepseekChatClient(ChatClient.Builder builder) {
return builder
.defaultOptions(DeepSeekChatOptions.builder()
.model("deepseek-chat") // DeepSeek-V4-Pro
.temperature(0.7)
.maxTokens(8192)
.build())
.build();
}
@Bean("zhipuChatClient")
public ChatClient zhipuChatClient(ChatClient.Builder builder) {
return builder
.defaultOptions(ZhipuAiChatOptions.builder()
.model("glm-4-flash")
.build())
.build();
}
@Bean("geminiChatClient")
public ChatClient geminiChatClient(ChatClient.Builder builder) {
return builder
.defaultOptions(GeminiChatOptions.builder()
.model("gemini-1.5-flash")
.build())
.build();
}
}
使用不同的 ChatClient
@RestController
public class MultiModelController {
private final ChatClient openAiClient;
private final ChatClient deepseekClient; // DeepSeek-V4-Pro
private final ChatClient zhipuClient;
private final ChatClient geminiClient;
public MultiModelController(
@Qualifier("openAiChatClient") ChatClient openAiClient,
@Qualifier("deepseekChatClient") ChatClient deepseekClient,
@Qualifier("zhipuChatClient") ChatClient zhipuClient,
@Qualifier("geminiChatClient") ChatClient geminiClient) {
this.openAiClient = openAiClient;
this.deepseekClient = deepseekClient;
this.zhipuClient = zhipuClient;
this.geminiClient = geminiClient;
}
@GetMapping("/chat/openai")
public String chatWithOpenAI(String message) {
return openAiClient.prompt()
.user(message)
.call()
.content();
}
@GetMapping("/chat/deepseek")
public String chatWithDeepSeek(String message) {
return deepseekClient.prompt()
.user(message)
.call()
.content();
}
@GetMapping("/chat/zhipu")
public String chatWithZhipu(String message) {
return zhipuClient.prompt()
.user(message)
.call()
.content();
}
@GetMapping("/chat/gemini")
public String chatWithGemini(String message) {
return geminiClient.prompt()
.user(message)
.call()
.content();
}
}
3.4 智能路由策略
根据问题复杂度自动选择模型:
@Component
public class ModelRouter {
private final ChatClient fastClient; // 快速模型(DeepSeek-V4-Pro)
private final ChatClient smartClient; // 智能模型(GPT-4o)
public ModelRouter(
@Qualifier("deepseekChatClient") ChatClient fastClient,
@Qualifier("openAiChatClient") ChatClient smartClient) {
this.fastClient = fastClient;
this.smartClient = smartClient;
}
public String routeAndChat(String message) {
// 判断问题复杂度
Complexity complexity = analyzeComplexity(message);
// 选择合适的模型
ChatClient selectedClient = switch (complexity) {
case SIMPLE -> fastClient; // 简单问题用 DeepSeek(便宜快速)
case MEDIUM -> fastClient; // 中等问题也用 DeepSeek
case COMPLEX -> smartClient; // 复杂问题用 GPT-4o
};
// 调用选中的模型
return selectedClient.prompt()
.user(message)
.call()
.content();
}
private Complexity analyzeComplexity(String message) {
// 简单启发式规则
if (message.length() < 50 && !containsKeywords(message)) {
return Complexity.SIMPLE;
} else if (message.length() < 200) {
return Complexity.MEDIUM;
} else {
return Complexity.COMPLEX;
}
}
private boolean containsKeywords(String message) {
return message.contains("分析") ||
message.contains("比较") ||
message.contains("为什么");
}
}
enum Complexity {
SIMPLE, MEDIUM, COMPLEX
}
成本对比:
| 模型 | 输入价格 | 输出价格 | 缓存输入价 | 速度 | 适用场景 |
|---|---|---|---|---|---|
| DeepSeek-V4-Pro | ¥3/百万 | ¥6/百万 | ¥0.025/百万 | ⚡⚡⚡ 快 | 日常对话、简单中等任务、长上下文 |
| GLM-4-Flash | 免费 | 免费 | 免费 | ⚡⚡ 中 | 简单问答、文本分类、轻量任务 |
| 智谱 GLM-5.1 | $1.26/百万 | $3.96/百万 | $0.32/百万 | ⚡ 偏慢 | 复杂推理、代码生成、专业创作 |
| 智谱 GLM-5-Turbo | ¥6/百万 | ¥22/百万 | ¥0.5/百万 | ⚡⚡⚡ 快 | 高并发接口、业务中台混合任务 |
| GPT-5.5 | $5.00/百万 | $30.00/百万 | $0.50/百万 | ⚡⚡⚡ 快 | 中等复杂度业务任务、高效推理 |
| GPT-4o | $2.50/百万 | $10.00/百万 | $1.25/百万 | ⚡ 较慢 | 深度复杂推理、专业创作、多模态 |
| Gemini 3 Flash | $0.50/百万 | $3.00/百万 | $0.05/百万 | ⚡⚡⚡⚡ 极速 | 高并发、日常问答、多模态速处理 |
| Gemini 2.5 Pro | $1.25/百万 | $5.00/百万 | 无 | ⚡⚡⚡ 中快 | 百万级长上下文、复杂分析、多模态旗舰 |
💰 性价比分析:
-
最经济选择:GLM-4-Flash(完全免费)
- 适合:原型开发、测试环境、轻量任务
- 注意:功能和性能有限
-
最佳性价比:DeepSeek-V4-Pro
- 价格仅为 GPT-4o 的 1/80(输入)和 1/160(输出)
- 速度快,中文优化好
- 适合:生产环境主力模型
-
最快响应:Gemini 3 Flash
- 速度等级:极速
- 价格适中($0.50/$3.00)
- 适合:高并发场景、实时交互
-
最强能力:GPT-5.5 / Gemini 3.1 Pro
- GPT-5.5:多模态能力强,深度推理
- Gemini 2.5 Pro:百万级长上下文
- 适合:复杂任务、专业创作
💡 智能路由策略建议:
@Component
public class SmartModelRouter {
private final ChatClient freeClient; // GLM-4-Flash(免费)
private final ChatClient fastClient; // DeepSeek-V4-Pro(高性价比)
private final ChatClient ultraFastClient; // Gemini 3 Flash(极速)
private final ChatClient smartClient; // GPT-4o(最强能力)
public String routeAndChat(String message, TaskType taskType) {
return switch (taskType) {
case SIMPLE_QA -> freeClient.prompt() // 免费模型
.user(message).call().content();
case DAILY_CHAT -> fastClient.prompt() // 高性价比
.user(message).call().content();
case HIGH_CONCURRENCY -> ultraFastClient.prompt() // 极速响应
.user(message).call().content();
case COMPLEX_REASONING -> smartClient.prompt() // 最强能力
.user(message).call().content();
};
}
}
3.5 模型选项详解
OpenAI 选项
OpenAiChatOptions options = OpenAiChatOptions.builder()
.model("gpt-5.5") // 模型名称
.temperature(0.7) // 创造性 (0-1),越高越随机
.maxTokens(2048) // 最大 token 数
.topP(0.9) // 核采样 (0-1)
.frequencyPenalty(0.0) // 频率惩罚 (-2 to 2)
.presencePenalty(0.0) // 存在惩罚 (-2 to 2)
.stop(List.of("\n\n", "END")) // 停止序列
.seed(42) // 随机种子(保证可重复)
.build();
DeepSeek 选项(推荐)
DeepSeekChatOptions options = DeepSeekChatOptions.builder()
.model("DeepSeek-V4-Pro") // DeepSeek-V4-Pro
.temperature(0.7) // 创造性 (0-1)
.maxTokens(8192) // 最大 token 数(支持更长输出)
.topP(0.9) // 核采样
.build();
DeepSeek-V4-Pro 特点:
- ✅ 支持超长上下文(64K-128K tokens)
- ✅ 优秀的代码生成能力
- ✅ 强大的数学和逻辑推理
- ✅ 中文理解能力出色
- ✅ API 兼容 OpenAI 格式
参数说明
| 参数 | 范围 | 说明 | 建议值 |
|---|---|---|---|
| temperature | 0-1 | 创造性,0 最确定,1 最随机 | 0.7(平衡) |
| maxTokens | 1-4096 | 最大输出长度 | 1024(够用) |
| topP | 0-1 | 核采样,控制多样性 | 0.9 |
| frequencyPenalty | -2 to 2 | 降低重复内容 | 0.0 |
| presencePenalty | -2 to 2 | 鼓励新话题 | 0.0 |
调优建议:
- 事实性问题:temperature=0.2(更准确)
- 创意写作:temperature=0.9(更有创意)
- 代码生成:temperature=0.3(更稳定)
- 闲聊:temperature=0.7(更自然)
💬 四、消息类型与上下文管理
4.1 消息类型详解
Spring AI 支持多种消息类型:
// 1. 系统消息(System Message)
Message systemMessage = new SystemMessage("你是专业的翻译助手");
// 2. 用户消息(User Message)
Message userMessage = new UserMessage("Hello, how are you?");
// 3. 助手消息(Assistant Message)
Message assistantMessage = new AssistantMessage("I'm fine, thank you!");
// 4. 工具消息(Tool Message)- Function Calling 时使用
Message toolMessage = new ToolMessage("result", "tool-call-id");
消息的作用:
System Message: 设定角色和行为准则(只在开头出现一次)
↓
User Message 1: 用户第一个问题
↓
Assistant Message 1: AI 的第一个回答
↓
User Message 2: 用户第二个问题(基于上下文)
↓
Assistant Message 2: AI 的第二个回答(考虑历史)
4.2 多轮对话实现
方式一:手动管理消息列表
@PostMapping("/conversation")
public String conversation(@RequestBody ConversationRequest request) {
// 构建消息列表
List<Message> messages = new ArrayList<>();
// 添加系统消息
messages.add(new SystemMessage("你是酒店客服助手"));
// 添加历史消息
for (MessageHistory history : request.getHistory()) {
if ("user".equals(history.getRole())) {
messages.add(new UserMessage(history.getContent()));
} else if ("assistant".equals(history.getRole())) {
messages.add(new AssistantMessage(history.getContent()));
}
}
// 添加当前消息
messages.add(new UserMessage(request.getCurrentMessage()));
// 调用 AI
ChatResponse response = chatClient.prompt()
.messages(messages)
.call();
// 返回回答
return response.getResult().getOutput().getContent();
}
请求示例:
{
"history": [
{"role": "user", "content": "你好"},
{"role": "assistant", "content": "你好!有什么可以帮助你的?"}
],
"currentMessage": "我想查询订单"
}
方式二:使用会话存储(推荐)
@Service
public class ConversationService {
private final ChatClient chatClient;
private final ConcurrentHashMap<String, List<Message>> sessions = new ConcurrentHashMap<>();
public String chatWithSession(String sessionId, String message) {
// 获取或创建会话
List<Message> messages = sessions.computeIfAbsent(sessionId,
id -> new ArrayList<>(List.of(
new SystemMessage("你是酒店客服助手")
))
);
// 添加用户消息
messages.add(new UserMessage(message));
// 限制历史长度(避免超出上下文窗口)
if (messages.size() > 20) {
// 保留系统消息 + 最近 18 条消息
messages = new ArrayList<>(messages.subList(messages.size() - 19, messages.size()));
}
// 调用 AI
ChatResponse response = chatClient.prompt()
.messages(messages)
.call();
// 获取回答
String answer = response.getResult().getOutput().getContent();
// 保存助手消息
messages.add(new AssistantMessage(answer));
// 更新会话
sessions.put(sessionId, messages);
return answer;
}
// 清除会话
public void clearSession(String sessionId) {
sessions.remove(sessionId);
}
}
控制器:
@RestController
@RequestMapping("/session")
public class SessionController {
private final ConversationService conversationService;
@PostMapping("/chat")
public String chat(
@RequestParam String sessionId,
@RequestParam String message) {
return conversationService.chatWithSession(sessionId, message);
}
@DeleteMapping("/clear")
public void clear(@RequestParam String sessionId) {
conversationService.clearSession(sessionId);
}
}
测试:
# 第一轮对话
curl -X POST "http://localhost:8080/session/chat?sessionId=user1&message=你好"
# 第二轮对话(AI 记得之前的内容)
curl -X POST "http://localhost:8080/session/chat?sessionId=user1&message=我想退房"
# 清除会话
curl -X DELETE "http://localhost:8080/session/clear?sessionId=user1"
方式三:持久化到数据库
@Entity
@Table(name = "conversation_messages")
@Data
public class ConversationMessage {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String sessionId;
@Enumerated(EnumType.STRING)
private MessageType type; // SYSTEM, USER, ASSISTANT
@Column(length = 4000)
private String content;
private LocalDateTime timestamp;
}
@Repository
public interface MessageRepository extends JpaRepository<ConversationMessage, Long> {
List<ConversationMessage> findBySessionIdOrderByTimestampAsc(String sessionId);
void deleteBySessionId(String sessionId);
}
@Service
public class PersistentConversationService {
private final ChatClient chatClient;
private final MessageRepository messageRepository;
public String chat(String sessionId, String message) {
// 从数据库加载历史
List<ConversationMessage> history = messageRepository.findBySessionIdOrderByTimestampAsc(sessionId);
// 转换为 Message 对象
List<Message> messages = history.stream()
.map(this::convertToMessage)
.collect(Collectors.toList());
// 添加当前消息
messages.add(new UserMessage(message));
// 调用 AI
ChatResponse response = chatClient.prompt()
.messages(messages)
.call();
String answer = response.getResult().getOutput().getContent();
// 保存到数据库
saveMessage(sessionId, MessageType.USER, message);
saveMessage(sessionId, MessageType.ASSISTANT, answer);
return answer;
}
private void saveMessage(String sessionId, MessageType type, String content) {
ConversationMessage msg = new ConversationMessage();
msg.setSessionId(sessionId);
msg.setType(type);
msg.setContent(content);
msg.setTimestamp(LocalDateTime.now());
messageRepository.save(msg);
}
}
4.3 上下文窗口管理
问题:模型的上下文窗口有限(如 GPT-4o 是 128K tokens),超出会报错。
解决方案:
策略1:截断历史
private List<Message> trimHistory(List<Message> messages, int maxMessages) {
if (messages.size() <= maxMessages) {
return messages;
}
// 保留系统消息 + 最近的 N 条消息
Message systemMessage = messages.get(0);
List<Message> recentMessages = messages.subList(
messages.size() - maxMessages + 1,
messages.size()
);
List<Message> trimmed = new ArrayList<>();
trimmed.add(systemMessage);
trimmed.addAll(recentMessages);
return trimmed;
}
策略2:摘要压缩
private String summarizeHistory(List<Message> messages) {
String historyText = messages.stream()
.map(msg -> msg.getType() + ": " + msg.getText())
.collect(Collectors.joining("\n"));
String summary = chatClient.prompt()
.system("请将以下对话历史总结为 100 字以内的摘要")
.user(historyText)
.call()
.content();
return summary;
}
// 使用
String summary = summarizeHistory(oldMessages);
List<Message> compacted = new ArrayList<>();
compacted.add(new SystemMessage("你是酒店客服助手"));
compacted.add(new SystemMessage("对话历史摘要:" + summary));
compacted.add(new UserMessage(currentMessage));
策略3:滑动窗口
// 只保留最近的 N 轮对话
int windowSize = 5; // 5 轮对话 = 10 条消息
List<Message> window = messages.subList(
Math.max(0, messages.size() - windowSize * 2),
messages.size()
);
📊 五、结构化输出:让 AI 返回 JSON
5.1 为什么需要结构化输出?
场景:你需要从用户输入中提取意图和参数。
非结构化输出的问题:
用户:我要退 1201 房间
AI:好的,我来帮您办理 1201 房间的退房手续...
❌ 难以程序化处理
结构化输出:
{
"intent": "CHECK_OUT",
"roomNo": "1201",
"confidence": 0.95
}
✅ 可直接用于业务逻辑
5.2 方法一:Prompt Engineering
@GetMapping("/intent-v1")
public IntentResponse extractIntentV1(@RequestParam String message) {
String systemPrompt = """
分析用户意图,严格返回 JSON 格式,不要有其他内容。
JSON 格式:
{
"intent": "CHECK_OUT|EXTEND_STAY|QUERY|CLEAN|BOOK|OTHER",
"roomNo": "房间号(字符串,没有则为 null)",
"days": 天数(整数,没有则为 null),
"confidence": 置信度 (0-1 的浮点数)
}
示例:
输入:"我要退 1201 房间"
输出:{"intent":"CHECK_OUT","roomNo":"1201","days":null,"confidence":0.95}
输入:"我想续住 2 天"
输出:{"intent":"EXTEND_STAY","roomNo":null,"days":2,"confidence":0.9}
""";
String jsonResult = chatClient.prompt()
.system(systemPrompt)
.user(message)
.call()
.content();
// 解析 JSON
ObjectMapper mapper = new ObjectMapper();
try {
return mapper.readValue(jsonResult, IntentResponse.class);
} catch (Exception e) {
log.error("JSON 解析失败: {}", jsonResult, e);
throw new RuntimeException("意图识别失败");
}
}
IntentResponse 类:
@Data
public class IntentResponse {
private String intent;
private String roomNo;
private Integer days;
private Double confidence;
}
测试:
输入:帮我预约明天上午打扫 1201 房间
输出:{
"intent": "CLEAN",
"roomNo": "1201",
"days": null,
"confidence": 0.92
}
5.3 方法二:使用 entity() 方法(推荐)
Spring AI 1.1.x 提供了更优雅的方式:
@GetMapping("/intent-v2")
public IntentResponse extractIntentV2(@RequestParam String message) {
String systemPrompt = """
分析用户意图,返回 JSON 格式。
可选意图:CHECK_OUT, EXTEND_STAY, QUERY, CLEAN, BOOK, OTHER
""";
return chatClient.prompt()
.system(systemPrompt)
.user(message)
.call()
.entity(IntentResponse.class); // 自动解析为对象
}
优势:
- ✅ 代码更简洁
- ✅ 自动处理 JSON 解析
- ✅ 类型安全
- ✅ 更好的错误提示
5.4 方法三:使用 Bean Output Converter
@Component
public class IntentExtractor {
private final ChatClient chatClient;
private final BeanOutputConverter<IntentResponse> converter;
public IntentExtractor(ChatClient chatClient) {
this.chatClient = chatClient;
this.converter = new BeanOutputConverter<>(IntentResponse.class);
}
public IntentResponse extract(String message) {
String formatInstructions = converter.getFormatInstructions();
String systemPrompt = """
分析用户意图。
{formatInstructions}
""".replace("{formatInstructions}", formatInstructions);
String result = chatClient.prompt()
.system(systemPrompt)
.user(message)
.call()
.content();
return converter.convert(result);
}
}
优势:
- ✅ 自动生成格式说明
- ✅ 支持复杂对象
- ✅ 内置验证
5.5 处理解析错误
public IntentResponse extractWithRetry(String message) {
int maxRetries = 3;
for (int i = 0; i < maxRetries; i++) {
try {
String jsonResult = chatClient.prompt()
.system(INTENT_SYSTEM_PROMPT)
.user(message)
.call()
.content();
ObjectMapper mapper = new ObjectMapper();
return mapper.readValue(jsonResult, IntentResponse.class);
} catch (Exception e) {
log.warn("第 {} 次解析失败", i + 1, e);
if (i == maxRetries - 1) {
// 最后一次失败,返回默认值
return new IntentResponse("OTHER", null, null, 0.0);
}
}
}
throw new RuntimeException("不应该到达这里");
}
5.6 复杂结构化输出
@Data
public class HotelRecommendation {
private String hotelName;
private String location;
private Double pricePerNight;
private Double rating;
private List<String> amenities;
private String reason;
}
@GetMapping("/recommend")
public HotelRecommendation recommendHotel(
@RequestParam String location,
@RequestParam Double budget) {
String systemPrompt = """
根据用户需求推荐酒店,返回 JSON 格式。
要求:
- 价格在预算范围内
- 评分 4.0 以上
- 列出主要设施
- 说明推荐理由
""";
String userMessage = """
位置:{location}
预算:{budget} 元/晚
""".replace("{location}", location)
.replace("{budget}", budget.toString());
return chatClient.prompt()
.system(systemPrompt)
.user(userMessage)
.call()
.entity(HotelRecommendation.class);
}
输出示例:
{
"hotelName": "XX 国际酒店",
"location": "市中心人民广场",
"pricePerNight": 480.0,
"rating": 4.7,
"amenities": ["健身房", "游泳池", "免费WiFi", "停车场"],
"reason": "位于市中心,交通便利,设施齐全,性价比高"
}
🏨 六、实战:构建智能客服机器人
6.1 需求分析
我们要构建一个酒店智能客服机器人,具备以下能力:
- 意图识别:识别用户的需求(退房、续住、查询等)
- 多轮对话:记住上下文,进行自然对话
- 函数调用:调用业务系统执行操作
- 个性化回复:根据用户历史提供个性化服务
6.2 架构设计
用户请求
↓
IntentController (接收请求)
↓
IntentService (意图识别)
↓
IntentRouter (路由到不同处理器)
↓
┌──────┬──────┬──────┬──────┐
│CheckOut│Extend│Query │Clean │ ← 各意图处理器
└──────┴──────┴──────┴──────┘
↓
BusinessService (调用业务系统)
↓
ResponseGenerator (生成回复)
↓
返回给用户
6.3 核心代码实现
意图识别服务
@Service
@Slf4j
public class IntentRecognitionService {
private final ChatClient chatClient;
public IntentRecognitionService(ChatClient chatClient) {
this.chatClient = chatClient;
}
public IntentResponse recognize(String message) {
String systemPrompt = """
你是意图识别专家。分析用户输入,识别意图和提取参数。
支持的意图:
- CHECK_OUT: 退房
- EXTEND_STAY: 续住
- QUERY: 查询订单/房间状态
- CLEAN: 预约打扫
- BOOK: 预订房间
- OTHER: 其他
返回 JSON 格式:
{
"intent": "意图类型",
"roomNo": "房间号(如果有)",
"days": 天数(如果是数字),
"date": 日期(如果有,格式 YYYY-MM-DD)",
"confidence": 置信度 (0-1)
}
只返回 JSON,不要有其他内容。
""";
try {
IntentResponse intent = chatClient.prompt()
.system(systemPrompt)
.user(message)
.call()
.entity(IntentResponse.class);
log.info("意图识别结果: {}", intent);
return intent;
} catch (Exception e) {
log.error("意图识别失败", e);
return new IntentResponse("OTHER", null, null, null, 0.0);
}
}
}
意图路由器
@Component
public class IntentRouter {
private final CheckOutHandler checkOutHandler;
private final ExtendStayHandler extendStayHandler;
private final QueryHandler queryHandler;
private final CleanHandler cleanHandler;
private final BookHandler bookHandler;
private final DefaultHandler defaultHandler;
public IntentRouter(
CheckOutHandler checkOutHandler,
ExtendStayHandler extendStayHandler,
QueryHandler queryHandler,
CleanHandler cleanHandler,
BookHandler bookHandler,
DefaultHandler defaultHandler) {
this.checkOutHandler = checkOutHandler;
this.extendStayHandler = extendStayHandler;
this.queryHandler = queryHandler;
this.cleanHandler = cleanHandler;
this.bookHandler = bookHandler;
this.defaultHandler = defaultHandler;
}
public String route(IntentResponse intent, String originalMessage) {
return switch (intent.getIntent()) {
case "CHECK_OUT" -> checkOutHandler.handle(intent, originalMessage);
case "EXTEND_STAY" -> extendStayHandler.handle(intent, originalMessage);
case "QUERY" -> queryHandler.handle(intent, originalMessage);
case "CLEAN" -> cleanHandler.handle(intent, originalMessage);
case "BOOK" -> bookHandler.handle(intent, originalMessage);
default -> defaultHandler.handle(intent, originalMessage);
};
}
}
退房处理器
@Component
public class CheckOutHandler {
private final HotelService hotelService;
private final ChatClient chatClient;
public String handle(IntentResponse intent, String originalMessage) {
String roomNo = intent.getRoomNo();
// 如果没有房间号,询问用户
if (roomNo == null || roomNo.isEmpty()) {
return chatClient.prompt()
.system("你是酒店客服助手")
.user("用户想退房,但没有提供房间号。请礼貌地询问房间号。")
.call()
.content();
}
// 调用业务系统办理退房
try {
hotelService.checkOut(roomNo);
return chatClient.prompt()
.system("你是酒店客服助手,语气友好")
.user("用户 {roomNo} 房间已成功退房。请生成友好的回复。"
.replace("{roomNo}", roomNo))
.call()
.content();
} catch (Exception e) {
return "抱歉,退房办理失败,请稍后重试或联系前台。";
}
}
}
主控制器
@RestController
@RequestMapping("/bot")
public class ChatBotController {
private final IntentRecognitionService intentService;
private final IntentRouter intentRouter;
private final ConversationService conversationService;
@PostMapping("/chat")
public ChatResponse chat(@RequestBody ChatRequest request) {
// 1. 意图识别
IntentResponse intent = intentService.recognize(request.getMessage());
// 2. 路由到对应处理器
String reply = intentRouter.route(intent, request.getMessage());
// 3. 保存对话历史
conversationService.saveMessage(request.getSessionId(), request.getMessage(), reply);
// 4. 返回响应
return new ChatResponse(reply, intent);
}
}
6.4 测试场景
场景1:直接退房
用户:我要退 1201 房间
AI 识别:{"intent":"CHECK_OUT","roomNo":"1201"}
AI 回复:好的,1201 房间的退房手续已办理。祝您旅途愉快!
场景2:缺少信息
用户:我想退房
AI 识别:{"intent":"CHECK_OUT","roomNo":null}
AI 回复:好的,我可以帮您办理退房。请问您的房间号是多少?
用户:1201
AI 识别:{"intent":"CHECK_OUT","roomNo":"1201"}
AI 回复:收到,1201 房间的退房手续已办理。祝您旅途愉快!
场景3:续住
用户:我想续住 2 天
AI 识别:{"intent":"EXTEND_STAY","days":2}
AI 回复:好的,我可以帮您办理续住。请问您的房间号是多少?
📝 七、总结与最佳实践
7.1 核心要点回顾
ChatClient
- ✅ 使用构造函数注入,保证不可变性
- ✅ 通过 Builder 配置默认值和选项
- ✅ 支持同步(call)和流式(stream)调用
- ✅ 模型无关,轻松切换
Prompt 工程
- ✅ System Prompt 定义角色和行为
- ✅ Few-shot Learning 提供示例
- ✅ Chain of Thought 引导推理
- ✅ 模板化实现动态 Prompt
- ✅ 明确、具体、有约束
Model 抽象
- ✅ 统一接口,屏蔽差异
- ✅ 多模型配置,按需选择
- ✅ 智能路由,优化成本
- ✅ 合理设置温度等参数
上下文管理
- ✅ 使用消息列表维护历史
- ✅ 限制长度,避免超限
- ✅ 会话隔离,保护隐私
- ✅ 持久化存储,支持离线
结构化输出
- ✅ 优先使用 entity() 方法
- ✅ Prompt 中明确 JSON 格式
- ✅ 提供示例,提高准确性
- ✅ 添加重试机制,增强鲁棒性
7.2 常见错误
❌ 错误1:硬编码 API Key
// ❌ 不安全
.apiKey("sk-xxxxx")
// ✅ 正确
.apiKey(System.getenv("OPENAI_API_KEY"))
❌ 错误2:不限制上下文长度
// ❌ 可能超出窗口
messages.addAll(fullHistory);
// ✅ 限制长度
messages.addAll(trimHistory(fullHistory, 20));
❌ 错误3:忽略错误处理
// ❌ 没有异常处理
String result = chatClient.prompt().user(msg).call().content();
// ✅ 添加异常处理
try {
String result = chatClient.prompt().user(msg).call().content();
} catch (Exception e) {
log.error("AI 调用失败", e);
return "抱歉,服务暂时不可用";
}
❌ 错误4:不验证结构化输出
// ❌ 直接解析,可能失败
IntentResponse intent = mapper.readValue(json, IntentResponse.class);
// ✅ 添加验证和重试
IntentResponse intent = extractWithRetry(message);
7.3 性能优化建议
- 缓存常见问答:
@Cacheable(value = "faq", key = "#question")
public String answerFAQ(String question) {
return chatClient.prompt()
.user(question)
.call()
.content();
}
- 异步处理:
@Async
public CompletableFuture<String> asyncChat(String message) {
String result = chatClient.prompt()
.user(message)
.call()
.content();
return CompletableFuture.completedFuture(result);
}
- 批量处理:
public List<String> batchChat(List<String> messages) {
return messages.parallelStream()
.map(msg -> chatClient.prompt()
.user(msg)
.call()
.content())
.collect(Collectors.toList());
}
7.4 安全注意事项
- 🔒 API Key 存储在环境变量或密钥管理服务
- 🔒 启用 HTTPS,加密传输
- 🔒 实施速率限制,防止滥用
- 🔒 记录审计日志,追踪可疑行为
- 🔒 对用户输入进行验证和过滤
- 🔒 脱敏敏感信息(如房间号、姓名)
🔮 八、下一步学习路径
恭喜你已经掌握了 Spring AI 的核心概念!接下来可以学习:
推荐阅读
- [第3篇] Spring AI 图片生成实战 - DALL-E、CogView 图片生成
- [第4篇] Spring AI 响应式编程与流式输出 - Reactor + SSE 实时聊天
- [第5篇] Spring AI 函数调用实战 - Function Calling 集成业务系统
实践项目
- 💬 完善酒店智能客服机器人
- 📝 开发 AI 写作助手
- 🔍 构建智能搜索引擎
- 🎨 创建图片生成应用
进阶主题
- Function Calling:让 AI 调用你的代码
- RAG:基于知识库的问答
- Agent:自主 AI 代理
- Multi-Agent:多智能体协作
🆕 附录:DeepSeek-V4-Pro 快速配置指南
1. 获取 API Key
访问 DeepSeek 开放平台 注册账号并获取 API Key。
2. Maven 依赖
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-deepseek-spring-boot-starter</artifactId>
<version>1.1.4</version>
</dependency>
3. 配置文件
spring:
ai:
deepseek:
api-key: ${DEEPSEEK_API_KEY} # 从环境变量读取
base-url: https://api.deepseek.com
chat:
options:
model: deepseek-chat # DeepSeek-V4-Pro
temperature: 0.7
max-tokens: 8192
4. 环境变量设置
# Linux/Mac
export DEEPSEEK_API_KEY=sk-your-api-key-here
# Windows PowerShell
$env:DEEPSEEK_API_KEY="sk-your-api-key-here"
# Windows CMD
set DEEPSEEK_API_KEY=sk-your-api-key-here
5. 代码示例
@RestController
@RequestMapping("/deepseek")
public class DeepSeekController {
private final ChatClient chatClient;
public DeepSeekController(ChatClient.Builder builder) {
this.chatClient = builder
.defaultOptions(DeepSeekChatOptions.builder()
.model("deepseek-chat")
.temperature(0.7)
.maxTokens(8192)
.build())
.build();
}
@GetMapping("/chat")
public String chat(@RequestParam String message) {
return chatClient.prompt()
.user(message)
.call()
.content();
}
}
6. DeepSeek-V4-Pro vs 其他模型
| 特性 | DeepSeek-V4-Pro | GPT-5.5 | GPT-4o | GLM-4-Flash | Gemini 3 Flash |
|---|---|---|---|---|---|
| 输入价格 | ¥3/百万 | $5.00/百万 | $2.50/百万 | 免费 | $0.50/百万 |
| 输出价格 | ¥6/百万 | $30.00/百万 | $10.00/百万 | 免费 | $3.00/百万 |
| 速度 | ⚡⚡⚡ 快 | ⚡⚡⚡ 快 | ⚡ 较慢 | ⚡⚡ 中 | ⚡⚡⚡⚡ 极速 |
| 中文能力 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| 代码生成 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| 长上下文 | 64K-128K | 128K | 128K | 128K | 1M+ |
| 推理能力 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| 缓存支持 | ✅ ¥0.025/百万 | ✅ $0.50/百万 | ✅ $1.25/百万 | ❌ | ✅ $0.05/百万 |
💰 价格对比(以 1000 万 tokens 为例):
| 模型 | 月成本(70%输入/30%输出) | 相比 GPT-4o |
|---|---|---|
| GLM-4-Flash | ¥0 | -100% |
| DeepSeek-V4-Pro | ¥3.90 ≈ $0.54 | -98.9% |
| Gemini 3 Flash | $4.40 | -90.7% |
| GPT-5.5 | $12.50 | -73.7% |
| GPT-4o | $47.50 | 基准 |
🎯 选择建议:
- 追求性价比 → DeepSeek-V4-Pro(最佳平衡)
- 追求速度 → Gemini 3 Flash(极速响应)
- 追求免费 → GLM-4-Flash(完全免费)
- 追求能力 → GPT-4o / GPT-5.5(最强推理)
7. 使用建议
✅ 推荐使用 DeepSeek-V4-Pro 的场景:
- 日常对话和客服机器人
- 中文文本处理和分析
- 代码生成和审查
- 需要长上下文的场景
- 成本敏感的项目
- 性价比之王:生产环境主力模型
✅ 推荐使用 Gemini 3 Flash 的场景:
- 高并发接口(极速响应)
- 实时交互应用
- 多模态速处理
- 需要快速反馈的场景
- 速度之王:用户体验优先
✅ 推荐使用 GLM-4-Flash 的场景:
- 原型开发和测试
- 简单问答和分类
- 轻量级任务
- 预算有限的项目
- 免费之王:零成本启动
✅ 推荐使用 GPT-5.5 / GPT-4o 的场景:
- 复杂逻辑推理
- 专业创作和艺术生成
- 多语言翻译
- 需要最高准确率的场景
- 多模态任务(GPT-4o)
- 能力之王:质量优先
✅ 推荐使用智谱 GLM-5 系列的场景:
- GLM-5.1:复杂推理、代码生成、专业创作
- GLM-5-Turbo:高并发接口、业务中台混合任务
- 国产化选择:符合国内合规要求
8. 性能优化技巧
// 技巧1:使用连接池
@Bean
public DeepSeekApi deepSeekApi() {
return DeepSeekApi.builder()
.apiKey(System.getenv("DEEPSEEK_API_KEY"))
.connectionPoolSize(10) // 连接池大小
.timeout(Duration.ofSeconds(30)) // 超时时间
.build();
}
// 技巧2:启用缓存
@Cacheable(value = "deepseek-responses", key = "#message")
public String cachedChat(String message) {
return chatClient.prompt()
.user(message)
.call()
.content();
}
// 技巧3:批量处理
public List<String> batchChat(List<String> messages) {
return messages.parallelStream()
.map(msg -> chatClient.prompt()
.user(msg)
.call()
.content())
.collect(Collectors.toList());
}
9. 常见问题
Q1: DeepSeek API 是否兼容 OpenAI 格式?
A: 是的,DeepSeek API 完全兼容 OpenAI 格式,可以直接使用 Spring AI 的 OpenAI starter。
Q2: 如何切换模型?
A: 修改配置文件中的 model 参数即可:
spring:
ai:
deepseek:
chat:
options:
model: deepseek-chat # 或 deepseek-reasoner
Q3: DeepSeek-V4-Pro 支持哪些功能?
A: 支持文本生成、代码生成、数学推理、长文本理解、Function Calling 等。
Q4: 有速率限制吗?
A: 默认限制为每分钟 100 次请求,可根据需求申请提升。
💬 互动环节
觉得有用?
- ⭐ 点赞支持
- 💾 收藏备用
- 🔄 分享给朋友
- 📢 关注我,不错过后续文章
上一期:《2026 Java 程序员新标配:Spring AI 最新版本1.1.4 从零搭建 + 避坑指南(收藏版)》(https://mp.weixin.qq.com/s/o37reGG1-IYLbgCMvUd2-g)
下一篇预告:《Spring AI 图片生成实战:从 智谱 CogView 到GPT-Image-2》
最后更新:2026-05-05
祝你学习愉快,成为 Spring AI 高手! 🚀
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)