浏览代码

接口标准化,支持word文档导入向量库

lamphua 4 天前
父节点
当前提交
555c95bed2

+ 8
- 0
llm-back/pom.xml 查看文件

@@ -205,6 +205,13 @@
205 205
                 <version>${ruoyi.version}</version>
206 206
             </dependency>
207 207
 
208
+            <!-- 大模型-->
209
+            <dependency>
210
+                <groupId>com.ruoyi</groupId>
211
+                <artifactId>ruoyi-llm</artifactId>
212
+                <version>${ruoyi.version}</version>
213
+            </dependency>
214
+
208 215
             <!-- 智能体-->
209 216
             <dependency>
210 217
                 <groupId>com.ruoyi</groupId>
@@ -217,6 +224,7 @@
217 224
 
218 225
     <modules>
219 226
         <module>ruoyi-admin</module>
227
+        <module>ruoyi-llm</module>
220 228
         <module>ruoyi-agent</module>
221 229
         <module>ruoyi-framework</module>
222 230
         <module>ruoyi-system</module>

+ 2
- 2
llm-back/ruoyi-admin/pom.xml 查看文件

@@ -62,10 +62,10 @@
62 62
             <artifactId>ruoyi-generator</artifactId>
63 63
         </dependency>
64 64
 
65
-        <!-- 智能体-->
65
+        <!-- 大模型-->
66 66
         <dependency>
67 67
             <groupId>com.ruoyi</groupId>
68
-            <artifactId>ruoyi-agent</artifactId>
68
+            <artifactId>ruoyi-llm</artifactId>
69 69
         </dependency>
70 70
 
71 71
     </dependencies>

+ 4
- 31
llm-back/ruoyi-agent/pom.xml 查看文件

@@ -22,39 +22,12 @@
22 22
             <artifactId>ruoyi-common</artifactId>
23 23
         </dependency>
24 24
 
25
-        <!-- 向量数据库-->
26
-        <dependency>
27
-            <groupId>io.milvus</groupId>
28
-            <artifactId>milvus-sdk-java</artifactId>
29
-            <version>2.3.3</version>
30
-        </dependency>
31
-
32
-        <!-- LangChain4j -->
33
-        <dependency>
34
-            <groupId>dev.langchain4j</groupId>
35
-            <artifactId>langchain4j</artifactId>
36
-            <version>0.35.0</version>
37
-        </dependency>
38
-
39
-        <!-- LangChain4j Milvus 集成 -->
40
-        <dependency>
41
-            <groupId>dev.langchain4j</groupId>
42
-            <artifactId>langchain4j-milvus</artifactId>
43
-            <version>0.35.0</version> <!-- 版本需与核心一致 -->
44
-        </dependency>
45
-
46
-        <!-- LangChain4j embedding 集成 -->
47
-        <dependency>
48
-            <groupId>dev.langchain4j</groupId>
49
-            <artifactId>langchain4j-embeddings-bge-small-zh-v15</artifactId>
50
-            <version>0.35.0</version>
51
-        </dependency>
52 25
 
53
-        <!-- LangChain4j pdfParser 集成 -->
26
+        <!-- Solon模型上下文协议 -->
54 27
         <dependency>
55
-            <groupId>dev.langchain4j</groupId>
56
-            <artifactId>langchain4j-document-parser-apache-pdfbox</artifactId>
57
-            <version>0.35.0</version>
28
+            <groupId>org.noear</groupId>
29
+            <artifactId>solon-ai-mcp</artifactId>
30
+            <version>3.3.1</version>
58 31
         </dependency>
59 32
 
60 33
     </dependencies>

+ 22
- 0
llm-back/ruoyi-agent/src/main/java/com/ruoyi/agent/RuoYiAgentApplication.java 查看文件

@@ -0,0 +1,22 @@
1
+package com.ruoyi.agent;
2
+
3
+import org.noear.solon.Solon;
4
+import org.springframework.boot.autoconfigure.SpringBootApplication;
5
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
6
+
7
+/**
8
+ * 启动程序
9
+ * 
10
+ * @author ruoyi
11
+ */
12
+@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
13
+public class RuoYiAgentApplication
14
+{
15
+    public static void main(String[] args)
16
+    {
17
+        Solon.start(RuoYiAgentApplication.class, args, app -> {
18
+            app.cfg().setProperty("server.port", "8081");
19
+        });
20
+        System.out.println("智能体启动成功 \n");
21
+    }
22
+}

+ 0
- 58
llm-back/ruoyi-agent/src/main/java/com/ruoyi/agent/controller/SessionController.java 查看文件

@@ -1,58 +0,0 @@
1
-package com.ruoyi.agent.controller;
2
-
3
-import com.alibaba.fastjson2.JSONObject;
4
-import com.ruoyi.common.core.controller.BaseController;
5
-import com.ruoyi.common.core.domain.AjaxResult;
6
-import okhttp3.*;
7
-import org.springframework.web.bind.annotation.GetMapping;
8
-import org.springframework.web.bind.annotation.RequestMapping;
9
-import org.springframework.web.bind.annotation.RestController;
10
-
11
-import java.io.IOException;
12
-import java.util.concurrent.TimeUnit;
13
-
14
-/**
15
- * session对话Controller
16
- * 
17
- * @author cmc
18
- * @date 2025-04-08
19
- */
20
-@RestController
21
-@RequestMapping("/llm/session")
22
-public class SessionController extends BaseController
23
-{
24
-    /**
25
-     * 生成回答
26
-     */
27
-    @GetMapping("/answer")
28
-    public AjaxResult answer(String question) throws IOException {
29
-
30
-        // 1. 调用本地LLM或HTTP服务
31
-        return success(generateAnswer(question));
32
-    }
33
-
34
-    // 调用LLM生成回答
35
-    public String generateAnswer(String question) throws IOException {
36
-        // 构建带动态参数的URL
37
-        HttpUrl url = HttpUrl.parse("http://192.168.28.188:8000/generate")
38
-                .newBuilder()
39
-                .addQueryParameter("prompt", question)
40
-//                .addQueryParameter("max_token", String.valueOf(1024))
41
-                .build();
42
-
43
-        Request request = new Request.Builder()
44
-                .url(url)
45
-                .build();
46
-
47
-        OkHttpClient client = new OkHttpClient.Builder()
48
-                .readTimeout(60, TimeUnit.SECONDS)      // 读取响应超时
49
-                .build();
50
-
51
-        try (Response response = client.newCall(request).execute()) {
52
-            String responseBody = response.body().string();
53
-            String responseResult = JSONObject.parseObject(responseBody).getString("generated_text");
54
-            return responseResult;
55
-        }
56
-    }
57
-
58
-}

+ 9
- 0
llm-back/ruoyi-agent/src/main/java/com/ruoyi/agent/service/IMcpService.java 查看文件

@@ -0,0 +1,9 @@
1
+package com.ruoyi.agent.service;
2
+
3
+/**
4
+ * (通过此接口,自动收集 McpServerEndpoint 组件类)
5
+ *
6
+ * @author noear 2025/5/6 created
7
+ */
8
+public interface IMcpService {
9
+}

+ 47
- 0
llm-back/ruoyi-agent/src/main/java/com/ruoyi/agent/service/impl/McpServiceImpl.java 查看文件

@@ -0,0 +1,47 @@
1
+package com.ruoyi.agent.service.impl;
2
+
3
+import com.ruoyi.agent.service.IMcpService;
4
+
5
+import org.noear.solon.ai.annotation.PromptMapping;
6
+import org.noear.solon.ai.annotation.ResourceMapping;
7
+import org.noear.solon.ai.annotation.ToolMapping;
8
+import org.noear.solon.ai.chat.message.ChatMessage;
9
+import org.noear.solon.ai.mcp.server.annotation.McpServerEndpoint;
10
+import org.noear.solon.annotation.Param;
11
+import org.springframework.stereotype.Service;
12
+
13
+import java.util.Arrays;
14
+import java.util.Collection;
15
+
16
+/**
17
+ * 自动构建服务端点服务(使用 springboot 容器)
18
+ * */
19
+@Service
20
+@McpServerEndpoint(sseEndpoint = "/llm/mcp/sse")
21
+public class McpServiceImpl implements IMcpService {
22
+
23
+    //
24
+    // 建议开启编译参数:-parameters (否则,最好再配置参数的 name)
25
+    //
26
+    @ToolMapping(description = "查询天气预报")
27
+    public String getWeather(@Param(description = "城市位置") String location) {
28
+        return "晴,14度";
29
+    }
30
+
31
+    @ResourceMapping(uri = "config://app-version", description = "获取应用版本号")
32
+    public String getAppVersion() {
33
+        return "v3.2.0";
34
+    }
35
+
36
+    @ResourceMapping(uri = "db://users/{user_id}/email", description = "根据用户ID查询邮箱")
37
+    public String getEmail(@Param(description = "用户Id") String user_id) {
38
+        return user_id + "@example.com";
39
+    }
40
+
41
+    @PromptMapping(description = "生成关于某个主题的提问")
42
+    public Collection<ChatMessage> askQuestion(@Param(description = "主题") String topic) {
43
+        return Arrays.asList(
44
+                ChatMessage.ofUser("请解释一下'" + topic + "'的概念?")
45
+        );
46
+    }
47
+}

+ 79
- 0
llm-back/ruoyi-llm/pom.xml 查看文件

@@ -0,0 +1,79 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<project xmlns="http://maven.apache.org/POM/4.0.0"
3
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5
+    <parent>
6
+        <artifactId>ruoyi</artifactId>
7
+        <groupId>com.ruoyi</groupId>
8
+        <version>3.8.9</version>
9
+    </parent>
10
+    <modelVersion>4.0.0</modelVersion>
11
+
12
+    <artifactId>ruoyi-llm</artifactId>
13
+
14
+    <description>
15
+        cmc大模型
16
+    </description>
17
+
18
+    <dependencies>
19
+
20
+        <dependency>
21
+            <groupId>com.ruoyi</groupId>
22
+            <artifactId>ruoyi-common</artifactId>
23
+        </dependency>
24
+
25
+        <dependency>
26
+            <groupId>com.ruoyi</groupId>
27
+            <artifactId>ruoyi-framework</artifactId>
28
+        </dependency>
29
+
30
+        <!-- 向量数据库-->
31
+        <dependency>
32
+            <groupId>io.milvus</groupId>
33
+            <artifactId>milvus-sdk-java</artifactId>
34
+            <version>2.3.3</version>
35
+        </dependency>
36
+
37
+        <!-- LangChain4j -->
38
+        <dependency>
39
+            <groupId>dev.langchain4j</groupId>
40
+            <artifactId>langchain4j</artifactId>
41
+            <version>0.35.0</version>
42
+        </dependency>
43
+
44
+        <!-- LangChain4j Milvus 集成 -->
45
+        <dependency>
46
+            <groupId>dev.langchain4j</groupId>
47
+            <artifactId>langchain4j-milvus</artifactId>
48
+            <version>0.35.0</version> <!-- 版本需与核心一致 -->
49
+        </dependency>
50
+
51
+        <!-- LangChain4j embedding 集成 -->
52
+        <dependency>
53
+            <groupId>dev.langchain4j</groupId>
54
+            <artifactId>langchain4j-embeddings-bge-small-zh-v15</artifactId>
55
+            <version>0.35.0</version>
56
+        </dependency>
57
+
58
+        <!-- LangChain4j pdfParser 集成 -->
59
+        <dependency>
60
+            <groupId>dev.langchain4j</groupId>
61
+            <artifactId>langchain4j-document-parser-apache-pdfbox</artifactId>
62
+            <version>0.35.0</version>
63
+        </dependency>
64
+
65
+        <!-- Solon模型上下文协议 -->
66
+        <dependency>
67
+            <groupId>org.noear</groupId>
68
+            <artifactId>solon-ai-mcp</artifactId>
69
+            <version>3.3.1</version>
70
+        </dependency>
71
+
72
+        <dependency>
73
+            <groupId>com.squareup.okhttp3</groupId>
74
+            <artifactId>okhttp</artifactId>
75
+        </dependency>
76
+
77
+    </dependencies>
78
+
79
+</project>

llm-back/ruoyi-agent/src/main/java/com/ruoyi/agent/controller/KnowLedgeController.java → llm-back/ruoyi-llm/src/main/java/com/ruoyi/web/llm/controller/KnowLedgeController.java 查看文件

@@ -1,17 +1,21 @@
1
-package com.ruoyi.agent.controller;
1
+package com.ruoyi.web.llm.controller;
2 2
 
3 3
 import com.alibaba.fastjson2.JSONArray;
4
-import com.ruoyi.agent.service.LangChainMilvusService;
5
-import com.ruoyi.common.config.RuoYiConfig;
4
+import com.ruoyi.web.llm.service.ILangChainMilvusService;
5
+import com.ruoyi.web.llm.service.IMilvusService;
6 6
 import com.ruoyi.common.core.controller.BaseController;
7 7
 import com.ruoyi.common.core.domain.AjaxResult;
8
-import com.ruoyi.agent.service.MilvusService;
9 8
 import dev.langchain4j.model.embedding.onnx.bgesmallzhv15.BgeSmallZhV15EmbeddingModel;
10 9
 import dev.langchain4j.model.embedding.EmbeddingModel;
10
+import io.milvus.client.MilvusServiceClient;
11
+import io.milvus.grpc.MutationResult;
12
+import io.milvus.param.ConnectParam;
13
+import io.milvus.param.R;
14
+import io.milvus.param.RpcStatus;
15
+import org.springframework.beans.factory.annotation.Autowired;
11 16
 import org.springframework.web.bind.annotation.*;
12 17
 import org.springframework.web.multipart.MultipartFile;
13 18
 
14
-import java.io.File;
15 19
 import java.io.IOException;
16 20
 import java.util.List;
17 21
 
@@ -25,16 +29,27 @@ import java.util.List;
25 29
 @RequestMapping("/llm/knowledge")
26 30
 public class KnowLedgeController extends BaseController
27 31
 {
28
-    private static final MilvusService milvusService = new MilvusService("192.168.28.188", 19530);
32
+    @Autowired
33
+    private IMilvusService milvusService;
34
+
35
+    @Autowired
36
+    private ILangChainMilvusService langChainMilvusService;
37
+
29 38
     private static final EmbeddingModel embeddingModel = new BgeSmallZhV15EmbeddingModel();
30 39
 
40
+    private static final MilvusServiceClient milvusClient = new MilvusServiceClient(
41
+            ConnectParam.newBuilder()
42
+                    .withHost("192.168.28.188")
43
+                    .withPort(19530)
44
+                    .build());
45
+
31 46
     /**
32 47
      * 新建知识库
33 48
      */
34 49
     @GetMapping("/list")
35 50
     public AjaxResult listKnowLedgeCollection()
36 51
     {
37
-        JSONArray collectionNames = milvusService.getCollectionNames();
52
+        JSONArray collectionNames = milvusService.getCollectionNames(milvusClient);
38 53
         return success(collectionNames);
39 54
     }
40 55
 
@@ -44,8 +59,8 @@ public class KnowLedgeController extends BaseController
44 59
     @PostMapping("/create")
45 60
     public AjaxResult createKnowLedgeCollection(String collectionName, String description)
46 61
     {
47
-        milvusService.createCollection(collectionName, description, 512);
48
-        return success();
62
+        R<RpcStatus> status = milvusService.createCollection(milvusClient, collectionName, description, 512);
63
+        return success(status);
49 64
     }
50 65
 
51 66
     /**
@@ -54,7 +69,7 @@ public class KnowLedgeController extends BaseController
54 69
     @PostMapping("/modify")
55 70
     public AjaxResult modifyKnowLedgeCollection(String collectionName, String newCollectionName)
56 71
     {
57
-        milvusService.collectionRename(collectionName, newCollectionName);
72
+        milvusService.collectionRename(milvusClient, collectionName, newCollectionName);
58 73
         return success();
59 74
     }
60 75
 
@@ -64,7 +79,7 @@ public class KnowLedgeController extends BaseController
64 79
     @DeleteMapping("/remove")
65 80
     public AjaxResult removeKnowLedgeCollection(String collectionName)
66 81
     {
67
-        milvusService.deleteCollectionName(collectionName);
82
+        milvusService.deleteCollectionName(milvusClient, collectionName);
68 83
         return success();
69 84
     }
70 85
 
@@ -74,31 +89,23 @@ public class KnowLedgeController extends BaseController
74 89
     @GetMapping("/listDocument")
75 90
     public AjaxResult listKnowledgeDocument(String collectionName, String fileType)
76 91
     {
77
-        List<String> documentList = milvusService.listDocument(collectionName, fileType);
92
+        List<String> documentList = milvusService.listDocument(milvusClient, collectionName, fileType);
78 93
         return success(documentList);
79 94
     }
80 95
 
81 96
     /**
82
-     * 入知识库文件
97
+     * 入知识库文件
83 98
      */
84 99
     @PostMapping("/insertDocument")
85
-    public AjaxResult insertKnowledgeDocument(MultipartFile file, String collectionName) throws IOException
86
-    {
87
-        LangChainMilvusService langChainMilvusService = new LangChainMilvusService(
88
-                "192.168.28.188",
89
-                19530,
90
-                collectionName,
91
-                embeddingModel);
92
-
93
-        File profilePath = new File( RuoYiConfig.getProfile() + "/upload/knowledge");
94
-        if (!profilePath.exists())
95
-            profilePath.mkdirs();
96
-        File transferFile = new File( profilePath + File.separator + file.getOriginalFilename());
97
-        if (!transferFile.exists()) {
98
-            file.transferTo(transferFile);
100
+    public AjaxResult insertKnowledgeDocument(MultipartFile file, String collectionName) throws IOException {
101
+        R<MutationResult> insertResult = langChainMilvusService.insertLangchainEmbeddingDocument(milvusClient, file, collectionName, embeddingModel);
102
+        String message = "文件导入成功";
103
+        if (insertResult.getStatus() != R.Status.Success.getCode()) {
104
+            message = "文件导入失败:" + insertResult.getMessage();
105
+            return error(message);
99 106
         }
100
-        langChainMilvusService.insertLangchainEmbeddingDocument(transferFile);
101
-        return success();
107
+        else
108
+            return success(message);
102 109
     }
103 110
 
104 111
     /**
@@ -107,7 +114,7 @@ public class KnowLedgeController extends BaseController
107 114
     @DeleteMapping("/removeDocument")
108 115
     public AjaxResult deleteKnowledgeDocument(String fileName, String collectionName)
109 116
     {
110
-        milvusService.removeDocument(collectionName, fileName);
117
+        milvusService.removeDocument(milvusClient, collectionName, fileName);
111 118
         return success();
112 119
     }
113 120
 

+ 39
- 0
llm-back/ruoyi-llm/src/main/java/com/ruoyi/web/llm/controller/McpController.java 查看文件

@@ -0,0 +1,39 @@
1
+package com.ruoyi.web.llm.controller;
2
+
3
+import com.ruoyi.common.core.controller.BaseController;
4
+import com.ruoyi.common.core.domain.AjaxResult;
5
+import org.noear.solon.ai.mcp.client.McpClientProvider;
6
+import org.springframework.web.bind.annotation.GetMapping;
7
+import org.springframework.web.bind.annotation.RequestMapping;
8
+import org.springframework.web.bind.annotation.RestController;
9
+
10
+import java.util.Collections;
11
+import java.util.Map;
12
+
13
+/**
14
+ * mcp模型上下文协议Controller
15
+ * 
16
+ * @author cmc
17
+ * @date 2025-04-08
18
+ */
19
+@RestController
20
+@RequestMapping("/llm/mcp")
21
+public class McpController extends BaseController
22
+{
23
+    /**
24
+     * 生成回答
25
+     */
26
+    @GetMapping("/answer")
27
+    public AjaxResult answer() {
28
+        McpClientProvider clientProvider = McpClientProvider.builder()
29
+                .apiUrl("http://localhost:52548/llm/mcp/sse")
30
+                .build();
31
+
32
+        Map<String, Object> map = Collections.singletonMap("location", "杭州");
33
+        String rst = clientProvider.callToolAsText("getWeather", map).getContent();
34
+        // 1. 调用本地LLM或HTTP服务
35
+        return success(rst);
36
+    }
37
+
38
+
39
+}

llm-back/ruoyi-agent/src/main/java/com/ruoyi/agent/controller/RagController.java → llm-back/ruoyi-llm/src/main/java/com/ruoyi/web/llm/controller/RagController.java 查看文件

@@ -1,10 +1,13 @@
1
-package com.ruoyi.agent.controller;
1
+package com.ruoyi.web.llm.controller;
2 2
 
3
+import com.ruoyi.web.llm.service.ILangChainMilvusService;
3 4
 import com.ruoyi.common.core.controller.BaseController;
4 5
 import com.ruoyi.common.core.domain.AjaxResult;
5
-import com.ruoyi.agent.service.LangChainMilvusService;
6 6
 import dev.langchain4j.model.embedding.EmbeddingModel;
7 7
 import dev.langchain4j.model.embedding.onnx.bgesmallzhv15.BgeSmallZhV15EmbeddingModel;
8
+import io.milvus.client.MilvusServiceClient;
9
+import io.milvus.param.ConnectParam;
10
+import org.springframework.beans.factory.annotation.Autowired;
8 11
 import org.springframework.web.bind.annotation.GetMapping;
9 12
 import org.springframework.web.bind.annotation.RequestMapping;
10 13
 import org.springframework.web.bind.annotation.RestController;
@@ -22,24 +25,25 @@ import java.util.List;
22 25
 @RequestMapping("/llm/rag")
23 26
 public class RagController extends BaseController
24 27
 {
28
+    @Autowired
29
+    private ILangChainMilvusService langChainMilvusService;
30
+
25 31
     private static final EmbeddingModel embeddingModel = new BgeSmallZhV15EmbeddingModel();
26 32
 
33
+    private static final MilvusServiceClient milvusClient = new MilvusServiceClient(
34
+            ConnectParam.newBuilder()
35
+                    .withHost("192.168.28.188")
36
+                    .withPort(19530)
37
+                    .build());
38
+
27 39
     /**
28 40
      * 增强检索生成回答
29 41
      */
30 42
     @GetMapping("/answer")
31 43
     public AjaxResult answer(String question, String collectionName) throws IOException {
32
-        LangChainMilvusService langChainMilvusService = new LangChainMilvusService(
33
-                "192.168.28.188",
34
-                19530,
35
-                collectionName,
36
-                embeddingModel);
37
-
38
-        // 1. Milvus检索
39
-        List<String> contexts = langChainMilvusService.retrieveFromMilvus(question, 1);
40
-        String result = langChainMilvusService.generateAnswerWithRag(question, contexts);
41
-        langChainMilvusService.releaseCollectionName();
42
-        // 2. 调用本地LLM或HTTP服务
44
+
45
+        List<String> contexts = langChainMilvusService.retrieveFromMilvus(milvusClient, embeddingModel, collectionName, question, 1);
46
+        String result = langChainMilvusService.generateAnswerWithRag(question, contexts, "http://192.168.28.188:8080/generate");
43 47
         return success(result);
44 48
     }
45 49
 

+ 34
- 0
llm-back/ruoyi-llm/src/main/java/com/ruoyi/web/llm/controller/SessionController.java 查看文件

@@ -0,0 +1,34 @@
1
+package com.ruoyi.web.llm.controller;
2
+
3
+import com.ruoyi.common.core.controller.BaseController;
4
+import com.ruoyi.common.core.domain.AjaxResult;
5
+import com.ruoyi.web.llm.service.ILangChainMilvusService;
6
+import org.springframework.beans.factory.annotation.Autowired;
7
+import org.springframework.web.bind.annotation.GetMapping;
8
+import org.springframework.web.bind.annotation.RequestMapping;
9
+import org.springframework.web.bind.annotation.RestController;
10
+
11
+import java.io.IOException;
12
+
13
+/**
14
+ * session对话Controller
15
+ * 
16
+ * @author cmc
17
+ * @date 2025-04-08
18
+ */
19
+@RestController
20
+@RequestMapping("/llm/session")
21
+public class SessionController extends BaseController
22
+{
23
+    @Autowired
24
+    private ILangChainMilvusService langChainMilvusService;
25
+
26
+    /**
27
+     * 生成回答
28
+     */
29
+    @GetMapping("/answer")
30
+    public AjaxResult answer(String question) throws IOException {
31
+        return success(langChainMilvusService.generateAnswer(question, "http://192.168.28.188:8000/generate"));
32
+    }
33
+
34
+}

+ 33
- 0
llm-back/ruoyi-llm/src/main/java/com/ruoyi/web/llm/service/ILangChainMilvusService.java 查看文件

@@ -0,0 +1,33 @@
1
+package com.ruoyi.web.llm.service;
2
+
3
+import dev.langchain4j.model.embedding.EmbeddingModel;
4
+import io.milvus.client.MilvusClient;
5
+import io.milvus.grpc.MutationResult;
6
+import io.milvus.param.R;
7
+import org.springframework.web.multipart.MultipartFile;
8
+
9
+import java.io.IOException;
10
+import java.util.List;
11
+
12
+public interface ILangChainMilvusService {
13
+
14
+    /**
15
+     * 导入知识库文件
16
+     */
17
+    public R<MutationResult> insertLangchainEmbeddingDocument(MilvusClient milvusClient, MultipartFile file, String collectionName, EmbeddingModel embeddingModel) throws IOException;
18
+
19
+    /**
20
+     * 从Milvus检索相关文档
21
+     */
22
+    public List<String> retrieveFromMilvus(MilvusClient milvusClient, EmbeddingModel embeddingModel, String collectionName, String query, int topK);
23
+
24
+    /**
25
+     * 调用LLM+RAG生成回答
26
+     */
27
+    public String generateAnswerWithRag(String question, List<String> contexts, String llmServiceUrl) throws IOException;
28
+
29
+    /**
30
+     * 调用LLM生成回答
31
+     */
32
+    public String generateAnswer(String llmServiceUrl, String question) throws IOException;
33
+}

+ 41
- 0
llm-back/ruoyi-llm/src/main/java/com/ruoyi/web/llm/service/IMilvusService.java 查看文件

@@ -0,0 +1,41 @@
1
+package com.ruoyi.web.llm.service;
2
+
3
+import com.alibaba.fastjson2.JSONArray;
4
+import io.milvus.client.MilvusClient;
5
+import io.milvus.param.R;
6
+import io.milvus.param.RpcStatus;
7
+
8
+import java.util.List;
9
+
10
+public interface IMilvusService {
11
+
12
+    /**
13
+     * 新建知识库Collection(含Schema、Field、Index)
14
+     */
15
+    public R<RpcStatus> createCollection(MilvusClient milvusClient, String collectionName, String description, int dimension);
16
+
17
+    /**
18
+     * 查询知识库Collection
19
+     */
20
+    public JSONArray getCollectionNames(MilvusClient milvusClient);
21
+
22
+    /**
23
+     * 修改知识库Collection
24
+     */
25
+    public void collectionRename(MilvusClient milvusClient, String collectionName, String newCollectionName);
26
+
27
+    /**
28
+     * 删除知识库Collection
29
+     */
30
+    public void deleteCollectionName(MilvusClient milvusClient, String collectionName);
31
+
32
+    /**
33
+     * 查询知识库文件
34
+     */
35
+    public List<String> listDocument(MilvusClient milvusClient, String collectionName, String fileType);
36
+
37
+    /**
38
+     * 删除知识库文件
39
+     */
40
+    public void removeDocument(MilvusClient milvusClient, String collectionName, String fileName);
41
+}

llm-back/ruoyi-agent/src/main/java/com/ruoyi/agent/service/LangChainMilvusService.java → llm-back/ruoyi-llm/src/main/java/com/ruoyi/web/llm/service/impl/LangChainMilvusServiceImpl.java 查看文件

@@ -1,29 +1,30 @@
1
-package com.ruoyi.agent.service;
1
+package com.ruoyi.web.llm.service.impl;
2 2
 
3 3
 import com.alibaba.fastjson2.JSONObject;
4
+import com.ruoyi.common.config.RuoYiConfig;
5
+import com.ruoyi.web.llm.service.ILangChainMilvusService;
4 6
 import dev.langchain4j.data.document.Document;
5 7
 import dev.langchain4j.data.document.parser.apache.pdfbox.ApachePdfBoxDocumentParser;
6 8
 import dev.langchain4j.data.document.splitter.DocumentByParagraphSplitter;
7 9
 import dev.langchain4j.data.segment.TextSegment;
8 10
 import dev.langchain4j.model.embedding.EmbeddingModel;
9 11
 
10
-import io.milvus.client.MilvusServiceClient;
12
+import io.milvus.client.MilvusClient;
11 13
 import io.milvus.grpc.MutationResult;
12 14
 import io.milvus.grpc.SearchResults;
13
-import io.milvus.param.ConnectParam;
14 15
 import io.milvus.param.MetricType;
15 16
 import io.milvus.param.R;
16 17
 import io.milvus.param.RpcStatus;
17 18
 import io.milvus.param.collection.LoadCollectionParam;
18 19
 import io.milvus.param.collection.ReleaseCollectionParam;
19
-import io.milvus.param.dml.DeleteParam;
20 20
 import io.milvus.param.dml.InsertParam;
21 21
 import io.milvus.param.dml.SearchParam;
22
-import io.milvus.param.highlevel.dml.QuerySimpleParam;
23
-import io.milvus.param.highlevel.dml.response.QueryResponse;
24
-import io.milvus.response.QueryResultsWrapper;
25 22
 import io.milvus.response.SearchResultsWrapper;
26 23
 import okhttp3.*;
24
+import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
25
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
26
+import org.springframework.stereotype.Service;
27
+import org.springframework.web.multipart.MultipartFile;
27 28
 
28 29
 import java.io.File;
29 30
 import java.io.FileInputStream;
@@ -33,34 +34,38 @@ import java.util.*;
33 34
 import java.util.concurrent.TimeUnit;
34 35
 import java.util.stream.Collectors;
35 36
 
36
-public class LangChainMilvusService {
37
-    private String LLM_SERVICE_URL;
38
-    private MilvusServiceClient milvusClient;
39
-    private String collectionName;
40
-    private EmbeddingModel embeddingModel;
41
-
42
-    /**
43
-     * 连接milvus知识库指定collection,加入langchain自带emdding
44
-     */
45
-    public LangChainMilvusService(String host, int port, String collectionName, EmbeddingModel embeddingModel) {
46
-        this.milvusClient = new MilvusServiceClient(
47
-                ConnectParam.newBuilder()
48
-                        .withHost(host)
49
-                        .withPort(port)
50
-                        .build()
51
-        );
52
-        this.LLM_SERVICE_URL = "http://" + host + ":8000/generate";
53
-        this.collectionName = collectionName;
54
-        this.embeddingModel = embeddingModel;
55
-    }
56
-
37
+@Service
38
+public class LangChainMilvusServiceImpl implements ILangChainMilvusService
39
+{
57 40
     /**
58
-     * 入知识库文件
41
+     * 导入知识库文件
59 42
      */
60
-    public void insertLangchainEmbeddingDocument(File file) throws IOException {
43
+    @Override
44
+    public R<MutationResult> insertLangchainEmbeddingDocument(MilvusClient milvusClient, MultipartFile file, String collectionName, EmbeddingModel embeddingModel) throws IOException
45
+    {
46
+        File profilePath = new File( RuoYiConfig.getProfile() + "/upload/knowledge");
47
+        if (!profilePath.exists())
48
+            profilePath.mkdirs();
49
+        File transferFile = new File( profilePath + File.separator + file.getOriginalFilename());
50
+        if (!transferFile.exists()) {
51
+            file.transferTo(transferFile);
52
+        }
61 53
         // 加载文档
62
-        InputStream fileInputStream = new FileInputStream(file);
63
-        Document document = new ApachePdfBoxDocumentParser().parse(fileInputStream);
54
+        Document document;
55
+        InputStream fileInputStream = new FileInputStream(transferFile);
56
+        String filename = file.getOriginalFilename().toLowerCase();
57
+        if (filename.endsWith(".docx")) {
58
+            XWPFDocument docx = new XWPFDocument(fileInputStream);
59
+            XWPFWordExtractor extractor = new XWPFWordExtractor(docx);
60
+            String text = extractor.getText();
61
+            document = Document.from(text);
62
+        }
63
+        else if (filename.endsWith(".pdf")) {
64
+            document = new ApachePdfBoxDocumentParser().parse(fileInputStream);
65
+        }
66
+        else {
67
+            throw new UnsupportedOperationException("不支持文件类型: " + filename);
68
+        }
64 69
         DocumentByParagraphSplitter splitter = new DocumentByParagraphSplitter(1024,0);;
65 70
         List<TextSegment> segments = splitter.split(document);
66 71
 
@@ -74,14 +79,14 @@ public class LangChainMilvusService {
74 79
             String text = segment.text();
75 80
             if (text.trim().isEmpty())
76 81
                 continue;
77
-            fileNames.add(file.getName());
78
-            String[] fileName = file.getName().split("\\.");
82
+            fileNames.add(file.getOriginalFilename());
83
+            String[] fileName = file.getOriginalFilename().split("\\.");
79 84
             fileTypes.add(fileName[fileName.length - 1]);
80 85
             texts.add(text);
81 86
             embeddings.add(embeddingModel.embed(text).content().vectorAsList());
82 87
         }
83 88
 
84
-        // 准备入数据
89
+        // 准备入数据
85 90
         List<InsertParam.Field> fields = new ArrayList<>();
86 91
         fields.add(new InsertParam.Field("file_name", fileNames));
87 92
         fields.add(new InsertParam.Field("file_type", fileTypes));
@@ -93,20 +98,27 @@ public class LangChainMilvusService {
93 98
                 .withFields(fields)
94 99
                 .build();
95 100
 
96
-        // 执行插入
97
-        R<MutationResult> insertResult = milvusClient.insert(insertParam);
98
-
99
-        if (insertResult.getStatus() != R.Status.Success.getCode()) {
100
-            throw new RuntimeException("插入文件失败: " + insertResult.getMessage());
101
-        }
101
+        // 执行导入
102
+        return milvusClient.insert(insertParam);
102 103
     }
103 104
 
104
-    // 从Milvus检索相关文档
105
-    public List<String> retrieveFromMilvus(String query, int topK) throws IOException {
106
-        List<List<Float>> queryVector = Arrays.asList(embeddingModel.embed(query).content().vectorAsList());
105
+    /**
106
+     * 从Milvus检索相关文档
107
+     */
108
+    @Override
109
+    public List<String> retrieveFromMilvus(MilvusClient milvusClient, EmbeddingModel embeddingModel, String collectionName, String query, int topK) {
110
+        List<List<Float>> queryVector = Collections.singletonList(embeddingModel.embed(query).content().vectorAsList());
107 111
 
108 112
         //  加载集合
109
-        loadCollectionName();
113
+        LoadCollectionParam loadParam = LoadCollectionParam.newBuilder()
114
+                .withCollectionName(collectionName)
115
+                .build();
116
+
117
+        R<RpcStatus> loadResponse = milvusClient.loadCollection(loadParam);
118
+        if (loadResponse.getStatus() != R.Status.Success.getCode()) {
119
+            System.err.println("加载Collection失败: " + loadResponse.getMessage());
120
+            milvusClient.close();
121
+        }
110 122
 
111 123
         // 构建SearchParam
112 124
         SearchParam searchParam = SearchParam.newBuilder()
@@ -122,16 +134,38 @@ public class LangChainMilvusService {
122 134
         R<SearchResults> response = milvusClient.search(searchParam);
123 135
         SearchResultsWrapper wrapper = new SearchResultsWrapper(response.getData().getResults());
124 136
 
137
+        // 释放集合
138
+        ReleaseCollectionParam param = ReleaseCollectionParam.newBuilder()
139
+                .withCollectionName(collectionName)
140
+                .build();
141
+        milvusClient.releaseCollection(param);
142
+
125 143
         return wrapper.getRowRecords(0).stream()
126 144
                 .map(record -> (String) record.get("content"))
127 145
                 .collect(Collectors.toList());
128 146
     }
129 147
 
130
-    // 调用LLM+RAG生成回答
131
-    public String generateAnswerWithRag(String question, List<String> contexts) throws IOException {
132
-        String prompt = buildPrompt(question, contexts);
148
+    /**
149
+     * 调用LLM+RAG生成回答
150
+     */
151
+    @Override
152
+    public String generateAnswerWithRag(String question, List<String> contexts, String llmServiceUrl) throws IOException {
153
+        StringBuilder sb = new StringBuilder();
154
+        sb.append("根据以下上下文回答问题:\n\n");
155
+        for (int i = 0; i < contexts.size(); i++) {
156
+            sb.append("上下文").append(i+1).append(": ").append(contexts.get(i)).append("\n\n");
157
+        }
158
+        sb.append("问题: ").append(question).append("\n回答: ");
133 159
         // 构建带动态参数的URL
134
-        HttpUrl url = HttpUrl.parse(LLM_SERVICE_URL)
160
+        return generateAnswer(llmServiceUrl, sb.toString());
161
+    }
162
+
163
+    /**
164
+     * 调用LLM生成回答
165
+     */
166
+    @Override
167
+    public String generateAnswer(String llmServiceUrl, String prompt) throws IOException {
168
+        HttpUrl url = HttpUrl.parse(llmServiceUrl)
135 169
                 .newBuilder()
136 170
                 .addQueryParameter("prompt", prompt)
137 171
 //                .addQueryParameter("max_token", String.valueOf(1024))
@@ -146,48 +180,12 @@ public class LangChainMilvusService {
146 180
                 .build();
147 181
 
148 182
         try (Response response = client.newCall(request).execute()) {
149
-            String responseBody = response.body().string();
150
-            String responseResult = JSONObject.parseObject(responseBody).getString("generated_text");
151
-            return responseResult;
152
-        }
153
-    }
154
-
155
-    private String buildPrompt(String question, List<String> contexts) {
156
-        StringBuilder sb = new StringBuilder();
157
-        sb.append("根据以下上下文回答问题:\n\n");
158
-        for (int i = 0; i < contexts.size(); i++) {
159
-            sb.append("上下文").append(i+1).append(": ").append(contexts.get(i)).append("\n\n");
160
-        }
161
-        sb.append("问题: ").append(question).append("\n回答: ");
162
-        return sb.toString();
163
-    }
164
-
165
-    /**
166
-     * 加载知识库Collection
167
-     */
168
-    public void loadCollectionName() {
169
-        LoadCollectionParam loadParam = LoadCollectionParam.newBuilder()
170
-                .withCollectionName(collectionName)
171
-                .build();
172
-
173
-        R<RpcStatus> loadResponse = milvusClient.loadCollection(loadParam);
174
-        if (loadResponse.getStatus() != R.Status.Success.getCode()) {
175
-            System.err.println("加载Collection失败: " + loadResponse.getMessage());
176
-            milvusClient.close();
183
+            if (response.body() != null) {
184
+                String responseBody = response.body().string();
185
+                return JSONObject.parseObject(responseBody).getString("generated_text");
186
+            }
187
+            else return null;
177 188
         }
178 189
     }
179 190
 
180
-    /**
181
-     * 释放知识库Collection
182
-     */
183
-    public void releaseCollectionName() {
184
-        ReleaseCollectionParam param = ReleaseCollectionParam.newBuilder()
185
-                .withCollectionName(collectionName)
186
-                .build();
187
-        milvusClient.releaseCollection(param);
188
-    }
189
-
190
-    public void close() {
191
-        milvusClient.close();
192
-    }
193 191
 }

llm-back/ruoyi-agent/src/main/java/com/ruoyi/agent/service/MilvusService.java → llm-back/ruoyi-llm/src/main/java/com/ruoyi/web/llm/service/impl/MilvusServiceImpl.java 查看文件

@@ -1,12 +1,11 @@
1
-package com.ruoyi.agent.service;
1
+package com.ruoyi.web.llm.service.impl;
2 2
 
3 3
 import com.alibaba.fastjson2.JSONArray;
4 4
 import com.alibaba.fastjson2.JSONObject;
5
-import io.milvus.client.MilvusServiceClient;
5
+import com.ruoyi.web.llm.service.IMilvusService;
6
+import io.milvus.client.MilvusClient;
6 7
 import io.milvus.grpc.*;
7
-import io.milvus.param.ConnectParam;
8
-import io.milvus.param.IndexType;
9
-import io.milvus.param.MetricType;
8
+import io.milvus.param.*;
10 9
 import io.milvus.param.collection.*;
11 10
 import io.milvus.param.dml.DeleteParam;
12 11
 import io.milvus.param.highlevel.collection.ListCollectionsParam;
@@ -15,6 +14,7 @@ import io.milvus.param.highlevel.dml.QuerySimpleParam;
15 14
 import io.milvus.param.highlevel.dml.response.QueryResponse;
16 15
 import io.milvus.param.index.CreateIndexParam;
17 16
 import io.milvus.response.QueryResultsWrapper;
17
+import org.springframework.stereotype.Service;
18 18
 
19 19
 import java.text.SimpleDateFormat;
20 20
 import java.util.ArrayList;
@@ -23,25 +23,14 @@ import java.util.List;
23 23
 import java.util.TimeZone;
24 24
 import java.util.stream.Collectors;
25 25
 
26
-public class MilvusService {
27
-    private MilvusServiceClient milvusClient;
28
-
29
-    /**
30
-     *  连接milvus知识库
31
-     */
32
-    public MilvusService(String host, int port) {
33
-        this.milvusClient = new MilvusServiceClient(
34
-                ConnectParam.newBuilder()
35
-                        .withHost(host)
36
-                        .withPort(port)
37
-                        .build()
38
-        );
39
-    }
26
+@Service
27
+public class MilvusServiceImpl implements IMilvusService {
40 28
 
41 29
     /**
42 30
      * 新建知识库Collection(含Schema、Field、Index)
43 31
      */
44
-    public void createCollection(String collectionName, String description, int dimension) {
32
+    @Override
33
+    public R<RpcStatus> createCollection(MilvusClient milvusClient, String collectionName, String description, int dimension) {
45 34
         FieldType idField = FieldType.newBuilder()
46 35
                 .withName("id")
47 36
                 .withDataType(DataType.Int64)
@@ -83,7 +72,7 @@ public class MilvusService {
83 72
                 .addFieldType(vectorField)
84 73
                 .build();
85 74
 
86
-        milvusClient.createCollection(createCollectionParam);
75
+        R<RpcStatus> createResult = milvusClient.createCollection(createCollectionParam);
87 76
 
88 77
         // 创建索引
89 78
         CreateIndexParam createIndexParam = CreateIndexParam.newBuilder()
@@ -95,12 +84,13 @@ public class MilvusService {
95 84
                 .build();
96 85
 
97 86
         milvusClient.createIndex(createIndexParam);
87
+        return createResult;
98 88
     }
99 89
 
100 90
     /**
101 91
      * 查询知识库Collection
102 92
      */
103
-    public JSONArray getCollectionNames() {
93
+    public JSONArray getCollectionNames(MilvusClient milvusClient) {
104 94
         JSONArray jsonArray = new JSONArray();
105 95
         ListCollectionsParam listParam = ListCollectionsParam.newBuilder().build();
106 96
         ListCollectionsResponse listResponse = milvusClient.listCollections(listParam).getData();
@@ -128,7 +118,7 @@ public class MilvusService {
128 118
     /**
129 119
      * 修改知识库Collection
130 120
      */
131
-    public void collectionRename(String collectionName, String newCollectionName) {
121
+    public void collectionRename(MilvusClient milvusClient, String collectionName, String newCollectionName) {
132 122
         RenameCollectionParam renameCollectionReq = RenameCollectionParam.newBuilder()
133 123
                 .withOldCollectionName(collectionName)
134 124
                 .withNewCollectionName(newCollectionName)
@@ -140,7 +130,7 @@ public class MilvusService {
140 130
     /**
141 131
      * 删除知识库Collection
142 132
      */
143
-    public void deleteCollectionName(String collectionName) {
133
+    public void deleteCollectionName(MilvusClient milvusClient, String collectionName) {
144 134
         DropCollectionParam param = DropCollectionParam.newBuilder()
145 135
                 .withCollectionName(collectionName)
146 136
                 .build();
@@ -150,9 +140,9 @@ public class MilvusService {
150 140
     /**
151 141
      * 查询知识库文件
152 142
      */
153
-    public List<String> listDocument(String collectionName, String fileType) {
143
+    public List<String> listDocument(MilvusClient milvusClient, String collectionName, String fileType) {
154 144
         List<String> documentList = new ArrayList<>();
155
-        loadCollectionName(collectionName);
145
+        loadCollectionName(milvusClient,collectionName);
156 146
         QuerySimpleParam queryParam = QuerySimpleParam.newBuilder()        
157 147
                 .withCollectionName(collectionName)
158 148
                 .withFilter("id > 0")
@@ -174,15 +164,15 @@ public class MilvusService {
174 164
                 documentList.add(rowRecord.get("file_name").toString());
175 165
             }
176 166
         }
177
-        releaseCollectionName(collectionName);
167
+        releaseCollectionName(milvusClient, collectionName);
178 168
         return documentList.stream().distinct().collect(Collectors.toList());
179 169
     }
180 170
 
181 171
     /**
182 172
      * 删除知识库文件
183 173
      */
184
-    public void removeDocument(String collectionName, String fileName) {
185
-        loadCollectionName(collectionName);
174
+    public void removeDocument(MilvusClient milvusClient, String collectionName, String fileName) {
175
+        loadCollectionName(milvusClient, collectionName);
186 176
         DeleteParam deleteParam = DeleteParam.newBuilder()
187 177
                 .withCollectionName(collectionName)
188 178
                 .withExpr(String.format("file_name == \"%s\"", fileName))
@@ -193,7 +183,7 @@ public class MilvusService {
193 183
     /**
194 184
      * 加载知识库Collection
195 185
      */
196
-    public void loadCollectionName(String collectionName) {
186
+    public void loadCollectionName(MilvusClient milvusClient, String collectionName) {
197 187
         LoadCollectionParam param = LoadCollectionParam.newBuilder()
198 188
                 .withCollectionName(collectionName)
199 189
                 .build();
@@ -203,14 +193,11 @@ public class MilvusService {
203 193
     /**
204 194
      * 释放知识库Collection
205 195
      */
206
-    public void releaseCollectionName(String collectionName) {
196
+    public void releaseCollectionName(MilvusClient milvusClient, String collectionName) {
207 197
         ReleaseCollectionParam param = ReleaseCollectionParam.newBuilder()
208 198
                 .withCollectionName(collectionName)
209 199
                 .build();
210 200
         milvusClient.releaseCollection(param);
211 201
     }
212 202
 
213
-    public void close() {
214
-        milvusClient.close();
215
-    }
216 203
 }

正在加载...
取消
保存