From f04db38d6c6626794a154fa5e2852a432c194e0d Mon Sep 17 00:00:00 2001 From: stageluo <979175267@qq.com> Date: Wed, 19 Nov 2025 15:03:24 +0800 Subject: [PATCH] =?UTF-8?q?=E5=85=B3=E9=94=AE=E8=AF=8D=E6=8F=90=E5=8F=96?= =?UTF-8?q?=E5=B7=A5=E4=BD=9C=E6=B5=81=E8=8A=82=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../KeywordExtractorNode.java | 104 ++++++++++++++++++ .../KeywordExtractorNodeConfig.java | 42 +++++++ 2 files changed, 146 insertions(+) create mode 100644 ruoyi-modules-api/ruoyi-workflow-api/src/main/java/org/ruoyi/workflow/workflow/node/keywordExtractor/KeywordExtractorNode.java create mode 100644 ruoyi-modules-api/ruoyi-workflow-api/src/main/java/org/ruoyi/workflow/workflow/node/keywordExtractor/KeywordExtractorNodeConfig.java diff --git a/ruoyi-modules-api/ruoyi-workflow-api/src/main/java/org/ruoyi/workflow/workflow/node/keywordExtractor/KeywordExtractorNode.java b/ruoyi-modules-api/ruoyi-workflow-api/src/main/java/org/ruoyi/workflow/workflow/node/keywordExtractor/KeywordExtractorNode.java new file mode 100644 index 00000000..0f1d579e --- /dev/null +++ b/ruoyi-modules-api/ruoyi-workflow-api/src/main/java/org/ruoyi/workflow/workflow/node/keywordExtractor/KeywordExtractorNode.java @@ -0,0 +1,104 @@ +package org.ruoyi.workflow.workflow.node.keywordExtractor; + +import dev.langchain4j.data.message.UserMessage; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.ruoyi.workflow.entity.WorkflowComponent; +import org.ruoyi.workflow.entity.WorkflowNode; +import org.ruoyi.workflow.util.SpringUtil; +import org.ruoyi.workflow.workflow.NodeProcessResult; +import org.ruoyi.workflow.workflow.WfNodeState; +import org.ruoyi.workflow.workflow.WfState; +import org.ruoyi.workflow.workflow.WorkflowUtil; +import org.ruoyi.workflow.workflow.data.NodeIOData; +import org.ruoyi.workflow.workflow.node.AbstractWfNode; + +import java.util.ArrayList; +import java.util.List; + +import static org.ruoyi.workflow.cosntant.AdiConstant.WorkflowConstant.DEFAULT_OUTPUT_PARAM_NAME; + +/** + * 【节点】关键词提取节点 + * 使用 LLM 从文本中提取关键词 + */ +@Slf4j +public class KeywordExtractorNode extends AbstractWfNode { + + public KeywordExtractorNode(WorkflowComponent wfComponent, WorkflowNode nodeDef, WfState wfState, WfNodeState nodeState) { + super(wfComponent, nodeDef, wfState, nodeState); + } + + /** + * 处理关键词提取 + * nodeConfig 格式: + * { + * "model_name": "deepseek-chat", + * "category": "llm", + * "top_n": 5, + * "prompt": "额外的提示词" + * } + * + * @return 提取的关键词列表 + */ + @Override + public NodeProcessResult onProcess() { + KeywordExtractorNodeConfig config = checkAndGetConfig(KeywordExtractorNodeConfig.class); + + // 获取输入文本 + String inputText = getFirstInputText(); + if (StringUtils.isBlank(inputText)) { + log.warn("Keyword extractor node has no input text, node: {}", state.getUuid()); + // 返回空结果 + List outputs = new ArrayList<>(); + outputs.add(NodeIOData.createByText(DEFAULT_OUTPUT_PARAM_NAME, "", "")); + return NodeProcessResult.builder().content(outputs).build(); + } + + log.info("Keyword extractor node config: {}", config); + log.info("Input text length: {}", inputText.length()); + + // 构建提示词 + String prompt = buildPrompt(config, inputText); + log.info("Keyword extraction prompt: {}", prompt); + + // 调用 LLM 进行关键词提取 + WorkflowUtil workflowUtil = SpringUtil.getBean(WorkflowUtil.class); + String modelName = config.getModelName(); + String category = config.getCategory(); + List systemMessage = List.of(UserMessage.from(prompt)); + + // 使用流式调用 + workflowUtil.streamingInvokeLLM(wfState, state, node, category, modelName, systemMessage); + + return new NodeProcessResult(); + } + + /** + * 构建关键词提取的提示词 + */ + private String buildPrompt(KeywordExtractorNodeConfig config, String inputText) { + StringBuilder promptBuilder = new StringBuilder(); + + // 基础提示词 + promptBuilder.append("请从以下文本中提取 ").append(config.getTopN()).append(" 个最重要的关键词。\n\n"); + + // 添加自定义提示词(如果有) + if (StringUtils.isNotBlank(config.getPrompt())) { + promptBuilder.append(config.getPrompt()).append("\n\n"); + } + + // 输出格式要求 + promptBuilder.append("要求:\n"); + promptBuilder.append("1. 只返回关键词,每个关键词用逗号分隔\n"); + promptBuilder.append("2. 关键词应该是名词或名词短语\n"); + promptBuilder.append("3. 按重要性从高到低排序\n"); + promptBuilder.append("4. 不要添加任何解释或额外的文字\n\n"); + + // 原始文本 + promptBuilder.append("文本内容:\n"); + promptBuilder.append(inputText); + + return promptBuilder.toString(); + } +} diff --git a/ruoyi-modules-api/ruoyi-workflow-api/src/main/java/org/ruoyi/workflow/workflow/node/keywordExtractor/KeywordExtractorNodeConfig.java b/ruoyi-modules-api/ruoyi-workflow-api/src/main/java/org/ruoyi/workflow/workflow/node/keywordExtractor/KeywordExtractorNodeConfig.java new file mode 100644 index 00000000..6071f410 --- /dev/null +++ b/ruoyi-modules-api/ruoyi-workflow-api/src/main/java/org/ruoyi/workflow/workflow/node/keywordExtractor/KeywordExtractorNodeConfig.java @@ -0,0 +1,42 @@ +package org.ruoyi.workflow.workflow.node.keywordExtractor; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 关键词提取节点配置 + */ +@EqualsAndHashCode +@Data +public class KeywordExtractorNodeConfig { + + /** + * 模型分类(如:llm, embedding 等) + */ + private String category; + + /** + * 模型名称 + */ + @NotNull + @JsonProperty("model_name") + private String modelName; + + /** + * 提取的关键词数量 + */ + @Min(1) + @Max(50) + @JsonProperty("top_n") + private Integer topN = 5; + + /** + * 提示词(可选) + * 用于指导关键词提取的额外说明 + */ + private String prompt; +}