类似Coze的工作流编排系统设计
引言
大叔最近一年一直在忙一个工作流编排系统,这是一个国民级大厂的项目。这里面有很多自认为不错的设计,今天就和大家一起分享交流一下,如果你有不同看法,欢迎评论区交流讨论。
主要分4点来讲
- 工作流编排的概念,和应用场景,其场景比较广泛,大概率你所在企业会遇到。
- 演示一下编排系统,让大家有个直观感受。
- 对比下与其它编排系统的不同,以及我为什么这样去设计?
- 最后讲一下里面用到的技术栈
一、什么是工作流编排
简单讲就是通过可视化的编辑器,通拖拉拽自动构建业务流程,主要用于企业各应用的快速集成,或快速对接第三方开放平台。
估计很多人会疑问?“这不就是后端的低代码吗?拖拖拽拽 还不如我直接写代码实现的快” 其实这个拖拽不是重点,重点是里面的业务场景,举个例子:
案例一: 关于企业应用集成问题
只要有一定规模的企业,它内部绝对不止一套IT系统,有OA、ERP、CRM、供应商管理等.. 大概率这些都来自不同供应商,采用不同的架构和协议,在加上各系统频繁变动,导致对接和维护成本非常高,谁也不原意去适配另一方。
添加图片注释,不超过 140 字(可选)
再回到刚刚问题,你可以硬编排直接实现,但是你的老板会让你这么做么?肯定不会,这样成本就加在公司身上了。
案例二:系统架构更新
再举个例子:假设公司架构要进行一次大迁移,由原来单体式架构,换成分布式架构,数据库从Oracle换成MySql, 淘宝当年就干过这事,换的过程中业务不能中断,原来整套架构保留,然后逐步切换到新架构中来。切换过程中老旧接口适配的问题,这个适配逻辑在哪写呢? 在旧的应用中写频繁更新升级将导致现有业务不稳定,在新架构中写 这又是一些临时逻辑,以后迁移稳定了,是没法做剥离的。 这种适配逻辑可全部写在编排层好处如下:
- 避免上下游改动,保证原业务稳定性 和让新架构更纯粹专注。
- 新旧业务切换灵活,基于自定义规则逐步逐量切换。
- 增强可用性,新业务出问题,自动切换回旧业务。
- 后期剥离成本低,直接暂停或删除就行了。
其它典型应用场景:
- 第三方开放平台快速集成
通过现成应用连接器与业务场景模板 ,可快完成业务集成,降低集成成本。
- 企业内部应用集成,解决信息孤岛问题:
企业各系统通常由多方参与,企业有集成需求,但由于需求易变各方都不愿为对方做兼容开发,编排系统可在中间做兼容适配,其灵活编排的特性可快速响应接口变化。
- 底层架构升级:
原业务代码不能动,新架构不方便兼容旧接口后期剥离成本大,可通过编排做中间适配,兼容调用方和提供方,上线稳定之后直接剥离。
- 与低代码平台集成,提供后端流程快速实现
- 与Apisix网关集成,提供可编排网关解决方案:
使系统运维人员能独立进行项目集成,具备改造或适配API的能力。或提供协议转换适配的能力
- 嵌入内部应用,为前端提供个性化接口:
前端人员可根据需求自行编排、转换接口,或作为mock服务使用。等同于BFF架构实现,后期通过扩展可直接兼容graphql等。
二、工作流编排演示:
编排的元素组成
添加图片注释,不超过 140 字(可选)
如上图所示编排系统由5个关键点组成,其核心是流程,通过触发器进入流程引擎,接着在引擎中调用、内部外部应用 以及中间件来实现业务。
一个编排集成系统这对这5个元素支持的深度与广度决定了它的能力范围,支持的越多能力越强。
下图关于触发器、协议以及中间件的支持:
添加图片注释,不超过 140 字(可选)
关于应用支持:
添加图片注释,不超过 140 字(可选)
简单流程演示
现在通过一个简单的示例 逐步认识该系统:
首先通过拖拽生成一个流程如下图,他调用一个API获取天气信息,然后判断天气是否太热(大于26度),根据判断返回不同的建议信息。
添加图片注释,不超过 140 字(可选)
这里关键是http节点的编辑,其有一个city城市参数是外部传入的,所以用input.city 表达示.
input是一个隐示对象表示各触发器传入流程的输入参数
添加图片注释,不超过 140 字(可选)
接下来点击右下角按钮即可进行测试,至止就完成了一个简单流程演示:
添加图片注释,不超过 140 字(可选)
为保证灵活性 所有的流程编辑保存后需要实时得以体现,这是一个编排系统基础操作,限于篇幅就不演示了.现在演示一个更为复杂的流程,即现在比较火AI工作流。
AI生成新闻稿件(复杂流程)
添加图片注释,不超过 140 字(可选)
这是一个生成新闻稿件的流程,总共有五步:
- 查询百度当前的热榜
- 循环获取热榜列表前10条的描述,并组成一个新列表
- 获取指定城市天气
- 将热榜描述与天气信息一起发给Kimi大模型生成稿件
- 将稿件发送到钉钉群中去。
主要复杂点在于第2步的迭代和第四步的大模型参数的封装。关于第2步又分成了4小步:
添加图片注释,不超过 140 字(可选)
- 输入:即获取上一步的结果列表
- 限数:取前10条
- 取描述:获取每一项中的描述字段
- 返回列表:将描述组成一个新列表返回
这里我没有采用一般编排系统中的流程循环来实现,其在流程图中表现过于复杂,所以我采用的是pipeline设计,所有数据依次进入管道 经过多个中间节点计算后 最后返回结果,其实现依赖java8 中的Stream流。
有个问题是Stream流是不允许有分支的,如果不同的数据需要分开进行计算怎么办呢?这就应该采用多个管道流,每个管道流负责一批数据的业务处理。
如果分支中又嵌套着分支,这将导致管道的数量急剧增多,那这复杂情况 费劲用图表示出来也很难看懂,这种只能交给“脚本”这个万金油方案了。
关于第四步中的大模型json参数其实也没啥好办法还得是脚本拼接:
添加图片注释,不超过 140 字(可选)
最后测试一下效果:
添加图片注释,不超过 140 字(可选)
其它功能
获取热榜与天气二者不存关联,完全可以并发执行 就像下面这样:
添加图片注释,不超过 140 字(可选)
三、双向编辑设计
双向编辑的特性
关于这里的设计亮点很多,如果只挑一个重点来讲就是双向编辑,意思是DSL(特定领域语言)与设计器互通,用户可选择编辑dsl文本来构建流程、也可以通过设计器拖拽来生成流程,并且这两种方式随时可以切换。
添加图片注释,不超过 140 字(可选)
上图所示 左边dsl文本中的每个任务都与流程图中节点对应,无论你在哪一边的编辑都会在另一边得以体现。
这么设计目的是解决编排系统的易用性与灵活性的问题,这是各编排系统或低代码平台普遍存在的一个问题。如果设计做的很强大很灵活,那么它整个编辑操作就变得很复杂,频繁打开各种窗口填写表单,一圈下来 发现还不如直接写代码来的快,所以很多程序员都抵触低代码。
但没有设计器直接编辑dsl对于用户的上手门槛比较高,即使一些简单场景 他也需要学习你的DSL语法,如果用户没有编程基础学习曲线将会更陡峭,比如功能测试人员或基础运维人员。
双向编辑就可以解决这个问题,想要“易用”就用设计器,想要“灵活快速”就直接编辑DSL ,复制粘贴就按平常的编码习惯来。
基于Groovy的DSL设计
要做到双向编辑,DSL设计是关键,这里DSL设计是基于Groovy实现,灵感来源于java构建工具Gradle。这种dsl是简化后的Groovy代码 所以是可以直接编辑的,此外主体结构进行规范化限制 不会像纯脚本代码一样的显的很乱。后面还可以加上像ide一样的语法错误提示、快捷提示等语法服务,编辑体验将进一步提升。
以下是dsl示例,只要你有一定编程基础 绝对能看懂一个大概:
/*构建时间:2025年5月21日 下午5:36:21*/
//调用http
http_1 = HTTP {
params["key"] = "Eu2TRjLPdS*****g3SsUntOgVg"
params["city"] = input.city //输入参数
method = "GET"
requestType = "formData"
url = "https://qqlykm.cn/api/weather/get"
}
//天气是否太热?
BOOLE_1 = BOOLE {
http_1.result.current_temperature > 26
}
//呆在家里
eval_1 = EVAL {
"当前温度${http_1.result.current_temperature}太热了还是在呆在家里吧"
}
//出门旅行
eval_2 = EVAL {
"当前温度${http_1.result.current_temperature}天气很好,建议出门放松好心情"
}
start {
run http_1
when BOOLE_1,eval_1,eval_2
}
这种设计还有个好处就是扩展性强,扩展一个新节点就像代码中添加一个函数那么简单,其底层依托于groovy不需要额外编写引擎对它进行解析。
双向编辑的弊端
但是弊端也很明显就是实现成本高设计器很复杂,从dsl文本到设计器图表需要4个转换步骤:
添加图片注释,不超过 140 字(可选)
图中的第1、4步由相关框架实现,但第2、3以及中间模型的设计都是实打实的工作量。但这就完了?当从设计器再转到dsl文本的时候又是沉甸甸的工作量:
添加图片注释,不超过 140 字(可选)
第一步由vueflow流程图框架实现,第2、3步则需自己实现。
其它编排系统的DSL就简单多了,比如n8n和Dify的DSL分别采用json与yml格式进行存储,dsl内容本身就是流程图模型数据,同时附带了逻辑执行相关的参数,所以在设计器中打开这个dsl几乎无需额外的转换,可直接打开。
但它的弊端就是引擎扩展成本高,每增加一个任务或其它特性引擎就需要写相关解析与执行代码,还有这种DSL很难直接编辑,1是结构复杂编辑的元素多记不住,2是无法提供语法服务。
下图是n8n的dsl示例:
添加图片注释,不超过 140 字(可选)
下图是Dify的示例采用yaml结构,同样存储节点、边线、以及逻辑参数:
添加图片注释,不超过 140 字(可选)
总结一下
基于groovy dsl设计的可进行双向编辑,引擎扩展能力强,弊端就是设计器实现复杂。而采用json或yaml的常规dsl设计,设计器实现方便,但无法进行双向编辑 ,当到达一定规模后就得面临易用性与灵活性的平衡
基于groovy的dsl设计 | 基于yaml或json的Dsl设计 | |
---|---|---|
引擎实现 | 简单 | 复杂 |
引擎扩展 | 简单 | 复杂 |
设计器实现 | 复杂 | 简单 |
是否可双向编辑 | 是 | 否 |
关于作者:
写了十几年代码,干了五六年技术培训,当前算是自由职业(IT临时工),最近一年一直在为某大厂做api编排解决方案与实现,如果你或你的公司有相关工作流集成需求,或有自建工作流编排系统的想法 欢迎找大叔咨询交流。 为个人和企业提供全套解决方案培训,加我微信z276386551看大纲、内容丰富、价格喜人、中年码农挣口饭吃,非诚勿扰感谢理解。