DeepSeek API 调用 - Spring Boot 实现

DeepSeek API 调用 - Spring Boot 实现

1. 项目依赖

pom.xml 中添加以下依赖:

xml 复制代码
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
    </dependency>
</dependencies>

2. 项目结构

复制代码
deepseek-project/
├── src/main/java/com/example/deepseek/
│   ├── DeepSeekApplication.java
│   ├── config/
│   │   └── DeepSeekConfig.java
│   ├── model/
│   │   ├── ChatRequest.java
│   │   ├── ChatResponse.java
│   │   └── Message.java
│   └── service/
│       └── DeepSeekService.java
└── conversation.txt

3. 完整代码实现

3.1 配置类 DeepSeekConfig.java
java 复制代码
package com.example.deepseek.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

@Configuration
@Getter
public class DeepSeekConfig {
    @Value("${deepseek.api.url}")
    private String apiUrl;

    @Value("${deepseek.api.key}")
    private String apiKey;
}
3.2 请求/响应模型

Message.java:

java 复制代码
package com.example.deepseek.model;

import lombok.Data;

@Data
public class Message {
    private String role;
    private String content;
}

ChatRequest.java:

java 复制代码
package com.example.deepseek.model;

import lombok.Data;
import java.util.List;

@Data
public class ChatRequest {
    private String model = "deepseek-ai/DeepSeek-V3";
    private List<Message> messages;
    private boolean stream = true;
    private int max_tokens = 2048;
    private double temperature = 0.7;
    private double top_p = 0.7;
    private int top_k = 50;
    private double frequency_penalty = 0.5;
    private int n = 1;
    private ResponseFormat response_format = new ResponseFormat("text");

    @Data
    public static class ResponseFormat {
        private String type;
        
        public ResponseFormat(String type) {
            this.type = type;
        }
    }
}

ChatResponse.java:

java 复制代码
package com.example.deepseek.model;

import lombok.Data;
import java.util.List;

@Data
public class ChatResponse {
    private List<Choice> choices;

    @Data
    public static class Choice {
        private Delta delta;
    }

    @Data
    public static class Delta {
        private String content;
    }
}
3.3 服务类 DeepSeekService.java
java 复制代码
package com.example.deepseek.service;

import com.example.deepseek.config.DeepSeekConfig;
import com.example.deepseek.model.ChatRequest;
import com.example.deepseek.model.ChatResponse;
import com.example.deepseek.model.Message;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Flux;

import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Collections;
import java.util.Scanner;

@Service
@RequiredArgsConstructor
public class DeepSeekService {
    private final DeepSeekConfig config;
    private final WebClient.Builder webClientBuilder;
    private final ObjectMapper objectMapper = new ObjectMapper();

    public void startInteractiveChat() {
        try (Scanner scanner = new Scanner(System.in);
             PrintWriter fileWriter = new PrintWriter(new FileWriter("conversation.txt", true))) {

            while (true) {
                System.out.print("\n请输入您的问题 (输入 q 退出): ");
                String question = scanner.nextLine().trim();

                if ("q".equalsIgnoreCase(question)) {
                    System.out.println("程序已退出");
                    break;
                }

                // 保存问题
                saveToFile(fileWriter, question, true);

                // 发起对话请求
                Flux<String> responseFlux = sendChatRequest(question);

                StringBuilder fullResponse = new StringBuilder();
                responseFlux
                    .doOnNext(chunk -> {
                        System.out.print(chunk);
                        fullResponse.append(chunk);
                    })
                    .doOnComplete(() -> {
                        // 保存完整回复
                        saveToFile(fileWriter, fullResponse.toString(), false);
                        System.out.println("\n----------------------------------------");
                        fileWriter.println("\n----------------------------------------");
                        fileWriter.flush();
                    })
                    .blockLast();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private Flux<String> sendChatRequest(String question) {
        ChatRequest request = new ChatRequest();
        Message userMessage = new Message();
        userMessage.setRole("user");
        userMessage.setContent(question);
        request.setMessages(Collections.singletonList(userMessage));

        return webClientBuilder.build()
            .post()
            .uri(config.getApiUrl())
            .header("Authorization", "Bearer " + config.getApiKey())
            .header("Content-Type", "application/json")
            .bodyValue(request)
            .retrieve()
            .bodyToFlux(String.class)
            .filter(line -> line.startsWith("data: ") && !line.equals("data: [DONE]"))
            .map(line -> {
                try {
                    String jsonStr = line.substring(6);
                    ChatResponse response = objectMapper.readValue(jsonStr, ChatResponse.class);
                    return response.getChoices().get(0).getDelta().getContent();
                } catch (Exception e) {
                    return "";
                }
            })
            .filter(content -> !content.isEmpty());
    }

    private void saveToFile(PrintWriter fileWriter, String content, boolean isQuestion) {
        String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        if (isQuestion) {
            fileWriter.printf("\n[%s] Question:\n%s\n\n[%s] Answer:\n", timestamp, content, timestamp);
        } else {
            fileWriter.print(content);
        }
        fileWriter.flush();
    }
}
3.4 主应用类 DeepSeekApplication.java
java 复制代码
package com.example.deepseek;

import com.example.deepseek.service.DeepSeekService;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class DeepSeekApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(DeepSeekApplication.class, args);
        DeepSeekService deepSeekService = context.getBean(DeepSeekService.class);
        deepSeekService.startInteractiveChat();
    }
}
3.5 配置文件 application.properties
properties 复制代码
deepseek.api.url=https://api.siliconflow.cn/v1/chat/completions
deepseek.api.key=YOUR_API_KEY

4. 代码详解

4.1 关键特性
  1. 使用 Spring WebFlux 的响应式编程模型
  2. 流式处理 API 响应
  3. 文件记录对话
  4. 错误处理和异常管理
4.2 主要组件
  • DeepSeekConfig: 管理 API 配置
  • DeepSeekService: 处理对话逻辑和 API 交互
  • 模型类: 定义请求和响应结构

5. 使用方法

  1. 替换 application.properties 中的 YOUR_API_KEY
  2. 运行 DeepSeekApplication
  3. 在控制台输入问题
  4. 输入 'q' 退出程序
  5. 查看 conversation.txt 获取对话记录

6. 性能和可扩展性

  • 使用响应式编程提高并发性能
  • 灵活的配置管理
  • 易于扩展和定制

7. 注意事项

  • 确保正确配置 API Key
  • 处理网络异常
  • 注意内存使用

总结

Spring Boot 实现提供了一个健壮、可扩展的 DeepSeek API 调用方案,利用响应式编程提供高效的流式对话体验。

立即体验

快来体验 DeepSeek:https://cloud.siliconflow.cn/i/vnCCfVaQ

相关推荐
yyt3630458411 分钟前
spring单例bean线程安全问题讨论
java·spring
小兔崽子去哪了11 分钟前
Docker 安装 PostgreSQL
数据库·后端·postgresql
Sweet锦12 分钟前
SpringBoot 3.5 集成 InfluxDB 1.8
spring boot·时序数据库
野犬寒鸦15 分钟前
Redis热点key问题解析与实战解决方案(附大厂实际方案讲解)
服务器·数据库·redis·后端·缓存·bootstrap
我是大猴子21 分钟前
事务失效的几种情况以及是为什么(详解)
java·开发语言
snakeshe10101 小时前
深入理解 Java 注解:从原理到实战
后端
Lucaju1 小时前
吃透 Spring AI Alibaba 多智能体|四大协同模式+完整代码
后端
Nyarlathotep01131 小时前
Redis的对象(5):有序集合对象
redis·后端
wertyuytrewm1 小时前
Java面试——Java基础
java·jvm·面试
Java水解1 小时前
Spring Boot 消息队列与异步处理
spring boot·后端