一、前言
Spring AI 提供跨 AI 供应商(如 OpenAI、Hugging Face 等)的一致性 API, 通过分装的ChatModel或ChatClient即可轻松调动LLM进行流式或非流式对话。
本专栏主要围绕着通过OpenAI方式调用各种大语言模型展开学习(因为95%以上模型都兼容OpenAI方式调用接口),接下来我们先从调用深度求索的DeepSeek模型开始探索吧~
上一篇文章:1. Spring AI概述-CSDN博客
二、术语
2.1 ChatModel 和ChatClient的区分
Spring AI 中的 ChatModel
和 ChatClient
是两种不同层级的 API 设计,分别针对不同复杂度的 AI 交互场景。以下是两者的核心差异、典型用法及适用场景分析:
PS : ChatClient是对ChatModel的高级封装, 是官方推荐的核心API !
a. 首次引入版本
-
- 里程碑版本:ChatClient 在 1.0.0-M5 中首次出现,但接口设计尚未稳定。
- 稳定版本:从 1.0.0-M7 开始接口基本定型,并在 1.0.0-M8 中进一步优化。
- 正式生产版本:1.0.0 GA(2025年5月20日发布)是首个稳定且支持生产环境的版本,ChatClient 成为官方推荐的核心 API。
b. 当前推荐版本
-
- 1.0.0 GA:功能完善,支持同步/流式调用、多模型切换、工具调用等企业级特性,是生产环境首选
2.2 OpenAI标准
OpenAI的API设计已成为行业事实标准,开发者生态庞大。国内绝大部分模型(如通义千问、DeepSeek、文心一言、智谱GLM、Kimi等)均提供与OpenAI兼容的API接口,开发者仅需替换base_url
、api_key
和 model
参数,即可快速调动大模型能力!
主流模型兼容OpenAI接口对比表:
三、DeepSeek开放平台
注册开放平台账号(DeepSeek),充值5块钱(开发够用了),然后创建API KEY
四、代码
4.1 项目依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.better</groupId>
<artifactId>spring-ai-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>models/chat/chat-openai-deepseek</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.4.5</version>
<relativePath/>
</parent>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
</dependencies>
<!--Spring AI模块的依赖版本管理-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<!--正式生产版本:1.0.0 GA(2025年5月20日发布)是首个稳定且支持生产环境的版本,ChatClient 成为官方推荐的核心 API-->
<version>1.0.0</version> <!-- GA 版本 -->
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
4.2 模型配置
server:
port: 8321
spring:
ai:
openai:
base-url: https://api.deepseek.com
api-key: ${OPENAI_API_KEY}
chat:
options:
model: deepseek-chat # 可选模型:deepseek-chat/deepseek-reasoner
temperature: 0.6 # 响应随机性控制,默认值
4.3 ChatClient
4.3.1 非流式对话
@GetMapping("/chat")
String chat(String question) {
return chatClient
.prompt(question)
.call()
.content();
4.3.2 流式对话
@GetMapping(value = "/chat/stream",produces = MediaType.TEXT_EVENT_STREAM_VALUE)
Flux<String> chatStream(String question) {
return chatClient
.prompt(question)
.stream()
.content();
}
4.3.3 通用LLM配置
适用于所有支持的 LLM 提供商,跨平台兼容性高,适配 OpenAI、DeepSeek等
@GetMapping("/chat/generic-options")
String chatGenericOptions(String question) {
return chatClient
.prompt(question)
.options(ChatOptions.builder()
.model("deepseek-reasoner") // 指定模型(deepSeek的推理模型)
.temperature(0.9) // 指定温度值
.build())
.call()
.content();
}
4.3.4 OpenAI配置
@GetMapping("/chat/provider-options")
String chatProviderOptions(String question) {
return chatClient
.prompt(question)
.options(OpenAiChatOptions.builder()
.logprobs(true) // 用于请求模型在生成文本时返回每个生成toke的对数概率
.build())
.call()
.content();
}
4.3.5 完整代码
package com.better.springai;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.prompt.ChatOptions;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
/**
* 高级封装ChatClient
*/
@RestController
class ChatClientController {
private final ChatClient chatClient;
public ChatClientController(ChatClient.Builder chatClientBuilder) {
this.chatClient = chatClientBuilder.build();
}
/**
* 非流式对话
* @param question 问题
* return java.lang.String
* @author luchuyan
* @time 2025/7/19 18:59
**/
@GetMapping("/chat")
String chat(String question) {
return chatClient
.prompt(question)
.call()
.content();
}
/**
* 流式对话
* @param question
* return reactor.core.publisher.Flux<java.lang.String>
* @author luchuyan
* @time 2025/7/19 19:00
**/
@GetMapping(value = "/chat/stream",produces = MediaType.TEXT_EVENT_STREAM_VALUE)
Flux<String> chatStream(String question) {
return chatClient
.prompt(question)
.stream()
.content();
}
/**
* 非流式对话-通用LLM配置
* PS: 适用于所有支持的 LLM 提供商,跨平台兼容性高,适配 OpenAI、DeepSeek等
* @param question
* return java.lang.String
* @author luchuyan
* @time 2025/7/19 19:09
**/
@GetMapping("/chat/generic-options")
String chatGenericOptions(String question) {
return chatClient
.prompt(question)
.options(ChatOptions.builder()
.model("deepseek-reasoner") // 指定模型(deepSeek的推理模型)
.temperature(0.9) // 指定温度值
.build())
.call()
.content();
}
/**
* 非流式对话-OpenAI专属配置
* PS: 仅适用于 OpenAI 或兼容 OpenAI 接口的服务(如 DeepSeek)
* @param question
* return java.lang.String
* @author luchuyan
* @time 2025/7/19 19:13
**/
@GetMapping("/chat/provider-options")
String chatProviderOptions(String question) {
return chatClient
.prompt(question)
.options(OpenAiChatOptions.builder()
.logprobs(true) // 用于请求模型在生成文本时返回每个生成toke的对数概率
.build())
.call()
.content();
}
}
4.4 ChatModel
用户和ChatClient差不多, 不再赘述~
4.4.1 完整代码
package com.better.springai;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.prompt.ChatOptions;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
/**
* 基础封装ChatModel
*/
@RestController
@RequestMapping("/model")
class ChatModelController {
private final ChatModel chatModel;
ChatModelController(ChatModel chatModel) {
this.chatModel = chatModel;
}
/**
* 非流式对话
* @param question 问题
* return java.lang.String
* @author luchuyan
* @time 2025/7/19 20:48
**/
@GetMapping("/chat")
String chat(String question) {
return chatModel.call(question);
}
/**
* 流式对话
* @param question
* return reactor.core.publisher.Flux<java.lang.String>
* @author luchuyan
* @time 2025/7/19 19:00
**/
@GetMapping(value = "/chat/stream",produces = MediaType.TEXT_EVENT_STREAM_VALUE)
Flux<String> chatStream(String question) {
return chatModel.stream(question);
}
/**
* 非流式对话-通用LLM配置
* PS: 适用于所有支持的 LLM 提供商,跨平台兼容性高,适配 OpenAI、DeepSeek等
* @param question
* return java.lang.String
* @author luchuyan
* @time 2025/7/19 19:09
**/
@GetMapping("/chat/generic-options")
String chatGenericOptions(String question) {
return chatModel.call(new Prompt(question, ChatOptions.builder()
.model("deepseek-reasoner") // 指定模型(deepSeek的推理模型)
.temperature(0.9)
.build()))
.getResult().getOutput().getText();
}
/**
* 非流式对话-OpenAI专属配置
* PS: 仅适用于 OpenAI 或兼容 OpenAI 接口的服务(如 DeepSeek)
* @param question
* return java.lang.String
* @author luchuyan
* @time 2025/7/19 19:13
**/
@GetMapping("/chat/provider-options")
String chatProviderOptions(String question) {
return chatModel.call(new Prompt(question, OpenAiChatOptions.builder()
.logprobs(true)
.build()))
.getResult().getOutput().getText();
}
}
五、参考资料
5.1 Spring AI官网文档
5.2 阿里云Maven仓库
5.3 Spring AI 依赖仓库
5.4 DeepSeek开发文档
---------------------------如果文章对你有帮助,别忘了点赞支持一下,谢谢~---------------------------