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

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 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.EndNode;
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.switcher.SwitcherNode;
public class WfNodeFactory {
public static AbstractWfNode create(WorkflowComponent wfComponent, WorkflowNode nodeDefinition,
@@ -14,7 +17,10 @@ public class WfNodeFactory {
switch (WfComponentNameEnum.getByName(wfComponent.getName())) {
case START -> wfNode = new StartNode(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 MAIL_SEND -> wfNode = new MailSendNode(wfComponent, nodeDefinition, wfState, nodeState);
case SWITCHER -> wfNode = new SwitcherNode(wfComponent, nodeDefinition, wfState, nodeState);
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.def.WfNodeParamRef;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.ruoyi.workflow.cosntant.AdiConstant.WorkflowConstant.DEFAULT_OUTPUT_PARAM_NAME;
@Slf4j
@@ -35,22 +33,48 @@ public class WorkflowUtil {
@Resource
private ChatServiceFactory chatServiceFactory;
@SuppressWarnings("unchecked")
public static String renderTemplate(String template, List<NodeIOData> values) {
// 🔒 关键修复:如果 template 为 null直接返回 null 或空字符串
if (template == null) {
return null; // 或 return ""; 根据业务需求
}
String result = template;
// 防御 values 为 null
if (values == null) {
return result;
}
for (NodeIOData next : values) {
if (next == null || next.getName() == null) {
continue;
}
String name = next.getName();
NodeIODataContent<?> dataContent = next.getContent();
if (dataContent.getType().equals(WfIODataTypeEnum.FILES.getValue())) {
List<String> value = (List<String>) dataContent.getValue();
result = result.replace("{" + name + "}", String.join(",", value));
} else if (dataContent.getType().equals(WfIODataTypeEnum.OPTIONS.getValue())) {
Map<String, Object> value = (Map<String, Object>) dataContent.getValue();
result = result.replace("{" + name + "}", value.toString());
} else {
result = result.replace("{" + name + "}", dataContent.getValue().toString());
if (dataContent == null || dataContent.getValue() == null) {
// 变量值为 null替换为空字符串
result = result.replace("{" + name + "}", "");
continue;
}
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;
}
@@ -81,8 +105,15 @@ public class WorkflowUtil {
.mapResult(response -> {
String responseTxt = response.aiMessage().text();
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());
})
.startingNode(node.getUuid())
@@ -141,9 +172,10 @@ public class WorkflowUtil {
* @return
*/
private Message getMessage(String role, Object value) {
log.info("Creating message with role: {}, content: {}", role, value); // 🔥
Message message = new Message();
message.setContent(String.valueOf(value));
message.setRole(role);
message.setContent(value);
return message;
}
@@ -154,9 +186,13 @@ public class WorkflowUtil {
* @param messages
*/
private void addSystemMessage(List<UserMessage> systemMessage, List<Message> messages) {
log.info("addSystemMessage received: {}", systemMessage); // 🔥 加这一行
if (CollUtil.isEmpty(systemMessage)) {
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 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;
if (state.getInputs().size() > 1) {
firstInputText = state.getInputs()
.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)
.findFirst()
.orElse("");
} else {
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;
}