← 工作流编排

可视化工作流引擎的数据模型怎么设计?流程复用时连线怎么复制?

中等 可视化工作流引擎 · 第 1 / 4 问 更新于 2026/09/29
工作流执行引擎数据模型低代码系统设计
本题落地项目AI企业流程编排系统

简化版

按「定义」和「运行」分开建表。定义三张:流程表说这是一条什么流程(编码、状态、是否可复用、归属人),节点表说每一步做什么,连线表说步骤之间怎么流转(起点、终点、条件、优先级)。运行两张:运行记录表记这一次跑出了什么,步骤日志表记每个节点的输入输出。节点类型很多时,用一张节点表加「类型 + JSON 配置」统一建模,执行引擎按类型分发。复制流程时,节点先逐个插入、记下「旧节点 ID → 新节点 ID」的映射,连线再按映射把起点和终点换成新 ID,否则副本的连线还指向原流程的节点。

详细版

定义(配置期)                          运行(执行期)
workflow       一条流程是什么            workflow_run       这一次跑出了什么
workflow_node  每一步做什么      ──▶     workflow_run_step  每一步的输入、输出、耗时
workflow_edge  步骤之间怎么流转
表关键字段设计要点
流程编码(唯一)、状态、是否启用、是否可复用、来源流程、归属人状态决定能不能被使用和复用
节点流程、编码(流程内唯一)、类型、通用内容字段、JSON 配置、输入变量、输出变量、画布坐标、启用所有类型共用一张表
连线流程、起点、终点、条件表达式、排序同一节点多条出边按排序依次判断
运行记录流程、发起人、输入、最终上下文、状态、耗时、错误失败也要落库
步骤日志运行、节点、节点名和类型快照、执行前上下文、输出、状态、耗时、顺序号节点后来被改,历史仍可读

复制流程三步:复制流程主记录(新编码、回到草稿、记来源)→ 逐个复制节点并记 ID 映射 → 按映射复制连线,映射不到的连线跳过。

完整版教学

一、为什么定义和运行要分开

一条流程会被运行成百上千次,定义只有一份。如果把运行结果写回定义表,比如在节点上存「上次输出」,同一流程两个人同时运行就会互相覆盖,也查不了历史。

定义:1 条流程 × 7 个节点 × 7 条连线         (改的时候才变)
运行:每天 500 次 × 每次 7 条步骤日志 = 3500 行 (每跑一次就追加)

两者的读写特征完全不同:定义表读多写少、要能随时编辑;运行表只追加、按时间和运行 ID 查询、量大需要清理策略。分开以后,编辑流程不影响正在查看的历史,历史数据也可以单独归档。

二、节点多态:一张表还是一类型一张表

节点类型有开始、知识检索、大模型、工具、条件、HTTP、结束等,每种要配的参数完全不同。两种建模方式:

方式做法优点代价
一张表 + JSON 配置公共字段做列,类型差异放 config_json加新类型不改表结构;连线、日志只需引用一张表配置字段没有数据库约束,要在保存时校验
一类型一张表每种节点一张子表字段强类型连线要引用多张表,加类型要建表改代码

低代码编排场景下新节点类型会不断增加,多数选第一种。常见的做法是把几个高频字段提成列:比如一个通用的「内容」字段,大模型节点存 Prompt、条件节点存判断表达式、HTTP 节点存请求体;输入变量、输出变量也是列,因为执行引擎每个节点都要读它们。其余参数(模型 ID、温度、知识库 ID、HTTP 方法、失败策略)放 JSON。

记忆钩子:执行引擎每一步都要读的字段做成列,只有某一类节点才用的参数放 JSON。

三、连线表要表达的三件事

连线不只是「从 A 到 B」,还要回答三个问题:

走不走:    condition_expression  为空表示无条件通过,否则按上下文求值
先判谁:    sort                  同一节点有多条出边时,按 sort 从小到大依次判断
显示什么:  label                 画布上连线旁的文字,如「需要记录工单」

一个条件节点后面接两条出边,一条条件是 needCreateTicket == true、排序 5,另一条是 needCreateTicket == false、排序 7。执行引擎按排序依次判断,取第一条为真的边。如果两条的条件写得有交集,排序就决定了谁优先,所以排序不是摆设。

四、保存时就要挡住的非法结构

图结构的错误越早拦越好,保存连线时至少校验:

校验防止什么
起点、终点都存在连线指向一个不存在的节点
起点和终点不能相同节点自己连自己
起终点都属于当前流程跨流程连线,复制和删除时出错
节点编码在流程内唯一(联合唯一索引)两个节点同名同编码,日志和配置对不上
删节点时先删它的连线节点没了、连线还指向它

有些问题在保存单条连线时发现不了,比如整条流程没有连线、连线形成了环。前者可以在「发布」时统一检查,节点数或连线数为 0 就不允许发布;后者在执行时用最大步数兜底,见「工作流执行引擎怎么按连线执行?条件分支和死循环怎么处理?」。

五、复制流程:ID 映射是关键

复用一条已发布的流程,本质是把「一张图」深拷贝一份。节点和连线都有自增主键,连线通过主键引用节点,所以不能各自照搬:

原流程节点 ID: 1  2  3  4  5  6  7
插入副本后:    8  9  10 11 12 13 14
映射表:       {1→8, 2→9, 3→10, 4→11, 5→12, 6→13, 7→14}

原连线 (6 → 5)  按映射改成  (13 → 12)
原连线 (6 → 4)  按映射改成  (13 → 11)

顺序必须是先复制节点、拿到新 ID,再复制连线。连线的起点或终点在映射里找不到(比如源数据里有脏连线),就跳过这条,不能插入一条指向原流程节点的连线。副本还要处理几个字段:编码加后缀保证全局唯一,状态回到草稿、默认不可复用,记下来源流程 ID 便于溯源,归属人改成当前用户。

六、状态与权限决定「谁能用、谁能改」

流程表的状态字段不只是展示用,它控制着流程的生命周期:

状态能做什么
草稿归属人可以编辑节点连线,可以发布
已发布可以运行;标记为可复用时,其他人也能看到并复制
已停用不再出现在运行入口,也不能被复用

多人使用时还要分清「看得到」和「改得了」:普通用户能看到自己的流程和别人已发布可复用的流程,但别人的流程只能复用、不能编辑和删除;要改就先复制成自己的草稿。运行记录和步骤日志同样要按发起人隔离,普通用户只看得到自己发起的运行。

七、步骤日志为什么要存快照

步骤日志引用节点 ID 就能关联到节点,为什么还要存节点名称和类型?因为节点会被修改甚至删除。三个月前的一次运行,节点那时叫「生成回复草稿」,现在被改成了「生成营销文案」,如果只存 ID,历史日志显示的就是现在的名字,排查时对不上。执行时把名称、类型拍成快照写进日志,节点后续怎么改都不影响历史记录。同理,执行前的完整上下文也存进日志,才能复现「这一步当时看到了什么」。

八、常见误区与追问

  • 误区:运行结果写回节点表最方便。 同一流程并发运行会互相覆盖,也查不了历史,运行数据要单独建表。
  • 误区:每种节点一张表更规范。 节点类型持续增加时,连线和日志要引用多张表,低代码场景多用一张表加 JSON 配置。
  • 误区:复制流程就是把节点和连线各复制一遍。 连线引用的是节点主键,必须按「旧 ID → 新 ID」映射改写,否则副本连到原流程。
  • 误区:连线的排序字段可有可无。 同一节点多条出边时按排序依次判断,条件有交集时排序决定走哪条。
  • 误区:步骤日志只存节点 ID 就够了。 节点会被改名或删除,日志要存名称和类型快照。
  • 追问:发布时应该校验什么? 至少校验节点和连线都不为空;更严格的还可以检查有没有开始和结束节点、有没有到不了的节点。
  • 追问:节点编码为什么是「流程内唯一」而不是全局唯一? 复制流程时节点编码原样照搬,全局唯一会让副本插不进去;流程内唯一既能区分节点,又不妨碍复制。

九、加强记忆

工作流数据模型记「三定义两运行」:流程表管身份和生命周期(编码唯一、草稿/已发布/已停用、可复用、来源),节点表用一张表加类型和 JSON 配置统一建模,每步都要读的输入输出变量做成列,连线表管走不走(条件)、先判谁(排序)、显示什么(标签)。运行记录和步骤日志只追加,失败也落库,日志存节点名称类型快照和执行前上下文。保存时挡住悬空、自连、跨流程的连线,发布时挡住空结构。复制流程先插节点记「旧 ID → 新 ID」映射,再按映射改写连线,映射不到就跳过,副本回到草稿、记来源。

项目实战落地

项目里怎么做的

《AI企业流程编排系统》用五张表撑起「配置 → 执行 → 观测 → 复用」:workflow 说是什么,workflow_node 说每步做什么,workflow_edge 说怎么流转,workflow_run 和 workflow_run_step 说跑出了什么。

  • 流程表:code 唯一索引;status 取草稿、已发布、已停用;另有 enabled、reusable、source_workflow_id、owner_user_id,节点数和连线数在增删节点连线时回写;
  • 节点表:开始、知识检索、大模型、工具、条件、HTTP、结束七种类型共用一张表,差异只在 node_type 和 config_json;prompt_content 按类型分别存 Prompt、判断表达式、请求体;(workflow_id, code) 联合唯一;
  • 连线表:condition_expression 和 sort;保存时校验起终点存在、不能相同、必须属于同一流程;删节点先删相关连线再删节点;
  • 发布与复用:发布前统计节点和连线,任一为 0 不允许发布;只有「已发布且可复用」的流程能复制,副本名称加「复用副本」、编码加 _COPY_ 和时间戳、回到草稿,节点逐条复制并记 nodeIdMap,连线按映射换成新节点 ID,映射不到的跳过;
  • 步骤日志:node_name、node_type 是执行时的快照,input_json 是执行本节点前的完整上下文。

示例流程「客户问题智能回复流程」是 7 个节点、7 条连线,每条连线都带条件,比如开始节点到知识检索那条是 customerQuestion != null。

为什么这样取舍

  • 一张节点表:执行引擎只需按 node_type 分发到不同执行方法,节点模型统一。
  • 复用必须连节点带连线:主表只有名称、场景、状态,真正的结构在节点和连线里,只复制主表得到的是空壳;复制后改副本的节点、Prompt 和连线条件都不影响原流程。

面试官还会追问

  • 大模型节点每次执行都新建一个 ChatClient 吗?管理员在后台改了 API Key,要重启才生效吗?
  • 步骤日志表里没有用户字段,普通用户「只能看自己的节点日志」是怎么实现的?

学完《AI企业流程编排系统》,上面这些追问你都会迎刃而解。

本题落地项目地狱锤炼AI企业流程编排系统基于Workflow、LLM节点、RAG节点、HTTP节点和Function节点,实现流程可视化编排、模板管理、工具调用、多步骤执行和运行日志追踪,适合AI编排观测和节点排查。SpringbootSpringAIWorkflowRAGLLM源码+SQL喂饭学习教程配套面试文档环境安装文档项目运行文档 学习这个项目