找回密码
 立即注册
首页 业界区 业界 .NET 开源工作流:Slickflow 流程自动化运行技术指南 ...

.NET 开源工作流:Slickflow 流程自动化运行技术指南

恶凝毛 2 小时前
概述

Slickflow.NET 作为基于 .NET 的开源工作流引擎,除了支持传统的人工审批流程(用户任务、会签、加签等),还提供了流程自动化运行能力。与需要人工介入的审批流程不同,自动化运行流程在启动后可按预定义顺序自动执行所有节点,直至流程结束,无需人工参与。
本文面向 Slickflow 引擎开发人员,重点讲解:

  • 流程自动化运行的底层逻辑与架构(相对于人工审批流程的差异)
  • 代码方式定义流程:使用 Workflow 类在内存中构建 BPMN 流程
  • 代码方式运行流程:使用 WorkflowExecutor 及 UseProcess(workflow) 执行
  • 两个完整测试用例:LocalMethod 订单金额计算流程、AI 多轮问答智能客服流程
一、流程自动化运行 vs 人工审批流程

1.1 核心差异

维度人工审批流程流程自动化运行执行模式每执行一个节点后暂停,等待人工操作启动后自动顺序执行所有节点,直到结束节点类型用户任务(UserTask)为主,需要签收、办理服务任务(ServiceTask)、AI 任务、脚本任务等自动节点持久化依赖数据库存储流程实例、活动实例、任务可选用纯内存执行,不落库上下文ActivityForwardContext、IDbSessionAutoExecutionContext、内存变量字典典型场景请假审批、报销审批、合同会签数据处理流水线、AI 对话编排、ETL 流程1.2 自动化运行的底层逻辑

自动化运行流程的核心是:引擎在启动流程后,循环执行“获取下一可执行活动 → 执行活动 → 推进流程”,直到没有可执行活动(流程结束)或达到步数上限。
简化伪代码:
  1. 启动流程 -> 创建流程实例
  2. while (存在可执行活动) {
  3.     获取下一可执行活动列表
  4.     foreach (活动 in 活动列表)
  5.         执行活动(调用 Service / AI / Script 执行器)
  6.     推进流程(Run)-> 更新当前节点、流转到下一节点
  7. }
  8. 返回执行结果
复制代码
与人工审批流程的区别在于:

  • 人工审批:执行完一个用户任务后,流程停在待办,需调用 WorkflowService.Run(runner) 时传入下一节点办理人,或由用户在前端签收后再继续。
  • 自动化运行:服务任务、AI 任务、脚本任务执行完毕后,引擎自动推进到下一节点,无需人工介入。
二、架构设计

2.1 整体架构
  1. ┌─────────────────────────────────────────────────────────────────┐
  2. │                    Workflow(流程定义层)                         │
  3. │  Slickflow.Graph.Model.Workflow                                 │
  4. │  .Start() .ServiceTask() .RagService() .End()                   │
  5. └───────────────────────────┬─────────────────────────────────────┘
  6.                             │ BuildInMemory()
  7.                             ▼
  8. ┌─────────────────────────────────────────────────────────────────┐
  9. │               ProcessEntity(内存流程实体)                       │
  10. │  ProcessXmlBuilder 序列化为 BPMN XML,不写入数据库                 │
  11. └───────────────────────────┬─────────────────────────────────────┘
  12.                             │ UseProcess(workflow)
  13.                             ▼
  14. ┌─────────────────────────────────────────────────────────────────┐
  15. │                 WorkflowExecutor(执行器)                        │
  16. │  UseApp / UseProcess / AddVariable / Run                        │
  17. └───────────────────────────┬─────────────────────────────────────┘
  18.                             │
  19.             ┌───────────────┼───────────────┐
  20.             ▼               ▼               ▼
  21. ┌───────────────┐ ┌───────────────┐ ┌───────────────┐
  22. │ ServiceTask   │ │ RagService    │ │ LocalService  │
  23. │ (LocalMethod) │ │ (AI/RAG)      │ │ (服务类)       │
  24. │ 委托注册表解析  │ │ 大模型调用      │ │ 反射实例化      │
  25. └───────────────┘ └───────────────┘ └───────────────┘
复制代码
2.2 关键组件

组件职责Workflow代码定义流程结构,支持 Start、Task、ServiceTask、RagService、LlmService、Agent、Parallels、Branch、End 等ProcessXmlBuilder将 Workflow 图结构序列化为 BPMN 2.0 XMLWorkflowExecutorExtensions.UseProcess(workflow)接收 Workflow 实例,调用 BuildInMemory() 生成 ProcessEntity,并按 ProcessId:Version 进行内存缓存,无需数据库ServiceTaskDelegateRegistryLocalMethod 委托注册表,按 key 解析并执行本地方法WorkflowActivityExecutor根据 ServiceDetail.Method 分发:LocalMethod / LocalService / WebAPI 等AutoExecutionContext内存执行上下文,Variables 字典存储输入输出变量三、代码方式定义流程

3.1 基本语法
  1. using Slickflow.Graph.Model;
  2. var wf = new Workflow("ProcessName", "ProcessCode");
  3. wf.Start("Start")
  4.     .ServiceTask("服务节点名", "ActivityCode", "DelegateKey")   // LocalMethod
  5.     .RagService("RAG 回答", "RAG001")                          // RAG 节点
  6.     .LlmService("LLM 智能节点", "LLM001")                     // 通用 LLM 节点
  7.     .ServiceTask<MyService>("保存", "Save001")                 // LocalService 服务类
  8.     .End("End");
复制代码

  • new Workflow(string name, string code):name 为流程名称,code 为流程编码;内部会自动生成 ProcessId = "process_xxx" 与默认版本号 Version = "1"。
  • Start("Start"):开始事件
  • ServiceTask(name, code, delegateKey):绑定 LocalMethod,delegateKey 对应委托注册表中的 key
  • RagService(name, code):RAG 增强的 AI 服务任务
  • LlmService(name, code):通用大模型服务任务节点(如 DeepSeek、通义千问等)
  • ServiceTask(name, code):绑定本地服务类
  • End("End"):结束事件
3.2 并行与分支(Parallels / Branch)

最新的 Workflow 支持更简洁的并行与分支语法,例如:
  1. // 简单并行:开始 -> 并行三个任务 -> 汇聚 -> 结束
  2. wf.Start("Start")
  3.   .AndSplit("并行网关")
  4.   .Parallels(
  5.       ("任务A", "TaskA"),
  6.       ("任务B", "TaskB"),
  7.       ("任务C", "TaskC"))
  8.   .AndJoin("并行汇聚")
  9.   .End("End");
复制代码
复杂分支可以通过 Branch + Lambda 定义分支内部节点:
  1. wf.Start("Start")
  2.   .Split("条件网关")
  3.   .Branch(
  4.       () => wf.Task("条件1处理", "Cond1"),
  5.       () => wf.Task("条件2处理", "Cond2"))
  6.   .End("End");
复制代码
3.3 Build() 与 BuildInMemory()

方法作用数据库wf.Build()序列化流程并插入 wf_process 表写入wf.BuildInMemory()仅生成内存中的 ProcessEntity不涉及使用 UseProcess(workflow) 时,内部调用 BuildInMemory(),并按 ProcessId:Version 将 ProcessEntity 缓存到内存中,不产生数据库写入,适合单元测试、Demo、嵌入式场景;同一进程内多次调用会复用缓存的流程定义。
四、代码方式运行流程

4.1 执行入口
  1. using Slickflow.Engine.Executor;
  2. using Slickflow.Engine.Core.Result;
  3. var wfe = new WorkflowExecutor();
  4. var result = await wfe
  5.     .UseApp("App-001", "AppName", "AppCode")
  6.     .UseProcess(wf)                    // 直接传入 Workflow 实例
  7.     .AddVariable("key", value)
  8.     .Run();
  9. if (result.Status == WfExecutedStatus.Success)
  10.     Console.WriteLine(result.Message);
复制代码
4.2 参数传递


  • 输入:AddVariable("key", value) 传入流程变量
  • 输出:服务节点 / AI 节点通过 context.Variables["VarName"] = result 写回
  • LocalMethod:通过 IEventService.GetVariable 读取、SaveVariable 或返回值写入
五、测试用例一:LocalMethod 订单金额计算流程

5.1 流程说明

流程:开始 → 校验订单 → 计算金额 → 通知结果 → 结束。其中「校验订单」「计算金额」「通知结果」均使用 LocalMethod 绑定本地方法。
5.2 定义本地方法并注册
  1. using Slickflow.Engine.Executor;
  2. using Slickflow.Engine.Event;
  3. using Slickflow.Engine.Common;
  4. // 校验订单:检查必填变量
  5. void ValidateOrder(IEventService ctx)
  6. {
  7.     var orderId = ctx.GetVariable(ProcessVariableScopeEnum.Process, "OrderId")?.ToString();
  8.     var quantity = ctx.GetVariable(ProcessVariableScopeEnum.Process, "Quantity")?.ToString();
  9.     if (string.IsNullOrEmpty(orderId) || string.IsNullOrEmpty(quantity))
  10.         throw new InvalidOperationException("OrderId and Quantity are required.");
  11. }
  12. // 计算金额:单价 * 数量,返回 ServiceTaskResult 指定输出变量名
  13. object CalcAmount(IEventService ctx)
  14. {
  15.     var price = decimal.Parse(ctx.GetVariable(ProcessVariableScopeEnum.Process, "UnitPrice")?.ToString() ?? "0");
  16.     var qty = int.Parse(ctx.GetVariable(ProcessVariableScopeEnum.Process, "Quantity")?.ToString() ?? "0");
  17.     var total = price * qty;
  18.     return ServiceTaskResult.WithVariable("Var_OrderTotal", total);
  19. }
  20. // 通知结果:打印到控制台
  21. void NotifyResult(IEventService ctx)
  22. {
  23.     var total = ctx.GetVariable(ProcessVariableScopeEnum.Process, "Var_OrderTotal");
  24.     Console.WriteLine($"[NotifyResult] 订单总金额: {total}");
  25. }
  26. // 注册到全局委托表
  27. ServiceTaskDelegateRegistry.Global.Register("ValidateOrder", ValidateOrder);
  28. ServiceTaskDelegateRegistry.Global.Register("CalcAmount", CalcAmount);
  29. ServiceTaskDelegateRegistry.Global.Register("NotifyResult", NotifyResult);
复制代码
5.3 定义流程
  1. using Slickflow.Graph.Model;
  2. var wf = new Workflow("OrderCalcProcess", "OrderCalcProcess_Code");
  3. wf.Start("Start")
  4.     .ServiceTask("校验订单", "Validate001", "ValidateOrder")
  5.     .ServiceTask("计算金额", "Calc001", "CalcAmount")
  6.     .ServiceTask("通知结果", "Notify001", "NotifyResult")
  7.     .End("End");
复制代码
5.4 执行并打印结果
  1. var result = await new WorkflowExecutor()
  2.     .UseApp("OrderApp-001", "OrderApp")
  3.     .UseProcess(wf)
  4.     .AddVariable("OrderId", "ORD-2025-001")
  5.     .AddVariable("Quantity", "3")
  6.     .AddVariable("UnitPrice", "99.50")
  7.     .Run();
  8. Console.WriteLine($"Status: {result.Status}");
  9. Console.WriteLine($"Message: {result.Message}");
  10. // 从返回结果中获取输出变量(若引擎支持)
  11. var vars = result.Variables;  // 或通过 result 的扩展属性获取
  12. if (vars != null && vars.TryGetValue("Var_OrderTotal", out var total))
  13.     Console.WriteLine($"OrderTotal: {total}");
复制代码
5.5 输出示例
  1. [NotifyResult] 订单总金额: 298.50
  2. Status: Success
  3. Message: 流程执行成功
  4. OrderTotal: 298.50
复制代码
六、测试用例二:AI 多轮问答智能客服流程

6.1 流程说明

流程:开始 → RAG 智能回复 → 提取联系方式 → 保存客户 → 保存对话 → 结束。其中 RAG 节点调用大模型实现多轮问答,后续节点处理结构化数据。
6.2 定义流程
  1. using Slickflow.Graph.Model;
  2. using Slickflow.Module.External.Customer;
  3. var wf = new Workflow("ChatAppProcess", "ChatAppProcess_Code");
  4. wf.Start("Start")
  5.     .RagService("RAG 智能回复", "RAG001")
  6.     .ServiceTask<ContactExtractService>("提取联系方式", "Extract001")
  7.     .ServiceTask<ContactSaveService>("保存客户", "Save001")
  8.     .ServiceTask<ConversationService>("保存对话记录", "Msg001")
  9.     .End("End");
复制代码
6.3 执行流程
  1. var messageId = Guid.NewGuid().ToString("N");
  2. var sessionId = "sess-001";
  3. var userMessage = "你好,我想了解一下你们的产品,我叫张三,手机 13812345678";
  4. var result = await new WorkflowExecutor()
  5.     .UseApp($"ChatApp-{messageId}-{sessionId}", "ChatAppMessage")
  6.     .UseProcess(wf)
  7.     .AddVariable("user_message", userMessage)
  8.     .AddVariable("customer_id", "cust-xxx")
  9.     .AddVariable("session_id", sessionId)
  10.     .AddVariable("industry_id", "1")
  11.     .SetNotifyClient(sessionId, (sid, data) => Console.WriteLine($"[Notify] {sid}: {data}"))
  12.     .Run();
  13. // RAG 节点会将 AI 回复写入 ai_response
  14. var aiResponse = result.AiResponse;
  15. Console.WriteLine($"AI 回复: {aiResponse}");
复制代码
6.4 数据流说明

变量来源用途user_message调用方 AddVariable用户输入,RAG 与 ConversationService 使用ai_responseRAG 节点写回大模型生成的回复customerContactExtractService 写回提取的联系方式 JSONcustomer_id, session_id, industry_id调用方 AddVariable业务上下文七、LocalMethod 与 AI 节点技术要点

7.1 LocalMethod 执行链路


  • WorkflowExecutor.Run 推进到 ServiceTask 节点
  • WorkflowActivityExecutor 识别 ServiceDetail.Method == LocalMethod
  • 从 ServiceDetail.Expression 取出 delegateKey(如 "CalcAmount")
  • ServiceTaskDelegateRegistry 按 key 解析委托
  • 调用 ExecuteLocalMethodInExecutor 执行委托,传入 IEventService 上下文
  • 若委托返回 ServiceTaskResult,按其中指定的变量名写回;否则写回默认变量
7.2 ServiceTaskResult 自定义输出变量
  1. // 默认写回 ServiceResult
  2. return total;
  3. // 自定义变量名
  4. return ServiceTaskResult.WithVariable("Var_OrderTotal", total);
复制代码
7.3 AI/RAG 节点执行链路


  • 引擎识别活动类型为 AIService / RagService
  • 从 ai_activity_config 或扩展属性读取 AI 配置(SystemPrompt、Temperature 等)
  • 用 context.Variables 构建 prompt(如 user_message、历史对话)
  • 调用大模型 API(OpenAI、DeepSeek、通义千问等)
  • 将返回内容写入 ai_response 或配置的输出变量
  • 通过 SetNotifyClient 可实时推送流式输出到前端
八、开发建议

8.1 单元测试


  • 使用 UseProcess(workflow) 避免数据库依赖
  • 使用 ServiceTaskDelegateRegistry 或 WithDelegateRegistry(customRegistry) 注入 Mock 委托
  • 断言 result.Status 与 result.Variables 中的关键变量
8.2 多租户与隔离


  • 为不同租户创建独立的 ServiceTaskDelegateRegistry,通过 WithDelegateRegistry 注入
  • 流程变量中传递 tenantId,在 LocalMethod 内按租户路由
8.3 与人工审批流程的混合

同一流程中可混用自动节点与用户任务:自动节点执行完毕后引擎自动推进;遇到用户任务时流程暂停,等待人工办理后再调用 Run 继续。
九、总结

Slickflow 流程自动化运行通过以下机制实现:

  • 代码定义流程:Workflow 类支持 ServiceTask、RagService 等自动节点,BuildInMemory() 生成内存 ProcessEntity
  • 代码运行流程:WorkflowExecutor.UseProcess(workflow) 直接使用内存流程,无需数据库
  • LocalMethod:通过 ServiceTaskDelegateRegistry 注册本地方法,实现快速原型与嵌入式场景
  • AI 节点:RagService 结合向量检索与大模型,实现多轮智能客服
本文所述两个测试用例(订单金额计算、AI 智能客服)可直接在 Slickflow.ConsoleTest 或自建控制台项目中运行,供引擎开发人员参考与扩展。
参考资料


  • Slickflow.NET 工作流引擎关于AI大模型的应用实践

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册