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