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/百万 ⚡⚡⚡ 中快 百万级长上下文、复杂分析、多模态旗舰

💰 性价比分析

  1. 最经济选择:GLM-4-Flash(完全免费)

    • 适合:原型开发、测试环境、轻量任务
    • 注意:功能和性能有限
  2. 最佳性价比:DeepSeek-V4-Pro

    • 价格仅为 GPT-4o 的 1/80(输入)和 1/160(输出)
    • 速度快,中文优化好
    • 适合:生产环境主力模型
  3. 最快响应:Gemini 3 Flash

    • 速度等级:极速
    • 价格适中($0.50/$3.00)
    • 适合:高并发场景、实时交互
  4. 最强能力: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 需求分析

我们要构建一个酒店智能客服机器人,具备以下能力:

  1. 意图识别:识别用户的需求(退房、续住、查询等)
  2. 多轮对话:记住上下文,进行自然对话
  3. 函数调用:调用业务系统执行操作
  4. 个性化回复:根据用户历史提供个性化服务

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 性能优化建议

  1. 缓存常见问答
@Cacheable(value = "faq", key = "#question")
public String answerFAQ(String question) {
    return chatClient.prompt()
        .user(question)
        .call()
        .content();
}
  1. 异步处理
@Async
public CompletableFuture<String> asyncChat(String message) {
    String result = chatClient.prompt()
        .user(message)
        .call()
        .content();
    return CompletableFuture.completedFuture(result);
}
  1. 批量处理
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 的核心概念!接下来可以学习:

推荐阅读

  1. [第3篇] Spring AI 图片生成实战 - DALL-E、CogView 图片生成
  2. [第4篇] Spring AI 响应式编程与流式输出 - Reactor + SSE 实时聊天
  3. [第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 高手! 🚀
在这里插入图片描述

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐