diff --git a/docs/script/sql/ruoyi-ai.sql b/docs/script/sql/ruoyi-ai.sql index 23d4c209..87caaf57 100644 --- a/docs/script/sql/ruoyi-ai.sql +++ b/docs/script/sql/ruoyi-ai.sql @@ -3476,6 +3476,7 @@ INSERT INTO `t_workflow_component` VALUES (18, '5cd6ac69bbb411f0bb7840c2ba9a7fbc INSERT INTO `t_workflow_component` VALUES (19, '5cd6c8eabbb411f0bb7840c2ba9a7fbc', 'Answer', '生成回答', '调用大语言模型回答问题', 0, 1, '2025-11-07 16:32:49', '2025-11-07 16:32:49', 0, '000000'); INSERT INTO `t_workflow_component` VALUES (26, 'bb00fc2f52c74fec82ee3f99725b56bb', 'Switcher', '条件分支', '根据条件执行不同分支', 0, 1, '2025-12-26 16:30:46', '2025-12-26 16:30:46', 0, '000000'); INSERT INTO `t_workflow_component` VALUES (37, 'a7f8c2d44e5b4c83a9d6f103c2b47e18', 'Google', '网络搜索', '调用智谱 Web Search 检索互联网信息', 40, 1, '2026-07-29 20:30:00', '2026-07-29 20:30:00', 0, '000000'); +INSERT INTO `t_workflow_component` VALUES (38, 'b8e3c1d55f6a4d92b0e7f214d3c58a29', 'KnowledgeRetrieval', '知识库检索', '从知识库中检索相关内容,支持向量检索和混合检索', 30, 1, '2026-09-11 10:00:00', '2026-09-11 10:00:00', 0, '000000'); -- ---------------------------- -- Table structure for t_workflow_edge diff --git a/docs/script/sql/update/2026-09-11-knowledge-retrieval-node.sql b/docs/script/sql/update/2026-09-11-knowledge-retrieval-node.sql new file mode 100644 index 00000000..c63ede23 --- /dev/null +++ b/docs/script/sql/update/2026-09-11-knowledge-retrieval-node.sql @@ -0,0 +1,24 @@ +-- 知识库检索工作流节点注册 +-- 为新安装和已有环境提供幂等的节点注册 + +INSERT INTO `t_workflow_component` + (`uuid`, `name`, `title`, `remark`, `display_order`, `is_enable`, + `create_time`, `update_time`, `is_deleted`, `tenant_id`) +SELECT + 'b8e3c1d55f6a4d92b0e7f214d3c58a29', + 'KnowledgeRetrieval', + '知识库检索', + '从知识库中检索相关内容,支持向量检索和混合检索', + 30, + 1, + NOW(), + NOW(), + 0, + '000000' +FROM DUAL +WHERE NOT EXISTS ( + SELECT 1 + FROM `t_workflow_component` + WHERE `name` = 'KnowledgeRetrieval' + AND `tenant_id` = '000000' +); diff --git a/ruoyi-modules/ruoyi-aiflow/src/main/java/org/ruoyi/workflow/workflow/node/knowledgeRetrieval/KnowledgeRetrievalNode.java b/ruoyi-modules/ruoyi-aiflow/src/main/java/org/ruoyi/workflow/workflow/node/knowledgeRetrieval/KnowledgeRetrievalNode.java index c962ca2c..ed93a99c 100644 --- a/ruoyi-modules/ruoyi-aiflow/src/main/java/org/ruoyi/workflow/workflow/node/knowledgeRetrieval/KnowledgeRetrievalNode.java +++ b/ruoyi-modules/ruoyi-aiflow/src/main/java/org/ruoyi/workflow/workflow/node/knowledgeRetrieval/KnowledgeRetrievalNode.java @@ -88,6 +88,15 @@ public class KnowledgeRetrievalNode extends AbstractWfNode { retrievalResult = retrieveFromVector(config, finalQuery); + // 严格模式处理:检索无结果时返回默认回复 + if (StringUtils.isBlank(retrievalResult) && Boolean.TRUE.equals(config.getIsStrict())) { + String defaultResp = config.getDefaultResponse(); + if (StringUtils.isNotBlank(defaultResp)) { + log.info("Knowledge retrieval returned no results, using default response (strict mode)"); + retrievalResult = defaultResp; + } + } + log.info("Retrieval result length: {}", retrievalResult.length()); // 构建输出 @@ -238,9 +247,9 @@ public class KnowledgeRetrievalNode extends AbstractWfNode { bo.setVectorModelName(kb.getVectorModel()); bo.setBaseUrl(embModel.getApiHost()); + // 节点明确选择的模式覆盖知识库配置,避免知识库开启混合检索时节点无法切回纯向量 String mode = config.getRetrievalMode() != null ? config.getRetrievalMode().toLowerCase() : "vector"; - boolean enableHybrid = "hybrid".equals(mode) - || (kb.getEnableHybrid() != null && kb.getEnableHybrid() == 1); + boolean enableHybrid = "hybrid".equals(mode); bo.setEnableHybrid(enableHybrid); bo.setHybridAlpha(kb.getHybridAlpha()); bo.setEnableRerank(kb.getEnableRerank() != null && kb.getEnableRerank() == 1); diff --git a/ruoyi-modules/ruoyi-aiflow/src/main/java/org/ruoyi/workflow/workflow/node/knowledgeRetrieval/KnowledgeRetrievalNodeConfig.java b/ruoyi-modules/ruoyi-aiflow/src/main/java/org/ruoyi/workflow/workflow/node/knowledgeRetrieval/KnowledgeRetrievalNodeConfig.java index e8697f7d..b29a31f0 100644 --- a/ruoyi-modules/ruoyi-aiflow/src/main/java/org/ruoyi/workflow/workflow/node/knowledgeRetrieval/KnowledgeRetrievalNodeConfig.java +++ b/ruoyi-modules/ruoyi-aiflow/src/main/java/org/ruoyi/workflow/workflow/node/knowledgeRetrieval/KnowledgeRetrievalNodeConfig.java @@ -12,26 +12,26 @@ import lombok.EqualsAndHashCode; @EqualsAndHashCode @Data public class KnowledgeRetrievalNodeConfig { - + /** * 知识库UUID(主要字段) */ @JsonProperty("knowledge_base_uuid") private String knowledgeBaseUuid; - + /** * 知识库ID(兼容字段) */ @JsonProperty("knowledge_id") private String knowledgeId; - + /** * 获取知识库ID(优先使用knowledgeBaseUuid) */ public String getKnowledgeId() { return knowledgeBaseUuid != null ? knowledgeBaseUuid : knowledgeId; } - + /** * 检索的最大结果数 */ @@ -39,20 +39,20 @@ public class KnowledgeRetrievalNodeConfig { @Max(100) @JsonProperty("top_k") private Integer topK = 5; - + /** * 检索的最大结果数(兼容字段,前端使用top_n) */ @JsonProperty("top_n") private Integer topN; - + /** * 获取topK值(优先使用topN) */ public Integer getTopK() { return topN != null ? topN : topK; } - + /** * 相似度阈值(0-1之间) */ @@ -60,52 +60,66 @@ public class KnowledgeRetrievalNodeConfig { @Max(1) @JsonProperty("similarity_threshold") private Double similarityThreshold = 0.7; - + /** * 相似度阈值(兼容字段,前端使用score) */ @JsonProperty("score") private Double score; - + /** * 获取相似度阈值(优先使用score) */ public Double getSimilarityThreshold() { return score != null ? score : similarityThreshold; } - + /** * 检索模式:vector(向量检索)、graph(图谱检索)、hybrid(混合检索) */ @JsonProperty("retrieval_mode") private String retrievalMode = "vector"; - + /** * 模型分类(用于LLM查询改写) */ private String category; - + /** * LLM模型名称(用于查询改写) */ @JsonProperty("model_name") private String modelName; - + /** * Embedding模型名称(用于向量检索) */ @JsonProperty("embedding_model") private String embeddingModel; - + /** * 是否返回原文 */ @JsonProperty("return_source") private Boolean returnSource = true; - + /** * 自定义查询提示词(可选) * 用于对查询进行预处理或改写 */ private String prompt; + + /** + * 是否开启严格模式 + * 开启后,当检索无结果时返回 defaultResponse;关闭则返回空字符串 + */ + @JsonProperty("is_strict") + private Boolean isStrict = true; + + /** + * 严格模式下的默认回复内容 + * 当检索无结果且严格模式开启时,返回此内容 + */ + @JsonProperty("default_response") + private String defaultResponse; }