DeepSeek API 调用 - Spring Boot 实现

DeepSeek API 调用 - Spring Boot 实现

1. 项目依赖

pom.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
复制代码
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:

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

import lombok.Data;

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

ChatRequest.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:

复制代码
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
复制代码
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("
请输入您的问题 (输入 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("
----------------------------------------");
                        fileWriter.println("
----------------------------------------");
                        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("
[%s] Question:
%s

[%s] Answer:
", timestamp, content, timestamp);
        } else {
            fileWriter.print(content);
        }
        fileWriter.flush();
    }
}
3.4 主应用类 DeepSeekApplication.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
复制代码
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

相关推荐
架构师沉默4 分钟前
程序员如何避免猝死?
java·后端·架构
椰奶燕麦21 分钟前
Windows PackageManager (winget) 核心故障排错与通用修复指南
后端
Zzxy24 分钟前
快速搭建SpringBoot项目并整合MyBatis-Plus
java·spring boot
zjjsctcdl1 小时前
springBoot发布https服务及调用
spring boot·后端·https
观测云1 小时前
SpringBootAI 接入观测云 MCP 最佳实践
spring boot·观测云·mcp
zdl6861 小时前
Spring Boot文件上传
java·spring boot·后端
世界哪有真情1 小时前
哇!绝了!原来这么简单!我的 Java 项目代码终于被 “拯救” 了!
java·后端
RMB Player1 小时前
Spring Boot 集成飞书推送超详细教程:文本消息、签名校验、封装工具类一篇搞定
java·网络·spring boot·后端·spring·飞书
重庆小透明2 小时前
【搞定面试之mysql】第三篇 mysql的锁
java·后端·mysql·面试·职场和发展
武超杰2 小时前
Spring Boot入门教程
java·spring boot·后端