优化工作流注册节点以及相关其他代码优化

This commit is contained in:
stageluo
2025-11-20 10:09:48 +08:00
parent 35194457e1
commit 8a1ac2264e
4 changed files with 91 additions and 16 deletions

View File

@@ -21,4 +21,14 @@ public class NodeProcessResult {
* 条件执行时使用 * 条件执行时使用
*/ */
private String nextNodeUuid; private String nextNodeUuid;
/**
* 是否发生错误
*/
private boolean error = false;
/**
* 错误或提示信息
*/
private String message;
} }

View File

@@ -5,7 +5,10 @@ import org.ruoyi.workflow.entity.WorkflowNode;
import org.ruoyi.workflow.workflow.node.AbstractWfNode; import org.ruoyi.workflow.workflow.node.AbstractWfNode;
import org.ruoyi.workflow.workflow.node.EndNode; import org.ruoyi.workflow.workflow.node.EndNode;
import org.ruoyi.workflow.workflow.node.answer.LLMAnswerNode; import org.ruoyi.workflow.workflow.node.answer.LLMAnswerNode;
import org.ruoyi.workflow.workflow.node.keywordExtractor.KeywordExtractorNode;
import org.ruoyi.workflow.workflow.node.mailSend.MailSendNode;
import org.ruoyi.workflow.workflow.node.start.StartNode; import org.ruoyi.workflow.workflow.node.start.StartNode;
import org.ruoyi.workflow.workflow.node.switcher.SwitcherNode;
public class WfNodeFactory { public class WfNodeFactory {
public static AbstractWfNode create(WorkflowComponent wfComponent, WorkflowNode nodeDefinition, public static AbstractWfNode create(WorkflowComponent wfComponent, WorkflowNode nodeDefinition,
@@ -14,7 +17,10 @@ public class WfNodeFactory {
switch (WfComponentNameEnum.getByName(wfComponent.getName())) { switch (WfComponentNameEnum.getByName(wfComponent.getName())) {
case START -> wfNode = new StartNode(wfComponent, nodeDefinition, wfState, nodeState); case START -> wfNode = new StartNode(wfComponent, nodeDefinition, wfState, nodeState);
case LLM_ANSWER -> wfNode = new LLMAnswerNode(wfComponent, nodeDefinition, wfState, nodeState); case LLM_ANSWER -> wfNode = new LLMAnswerNode(wfComponent, nodeDefinition, wfState, nodeState);
case KEYWORD_EXTRACTOR -> wfNode = new KeywordExtractorNode(wfComponent, nodeDefinition, wfState, nodeState);
case END -> wfNode = new EndNode(wfComponent, nodeDefinition, wfState, nodeState); case END -> wfNode = new EndNode(wfComponent, nodeDefinition, wfState, nodeState);
case MAIL_SEND -> wfNode = new MailSendNode(wfComponent, nodeDefinition, wfState, nodeState);
case SWITCHER -> wfNode = new SwitcherNode(wfComponent, nodeDefinition, wfState, nodeState);
default -> { default -> {
} }
} }

View File

@@ -20,12 +20,10 @@ import org.ruoyi.workflow.workflow.data.NodeIOData;
import org.ruoyi.workflow.workflow.data.NodeIODataContent; import org.ruoyi.workflow.workflow.data.NodeIODataContent;
import org.ruoyi.workflow.workflow.def.WfNodeParamRef; import org.ruoyi.workflow.workflow.def.WfNodeParamRef;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import static org.ruoyi.workflow.cosntant.AdiConstant.WorkflowConstant.DEFAULT_OUTPUT_PARAM_NAME; import static org.ruoyi.workflow.cosntant.AdiConstant.WorkflowConstant.DEFAULT_OUTPUT_PARAM_NAME;
@Slf4j @Slf4j
@@ -35,22 +33,48 @@ public class WorkflowUtil {
@Resource @Resource
private ChatServiceFactory chatServiceFactory; private ChatServiceFactory chatServiceFactory;
@SuppressWarnings("unchecked")
public static String renderTemplate(String template, List<NodeIOData> values) { public static String renderTemplate(String template, List<NodeIOData> values) {
// 🔒 关键修复:如果 template 为 null直接返回 null 或空字符串
if (template == null) {
return null; // 或 return ""; 根据业务需求
}
String result = template; String result = template;
// 防御 values 为 null
if (values == null) {
return result;
}
for (NodeIOData next : values) { for (NodeIOData next : values) {
if (next == null || next.getName() == null) {
continue;
}
String name = next.getName(); String name = next.getName();
NodeIODataContent<?> dataContent = next.getContent(); NodeIODataContent<?> dataContent = next.getContent();
if (dataContent.getType().equals(WfIODataTypeEnum.FILES.getValue())) { if (dataContent == null || dataContent.getValue() == null) {
List<String> value = (List<String>) dataContent.getValue(); // 变量值为 null替换为空字符串
result = result.replace("{" + name + "}", String.join(",", value)); result = result.replace("{" + name + "}", "");
} else if (dataContent.getType().equals(WfIODataTypeEnum.OPTIONS.getValue())) { continue;
Map<String, Object> value = (Map<String, Object>) dataContent.getValue();
result = result.replace("{" + name + "}", value.toString());
} else {
result = result.replace("{" + name + "}", dataContent.getValue().toString());
} }
String replacement;
if (dataContent.getType().equals(WfIODataTypeEnum.FILES.getValue())) {
@SuppressWarnings("unchecked")
List<String> value = (List<String>) dataContent.getValue();
replacement = String.join(",", value);
} else if (dataContent.getType().equals(WfIODataTypeEnum.OPTIONS.getValue())) {
@SuppressWarnings("unchecked")
Map<String, Object> value = (Map<String, Object>) dataContent.getValue();
replacement = value.toString();
} else {
replacement = dataContent.getValue().toString();
}
result = result.replace("{" + name + "}", replacement);
} }
return result; return result;
} }
@@ -81,8 +105,15 @@ public class WorkflowUtil {
.mapResult(response -> { .mapResult(response -> {
String responseTxt = response.aiMessage().text(); String responseTxt = response.aiMessage().text();
log.info("llm response:{}", responseTxt); log.info("llm response:{}", responseTxt);
NodeIOData output = NodeIOData.createByText(DEFAULT_OUTPUT_PARAM_NAME, "", responseTxt);
wfState.getNodeStateByNodeUuid(node.getUuid()).ifPresent(item -> item.getOutputs().add(output)); // 传递所有输入数据 + 添加 LLM 输出
wfState.getNodeStateByNodeUuid(node.getUuid()).ifPresent(item -> {
List<NodeIOData> outputs = new ArrayList<>(item.getInputs());
NodeIOData output = NodeIOData.createByText(DEFAULT_OUTPUT_PARAM_NAME, "", responseTxt);
outputs.add(output);
item.setOutputs(outputs);
});
return Map.of("completeResult", response.aiMessage().text()); return Map.of("completeResult", response.aiMessage().text());
}) })
.startingNode(node.getUuid()) .startingNode(node.getUuid())
@@ -141,9 +172,10 @@ public class WorkflowUtil {
* @return * @return
*/ */
private Message getMessage(String role, Object value) { private Message getMessage(String role, Object value) {
log.info("Creating message with role: {}, content: {}", role, value); // 🔥
Message message = new Message(); Message message = new Message();
message.setContent(String.valueOf(value));
message.setRole(role); message.setRole(role);
message.setContent(value);
return message; return message;
} }
@@ -154,9 +186,13 @@ public class WorkflowUtil {
* @param messages * @param messages
*/ */
private void addSystemMessage(List<UserMessage> systemMessage, List<Message> messages) { private void addSystemMessage(List<UserMessage> systemMessage, List<Message> messages) {
log.info("addSystemMessage received: {}", systemMessage); // 🔥 加这一行
if (CollUtil.isEmpty(systemMessage)) { if (CollUtil.isEmpty(systemMessage)) {
return; return;
} }
systemMessage.stream().map(userMsg -> getMessage("system", userMsg.singleText())).forEach(messages::add); systemMessage.stream()
.map(userMsg -> getMessage("system", userMsg.singleText()))
.forEach(messages::add);
} }
} }

View File

@@ -166,17 +166,40 @@ public abstract class AbstractWfNode {
protected abstract NodeProcessResult onProcess(); protected abstract NodeProcessResult onProcess();
protected String getFirstInputText() { protected String getFirstInputText() {
// 检查输入是否为空
if (state.getInputs() == null || state.getInputs().isEmpty()) {
log.warn("No inputs available for node: {}", state.getUuid());
return "";
}
// 优先查找 output 参数LLM 节点的输出)
Optional<String> outputParam = state.getInputs()
.stream()
.filter(item -> DEFAULT_OUTPUT_PARAM_NAME.equals(item.getName()))
.map(NodeIOData::valueToString)
.findFirst();
if (outputParam.isPresent()) {
log.debug("Found output parameter for node: {}", state.getUuid());
return outputParam.get();
}
// 如果没有 output查找其他文本类型参数排除 input
String firstInputText; String firstInputText;
if (state.getInputs().size() > 1) { if (state.getInputs().size() > 1) {
firstInputText = state.getInputs() firstInputText = state.getInputs()
.stream() .stream()
.filter(item -> WfIODataTypeEnum.TEXT.getValue().equals(item.getContent().getType()) && !DEFAULT_INPUT_PARAM_NAME.equals(item.getName())) .filter(item -> WfIODataTypeEnum.TEXT.getValue().equals(item.getContent().getType())
&& !DEFAULT_INPUT_PARAM_NAME.equals(item.getName()))
.map(NodeIOData::valueToString) .map(NodeIOData::valueToString)
.findFirst() .findFirst()
.orElse(""); .orElse("");
} else { } else {
firstInputText = state.getInputs().get(0).valueToString(); firstInputText = state.getInputs().get(0).valueToString();
} }
log.debug("Using first input text for node: {}, value: {}", state.getUuid(),
firstInputText.length() > 50 ? firstInputText.substring(0, 50) + "..." : firstInputText);
return firstInputText; return firstInputText;
} }