From c4d5a7b300abc4fd813dda7a2ef5844ecd3f4817 Mon Sep 17 00:00:00 2001 From: v-zhangjc9 Date: Wed, 4 Jun 2025 17:43:22 +0800 Subject: [PATCH] =?UTF-8?q?feat(knowledge):=20=E5=A2=9E=E5=8A=A0rerank?= =?UTF-8?q?=E6=A8=A1=E5=9E=8B=E9=80=82=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- service-ai/pom.xml | 11 +++ service-ai/service-ai-knowledge/pom.xml | 8 ++ .../configuration/SolonConfiguration.java | 21 +++++ .../configuration/SolonProperties.java | 78 +++++++++++++++++++ ...ller.java => KnowledgeBaseController.java} | 25 +++--- .../knowledge/service/EmbeddingService.java | 10 +-- .../ai/knowledge/service/GroupService.java | 2 +- ...Service.java => KnowledgeBaseService.java} | 23 ++++-- .../ai/knowledge/service/SegmentService.java | 10 +-- .../src/main/resources/application.yml | 6 ++ 10 files changed, 165 insertions(+), 29 deletions(-) create mode 100644 service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/configuration/SolonConfiguration.java create mode 100644 service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/configuration/SolonProperties.java rename service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/controller/{KnowledgeController.java => KnowledgeBaseController.java} (85%) rename service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/service/{KnowledgeService.java => KnowledgeBaseService.java} (88%) diff --git a/service-ai/pom.xml b/service-ai/pom.xml index 6ccfe6a..f54116c 100644 --- a/service-ai/pom.xml +++ b/service-ai/pom.xml @@ -25,6 +25,7 @@ 3.4.3 2024.0.1 1.0.0 + 3.3.1 11.1.0 5.1.0 5.8.27 @@ -136,6 +137,16 @@ liteflow-spring-boot-starter 2.13.2 + + org.noear + solon-ai + ${solon-ai.version} + + + org.noear + solon-ai-dialect-openai + ${solon-ai.version} + diff --git a/service-ai/service-ai-knowledge/pom.xml b/service-ai/service-ai-knowledge/pom.xml index 92caba7..380f8ac 100644 --- a/service-ai/service-ai-knowledge/pom.xml +++ b/service-ai/service-ai-knowledge/pom.xml @@ -54,6 +54,14 @@ org.springframework.ai spring-ai-pdf-document-reader + + org.noear + solon-ai + + + org.noear + solon-ai-dialect-openai + diff --git a/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/configuration/SolonConfiguration.java b/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/configuration/SolonConfiguration.java new file mode 100644 index 0000000..b255233 --- /dev/null +++ b/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/configuration/SolonConfiguration.java @@ -0,0 +1,21 @@ +package com.lanyuanxiaoyao.service.ai.knowledge.configuration; + +import cn.hutool.core.util.StrUtil; +import org.noear.solon.ai.reranking.RerankingModel; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * @author lanyuanxiaoyao + * @version 20250604 + */ +@Configuration +public class SolonConfiguration { + @Bean + public RerankingModel rerankingModel(SolonProperties solonProperties) { + return RerankingModel.of(StrUtil.format("{}{}", solonProperties.getBaseUrl(), solonProperties.getRerank().getEndpoint())) + .apiKey(solonProperties.getApiKey()) + .model(solonProperties.getRerank().getModel()) + .build(); + } +} diff --git a/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/configuration/SolonProperties.java b/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/configuration/SolonProperties.java new file mode 100644 index 0000000..399c219 --- /dev/null +++ b/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/configuration/SolonProperties.java @@ -0,0 +1,78 @@ +package com.lanyuanxiaoyao.service.ai.knowledge.configuration; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +/** + * @author lanyuanxiaoyao + * @version 20250604 + */ +@Configuration +@ConfigurationProperties(prefix = "solon") +public class SolonProperties { + private String baseUrl; + private String apiKey; + private Rerank rerank; + + public String getBaseUrl() { + return baseUrl; + } + + public void setBaseUrl(String baseUrl) { + this.baseUrl = baseUrl; + } + + public String getApiKey() { + return apiKey; + } + + public void setApiKey(String apiKey) { + this.apiKey = apiKey; + } + + public Rerank getRerank() { + return rerank; + } + + public void setRerank(Rerank rerank) { + this.rerank = rerank; + } + + @Override + public String toString() { + return "SolonProperties{" + + "baseUrl='" + baseUrl + '\'' + + ", apiKey='" + apiKey + '\'' + + ", rerank=" + rerank + + '}'; + } + + public static final class Rerank { + private String model; + private String endpoint; + + public String getModel() { + return model; + } + + public void setModel(String model) { + this.model = model; + } + + public String getEndpoint() { + return endpoint; + } + + public void setEndpoint(String endpoint) { + this.endpoint = endpoint; + } + + @Override + public String toString() { + return "Rerank{" + + "model='" + model + '\'' + + ", endpoint='" + endpoint + '\'' + + '}'; + } + } +} diff --git a/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/controller/KnowledgeController.java b/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/controller/KnowledgeBaseController.java similarity index 85% rename from service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/controller/KnowledgeController.java rename to service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/controller/KnowledgeBaseController.java index c757195..168fcd3 100644 --- a/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/controller/KnowledgeController.java +++ b/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/controller/KnowledgeBaseController.java @@ -5,7 +5,8 @@ import com.lanyuanxiaoyao.service.ai.core.entity.amis.AmisMapResponse; import com.lanyuanxiaoyao.service.ai.core.entity.amis.AmisResponse; import com.lanyuanxiaoyao.service.ai.knowledge.entity.vo.SegmentVO; import com.lanyuanxiaoyao.service.ai.knowledge.service.EmbeddingService; -import com.lanyuanxiaoyao.service.ai.knowledge.service.KnowledgeService; +import com.lanyuanxiaoyao.service.ai.knowledge.service.KnowledgeBaseService; +import java.io.IOException; import java.util.concurrent.ExecutionException; import org.eclipse.collections.api.factory.Lists; import org.eclipse.collections.api.list.ImmutableList; @@ -24,14 +25,14 @@ import org.springframework.web.bind.annotation.RestController; */ @RestController @RequestMapping("knowledge") -public class KnowledgeController { - private static final Logger logger = LoggerFactory.getLogger(KnowledgeController.class); +public class KnowledgeBaseController { + private static final Logger logger = LoggerFactory.getLogger(KnowledgeBaseController.class); - private final KnowledgeService knowledgeService; + private final KnowledgeBaseService knowledgeBaseService; private final EmbeddingService embeddingService; - public KnowledgeController(KnowledgeService knowledgeService, EmbeddingService embeddingService) { - this.knowledgeService = knowledgeService; + public KnowledgeBaseController(KnowledgeBaseService knowledgeBaseService, EmbeddingService embeddingService) { + this.knowledgeBaseService = knowledgeBaseService; this.embeddingService = embeddingService; } @@ -40,23 +41,23 @@ public class KnowledgeController { @RequestParam("name") String name, @RequestParam("strategy") String strategy ) throws ExecutionException, InterruptedException { - knowledgeService.add(name, strategy); + knowledgeBaseService.add(name, strategy); } @GetMapping("name") public AmisMapResponse name(@RequestParam("id") Long id) { return AmisResponse.responseMapData() - .setData("name", knowledgeService.getName(id)); + .setData("name", knowledgeBaseService.getName(id)); } @GetMapping("list") public AmisResponse list() { - return AmisResponse.responseCrudData(knowledgeService.list()); + return AmisResponse.responseCrudData(knowledgeBaseService.list()); } @GetMapping("delete") public void delete(@RequestParam("id") Long id) throws ExecutionException, InterruptedException { - knowledgeService.remove(id); + knowledgeBaseService.remove(id); } @PostMapping("preview_text") @@ -114,7 +115,7 @@ public class KnowledgeController { @RequestParam(value = "limit", defaultValue = "5") Integer limit, @RequestParam(value = "threshold", defaultValue = "0.6") Double threshold, @RequestBody String text - ) throws ExecutionException, InterruptedException { - return knowledgeService.query(id, text, limit, threshold); + ) throws ExecutionException, InterruptedException, IOException { + return knowledgeBaseService.query(id, text, limit, threshold); } } diff --git a/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/service/EmbeddingService.java b/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/service/EmbeddingService.java index 268cfb9..0b4be14 100644 --- a/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/service/EmbeddingService.java +++ b/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/service/EmbeddingService.java @@ -29,15 +29,15 @@ public class EmbeddingService { private final DataFileService dataFileService; private final FlowExecutor executor; - private final KnowledgeService knowledgeService; + private final KnowledgeBaseService knowledgeBaseService; private final GroupService groupService; private final ExecutorService executors = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") - public EmbeddingService(DataFileService dataFileService, FlowExecutor executor, KnowledgeService knowledgeService, GroupService groupService) { + public EmbeddingService(DataFileService dataFileService, FlowExecutor executor, KnowledgeBaseService knowledgeBaseService, GroupService groupService) { this.dataFileService = dataFileService; this.executor = executor; - this.knowledgeService = knowledgeService; + this.knowledgeBaseService = knowledgeBaseService; this.groupService = groupService; } @@ -63,7 +63,7 @@ public class EmbeddingService { public void submit(Long id, String mode, String content) { executors.submit(() -> { - Knowledge knowledge = knowledgeService.get(id); + Knowledge knowledge = knowledgeBaseService.get(id); Long groupId = groupService.add(knowledge.getId(), StrUtil.format("文本-{}", IdUtil.nanoId(10))); EmbeddingContext context = EmbeddingContext.builder() .vectorSourceId(knowledge.getVectorSourceId()) @@ -80,7 +80,7 @@ public class EmbeddingService { public void submit(Long id, String mode, ImmutableList ids) { executors.submit(() -> { - Knowledge knowledge = knowledgeService.get(id); + Knowledge knowledge = knowledgeBaseService.get(id); List> vos = Lists.mutable.empty(); for (String fileId : ids) { DataFileVO vo = dataFileService.downloadFile(Long.parseLong(fileId)); diff --git a/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/service/GroupService.java b/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/service/GroupService.java index bad5e28..7f3329a 100644 --- a/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/service/GroupService.java +++ b/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/service/GroupService.java @@ -102,7 +102,7 @@ public class GroupService { public void remove(Long groupId) throws ExecutionException, InterruptedException { Long vectorSourceId = template.queryForObject( SqlBuilder.select("k.vector_source_id") - .from(Alias.of(GROUP_TABLE_NAME, "g"), Alias.of(KnowledgeService.KNOWLEDGE_TABLE_NAME, "k")) + .from(Alias.of(GROUP_TABLE_NAME, "g"), Alias.of(KnowledgeBaseService.KNOWLEDGE_TABLE_NAME, "k")) .whereEq("g.knowledge_id", Column.as("k.id")) .andEq("g.id", groupId) .precompileSql(), diff --git a/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/service/KnowledgeService.java b/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/service/KnowledgeBaseService.java similarity index 88% rename from service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/service/KnowledgeService.java rename to service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/service/KnowledgeBaseService.java index 09ab7ad..cf85fb8 100644 --- a/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/service/KnowledgeService.java +++ b/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/service/KnowledgeBaseService.java @@ -9,11 +9,13 @@ import com.lanyuanxiaoyao.service.ai.knowledge.entity.vo.KnowledgeVO; import com.lanyuanxiaoyao.service.common.Constants; import io.qdrant.client.QdrantClient; import io.qdrant.client.grpc.Collections; +import java.io.IOException; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; import org.eclipse.collections.api.factory.Lists; import org.eclipse.collections.api.list.ImmutableList; +import org.noear.solon.ai.reranking.RerankingModel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ai.document.Document; @@ -31,9 +33,9 @@ import org.springframework.transaction.annotation.Transactional; * @version 20250522 */ @Service -public class KnowledgeService { +public class KnowledgeBaseService { public static final String KNOWLEDGE_TABLE_NAME = Constants.DATABASE_NAME + ".service_ai_knowledge"; - private static final Logger logger = LoggerFactory.getLogger(KnowledgeService.class); + private static final Logger logger = LoggerFactory.getLogger(KnowledgeBaseService.class); private static final RowMapper knowledgeMapper = (rs, row) -> { Knowledge knowledge = new Knowledge(); knowledge.setId(rs.getLong(1)); @@ -48,12 +50,14 @@ public class KnowledgeService { private final EmbeddingModel model; private final QdrantClient client; private final GroupService groupService; + private final RerankingModel rerankingModel; - public KnowledgeService(JdbcTemplate template, EmbeddingModel model, VectorStore vectorStore, GroupService groupService) { + public KnowledgeBaseService(JdbcTemplate template, EmbeddingModel model, VectorStore vectorStore, GroupService groupService, RerankingModel rerankingModel) { this.template = template; this.model = model; this.client = (QdrantClient) vectorStore.getNativeClient().orElseThrow(); this.groupService = groupService; + this.rerankingModel = rerankingModel; } public Knowledge get(Long id) { @@ -166,7 +170,8 @@ public class KnowledgeService { Long id, String text, Integer limit, - Double threshold) throws ExecutionException, InterruptedException { + Double threshold + ) throws ExecutionException, InterruptedException, IOException { Knowledge knowledge = get(id); Boolean exists = client.collectionExistsAsync(String.valueOf(knowledge.getVectorSourceId())).get(); if (!exists) { @@ -183,7 +188,13 @@ public class KnowledgeService { .similarityThreshold(threshold) .build() ); - return Lists.immutable.ofAll(documents) - .collect(Document::getText); + List rerankDocuments = rerankingModel.rerank( + text, + documents.stream() + .map(doc -> new org.noear.solon.ai.rag.Document(doc.getId(), doc.getText(), doc.getMetadata(), doc.getScore())) + .toList() + ); + return Lists.immutable.ofAll(rerankDocuments) + .collect(org.noear.solon.ai.rag.Document::getContent); } } \ No newline at end of file diff --git a/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/service/SegmentService.java b/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/service/SegmentService.java index 54fbd69..700cc06 100644 --- a/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/service/SegmentService.java +++ b/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/service/SegmentService.java @@ -23,16 +23,16 @@ import org.springframework.stereotype.Service; public class SegmentService { private static final Logger logger = LoggerFactory.getLogger(SegmentService.class); - private final KnowledgeService knowledgeService; + private final KnowledgeBaseService knowledgeBaseService; private final QdrantClient client; - public SegmentService(KnowledgeService knowledgeService, VectorStore vectorStore) { - this.knowledgeService = knowledgeService; + public SegmentService(KnowledgeBaseService knowledgeBaseService, VectorStore vectorStore) { + this.knowledgeBaseService = knowledgeBaseService; this.client = (QdrantClient) vectorStore.getNativeClient().orElseThrow(); } public ImmutableList list(Long id, Long groupId) throws ExecutionException, InterruptedException { - Knowledge knowledge = knowledgeService.get(id); + Knowledge knowledge = knowledgeBaseService.get(id); Points.ScrollResponse response = client.scrollAsync( Points.ScrollPoints.newBuilder() .setCollectionName(String.valueOf(knowledge.getVectorSourceId())) @@ -59,7 +59,7 @@ public class SegmentService { } public void remove(Long knowledgeId, Long segmentId) throws ExecutionException, InterruptedException { - Knowledge knowledge = knowledgeService.get(knowledgeId); + Knowledge knowledge = knowledgeBaseService.get(knowledgeId); client.deletePayloadAsync( String.valueOf(knowledgeId), List.of(String.valueOf(segmentId)), diff --git a/service-ai/service-ai-knowledge/src/main/resources/application.yml b/service-ai/service-ai-knowledge/src/main/resources/application.yml index 41a042a..f223948 100644 --- a/service-ai/service-ai-knowledge/src/main/resources/application.yml +++ b/service-ai/service-ai-knowledge/src/main/resources/application.yml @@ -22,3 +22,9 @@ liteflow: rule-source: config/flow.xml print-banner: false check-node-exists: false +solon: + base-url: http://132.121.206.65:10086 + api-key: ENC(K+Hff9QGC+fcyi510VIDd9CaeK/IN5WBJ9rlkUsHEdDgIidW+stHHJlsK0lLPUXXREha+ToQZqqDXJrqSE+GUKCXklFhelD8bRHFXBIeP/ZzT2cxhzgKUXgjw3S0Qw2R) + rerank: + model: 'Bge-reranker-v2-vllm' + endpoint: '/v1/rerank' \ No newline at end of file