当前位置: 首页 > news >正文

SpringBoot对接DeepSeek

文章目录

  • Spring Boot 集成 DeepSeek API 详细步骤
    • 1. 创建API Key
      • 1.访问 [DeepSeek控制台](https://platform.deepseek.com/usage) 并登录。
      • 2.点击 Create API Key 生成新密钥。
      • 3.复制并保存密钥(需在Spring Boot配置文件中使用)。
    • 2. 创建Spring Boot工程
    • 3. 配置项目依赖
    • 4. 核心代码实现
      • 4.1 定义响应实体类
      • 4.2 控制器实现(支持SSE流式响应)
    • 5. 配置文件说明
    • 6. 测试与验证
      • 6.1启动应用后,通过浏览器或工具发送请求:
      • 6.2预期输出(流式响应):

Spring Boot 集成 DeepSeek API 详细步骤

1. 创建API Key

1.访问 DeepSeek控制台 并登录。

在这里插入图片描述

2.点击 Create API Key 生成新密钥。

3.复制并保存密钥(需在Spring Boot配置文件中使用)。

2. 创建Spring Boot工程

使用 Spring Initializr 创建项目,选择以下依赖:

  • Spring Web

  • Lombok(简化实体类代码)

3. 配置项目依赖

在 pom.xml 中添加必要依赖:

<!-- OkHttp 实现HTTP请求 -->
<dependency><groupId>com.squareup.okhttp3</groupId><artifactId>okhttp</artifactId><version>4.12.0</version>
</dependency><!-- FastJSON 用于JSON解析 -->
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>2.0.48</version>
</dependency><!-- SSE 事件流支持 -->
<dependency><groupId>com.squareup.okhttp3</groupId><artifactId>okhttp-sse</artifactId><version>4.12.0</version>
</dependency>

4. 核心代码实现

4.1 定义响应实体类

@Data
public class AiResult {private Integer code;private String message;private String sid;private String id;private Long created;private List<AiResultChoices> choices;private AiResultUsage usage;
}@Data
public class AiResultChoices {private AiResultDelta delta;private Integer index;
}@Data
public class AiResultDelta {private String role;private String content;
}@Data
public class AiResultUsage {private Integer prompt_tokens;private Integer completion_tokens;private Integer total_tokens;
}@Data
public class ContentDto {private String content;
}

4.2 控制器实现(支持SSE流式响应)

/*** DeepSeek AI接口请求控制器* 功能:处理SSE(Server-Sent Events)流式请求,与DeepSeek API交互* 主要职责:* 1. 接收前端SSE请求* 2. 构造DeepSeek API请求* 3. 处理流式响应并转发给客户端* 4. 管理连接生命周期和异常处理*/
@RestController
public class SeekController {// 日志记录器private static final Logger log = LoggerFactory.getLogger(SeekController.class);// 流式结束标识符(符合OpenAI标准)private static final String DONE_FLAG = "[DONE]";// HTTP请求超时时间(单位:秒)private static final int TIMEOUT_SECONDS = 60;// DeepSeek API端点private static final String AI_URL = "https://api.deepseek.com/chat/completions";// JSON媒体类型常量private static final MediaType JSON_MEDIA_TYPE = MediaType.parse("application/json");// 从配置文件注入API密钥@Value("${api.key}")private String apiKey;// OkHttp客户端配置(线程安全)private final OkHttpClient httpClient = new OkHttpClient.Builder().connectTimeout(TIMEOUT_SECONDS, TimeUnit.SECONDS)  // 连接超时.readTimeout(TIMEOUT_SECONDS, TimeUnit.SECONDS)     // 读取超时.writeTimeout(TIMEOUT_SECONDS, TimeUnit.SECONDS)    // 写入超时.build();/*** SSE请求处理入口* @param message 用户输入消息* @param response HTTP响应对象* @throws IOException 当响应流出现问题时抛出*/@GetMapping("/stream")public void handleSse(@RequestParam String message, HttpServletResponse response) throws IOException {// 配置SSE响应头configureSSEResponse(response);PrintWriter pw = null;try {// 获取响应输出流pw = response.getWriter();// 创建同步锁(初始计数器为1)CountDownLatch latch = new CountDownLatch(1);// 执行SSE请求executeSSERequest(pw, buildRequest(message), latch);// 等待异步操作完成(最大等待TIMEOUT_SECONDS秒)if (!latch.await(TIMEOUT_SECONDS, TimeUnit.SECONDS)) {log.warn("SSE请求超时");}} catch (InterruptedException e) {// 正确处理线程中断Thread.currentThread().interrupt();log.error("请求被中断", e);response.sendError(503, "服务不可用");} catch (Exception e) {log.error("SSE请求异常", e);response.sendError(500, "服务器内部错误");} finally {// 确保关闭输出流if (pw != null) {try {pw.close();} catch (Exception e) {log.warn("关闭PrintWriter异常", e);}}}}/*** 配置SSE响应头* @param response HTTP响应对象*/private void configureSSEResponse(HttpServletResponse response) {response.setContentType("text/event-stream");  // MIME类型response.setCharacterEncoding("UTF-8");        // 字符编码response.setHeader("Connection", "keep-alive"); // 保持长连接response.setHeader("Cache-Control", "no-cache"); // 禁用缓存}/*** 构建DeepSeek API请求* @param content 用户输入内容* @return 构造好的Request对象*/private Request buildRequest(String content) {// 构造请求参数Map<String, Object> params = new HashMap<>();params.put("model", "deepseek-chat");    // 使用的模型params.put("stream", true);              // 启用流式传输// 构造消息列表(使用双括号初始化语法)params.put("messages", Collections.singletonList(new HashMap<String, String>() {{put("role", "user");         // 消息角色put("content", content);     // 消息内容}}));// 构建OkHttp请求return new Request.Builder().url(AI_URL)  // API地址.post(RequestBody.create(JSON.toJSONString(params), JSON_MEDIA_TYPE)) // JSON请求体.addHeader("Authorization", "Bearer " + apiKey) // 认证头.addHeader("Accept", "text/event-stream")       // 接受SSE流.build();}/*** 执行SSE请求核心方法* @param pw 响应输出流* @param request 构造好的API请求* @param latch 线程同步锁*/private void executeSSERequest(PrintWriter pw, Request request, CountDownLatch latch) {// 创建事件源监听器RealEventSource eventSource = new RealEventSource(request, new EventSourceListener() {/*** 事件处理回调* @param eventSource 事件源* @param id 事件ID(未使用)* @param type 事件类型(未使用)* @param data 接收到的数据*/@Overridepublic void onEvent(EventSource eventSource, String id, String type, String data) {try {// 处理结束标志if (DONE_FLAG.equals(data)) {sendData(pw, new ContentDto(DONE_FLAG));return;}// 解析并发送有效内容String content = parseContent(data);if (!content.isEmpty()) {sendData(pw, new ContentDto(content));}} catch (Exception e) {log.error("事件处理异常", e);}}/*** 失败处理回调*/@Overridepublic void onFailure(EventSource eventSource, Throwable t, Response response) {log.error("API调用失败: {},响应码:{}", t.getMessage(), (response != null ? response.code() : "N/A"));latch.countDown(); // 释放同步锁}/*** 连接关闭回调*/@Overridepublic void onClosed(EventSource eventSource) {try {sendData(pw, new ContentDto(DONE_FLAG)); // 发送结束标志} finally {latch.countDown(); // 确保释放同步锁}}});// 发起异步连接eventSource.connect(httpClient);}/*** 线程安全的数据发送方法* @param pw 响应输出流* @param dto 要发送的数据传输对象*/private synchronized void sendData(PrintWriter pw, ContentDto dto) {try {// 按照SSE格式发送数据pw.write("data:" + JSON.toJSONString(dto) + "\n\n");pw.flush(); // 立即刷新缓冲区} catch (Exception e) {log.error("数据发送失败", e);}}/*** 解析API响应内容* @param data 原始响应字符串* @return 解析出的内容文本*/private String parseContent(String data) {try {// 使用FastJSON反序列化AiResult result = JSON.parseObject(data, AiResult.class);// 使用Optional处理可能为空的字段return Optional.ofNullable(result.getChoices()).flatMap(list -> list.stream().findFirst())  // 取第一个choice.map(AiResultChoices::getDelta)              // 获取delta对象.map(AiResultDelta::getContent)              // 获取content字段.orElse("");                                 // 默认返回空字符串} catch (Exception e) {log.error("数据解析异常,原始数据:{}", data, e);return "";}}
}

5. 配置文件说明

在 application.yml 中添加配置:

deepseek:api-key: your_api_key_here  # 替换为实际API Key

6. 测试与验证

6.1启动应用后,通过浏览器或工具发送请求:

GET http://localhost:8080/stream?message=你好,介绍一下你自己

6.2预期输出(流式响应):

在这里插入图片描述


http://www.mrgr.cn/news/95091.html

相关文章:

  • dify+deepseek联网搜索:免费开源搜索引擎Searxng使用(让你的大模型也拥有联网的功能)
  • Python功能完美的宝库——内置的强大“武器库”builtins
  • 春天遇到了冬天的吻
  • 【Java】Mybatis学习笔记
  • 火星探测发展概述2025.3.20
  • 如何判断 MSF 的 Payload 是 Staged 还是 Stageless(含 Meterpreter 与普通 Shell 对比)
  • scrollIntoView 的behavior都有哪些属性
  • STM32HAL库,解决串口UART中断接收到的第一个字节数据丢失
  • 基于springboot的房屋租赁系统(008)
  • L2TP实验 作业
  • 数学之握手问题
  • 基于单片机控制的电动汽车双闭环调速系统(论文+源码)
  • 微前端 qiankun vite vue3
  • Day20:丑数
  • 爬虫案例-爬取某狗音乐
  • 神经网络中层与层之间的关联
  • C++ 各种map对比
  • C语言的内存函数
  • 动平衡仿真程序设计
  • 【链表】一文搞定链表算法:从基础到实战