SpringAI接入DeepSeek大模型实现流式对话

一、 环境配置

Spring AI 支持 Spring Boot 3.4.x,JDK支持需要17以上

添加快照存储库

language 复制代码
<repositories>
  <repository>
    <id>spring-snapshots</id>
    <name>Spring Snapshots</name>
    <url>https://repo.spring.io/snapshot</url>
    <releases>
      <enabled>false</enabled>
    </releases>
  </repository>
  <repository>
    <name>Central Portal Snapshots</name>
    <id>central-portal-snapshots</id>
    <url>https://central.sonatype.com/repository/maven-snapshots/</url>
    <releases>
      <enabled>false</enabled>
    </releases>
    <snapshots>
      <enabled>true</enabled>
    </snapshots>
  </repository>
</repositories>

注意:

将 Maven 与 Spring AI 快照结合使用时,请注意 Maven 镜像配置。如果您已在项目中配置了镜像,settings.xml如下所示:

language 复制代码
<mirror>
    <id>my-mirror</id>
    <mirrorOf>*</mirrorOf>
    <url>https://my-company-repository.com/maven</url>
</mirror>

通配符*会将所有仓库请求重定向到你的镜像,从而阻止访问 Spring 快照仓库。要解决此问题,请修改mirrorOf配置以排除 Spring 仓库:

此配置允许 Maven 直接访问 Spring 快照存储库,同时仍使用镜像来获取其他依赖项。

java 复制代码
<mirror>
    <id>my-mirror</id>
    <mirrorOf>*,!spring-snapshots,!central-portal-snapshots</mirrorOf>
    <url>https://my-company-repository.com/maven</url>
</mirror>

依赖管理

java 复制代码
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-bom</artifactId>
            <version>1.0.0-SNAPSHOT</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

二、接入DeepSeek大模型

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

先决条件

您需要使用 DeepSeek 创建 API 密钥才能访问 DeepSeek 语言模型。

在DeepSeek 注册页面创建一个帐户,并在API Keys 页面生成一个令牌。

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

java 复制代码
server:
  port: 8080

# In application.yml
spring:
  ai:
    deepseek:
      api-key: your-api-key
      base-url: https://api.deepseek.com # DeepSeek 的请求 URL, 可不填,默认值为 api.deepseek.com
      chat:
        options:
          model: deepseek-chat # 使用哪个模型
          temperature: 0.8 # 温度值

spring.ai.deepseek.chat.options.temperature: 使用的采样温度,介于 0 到 2 之间。较高的值(例如 0.8)会使输出更加随机,而较低的值(例如 0.2)会使输出更加集中且确定。我们通常建议更改此值或

top_p,但不要同时更改两者。
spring.ai.deepseek.chat.options.model: 目前deepseek模型有两种,deepseek-chat对话模型,deepseek-reasoner推理模型

自动配置

Spring AI 为 DeepSeek 聊天模型提供了 Spring Boot 自动配置功能。要启用此功能,请将以下依赖项添加到项目的 Mavenpom.xml文件中:

java 复制代码
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-model-deepseek</artifactId>
</dependency>

此时的完整POM配置

java 复制代码
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.4.1</version>
        <relativePath/>
    </parent>

    <groupId>com.mrsunn</groupId>
    <artifactId>ai-robot</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <description>AI机器人</description>

    <properties>
        <java.version>17</java.version>
        <!-- Spring AI 版本 -->
        <spring-ai.version>1.0.2</spring-ai.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.ai</groupId>
                <artifactId>spring-ai-bom</artifactId>
                <version>${spring-ai.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-model-deepseek</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-snapshots</id>
            <name>Spring Snapshots</name>
            <url>https://repo.spring.io/snapshot</url>
            <releases>
                <enabled>false</enabled>
            </releases>
        </repository>
        <repository>
            <name>Central Portal Snapshots</name>
            <id>central-portal-snapshots</id>
            <url>https://central.sonatype.com/repository/maven-snapshots/</url>
            <releases>
                <enabled>false</enabled>
            </releases>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>

        <!-- 添加华为云、阿里云 maven 中央仓库,提升 Jar 包下载速度 -->
        <repository>
            <id>huaweicloud</id>
            <name>huawei</name>
            <url>https://mirrors.huaweicloud.com/repository/maven/</url>
        </repository>
        <repository>
            <id>aliyunmaven</id>
            <name>aliyun</name>
            <url>https://maven.aliyun.com/repository/public</url>
        </repository>
    </repositories>

</project>

实现对话效果(deepseek-chat)

java 复制代码
@RestController
@RequestMapping("/ai")
public class ChatController {

    @Resource
    private DeepSeekChatModel chatModel;

    @GetMapping("/generate")
    public Map generate(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {
        return Map.of("generation", chatModel.call(message));
    }

    /**
     * 流式对话
     * @param message
     * @return
     */
    @GetMapping(value = "/generateStream", produces = "text/html;charset=utf-8")
    public Flux<String> generateStream(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {
        // 构建提示词
        Prompt prompt = new Prompt(new UserMessage(message));
        // 流式输出
        return chatModel.stream(prompt)
                .mapNotNull(chatResponse -> chatResponse.getResult().getOutput().getText());
    }

}

produces = "text/html;charset=utf-8",把返回的对象设置成html格式,并且设置编码,不然会乱码返回

如果你只是直接在浏览器地址栏输入接口地址(如
http://localhost:8080/generateStream?message=你好),那么无论你的后端返回的是

Flux 还是什么流,浏览器都只会一次性接收最终的响应内容,或者根本无法逐步显示,无法实现"打字机效果"。

推理模型(deepseek-reasoner)

这deepseek-reasoner是 DeepSeek 开发的推理模型。在得出最终答案之前,该模型会首先生成思维链 (CoT),以提高其响应的准确性。我们的 API 允许用户访问 生成的 CoT 内容deepseek-reasoner

,以便他们查看、显示和提取这些内容。
修改DeepSeek模型

yml 复制代码
spring:
  ai:
    deepseek:
      api-key: your-api-key
      base-url: https://api.deepseek.com # DeepSeek 的请求 URL, 可不填,默认值为 api.deepseek.com
      chat:
        options:
          model: deepseek-reasoner # 使用深度思考模型
          temperature: 0.8 # 温度值
java 复制代码
@Resource
private DeepSeekChatModel chatModel;

@GetMapping(value = "/generateStream", produces = "text/html;charset=utf-8")
public Flux<String> generateStream(@RequestParam(value = "message", defaultValue = "你是谁?") String message) {
    Prompt prompt = new Prompt(new UserMessage(message));
    AtomicBoolean hasSentSeparator = new AtomicBoolean(false);

    return chatModel.stream(prompt)
            .mapNotNull(chatResponse -> {
                DeepSeekAssistantMessage assistantMessage = (DeepSeekAssistantMessage) chatResponse.getResult().getOutput();

                String content = null;
                boolean isFinalAnswer = false;

                // 优先处理思考内容
                if (assistantMessage.getReasoningContent() != null) {
                    content = assistantMessage.getReasoningContent();
                }
                // 处理正式回答
                else if (assistantMessage.getText() != null) {
                    content = assistantMessage.getText();
                    isFinalAnswer = true;
                }

                if (StringUtils.isBlank(content)) {
                    return null;
                }

                // 添加分隔符(思考到回答的过渡)
                if (isFinalAnswer && !hasSentSeparator.get()) {
                    hasSentSeparator.set(true);
                    return "<br>--- 思考过程结束 ---<br>" + content;
                }

                return content;
            });
}

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

assistantMessage.getReasoningContent() 思考内容

assistantMessage.getText() 正式回答

使用ChatClient实现对话

ChatClient和ChatModel的区别

维度 ChatModel ChatClient
交互方式 直接调用模型,需手动处理请求/响应 链式调用,自动封装提示词和解析响应
功能扩展 强,内置 Advisor 机制(如对话历史管理、RAG)
结构化输出 需手动解析响应文本 支持自动映射为 Java 对象(如 entity(Recipe.class))
适用场景 实现简单功能和场景 快速开发复杂功能的场景,如企业级智能客服、连接外部工具等
  • ChatClient:若追求开发效率、需要内置高级功能(如记忆、RAG)或标准化交互使用 ChatClient。
  • ChatModel:若实现简单的大模型对接场景使用 ChatModel。

ChatClient使用对象创建。ChatClient.Builder您可以获取ChatClient.Builder任何ChatModelSpring Boot 自动配置的自动配置实例,也可以通过编程方式创建一个。

java 复制代码
@Configuration
public class ChatClientConfig {
    
    @Bean
    public ChatClient deepSeekChatClient(DeepSeekChatModel chatModel) {
        return ChatClient.create(chatModel);
    }
    
}
java 复制代码
@Autowired
private ChatClient deepSeekChatClient;

@GetMapping(value = "/generate", produces = "text/html;charset=utf-8")
public String generation(@RequestParam(value = "message", defaultValue = "你是谁?") String message) {
    return this.deepSeekChatClient.prompt()
            .user(message)
            .call()
            .content();
}

具有单一模型类型的多个 ChatClients

本节介绍一个常见的用例,您需要创建多个 ChatClient 实例,它们都使用相同的底层模型类型但具有不同的配置。

java 复制代码
@Autowired
private DeepSeekChatModel deepSeekChatModel;

ChatClient chatClient = ChatClient.create(deepSeekChatModel);
chatClient.mutate().defaultOptions(ChatOptions.builder().build());

ChatClient.Builder builder = ChatClient.builder(deepSeekChatModel);
ChatClient customChatClient = builder
        .defaultOptions(ChatOptions.builder().build())
        .defaultSystem("You are a helpful assistant.")
        .build();

使用同一个deepSeekChatModel模型,可以配置不同参数的ChatClient
​延伸阅读​:如需更深入的技术解析或学习资源,欢迎访问 Mr.Sun的博客(专注Java领域干货分享,持续更新中~)

相关推荐
大模型真好玩8 小时前
大模型工程面试经典(七)—如何评估大模型微调效果?
人工智能·面试·deepseek
沐浴露z3 天前
【Java SpringAI智能体开发学习 | 2】SpringAI 实用特性:自定义Advisor,结构化输出,对话记忆持久化,prompt模板,多模态
java·spring·springai
mask哥3 天前
详解mcp以及agen架构设计与实现
java·微服务·flink·大模型·ai agent·springai·mcp
量子位5 天前
DeepDiver-V2来了,华为最新开源原生多智能体系统,“团战”深度研究效果惊人
ai编程·deepseek
封奚泽优5 天前
班级互动小程序(Python)
python·deepseek
陈敬雷-充电了么-CEO兼CTO5 天前
视频理解新纪元!VideoChat双模架构突破视频对话瓶颈,开启多模态交互智能时代
人工智能·chatgpt·大模型·多模态·世界模型·kimi·deepseek
大模型真好玩5 天前
大模型工程面试经典(五)—大模型微调与RAG该如何选?
人工智能·面试·deepseek
文 丰7 天前
【centos7】部署ollama+deepseek
centos·deepseek
文 丰7 天前
【openEuler 24.03 LTS SP2】真实实验部署ollama0.11.6+deepseekR1:1.5b+open-webUI
centos·deepseek