feat: 收敛知识库检索调度与评分语义
- 固定 rag.engine 与 Milvus 配置,补齐启动期检索基础设施校验 - 支持调用方配置 retrievalMode,并统一知识库检索入口与结果来源展示 - 修正关键词检索 knowledgeId 过滤、混合检索评分归一化与本地 ES 默认配置
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package tech.easyflow.admin.controller.ai;
|
||||
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import tech.easyflow.ai.dto.BotKnowledgeBindingRequest;
|
||||
import tech.easyflow.ai.entity.BotDocumentCollection;
|
||||
import tech.easyflow.ai.entity.DocumentCollection;
|
||||
import tech.easyflow.ai.permission.KnowledgeReadAccessSnapshot;
|
||||
@@ -63,20 +64,21 @@ public class BotDocumentCollectionController extends BaseCurdController<BotDocum
|
||||
}
|
||||
|
||||
@PostMapping("updateBotKnowledgeIds")
|
||||
public Result<?> save(@JsonBody("botId") BigInteger botId, @JsonBody("knowledgeIds") BigInteger [] knowledgeIds) {
|
||||
if (knowledgeIds != null) {
|
||||
for (BigInteger knowledgeId : knowledgeIds) {
|
||||
if (knowledgeId == null) {
|
||||
public Result<?> save(@JsonBody("botId") BigInteger botId,
|
||||
@JsonBody("knowledgeBindings") List<BotKnowledgeBindingRequest> knowledgeBindings) {
|
||||
if (knowledgeBindings != null) {
|
||||
for (BotKnowledgeBindingRequest binding : knowledgeBindings) {
|
||||
if (binding == null || binding.getKnowledgeId() == null) {
|
||||
continue;
|
||||
}
|
||||
DocumentCollection collection = documentCollectionService.getById(knowledgeId);
|
||||
DocumentCollection collection = documentCollectionService.getById(binding.getKnowledgeId());
|
||||
if (collection == null) {
|
||||
continue;
|
||||
}
|
||||
resourceAccessService.assertAccess(CategoryResourceType.KNOWLEDGE, collection, ResourceAction.READ, "无权限绑定知识库");
|
||||
}
|
||||
}
|
||||
service.saveBotAndKnowledge(botId, knowledgeIds);
|
||||
service.saveBotAndKnowledge(botId, knowledgeBindings);
|
||||
return Result.ok();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package tech.easyflow.admin.controller.ai;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import com.easyagents.core.document.Document;
|
||||
import com.easyagents.rag.retrieval.RagRetrievalMetadataKeys;
|
||||
import com.mybatisflex.core.paginate.Page;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -12,9 +13,12 @@ import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.ai.permission.KnowledgeVisibilityQueryHelper;
|
||||
import tech.easyflow.ai.documentimport.DocumentImportDtos;
|
||||
import tech.easyflow.ai.dto.KnowledgeSearchResultItem;
|
||||
import tech.easyflow.ai.entity.BotDocumentCollection;
|
||||
import tech.easyflow.ai.entity.DocumentCollection;
|
||||
import tech.easyflow.ai.entity.Model;
|
||||
import tech.easyflow.ai.rag.KnowledgeRetrievalRequest;
|
||||
import tech.easyflow.ai.rag.KnowledgeRetrievalModes;
|
||||
import tech.easyflow.ai.service.BotDocumentCollectionService;
|
||||
import tech.easyflow.ai.service.DocumentChunkService;
|
||||
import tech.easyflow.ai.service.DocumentCollectionService;
|
||||
@@ -32,11 +36,15 @@ import tech.easyflow.system.service.ResourceAccessService;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* 控制层。
|
||||
@@ -105,13 +113,11 @@ public class DocumentCollectionController extends BaseCurdController<DocumentCol
|
||||
Map<String, Object> options = entity.getOptions() == null
|
||||
? new HashMap<>()
|
||||
: new HashMap<>(entity.getOptions());
|
||||
if (entity.getSearchEngineEnable() == null){
|
||||
entity.setSearchEngineEnable(false);
|
||||
}
|
||||
options.putIfAbsent(DocumentCollection.KEY_CAN_UPDATE_EMBEDDING_MODEL, true);
|
||||
options.putIfAbsent(DocumentCollection.KEY_RERANK_ENABLE, entity.getRerankModelId() != null);
|
||||
entity.setOptions(options);
|
||||
}
|
||||
normalizeInfrastructureFields(entity, isSave);
|
||||
return super.onSaveOrUpdateBefore(entity, isSave);
|
||||
}
|
||||
|
||||
@@ -124,8 +130,16 @@ public class DocumentCollectionController extends BaseCurdController<DocumentCol
|
||||
idExpr = "#knowledgeId",
|
||||
denyMessage = "无权限访问知识库"
|
||||
)
|
||||
public Result<List<Document>> search(@RequestParam BigInteger knowledgeId, @RequestParam String keyword) {
|
||||
return Result.ok(service.search(knowledgeId, keyword));
|
||||
public Result<List<KnowledgeSearchResultItem>> search(@RequestParam BigInteger knowledgeId,
|
||||
@RequestParam String keyword,
|
||||
@RequestParam(required = false) String retrievalMode) {
|
||||
KnowledgeRetrievalRequest request = new KnowledgeRetrievalRequest();
|
||||
request.setKnowledgeId(knowledgeId);
|
||||
request.setQuery(keyword);
|
||||
request.setRetrievalMode(KnowledgeRetrievalModes.parse(retrievalMode));
|
||||
request.setCallerType("API");
|
||||
request.setCallerId(String.valueOf(knowledgeId));
|
||||
return Result.ok(toKnowledgeSearchResult(service.search(request)));
|
||||
}
|
||||
|
||||
|
||||
@@ -234,4 +248,85 @@ public class DocumentCollectionController extends BaseCurdController<DocumentCol
|
||||
}
|
||||
return collection;
|
||||
}
|
||||
|
||||
private void normalizeInfrastructureFields(DocumentCollection entity, boolean isSave) {
|
||||
if (entity == null) {
|
||||
return;
|
||||
}
|
||||
if (isSave) {
|
||||
entity.setVectorStoreEnable(true);
|
||||
entity.setVectorStoreType("milvus");
|
||||
entity.setSearchEngineEnable(true);
|
||||
entity.setVectorStoreCollection(generateVectorCollectionName());
|
||||
return;
|
||||
}
|
||||
if (entity.getVectorStoreEnable() != null) {
|
||||
entity.setVectorStoreEnable(true);
|
||||
}
|
||||
if (entity.getVectorStoreType() != null) {
|
||||
entity.setVectorStoreType("milvus");
|
||||
}
|
||||
if (entity.getSearchEngineEnable() != null) {
|
||||
entity.setSearchEngineEnable(true);
|
||||
}
|
||||
}
|
||||
|
||||
private String generateVectorCollectionName() {
|
||||
return "kb_" + UUID.randomUUID().toString().replace("-", "").substring(0, 28);
|
||||
}
|
||||
|
||||
private List<KnowledgeSearchResultItem> toKnowledgeSearchResult(List<Document> documents) {
|
||||
List<KnowledgeSearchResultItem> results = new ArrayList<>();
|
||||
if (documents == null) {
|
||||
return results;
|
||||
}
|
||||
for (int index = 0; index < documents.size(); index++) {
|
||||
Document document = documents.get(index);
|
||||
if (document == null) {
|
||||
continue;
|
||||
}
|
||||
KnowledgeSearchResultItem item = new KnowledgeSearchResultItem();
|
||||
item.setSorting(index + 1);
|
||||
item.setContent(document.getContent());
|
||||
item.setScore(roundScore(document.getScore()));
|
||||
item.setHitSource(readMetadataAsString(document, RagRetrievalMetadataKeys.HIT_SOURCE));
|
||||
item.setVectorScore(roundScore(readMetadataAsDouble(document, RagRetrievalMetadataKeys.VECTOR_SCORE)));
|
||||
item.setKeywordScore(roundScore(readMetadataAsDouble(document, RagRetrievalMetadataKeys.KEYWORD_SCORE)));
|
||||
results.add(item);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private String readMetadataAsString(Document document, String key) {
|
||||
Object value = document == null ? null : document.getMetadata(key);
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
String text = String.valueOf(value);
|
||||
return StringUtils.hasText(text) ? text : null;
|
||||
}
|
||||
|
||||
private Double readMetadataAsDouble(Document document, String key) {
|
||||
Object value = document == null ? null : document.getMetadata(key);
|
||||
if (value instanceof Number) {
|
||||
return ((Number) value).doubleValue();
|
||||
}
|
||||
if (value instanceof String && StringUtils.hasText((String) value)) {
|
||||
try {
|
||||
return Double.valueOf((String) value);
|
||||
} catch (NumberFormatException ignore) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Double roundScore(Double value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
return new BigDecimal(String.valueOf(value))
|
||||
.setScale(4, RoundingMode.HALF_UP)
|
||||
.doubleValue();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user