4.4 DeepSeek Chat

71 阅读8分钟

DeepSeek Chat

Spring AI 参考文档 - DeepSeek Chat 模型集成指南

概述

Spring AI 支持来自 DeepSeek 的各种 AI 语言模型。您可以与 DeepSeek 语言模型交互,并基于 DeepSeek 模型创建多语言对话助手。

先决条件

您需要在 DeepSeek 创建 API 密钥以访问 DeepSeek 语言模型。

DeepSeek 注册页面 创建账户,并在 API 密钥页面 生成令牌。

Spring AI 项目定义了一个名为 spring.ai.deepseek.api-key 的配置属性,您应该将其设置为从 API 密钥页面获得的 API Key 的值。

您可以在 application.properties 文件中设置此配置属性:

spring.ai.deepseek.api-key=<您的DeepSeek API密钥>

为了在处理 API 密钥等敏感信息时增强安全性,您可以使用 Spring 表达式语言 (SpEL) 来引用自定义环境变量:

# 在 application.yml 中
spring:
  ai:
    deepseek:
      api-key: ${DEEPSEEK_API_KEY}
# 在您的环境或 .env 文件中
export DEEPSEEK_API_KEY=<您的DeepSeek API密钥>

您也可以在应用程序代码中以编程方式设置此配置:

// 从安全源或环境变量检索 API 密钥
String apiKey = System.getenv("DEEPSEEK_API_KEY");

添加存储库和 BOM

Spring AI 构件发布在 Spring Milestone 和 Snapshot 存储库中。 请参考构件存储库部分,将这些存储库添加到您的构建系统。

为了帮助依赖管理,Spring AI 提供了 BOM(物料清单)以确保在整个项目中使用一致的 Spring AI 版本。请参考依赖管理部分,将 Spring AI BOM 添加到您的构建系统。

自动配置

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 BOM 添加到您的构建文件中。

聊天属性

重试属性

前缀 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连接的 URLhttps://api.deepseek.com
spring.ai.deepseek.api-keyAPI 密钥-
配置属性

前缀 spring.ai.deepseek.chat 是属性前缀,让您可以为 DeepSeek 配置聊天模型实现。

属性描述默认值
spring.ai.deepseek.chat.enabled启用 DeepSeek 聊天模型true
spring.ai.deepseek.chat.base-url可选地覆盖 spring.ai.deepseek.base-url 以提供聊天特定的 URLhttps://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-pathbeta 功能端点的前缀路径/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% 概率质量的令牌。我们通常建议更改此参数或温度,但不要同时更改两者。1.0F
spring.ai.deepseek.chat.options.logprobs是否返回输出令牌的对数概率。如果为 true,则返回消息内容中返回的每个输出令牌的对数概率。-
spring.ai.deepseek.chat.options.topLogprobs0 到 20 之间的整数,指定在每个令牌位置返回的最可能令牌的数量,每个令牌都有相关的对数概率。如果使用此参数,必须将 logprobs 设置为 true。-

注意:您可以覆盖 ChatModel 实现的通用 spring.ai.deepseek.base-urlspring.ai.deepseek.api-key。如果设置了 spring.ai.deepseek.chat.base-urlspring.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(
        "Generate the names of 5 famous pirates. Please provide the JSON response without any code block markers such as ```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 = "Tell me a joke") String message) {
        return Map.of("generation", chatModel.call(message));
    }

    @GetMapping("/ai/generateStream")
	public Flux<ChatResponse> generateStream(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {
        var prompt = new Prompt(new UserMessage(message));
        return chatModel.stream(prompt);
    }
}

聊天前缀完成

聊天前缀完成遵循聊天完成 API,其中用户提供助手的前缀消息供模型完成消息的其余部分。

使用前缀完成时,用户必须确保消息列表中的最后一条消息是 DeepSeekAssistantMessage。

以下是聊天前缀完成的完整 Java 代码示例。在此示例中,我们将助手的前缀消息设置为 "```python\n" 以强制模型输出 Python 代码,并将 stop 参数设置为 ['`'] 以防止模型进行额外解释。

@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 = "Please write quick sort code") 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 生成的 CoT 内容,使他们能够查看、显示和提取它。

您可以使用 DeepSeekAssistantMessage 来获取由 deepseek-reasoner 生成的 CoT 内容。

public void deepSeekReasonerExample() {
    DeepSeekChatOptions promptOptions = DeepSeekChatOptions.builder()
            .model(DeepSeekApi.ChatModel.DEEPSEEK_REASONER.getValue())
            .build();
    Prompt prompt = new Prompt("9.11 and 9.8, which is greater?", promptOptions);
    ChatResponse response = chatModel.call(prompt);

    // 获取 deepseek-reasoner 生成的 CoT 内容,仅在使用 deepseek-reasoner 模型时可用
    DeepSeekAssistantMessage deepSeekAssistantMessage = (DeepSeekAssistantMessage) response.getResult().getOutput();
    String reasoningContent = deepSeekAssistantMessage.getReasoningContent();
    String text = deepSeekAssistantMessage.getText();
}

推理模型多轮对话

在对话的每一轮中,模型输出 CoT (reasoning_content) 和最终答案 (content)。在下一轮对话中,前几轮的 CoT 不会连接到上下文中,如下图所示:

多轮对话示例

请注意,如果 reasoning_content 字段包含在输入消息序列中,API 将返回 400 错误。因此,您应该在发出 API 请求之前从 API 响应中删除 reasoning_content 字段,如 API 示例所示。

public String deepSeekReasonerMultiRoundExample() {
    List<Message> messages = new ArrayList<>();
    messages.add(new UserMessage("9.11 and 9.8, which is greater?"));
    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(new AssistantMessage(Objects.requireNonNull(text)));
    messages.add(new UserMessage("How many Rs are there in the word 'strawberry'?"));
    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 实现了 ChatModelStreamingChatModel,并使用低级 DeepSeekApi 客户端连接到 DeepSeek 服务。

spring-ai-deepseek 依赖项添加到您项目的 Maven pom.xml 文件中:

<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 BOM 添加到您的构建文件中。

接下来,创建 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("Generate the names of 5 famous pirates."));

// 或使用流式响应
Flux<ChatResponse> streamResponse = chatModel.stream(
    new Prompt("Generate the names of 5 famous pirates."));

DeepSeekChatOptions 为聊天请求提供配置信息。 DeepSeekChatOptions.Builder 是一个流式选项构建器。

低级 DeepSeekApi 客户端

DeepSeekApi 是一个轻量级的 DeepSeek API Java 客户端。

这是一个显示如何以编程方式使用 API 的简单片段:

DeepSeekApi deepSeekApi =
    new DeepSeekApi(System.getenv("DEEPSEEK_API_KEY"));

ChatCompletionMessage chatCompletionMessage =
    new ChatCompletionMessage("Hello world", 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 的 JavaDoc 获取更多信息。

DeepSeekApi 示例

相关资源