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

springboot、deepseek4j、bge-m3和milvus

1、pom

<?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.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.lee</groupId>
    <artifactId>deepseektest</artifactId>
    <version>0.0.1</version>
    <name>deepseektest</name>
    <description>deepseektest</description>
    <properties>
        <java.version>23</java.version>
        <spring-ai.version>1.0.0-M5</spring-ai.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>io.github.pig-mesh.ai</groupId>
            <artifactId>deepseek-spring-boot-starter</artifactId>
            <version>1.4.5</version>
        </dependency>

        <dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
            <version>4.12.0</version>
        </dependency>
        <dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp-sse</artifactId>
            <version>4.12.0</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson</groupId>
            <artifactId>jackson-bom</artifactId>
            <version>2.12.4</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.83_noneautotype</version>
        </dependency>

        <!-- 链接 milvus SDK-->
        <dependency>
            <groupId>io.milvus</groupId>
            <artifactId>milvus-sdk-java</artifactId>
            <version>2.5.3</version>
        </dependency>

    </dependencies>
    <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>

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

</project>

2、配置文件

# 推理模型链接信息
deepseek.api-key=sk-bedafbqsexpyunwgfawojwcachflvafxxksdgszvdsahwtlu
deepseek.model=deepseek-r1:32b
deepseek.base-url=http://172.16.50.25:11434/v1
# 向量模型链接信息
embedding.api-key=sk-bedafbqsexpyunwgfawojwcachflvafxxksdgszvdsahwtlu
embedding.base-url=http://172.16.50.25:11434/v1
embedding.model=bge-m3:latest

3、向量数据库 milvus代码

package com.lee.deepseektest.config;

import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MilvusConfig {


    @Bean
    public MilvusClientV2 MilvusClientV2() {

        ConnectConfig config = ConnectConfig.builder()
                .uri("http://xxx.xxx.xxx.xxx:19530")
                .build();
        MilvusClientV2 client = new MilvusClientV2(config);
        return client;
    }
}

4、向量数据库插入数据

package com.lee.deepseektest.controller;

import ch.qos.logback.core.util.FileUtil;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import io.github.pigmesh.ai.deepseek.core.EmbeddingClient;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.service.vector.request.InsertReq;
import io.milvus.v2.service.vector.response.InsertResp;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

@RestController
public class MilvusController {


    @Autowired
    MilvusClientV2 milvusClientV2;

    @Autowired
    EmbeddingClient embeddingClient;

    @GetMapping("/milvus")
    public String insert() {
        // 这里以 2025最新的我司保密条例演示,可以换成你自己的
//        String law = FileUtil.readString("/Users/lengleng/Downloads/law.txt", Charset.defaultCharset());
//        String[] lawSplits = StrUtil.split(law, 400);
        String[] lawSplits = new String[]{"高速公路", "航运"};

        List<JsonObject> data = new ArrayList<>();
        for (String lawSplit : lawSplits) {
            List<Float> floatList = embeddingClient.embed(lawSplit);

            JsonObject jsonObject = new JsonObject();

            // 将 List<Float> 转换为 JsonArray
            JsonArray jsonArray = new JsonArray();
            for (Float value : floatList) {
                jsonArray.add(value);
            }
            jsonObject.add("vector", jsonArray);
            jsonObject.addProperty("text", lawSplit);

            data.add(jsonObject);
        }

        InsertReq insertReq = InsertReq.builder()
                .collectionName("deepseek4jtest")
                .data(data)
                .build();

        InsertResp insertResp =  milvusClientV2.insert(insertReq);
        System.out.println(insertResp.getInsertCnt());
        return "ok";
    }


}

5、deepseek模型使用

package com.lee.deepseektest.controller;

import io.github.pigmesh.ai.deepseek.core.DeepSeekClient;
import io.github.pigmesh.ai.deepseek.core.Json;
import io.github.pigmesh.ai.deepseek.core.chat.ChatCompletionChoice;
import io.github.pigmesh.ai.deepseek.core.chat.ChatCompletionRequest;
import io.github.pigmesh.ai.deepseek.core.chat.ChatCompletionResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;

import java.util.HashMap;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

@RestController
public class DeepSeekController {

    @Autowired
    private DeepSeekClient deepSeekClient;

    public final static HashMap<String, String> cache = new HashMap<>();

    Function<List<ChatCompletionChoice>, String> choicesProcess = list -> list.stream().map(e -> e.delta().content())
            .collect(Collectors.joining());

    Function<String, String> elt = s -> s.replaceAll("<think>[\\s\\S]*?</think>", "").replaceAll("\n", "");


    /**
     *  流式返回示例
     * @param prompt
     * @return
     */
    @GetMapping(value = "/chat", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<ChatCompletionResponse> chat(String prompt) {
        return deepSeekClient.chatFluxCompletion(prompt);
    }

    @GetMapping(value = "/sync/chat")
    public ChatCompletionResponse syncChat(String prompt) {
        ChatCompletionRequest request = ChatCompletionRequest.builder()
                // 根据渠道模型名称动态修改这个参数
//                .model(deepSeekProperties.getModel())
                .addUserMessage(prompt).build();

        return deepSeekClient.chatCompletion(request).execute();
    }



    @GetMapping(value = "/chat/advanced", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<ChatCompletionResponse> chatAdvanced(String prompt, String cacheCode) {
        ChatCompletionRequest request = ChatCompletionRequest.builder()
//                .model(deepSeekProperties.getModel())
                .addUserMessage(prompt).addAssistantMessage(elt.apply(cache.getOrDefault(cacheCode, "")))
                .addSystemMessage("你是一个专业的助手").maxCompletionTokens(5000).build();
        // 只保留上一次回答内容
        cache.remove(cacheCode);
        return deepSeekClient.chatFluxCompletion(request).doOnNext(i -> {
            String content = choicesProcess.apply(i.choices());
            // 其他ELT流程
            cache.merge(cacheCode, content, String::concat);
        }).doOnError(e -> System.out.println(e.getMessage()));
    }

}

6、deepseek4j官方文档

deepseek4j简介 - 零基础入门Java AI

7、测试推理过程

deepseek 调试

8、向量数据库中的collections在使用时必须要先加载

判断和加载向量数据库milvus中的collection

package com.lee.deepseektest.service;

import io.milvus.param.R;
import io.milvus.param.collection.LoadCollectionParam;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.service.collection.request.GetLoadStateReq;
import io.milvus.v2.service.collection.request.HasCollectionReq;
import io.milvus.v2.service.collection.request.LoadCollectionReq;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class MilvusService {

    @Autowired
    MilvusClientV2 milvusClientV2;

    public boolean loadCollection(String collectionName) {

        //先判断是否有 collection
        HasCollectionReq hasCollectionReq = HasCollectionReq.builder()
                .collectionName(collectionName).build();
        boolean hasCollection = milvusClientV2.hasCollection(hasCollectionReq);

        //在判断是否已加载 collection
        GetLoadStateReq getLoadStateReq = GetLoadStateReq.builder()
                .collectionName(collectionName).build();
        boolean hasLoad = milvusClientV2.getLoadState(getLoadStateReq);

        // 加载集合到内存
        LoadCollectionReq loadCollectionReq = LoadCollectionReq.builder()
                .collectionName(collectionName).build();
        milvusClientV2.loadCollection(loadCollectionReq);
        hasCollection = milvusClientV2.hasCollection(hasCollectionReq);
        return hasCollection;

    }
}

9、RAG接口

package com.lee.deepseektest.controller;

import io.github.pigmesh.ai.deepseek.core.DeepSeekClient;
import io.github.pigmesh.ai.deepseek.core.EmbeddingClient;
import io.github.pigmesh.ai.deepseek.core.Json;
import io.github.pigmesh.ai.deepseek.core.chat.ChatCompletionChoice;
import io.github.pigmesh.ai.deepseek.core.chat.ChatCompletionRequest;
import io.github.pigmesh.ai.deepseek.core.chat.ChatCompletionResponse;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.service.vector.request.SearchReq;
import io.milvus.v2.service.vector.request.data.FloatVec;
import io.milvus.v2.service.vector.response.SearchResp;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

@RestController
public class DeepSeekController {

    @Autowired
    private DeepSeekClient deepSeekClient;


    @Autowired
    MilvusClientV2 milvusClientV2;

    @Autowired
    EmbeddingClient embeddingClient;

    public final static HashMap<String, String> cache = new HashMap<>();

    Function<List<ChatCompletionChoice>, String> choicesProcess = list -> list.stream().map(e -> e.delta().content())
            .collect(Collectors.joining());

    Function<String, String> elt = s -> s.replaceAll("<think>[\\s\\S]*?</think>", "").replaceAll("\n", "");


    /**
     *  流式返回示例
     * @param prompt
     * @return
     */
    @GetMapping(value = "/chat", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<ChatCompletionResponse> chat(String prompt) {
        return deepSeekClient.chatFluxCompletion(prompt);
    }

    @GetMapping(value = "/sync/chat")
    public ChatCompletionResponse syncChat(String prompt) {
        ChatCompletionRequest request = ChatCompletionRequest.builder()
                // 根据渠道模型名称动态修改这个参数
//                .model(deepSeekProperties.getModel())
                .addUserMessage(prompt).build();

        return deepSeekClient.chatCompletion(request).execute();
    }


    /**
     * 多轮会话
     * @param prompt
     * @param cacheCode
     * @return
     */
    @GetMapping(value = "/chat/advanced", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<ChatCompletionResponse> chatAdvanced(String prompt, String cacheCode) {
        ChatCompletionRequest request = ChatCompletionRequest.builder()
//                .model(deepSeekProperties.getModel())
                .addUserMessage(prompt).addAssistantMessage(elt.apply(cache.getOrDefault(cacheCode, "")))
                .addSystemMessage("你是一个专业的助手").maxCompletionTokens(5000).build();
        // 只保留上一次回答内容
        cache.remove(cacheCode);
        return deepSeekClient.chatFluxCompletion(request).doOnNext(i -> {
            String content = choicesProcess.apply(i.choices());
            // 其他ELT流程
            cache.merge(cacheCode, content, String::concat);
        }).doOnError(e -> System.out.println(e.getMessage()));
    }


    /**
     * RAG知识库接口
     * @param prompt
     * @return
     */
    @GetMapping(value = "/rag/chat", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<ChatCompletionResponse> ragchat(String prompt) {

        List<Float> floatList = embeddingClient.embed(prompt);

        SearchReq searchReq = SearchReq.builder()
                .collectionName("test1")
                .data(Collections.singletonList(new FloatVec(floatList)))
                .outputFields(Collections.singletonList("text"))
                .topK(3)
                .build();

        SearchResp searchResp = milvusClientV2.search(searchReq);

        List<String> resultList = new ArrayList<>();
        List<List<SearchResp.SearchResult>> searchResults = searchResp.getSearchResults();
        for (List<SearchResp.SearchResult> results : searchResults) {
            System.out.println("TopK results:");
            for (SearchResp.SearchResult result : results) {
                resultList.add(result.getEntity().get("text").toString());
            }
        }


        ChatCompletionRequest request = ChatCompletionRequest.builder()
                // 根据渠道模型名称动态修改这个参数
                .model("deepseek-r1:32b")
                .addUserMessage(String.format("你要根据用户输入的问题:%s \n \n 参考如下内容: %s  \n\n 整理处理最终结果", prompt, resultList)).build();

        return deepSeekClient.chatFluxCompletion(request);
    }
}


http://www.kler.cn/a/567362.html

相关文章:

  • Airflow和PySPARK实现带多组参数和标签的Amazon Redshift数据仓库批量数据导出程序
  • 【网络】数据链路层(以太网帧格式、MTU、ARP)、NAT、内网穿透
  • vue3 keep-alive 页面切换不触发onActivated和onDeactivated方法周期
  • Channel State Information 信道状态信息
  • ESP32+Mixly+LED交通信号灯模块
  • 02 2个交换机+vlan构造两个逻辑上的子网
  • 25年前端如何走的更稳
  • 【练习】【贪心】力扣452. 用最少数量的箭引爆气球
  • Flink如何做流计算?大数据世界的“实时魔法”
  • kali liux的下载
  • Transformer 代码剖析10 - TransformerEmbedding (pytorch实现)
  • 服务器硬防的优势有哪些?
  • 对 Steam 下载的一次猜想
  • DeepSeek开源周,第五弹再次来袭,3FS
  • 看得见摸得着的AI:具身智能
  • vmware centos 挂载windows 文件目录
  • DeepSeek 开源周:在 AGI 探索中不断挑战自己的极限
  • 使用C#控制台调用本地部署的DeepSeek
  • JAVA安全—手搓内存马
  • 荣耀AI PC 2.0战略发布,推出新品笔电荣耀MagicBook Pro 14