SpringBoot或SpringAI对接DeekSeek大模型

news2025/1/30 14:14:13

今日除夕夜,deepseek可是出尽了风头,但是我看网上还没有这方面的内容对接,官网也并没有,故而本次对接是为了完成这个空缺

我看很多的博客内容是流式请求虽然返回时正常的,但是他并不是实时返回,而是全部响应结束之后返回,是有问题的,我这里的这个方法弥补了这个缺陷

下一次我应该会开源一个Starter,让大家使用起来更加方便,下一次直接开源出来,供大家参考,应该就在这一两天,可以期待一下

这里需要仔细看一下了

因为我使用的是JDK21,不过你也可以使用JDK8去做这件事情,但是前提fastjson和okHttp的版本,因为有些方法可能不是很兼容,如果想要完成可能有一些方法需要替换一下,但是肯定是可以用的

文章目录

  • 前言
  • 目录

    文章目录

    一、DeepSeek是什么?

    二、使用步骤

    1.引入库

    2.配置环境变量

     3.配置

    三、 请求

    1.流式请求

     2.非流失请求

    1.定义类

     2.非流式请求

     四、返回结果

    1.流式结果

     2.非流式请求

    总结



一、DeepSeek是什么?

我是由中国的深度求索(DeepSeek)公司开发的智能助手DeepSeek-V3。

  • 开发者:深度求索(DeepSeek),一家专注于实现AGI(通用人工智能)的中国科技公司。

  • 技术架构:基于大规模语言模型(LLM),通过深度学习技术训练,具备自然语言理解、生成和推理能力。

  • 数据来源:训练数据涵盖多领域公开文本(如书籍、网页、学术论文等),经过严格清洗和过滤,符合伦理与安全规范。

二、使用步骤

1.引入库

代码如下(示例):

        <!--fastjson-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.66</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp -->
        <dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
            <version>4.12.0</version>
        </dependency>

2.配置环境变量

spring:
  ai:
    deepseek:
      api-key: 这里填写自己的APIKey
      api-host: https://api.deepseek.com/chat/completions

 3.配置

package com.hhh.springai_test.config;


import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class ChatConfig {


    @Value("${spring.ai.deepseek.api-key}")
    private String DeepSeekConfigUrl;

    @Value("${spring.ai.deepseek.api-host}")
    private String DeepSeekConfigHost;


    public String getDeepSeekConfigUrl() {
        return DeepSeekConfigUrl;
    }

    public String getDeepSeekConfigHost() {
        return DeepSeekConfigHost;
    }

}

三、 请求

1.流式请求

@Resource
private ChatConfig config;

@GetMapping(value = "/ai/generateStreamAsString2", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> generateStreamAsString2(@RequestParam(value = "message") String message) throws Exception {
        // 初始化 OkHttpClient
        OkHttpClient client = new OkHttpClient().newBuilder().build();
        // 创建动态请求体,使用流式传输
        RequestBody body = new RequestBody() {
            @Override
            public okhttp3.MediaType contentType() {
                return okhttp3.MediaType.parse("application/json");
            }

            @Override
            public void writeTo(BufferedSink sink) throws IOException {
                // 构建请求体 JSON 数据
                String requestBodyJson = "{\n" +
                        "  \"messages\": [\n" +
                        "    {\n" +
                        "      \"content\": \"" + message + "\",\n" +  // 动态插入用户消息
                        "      \"role\": \"user\"\n" +
                        "    }\n" +
                        "  ],\n" +
                        "  \"model\": \"deepseek-chat\",\n" +
                        "  \"frequency_penalty\": 0,\n" +
                        "  \"max_tokens\": 1024,\n" +
                        "  \"presence_penalty\": 0,\n" +
                        "  \"response_format\": {\n" +
                        "    \"type\": \"text\"\n" +
                        "  },\n" +
                        "  \"stop\": null,\n" +
                        "  \"stream\": true,\n" +
                        "  \"stream_options\": null,\n" +
                        "  \"temperature\": 1,\n" +
                        "  \"top_p\": 1,\n" +
                        "  \"tools\": null,\n" +
                        "  \"tool_choice\": \"none\",\n" +
                        "  \"logprobs\": false,\n" +
                        "  \"top_logprobs\": null\n" +
                        "}";
                // 写入请求体数据
                sink.writeUtf8(requestBodyJson);
            }
        };
        // 创建 Headers
        Headers headers = new Headers.Builder()
                .add("Content-Type", "application/json")
                .add("Accept", "application/json")
                .add("Authorization", "Bearer " + config.getDeepSeekConfigUrl())  // 使用您的 API 密钥
                .build();
        // 创建 HttpUrl
        HttpUrl url = HttpUrl.parse(config.getDeepSeekConfigHost()); // 使用您的 API URL
        if (url == null) {
            throw new IllegalArgumentException("您此时未携带URL参数");
        }
        // 构造 Request
        okhttp3.Request request = new okhttp3.Request.Builder()
                .url(url)
                .post(body)  // 使用流式请求体
                .headers(headers)
                .build();
        // 执行请求并返回 Flux 流
        return Flux.create(sink -> {
            client.newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(@NotNull Call call, @NotNull IOException e) {
                    // 异常发生时调用 sink.error()
                    sink.error(e);
                }
                @Override
                public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                    ResponseBody responseBody = response.body();
                    BufferedSource source = responseBody.source();
                    while (true) {
                        // 逐行读取响应数据
                        String line = source.readUtf8Line();
                        if (line == null) {
                            break;
                        } else if (line.startsWith("data:")) {
                            String data = line.substring(5).trim();
                            // 检查数据是否为结束信号"[DONE]"
                            if (!"[DONE]".equals(data)) {
                                // 解析接收到的数据为JSON对象
                                JSONObject jsonResponse = new JSONObject(data);
                                String finishReason = jsonResponse.getJSONArray("choices").getJSONObject(0).optString("finish_reason");
                                if ("stop".equals(finishReason)) {
                                    // 结束时推送数据并完成
                                    sink.next(data);
                                    sink.complete();
                                    break;
                                } else {
                                    // 否则继续推送数据
                                    sink.next(data);
                                }
                                // 打印调试信息
                                System.out.println(jsonResponse.getJSONArray("choices"));
                            }
                        }
                    }
                }
            });
        });
    }

 2.非流失请求

1.定义类

package com.hhh.springai_test.model.dto.DeepSeekChat;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class ChatCompletionResponse {

    private String id;
    private String object;
    private long created;
    private String model;
    private List<Choice> choices;
    private Usage usage;
    private String system_fingerprint;

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class Choice {
        private int index;
        private Message message;
        private Object logprobs;
        private String finish_reason;
    }

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

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class Usage {
        private int prompt_tokens;
        private int completion_tokens;
        private int total_tokens;
        private PromptTokensDetails prompt_tokens_details;
        private int prompt_cache_hit_tokens;
        private int prompt_cache_miss_tokens;
    }

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class PromptTokensDetails {
        private int cached_tokens;
    }
}

 2.非流式请求

//引入这个bean
@Resource
private ChatConfig config;

 
   @GetMapping(value = "/ai/generateAsString3")
    public ChatCompletionResponse generateStreamAsString3(@RequestParam(value = "message") String message) {
        // 初始化 OkHttpClient
        OkHttpClient client = new OkHttpClient().newBuilder().build();
        okhttp3.MediaType mediaType = okhttp3.MediaType.parse("application/json");
        RequestBody requestBody = RequestBody.create(mediaType, "{\n" +
                "  \"messages\": [\n" +
                "    {\n" +
                "      \"content\": \"" + "请介绍一下你自己" + "\",\n" +  // 动态插入用户消息
                "      \"role\": \"user\"\n" +
                "    },\n" +
                "    {\n" +
                "      \"content\": \"" + message + "\",\n" +  // 动态插入用户消息
                "      \"role\": \"user\"\n" +
                "    }\n" +
                "  ],\n" +
                "  \"model\": \"deepseek-chat\",\n" +
                "  \"frequency_penalty\": 0,\n" +
                "  \"max_tokens\": 1024,\n" +
                "  \"presence_penalty\": 0,\n" +
                "  \"response_format\": {\n" +
                "    \"type\": \"text\"\n" +
                "  },\n" +
                "  \"stop\": null,\n" +
                "  \"stream\": false,\n" +
                "  \"stream_options\": null,\n" +
                "  \"temperature\": 1,\n" +
                "  \"top_p\": 1,\n" +
                "  \"tools\": null,\n" +
                "  \"tool_choice\": \"none\",\n" +
                "  \"logprobs\": false,\n" +
                "  \"top_logprobs\": null\n" +
                "}");
        Buffer buffer = new Buffer();
        try {
            requestBody.writeTo(buffer);
            System.out.println("Request Body Content: " + buffer.readUtf8());
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 创建 Headers
        Headers headers = new Headers.Builder()
                .add("Content-Type", "application/json")
                .add("Accept", "application/json")
                .add("Authorization", "Bearer " + config.getDeepSeekConfigUrl())  // 使用您的 API 密钥
                .build();
        // 创建 HttpUrl
        HttpUrl url = HttpUrl.parse(config.getDeepSeekConfigHost());
        if (url == null) {
            throw new IllegalArgumentException("您此时未携带URL参数");
        }
        // 构造 Request
        okhttp3.Request request = new okhttp3.Request.Builder()
                .url(url)
                .post(requestBody)
                .headers(headers)
                .build();
        // 执行请求并打印响应
        try (Response response = client.newCall(request).execute()) {
            String responseBody = response.body().string();
            System.out.println(responseBody);
            ChatCompletionResponse responseVo = JSON.parseObject(responseBody, ChatCompletionResponse.class);
            return responseVo;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

 四、返回结果

1.流式结果

 2.非流式请求


总结

因为我使用的是JDK21,不过你也可以使用JDK8去做这件事情,但是前提fastjson和okHttp的版本,因为有些方法可能不是很兼容,如果想要完成可能有一些方法需要替换一下,但是肯定是可以用的

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2284793.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Funnel-Transformer:通过过滤序列冗余实现高效语言处理

摘要 随着语言预训练的成功&#xff0c;开发更具扩展性且能高效利用大量未标注数据的架构变得尤为重要。为了提高效率&#xff0c;我们研究了在维持完整token级别表示时的冗余问题&#xff0c;尤其是对于仅需要序列单向量表示的任务。基于这一直觉&#xff0c;我们提出了Funne…

【搜索回溯算法】:BFS的魔力--如何使用广度优先搜索找到最短路径

✨感谢您阅读本篇文章&#xff0c;文章内容是个人学习笔记的整理&#xff0c;如果哪里有误的话还请您指正噢✨ ✨ 个人主页&#xff1a;余辉zmh–CSDN博客 ✨ 文章所属专栏&#xff1a;搜索回溯算法篇–CSDN博客 文章目录 一.广度优先搜索&#xff08;BFS&#xff09;解决最短路…

【算法】经典博弈论问题——威佐夫博弈 python

目录 威佐夫博弈(Wythoff Game)【模板】 威佐夫博弈(Wythoff Game) 有两堆石子&#xff0c;数量任意&#xff0c;可以不同&#xff0c;游戏开始由两个人轮流取石子 游戏规定&#xff0c;每次有两种不同的取法 1)在任意的一堆中取走任意多的石子 2)可以在两堆中同时取走相同数量…

CUDA学习-内存访问

一 访存合并 1.1 说明 本部分内容主要参考: 搞懂 CUDA Shared Memory 上的 bank conflicts 和向量化指令(LDS.128 / float4)的访存特点 - 知乎 1.2 share memory结构 图1.1 share memory结构 放在 shared memory 中的数据是以 4 bytes(即 32 bits)作为 1 个 word,依…

力扣动态规划-13【算法学习day.107】

前言 ###我做这类文章一个重要的目的还是给正在学习的大家提供方向&#xff08;例如想要掌握基础用法&#xff0c;该刷哪些题&#xff1f;建议灵神的题单和代码随想录&#xff09;和记录自己的学习过程&#xff0c;我的解析也不会做的非常详细&#xff0c;只会提供思路和一些关…

《剪映5.9官方安装包》免费自动生成字幕

&#xff08;避免失效建议存自己网盘后下载&#xff09;剪映5.9官方Win.Mac 链接&#xff1a;https://pan.xunlei.com/s/VOHc-Fg2XRlD50MueEaOOeW1A1?pwdawtt# 官方唯一的免费版&#xff0c;Win和Mac都有&#xff0c;此版本官方已下架&#xff0c;觉得有用可转存收藏&#xf…

Brave132 编译指南 Windows 篇:安装 Visual Studio 2022(二)

1. 引言 在着手编译 Brave 浏览器的 132 版本之前&#xff0c;构建一个完备的开发环境至关重要。Visual Studio 2022 作为一款功能强大的集成开发环境&#xff08;IDE&#xff09;&#xff0c;为 Brave 浏览器的编译提供了坚实的工具链和技术支持。它不仅提供了高效的代码编辑…

DBO-高斯回归预测matlab

蜣螂优化算法(Dung Beetle Optimizer, DBO)是一种新型的群智能优化算法&#xff0c;在2022年底提出&#xff0c;主要是受蜣螂的的滚球、跳舞、觅食、偷窃和繁殖行为的启发。 本次研究使用的是 Excel 格式的股票预测数据。数据集按照 8&#xff1a;1&#xff1a;1 的比例&#x…

2025美国大学生数学建模竞赛美赛E题成品参考论文(48页)(含模型,可运行代码,求解结果)

2025美国大学生数学建模竞赛E题成品参考论文 目录 一、问题重述 二、问题分析 三、模型假设 四、模型建立与求解 4.1问题1 4.1.1问题1思路分析 4.1.2问题1模型建立 4.1.3问题1代码&#xff08;仅供参考&#xff09; 4.1.4问题1求解结果&#xff08;仅供参考&…

VMware 中Ubuntu无网络连接/无网络标识解决方法【已解决】

参考文档 Ubuntu无网络连接/无网络标识解决方法_ubuntu没网-CSDN博客 再我们正常使用VMware时&#xff0c;就以Ubuntu举例可能有时候出现无网络连接&#xff0c;甚至出现无网络标识的情况&#xff0c;那么废话不多说直接上教程 环境&#xff1a;无网络 解决方案&#…

基于RIP的MGRE VPN综合实验

实验拓扑 实验需求 1、R5为ISP&#xff0c;只能进行IP地址配置&#xff0c;其所有地址均配为公有IP地址&#xff1b; 2、R1和R5间使用PPP的PAP认证&#xff0c;R5为主认证方&#xff1b; R2与R5之间使用ppp的CHAP认证&#xff0c;R5为主认证方&#xff1b; R3与R5之间使用HDLC封…

Autosar-Os是怎么运行的?(Os基础模块)

写在前面&#xff1a; 入行一段时间了&#xff0c;基于个人理解整理一些东西&#xff0c;如有错误&#xff0c;欢迎各位大佬评论区指正&#xff01;&#xff01;&#xff01; 书接上文 Autosar-Os是怎么运行的&#xff1f;&#xff08;一&#xff09;-CSDN博客 目录 1.Resourc…

OPencv3.4.1安装及配置教程

来到GitHub上opencv的项目地址 https://github.com/opencv/opencv/releases/tag/3.4.1 以上资源包都是 OpenCV 3.4.1 版本相关资源&#xff0c;它们的区别如下&#xff1a; (1). opencv-3.4.1-android-sdk.zip&#xff1a;适用于 Android 平台的软件开发工具包&#xff08;SDK…

选择困难?直接生成pynput快捷键字符串

from pynput import keyboard# 文档&#xff1a;https://pynput.readthedocs.io/en/latest/keyboard.html#monitoring-the-keyboard # 博客(pynput相关源码)&#xff1a;https://blog.csdn.net/qq_39124701/article/details/145230331 # 虚拟键码(十六进制)&#xff1a;https:/…

LeetCode题练习与总结:安装栅栏--587

一、题目描述 给定一个数组 trees&#xff0c;其中 trees[i] [xi, yi] 表示树在花园中的位置。 你被要求用最短长度的绳子把整个花园围起来&#xff0c;因为绳子很贵。只有把 所有的树都围起来&#xff0c;花园才围得很好。 返回恰好位于围栏周边的树木的坐标。 示例 1: 输…

< OS 有关 > 阿里云 几个小时前 使用密钥替换 SSH 密码认证后, 发现主机正在被“攻击” 分析与应对

信息来源&#xff1a; 文件&#xff1a;/var/log/auth.log 因为在 sshd_config 配置文件中&#xff0c;已经定义 LogLevel INFO 部分内容&#xff1a; 2025-01-27T18:18:55.68272708:00 jpn sshd[15891]: Received disconnect from 45.194.37.171 port 58954:11: Bye Bye […

使用八爪鱼爬虫和Web Scraper抓取数据实战案例,附详细教程

最近有不少小伙伴咨询怎么抓取抖音视频或者评论的数据&#xff0c;他们多是自媒体或者商家&#xff0c;想要模仿爆火视频或者分析视频评论区的舆情信息&#xff0c;确实呀&#xff0c;现在抖音是流量高地&#xff0c;淘金的地方&#xff0c;真的是一个值得挖掘的宝藏。当然我一…

海外问卷调查渠道查如何设置:最佳实践+示例

随着经济全球化和一体化进程的加速&#xff0c;企业间的竞争日益加剧&#xff0c;为了获得更大的市场份额&#xff0c;对企业和品牌而言&#xff0c;了解受众群体的的需求、偏好和痛点才是走向成功的关键。而海外问卷调查才是获得受众群体痛点的关键&#xff0c;制作海外问卷调…

【C++数论】880. 索引处的解码字符串|2010

本文涉及知识点 数论&#xff1a;质数、最大公约数、菲蜀定理 LeetCode880. 索引处的解码字符串 给定一个编码字符串 s 。请你找出 解码字符串 并将其写入磁带。解码时&#xff0c;从编码字符串中 每次读取一个字符 &#xff0c;并采取以下步骤&#xff1a; 如果所读的字符是…

从ai产品推荐到利用cursor快速掌握一个开源项目再到langchain手搓一个Text2Sql agent

目录 0. 经验分享&#xff1a;产品推荐 1. 经验分享&#xff1a;提示词优化 2. 经验分享&#xff1a;使用cursor 阅读一篇文章 3. 经验分享&#xff1a;使用cursor 阅读一个完全陌生的开源项目 4. 经验分享&#xff1a;手搓一个text2sql agent &#xff08;使用langchain l…