DeepSeek Chat
Spring AI 支持来自深度求索(DeepSeek)的各类人工智能大语言模型。你可以与 DeepSeek 大语言模型进行交互,并基于 DeepSeek 模型创建多语种对话助手。
前提条件
你需要创建一个 DeepSeek API 密钥才能访问 DeepSeek 大语言模型。
在 DeepSeek 注册页面创建账号,并在 API 密钥页面生成令牌。
Spring AI 项目定义了一个名为 spring.ai.deepseek.api-key 的配置属性,你需要将其设置为从 API 密钥页面获取的 API 密钥值。
你可以在 application.properties 文件中设置该配置属性:
spring.ai.deepseek.api-key=<your-deepseek-api-key>
为了在处理 API 密钥等敏感信息时提升安全性,你可以使用 Spring 表达式语言(SpEL)引用自定义环境变量:
# 在 application.yml 中
spring:
ai:
deepseek:
api-key: ${DEEPSEEK_API_KEY}
# 在你的环境变量或 .env 文件中
export DEEPSEEK_API_KEY=<your-deepseek-api-key>你也可以在应用程序代码中通过编程方式设置该配置:
// 从安全来源或环境变量中获取 API 密钥
String apiKey = System.getenv("DEEPSEEK_API_KEY");添加仓库和物料清单(BOM)
Spring AI 构件发布在 Spring 里程碑仓库和快照仓库中。参考构件仓库章节将这些仓库添加到你的构建系统中。
为了方便依赖管理,Spring AI 提供了物料清单(BOM),确保整个项目使用一致版本的 Spring AI。参考依赖管理章节将 Spring AI 物料清单添加到你的构建系统中。
自动配置
Spring AI 为 DeepSeek 对话模型提供了 Spring Boot 自动配置。要启用该功能,请在项目的 Maven pom.xml 文件中添加以下依赖:
<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-model-deepseek</artifactId> </dependency>
或者在 Gradle build.gradle 文件中添加:
dependencies {
implementation 'org.springframework.ai:spring-ai-starter-model-deepseek'
}参考依赖管理章节将 Spring AI 物料清单添加到你的构建文件中。
对话属性配置
重试属性
spring.ai.retry 前缀用于配置 DeepSeek 对话模型的重试机制。
| 属性 | 描述 | 默认值 |
|---|---|---|
| spring.ai.retry.max-attempts | 最大重试次数 | 10 |
| spring.ai.retry.backoff.initial-interval | 指数退避策略的初始休眠时长 | 2秒 |
| spring.ai.retry.backoff.multiplier | 退避间隔乘数 | 5 |
| spring.ai.retry.backoff.max-interval | 最大退避时长 | 3分钟 |
| spring.ai.retry.on-client-errors | 若为 false,抛出 NonTransientAiException 异常,且不会对 4xx 客户端错误码进行重试 | false |
| spring.ai.retry.exclude-on-http-codes | 不应触发重试的 HTTP 状态码列表(例如抛出 NonTransientAiException) | 空 |
| spring.ai.retry.on-http-codes | 应触发重试的 HTTP 状态码列表(例如抛出 TransientAiException) | 空 |
连接属性
spring.ai.deepseek 前缀用于配置 DeepSeek 连接参数。
| 属性 | 描述 | 默认值 |
|---|---|---|
| spring.ai.deepseek.base-url | 连接地址 | https://api.deepseek.com |
| spring.ai.deepseek.api-key | API 密钥 | - |
配置属性
spring.ai.deepseek.chat 前缀用于配置 DeepSeek 对话模型实现。
| 属性 | 描述 | 默认值 |
|---|---|---|
| spring.ai.deepseek.chat.enabled | 启用 DeepSeek 对话模型 | true |
| spring.ai.deepseek.chat.base-url | 可选覆盖 spring.ai.deepseek.base-url,提供对话专属地址 | https://api.deepseek.com/ |
| spring.ai.deepseek.chat.api-key | 可选覆盖 spring.ai.deepseek.api-key,提供对话专属 API 密钥 | - |
| spring.ai.deepseek.chat.completions-path | 对话补全接口路径 | /chat/completions |
| spring.ai.deepseek.chat.beta-prefix-path | 测试版功能接口前缀路径 | /beta |
| spring.ai.deepseek.chat.options.model | 使用的模型 ID,可选 deepseek-reasoner 或 deepseek-chat | deepseek-chat |
| spring.ai.deepseek.chat.options.frequencyPenalty | -2.0 至 2.0 之间的数值,正值会基于文本中已出现的频率惩罚新令牌,降低模型逐字重复相同语句的概率 | 0.0f |
| spring.ai.deepseek.chat.options.maxTokens | 对话补全生成的最大令牌数,输入令牌和生成令牌的总长度受模型上下文长度限制 | - |
| spring.ai.deepseek.chat.options.presencePenalty | -2.0 至 2.0 之间的数值,正值会基于文本中是否出现过惩罚新令牌,提升模型讨论新话题的概率 | 0.0f |
| spring.ai.deepseek.chat.options.stop | 最多 4 个序列,API 遇到这些序列时会停止生成后续令牌 | - |
| spring.ai.deepseek.chat.options.temperature | 采样温度,0 至 2 之间,数值越高(如 0.8)输出越随机,数值越低(如 0.2)输出越聚焦确定,建议仅调整该参数或 top_p 中的一个 | 1.0F |
| spring.ai.deepseek.chat.options.topP | 核采样,替代温度采样,模型仅考虑概率质量前 top_p 的令牌结果,0.1 表示仅考虑前 10% 概率质量的令牌,建议仅调整该参数或 temperature 中的一个 | 1.0F |
| spring.ai.deepseek.chat.options.logprobs | 是否返回输出令牌的对数概率,若为 true,返回消息内容中每个输出令牌的对数概率 | - |
| spring.ai.deepseek.chat.options.topLogprobs | 0 至 20 之间的整数,指定每个令牌位置返回的最可能令牌数量及对应对数概率,使用该参数时 logprobs 必须设为 true | - |
| spring.ai.deepseek.chat.options.tool-names | 单次提示请求中启用函数调用的工具名称列表,对应名称的工具必须存在于 ToolCallback 注册表中 | - |
| spring.ai.deepseek.chat.options.tool-callbacks | 向 ChatModel 注册的工具回调 | - |
| spring.ai.deepseek.chat.options.internal-tool-execution-enabled | 若为 false,Spring AI 不会内部处理工具调用,而是转发给客户端,由客户端负责处理、调度并返回结果;若为 true(默认),Spring AI 内部处理函数调用,仅适用于支持函数调用的对话模型 | true |
你可以为 ChatModel 实现覆盖通用的 spring.ai.deepseek.base-url 和 spring.ai.deepseek.api-key。如果设置了 spring.ai.deepseek.chat.base-url 和 spring.ai.deepseek.chat.api-key 属性,优先级高于通用属性。当你需要为不同模型和接口使用不同 DeepSeek 账号时,该功能非常实用。
所有以 spring.ai.deepseek.chat.options 为前缀的属性,都可以在运行时通过向 Prompt 调用添加请求专属的运行时选项来覆盖。
运行时选项
DeepSeekChatOptions.java 提供模型配置,例如使用的模型、温度、频率惩罚等。
启动时,可以通过 DeepSeekChatModel(api, options) 构造方法或 spring.ai.deepseek.chat.options.* 属性配置默认选项。
运行时,你可以通过向 Prompt 调用添加新的请求专属选项覆盖默认选项。例如,为特定请求覆盖默认模型和温度:
ChatResponse response = chatModel.call( new Prompt( "生成5位著名海盗的名字。请返回JSON格式结果,不要添加```json```等代码块标记。", DeepSeekChatOptions.builder() .withModel(DeepSeekApi.ChatModel.DEEPSEEK_CHAT.getValue()) .withTemperature(0.8f) .build() ));
除了模型专属的 DeepSeekChatOptions,你还可以使用通过 ChatOptions#builder() 创建的通用 ChatOptions 实例。
示例控制器(自动配置)
创建新的 Spring Boot 项目,并将 spring-ai-starter-model-deepseek 添加到 pom(或 gradle)依赖中。
在 src/main/resources 目录下添加 application.properties 文件,启用并配置 DeepSeek 对话模型:
spring.ai.deepseek.api-key=YOUR_API_KEY spring.ai.deepseek.chat.options.model=deepseek-chat spring.ai.deepseek.chat.options.temperature=0.8
将 api-key 替换为你的 DeepSeek 凭证。
这会创建一个 DeepSeekChatModel 实现,你可以将其注入到类中。以下是一个简单的 @Controller 类示例,使用对话模型进行文本生成:
@RestController
public class ChatController {
private final DeepSeekChatModel chatModel;
@Autowired
public ChatController(DeepSeekChatModel chatModel) {
this.chatModel = chatModel;
}
@GetMapping("/ai/generate")
public Map generate(@RequestParam(value = "message", defaultValue = "给我讲个笑话") String message) {
return Map.of("generation", chatModel.call(message));
}
@GetMapping("/ai/generateStream")
public Flux<ChatResponse> generateStream(@RequestParam(value = "message", defaultValue = "给我讲个笑话") String message) {
var prompt = new Prompt(new UserMessage(message));
return chatModel.stream(prompt);
}
}对话前缀补全
对话前缀补全遵循对话补全 API 规范,用户提供助手前缀消息,模型完成消息剩余内容。
使用前缀补全时,用户必须确保消息列表中的最后一条消息是 DeepSeekAssistantMessage。
以下是对话前缀补全的完整 Java 代码示例。在该示例中,我们将助手的前缀消息设置为 "```python\n",强制模型输出 Python 代码,并将停止参数设置为 ['`'],防止模型生成额外解释。
@RestController
public class CodeGenerateController {
private final DeepSeekChatModel chatModel;
@Autowired
public ChatController(DeepSeekChatModel chatModel) {
this.chatModel = chatModel;
}
@GetMapping("/ai/generatePythonCode")
public String generate(@RequestParam(value = "message", defaultValue = "请编写快速排序代码") String message) {
UserMessage userMessage = new UserMessage(message);
Message assistantMessage = DeepSeekAssistantMessage.prefixAssistantMessage("```python\\n");
Prompt prompt = new Prompt(List.of(userMessage, assistantMessage), ChatOptions.builder().stopSequences(List.of("```")).build());
ChatResponse response = chatModel.call(prompt);
return response.getResult().getOutput().getText();
}
}推理模型(deepseek-reasoner)
deepseek-reasoner 是 DeepSeek 开发的推理模型。在输出最终答案前,模型会先生成思维链(CoT),提升回答准确性。我们的 API 支持用户获取 deepseek-reasoner 生成的思维链内容,方便查看、展示和提炼。
你可以使用 DeepSeekAssistantMessage 获取 deepseek-reasoner 生成的思维链内容。
public void deepSeekReasonerExample() {
DeepSeekChatOptions promptOptions = DeepSeekChatOptions.builder()
.model(DeepSeekApi.ChatModel.DEEPSEEK_REASONER.getValue())
.build();
Prompt prompt = new Prompt("9.11 和 9.8 哪个更大?", promptOptions);
ChatResponse response = chatModel.call(prompt);
// 获取 deepseek-reasoner 生成的思维链内容,仅使用该模型时可用
DeepSeekAssistantMessage deepSeekAssistantMessage = (DeepSeekAssistantMessage) response.getResult().getOutput();
String reasoningContent = deepSeekAssistantMessage.getReasoningContent();
String text = deepSeekAssistantMessage.getText();
}推理模型多轮对话
每轮对话中,模型会输出思维链(reasoning_content)和最终答案(content)。下一轮对话中,不会将历史思维链拼接到上下文,如下图所示:
请注意:如果输入消息序列中包含 reasoning_content 字段,API 会返回 400 错误。因此,发起 API 请求前,你需要从 API 响应中移除 reasoning_content 字段,如 API 示例所示。
public String deepSeekReasonerMultiRoundExample() {
List<Message> messages = new ArrayList<>();
messages.add(new UserMessage("9.11 和 9.8 哪个更大?"));
DeepSeekChatOptions promptOptions = DeepSeekChatOptions.builder()
.model(DeepSeekApi.ChatModel.DEEPSEEK_REASONER.getValue())
.build();
Prompt prompt = new Prompt(messages, promptOptions);
ChatResponse response = chatModel.call(prompt);
DeepSeekAssistantMessage deepSeekAssistantMessage = (DeepSeekAssistantMessage) response.getResult().getOutput();
String reasoningContent = deepSeekAssistantMessage.getReasoningContent();
String text = deepSeekAssistantMessage.getText();
messages.add(AssistantMessage.builder().content(Objects.requireNonNull(text)).build());
messages.add(new UserMessage("单词'strawberry'中有多少个字母R?"));
Prompt prompt2 = new Prompt(messages, promptOptions);
ChatResponse response2 = chatModel.call(prompt2);
DeepSeekAssistantMessage deepSeekAssistantMessage2 = (DeepSeekAssistantMessage) response2.getResult().getOutput();
String reasoningContent2 = deepSeekAssistantMessage2.getReasoningContent();
return deepSeekAssistantMessage2.getText();
}手动配置
DeepSeekChatModel 实现了 ChatModel 和 StreamingChatModel 接口,并使用底层 DeepSeekApi 客户端连接 DeepSeek 服务。
在项目的 Maven pom.xml 文件中添加 spring-ai-deepseek 依赖:
<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-deepseek</artifactId> </dependency>
或者在 Gradle build.gradle 文件中添加:
dependencies {
implementation 'org.springframework.ai:spring-ai-deepseek'
}参考依赖管理章节将 Spring AI 物料清单添加到你的构建文件中。
接下来,创建 DeepSeekChatModel 并用于文本生成:
DeepSeekApi deepSeekApi = DeepSeekApi.builder()
.apiKey(System.getenv("DEEPSEEK_API_KEY"))
.build();
DeepSeekChatOptions options = DeepSeekChatOptions.builder()
.model(DeepSeekApi.ChatModel.DEEPSEEK_CHAT.getValue())
.temperature(0.4)
.maxTokens(200)
.build();
DeepSeekChatModel chatModel = DeepSeekChatModel.builder()
.deepSeekApi(deepSeekApi)
.defaultOptions(options)
.build();
ChatResponse response = chatModel.call(
new Prompt("生成5位著名海盗的名字。"));
// 或使用流式响应
Flux<ChatResponse> streamResponse = chatModel.stream(
new Prompt("生成5位著名海盗的名字。"));DeepSeekChatOptions 提供对话请求的配置信息,DeepSeekChatOptions.Builder 是流式选项构建器。
底层 DeepSeekApi 客户端
DeepSeekApi 是轻量级的 DeepSeek API Java 客户端。
以下是通过编程方式使用该 API 的简单代码片段:
DeepSeekApi deepSeekApi =
new DeepSeekApi(System.getenv("DEEPSEEK_API_KEY"));
ChatCompletionMessage chatCompletionMessage =
new ChatCompletionMessage("你好世界", Role.USER);
// 同步请求
ResponseEntity<ChatCompletion> response = deepSeekApi.chatCompletionEntity(
new ChatCompletionRequest(List.of(chatCompletionMessage), DeepSeekApi.ChatModel.DEEPSEEK_CHAT.getValue(), 0.7, false));
// 流式请求
Flux<ChatCompletionChunk> streamResponse = deepSeekApi.chatCompletionStream(
new ChatCompletionRequest(List.of(chatCompletionMessage), DeepSeekApi.ChatModel.DEEPSEEK_CHAT.getValue(), 0.7, true));更多信息参考 DeepSeekApi.java 的 Java 文档。