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);
    }
}

### 安装和配置bge-m3模型至本地DeepSeek环境 #### 准备工作 为了成功安装并配置bge-m3模型,在开始之前需确认已经具备运行DeepSeek所需的基础环境,这通常意味着Linux或macOS操作系统,并且Python开发环境已就绪。此外,还需确保网络连接正常以便下载必要的依赖包。 #### 下载bge-m3模型 访问Ollama官方网站提供的搜索界面[^4],定位到`bge-m3`条目,依据官方指引获取预训练权重文件和其他辅助资源。此过程可能涉及注册账号、同意服务条款等操作。 #### 修改配置文件 编辑位于项目根目录下的`model_settings.yaml`文件来指定使用的LLM(Large Language Model)版本为`deepseek-r1:14b`以及embedding模型为`bge-m3`。具体来说就是更新相应的字段值以匹配所选模型名称及其参数选项: ```yaml # model_settings.yaml 示例片段 models: llm: name: "deepseek-r1" size: "14b" embedding: name: "bge-m3" ``` 对于希望简化用户界面的情况,可以选择仅保留对ollama的支持而移除不必要的集成部分,从而让管理面板更加直观易用。 #### 加载平台设置调整 针对模型加载平台的选择,建议专注于ollama这一渠道来进行后续的操作。关闭其他不必要组件可以减少潜在冲突的风险,同时也使得整个系统的维护成本更低。 #### 测试验证 完成上述更改之后重启应用程序服务器,通过API请求或其他交互方式测试新加入的bge-m3功能模块是否能够按预期工作。如果一切顺利,则说明bge-m3已被成功引入到了现有的DeepSeek架构之中[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

非ban必选

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值