如果说 RAG 是 Dify 的“海马体”(负责记忆),那么 Workflow 引擎无疑是它的“前额叶皮层”——负责逻辑推理、决策制定和任务编排。
Dify 的 Workflow 是一个可视化的、基于图(Graph-based)的编排系统。本篇作为 Workflow 系列的上篇,我们将深入 core/workflow 模块,剖析 Dify 是如何通过 DSL(领域特定语言)定义业务逻辑,并将前端拖拽的“图”转化为后端可执行的代码对象的。
核心代码路径:
api/core/workflow
1. 什么是 Workflow DSL?
在 Dify 中,用户在画布上拖拽生成的每一个 Workflow,最终都会被序列化为一个 JSON 对象。这个 JSON 就是 Dify 的 DSL。它描述了节点(Nodes)的存在以及它们之间的数据流向(Edges)。
1.1 数据结构概览
一个典型的 Workflow DSL 结构包含以下核心要素:
JSON
{
"graph": {
"nodes": [
{
"id": "llm_1",
"data": {
"title": "LLM 节点",
"type": "llm",
"model": { "provider": "openai", "name": "gpt-4" },
"prompt_template": "..."
},
"position": { "x": 100, "y": 200 },
...
}
],
"edges": [
{
"source": "start_node",
"target": "llm_1",
...
}
]
}
}
-
Nodes (节点): 定义了任务单元。包含
id(唯一标识)、data(业务配置,如提示词、模型参数)和type(节点类型)。 -
Edges (边): 定义了控制流。即“谁执行完之后轮到谁”。
-
View Data: 如
position等前端展示数据,后端在解析执行时通常会忽略,但在存储时必须保留以还原画布。
2. 核心抽象:Node (节点) 的设计
在后端代码 core/workflow/nodes 中,所有的节点都遵循严格的继承体系。
2.1 基类设计 (BaseNode)
所有具体节点(如 LLMNode, CodeNode, KnowledgeRetrievalNode)都继承自 BaseNode。这个基类定义了所有节点必须遵守的“契约”:
-
Config Schema (配置校验): 每个节点必须定义自己的配置结构验证规则(通常使用 Pydantic 或 Marshmallow),确保前端传入的
data字段合法。 -
Input/Output (输入输出): 显式定义该节点接受什么变量,输出什么变量。
-
Run (执行入口): 抽象方法
_run,子类必须实现具体的业务逻辑。
2.2 节点的多态实现
Dify 利用工厂模式根据 DSL 中的 type 字段实例化不同的节点类:
-
LLM Node: 封装了对
model_runtime的调用,处理 Prompt 组装和模型推理。 -
Code Node: 一个安全的沙箱环境(Sandbox),允许用户运行 Python/Node.js 代码片段来转换数据。
-
If/Else Node: 逻辑分支节点,它不产生新数据,而是决定控制流的走向。
3. 解析器:从 JSON 到对象 (The Parser)
当请求到达后端时,原始的 JSON 字符串是一堆死数据,无法直接运行。WorkflowParser (core/workflow/parser.py) 承担了“编译器”的角色。
3.1 解析流程
WorkflowParser 的工作主要包含三个步骤:
-
结构反序列化: 将 JSON 转换为 Python 字典和对象。
-
拓扑验证 (Validation):
-
连通性检查: 检查是否存在孤立节点。
-
环路检测: Workflow 通常是一个 DAG(有向无环图)。解析器需要检测是否存在死循环(虽然某些高级场景允许循环,但基础检查必不可少)。
-
起点/终点检查: 确保有 Start 节点和 End 节点。
-
-
变量引用解析 (Variable Selector Validation):
这是最复杂的一步。节点 B 想要使用节点 A 的输出,必须验证:
-
节点 A 是否是节点 B 的上游(Predecessor)。
-
节点 A 输出的变量名是否存在。
-
3.2 变量选择器 (Value Selector)
在 Dify 的 DSL 中,变量引用通常表示为一个数组,例如 ["llm_1", "text"]。
解析器会构建一个**变量池(Variable Pool)**的概念。在解析阶段,解析器会模拟遍历整个图,收集每个节点可能产生的 Output Schema,从而验证下游节点的引用是否合法。
4. 关键设计思考:逻辑与执行分离
Dify 的架构设计体现了一个重要的工程原则:定义与执行分离。
-
Definition Layer (
core/workflow/graph_engine): 负责构建图的结构,处理节点间的依赖关系。它只关心“图长什么样”。 -
Execution Layer (
core/workflow/runner): 负责真正的运行。它并不直接操作 JSON,而是操作由 Parser 生成的WorkflowGraph对象。
这种分离带来的好处是:
-
安全性: 在运行前就能拦截大部分配置错误。
-
可测试性: 可以单独测试 Parser 的校验逻辑,而无需真的去调用 OpenAI API。
-
扩展性: 新增一种节点类型,只需增加对应的 Node 类和 Schema 定义,无需修改图的核心解析逻辑。
5. 总结
core/workflow 的静态部分展示了 Dify 如何将复杂的业务逻辑抽象为结构化的数据:
-
DSL 是前后端通信的契约。
-
Node 是业务逻辑的封装单元。
-
Parser 是保证图结构合法、逻辑通顺的守门员。
理解了这些,你就看懂了 Dify Workflow 的“骨架”。
下期预告:
下一篇我们将进入 Dify Workflow 引擎(下)——拓扑排序与节点执行调度

477

被折叠的 条评论
为什么被折叠?



