关于 dify-workflow-skills
用于创建、编辑和验证 Dify 工作流 DSL 文件的技能,面向构建 Dify 自动化工作流的场景。内容涵盖节点、连接、变量及错误处理模式。
主要功能
- 01根据描述生成工作流 YAML
- 02编辑节点与连接
- 03验证 DSL 结构
- 04设计分支、循环和错误处理
- 05查阅节点类型与工作流模式
适用场景
- 01创建新的 Dify 自动化工作流
- 02在现有工作流中增删节点
- 03检查节点 ID、连接和变量引用
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ mango-svip/ dify-workflow-skills --skill dify-workflow-skills安装后在 Claude Code 中输入/dify-workflow-skills确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
assets/simple_llm_workflow.ymlerror_handling_workflow.ymlconditional_workflow.ymlreferences/node_types.mdnode_positioning.mdworkflow_structure.mdedge_types.mdscripts/generate_id.pyvalidate_workflow.py详细介绍
Dify 工作流 DSL 构建器
构建、编辑和验证 Dify 工作流 DSL(领域特定语言)文件,以创建 AI 驱动的自动化工作流。
此技能基于 Dify 开源平台的工作流引擎,该引擎通过基于 React Flow 的可视化编辑器为 Workflow 应用和 Advanced Chat 应用提供支持。
架构概览
Dify 工作流采用基于队列、事件驱动的架构,包含:
后端(Python - 执行引擎)
- GraphEngine:负责管理工作流执行的中央协调器
- WorkerPool:用于并行执行节点的线程池
- VariablePool:集中管理各节点间的变量
- EdgeProcessor:处理条件路由和分支选择
- Graph Validator:在执行前确保工作流完整性
前端(React/TypeScript - 可视化编辑器)
- React Flow:基于画布的节点图编辑器
- Zustand Store:管理节点、边和视口状态
- WorkflowContext:向组件树提供工作流状态
- BaseNode:所有节点类型的通用封装,包含连接点、标题栏和交互功能
- 面板系统:为每种节点类型提供动态配置面板
- Hook 注入模式:将 UI 与执行逻辑解耦(草稿同步、工作流运行)
集成层
- workflow:核心画布引擎(通用 React Flow 实现)
- workflow-app:应用封装层(业务逻辑、API 集成、生命周期管理)
- 草稿管理:自动保存,并通过防抖和
sendBeacon提高安全性- 使用防抖同步,避免过多 API 调用
- 卸载时取消待处理的同步,避免竞态条件
- 使用
isWorkflowDataLoaded标志跟踪加载状态
- 功能系统:与工作流集成的可选功能(文件上传、语音转文本、引用)
- 触发器状态管理:独立的存储,用于跟踪触发器节点的启用/禁用状态
- 可独立启用或禁用触发器节点
- 状态会在工作流编辑器会话之间保留
- 用于 webhook、计划任务和插件触发器
核心功能
- 创建新工作流 - 根据描述生成完整的工作流 YAML 文件
- 编辑现有工作流 - 添加、修改或移除节点和连接
- 验证工作流 - 检查 DSL 语法和结构
- 设计复杂流程 - 构建包含 LLM 节点、代码执行、分支、循环和错误处理的工作流
- 错误处理策略 - 实现失败分支、重试或默认值错误处理
快速参考
节点类型:完整列表请参阅 references/node_types.md,包括:
- 核心流程:start、end、answer
- LLM 与 AI:llm、agent、parameter-extractor
- 逻辑与控制:if-else、question-classifier、loop、iteration
- 数据处理:code、template-transform、variable-aggregator、assigner、list-operator、document-extractor
- 外部集成:http-request、tool、knowledge-retrieval、knowledge-index、datasource
- 高级:trigger-webhook、trigger-schedule、trigger-plugin、human-input
边类型与连接:以下内容请参阅 references/edge_types.md:
- 源句柄类型(source、true/false、success-branch/fail-branch、loop)
- 边的数据属性和验证规则
- 常见连接模式
节点定位:以下内容请参阅 references/node_positioning.md:
- 画布坐标系和间距指南
- 布局模式(线性、分支、错误处理、迭代)
- 位置计算公式
常见节点属性:所有节点都支持以下内部属性(以 _ 为前缀):
_runningStatus:当前执行状态(running、succeeded、failed)_connectedSourceHandleIds/_connectedTargetHandleIds:连接跟踪_isSingleRun:用于调试的单次执行模式_isCandidate:拖动连接时显示的虚拟节点_children:容器类型节点(iteration、loop)的子节点_iterationLength/_iterationIndex:迭代状态跟踪_loopLength/_loopIndex:循环状态跟踪_retryIndex:当前重试次数_waitingRun:排队等待执行的 human-input
工作流结构:完整的 DSL 格式请参阅 references/workflow_structure.md
边类型:连接模式和句柄类型请参阅 references/edge_types.md
节点定位:布局指南请参阅 references/node_positioning.md
模板:请查看 assets/ 中的工作流示例
创建新工作流
步骤 1:了解需求
询问用户:
- 工作流应该做什么?
- 输入和输出是什么?
- 需要哪些处理步骤?
- 是否需要条件逻辑或错误处理?
步骤 2:设计节点流程
规划工作流结构:
- 开始节点 - 定义输入变量
- 处理节点 - LLM、代码、工具等
- 控制流 - 使用 if-else 分支,使用 loop 迭代
- 错误处理 - 在代码节点上使用 fail-branch
- 输出聚合 - 使用 variable-aggregator 合并分支
- 结束节点 - 定义输出
步骤 3:生成节点 ID
使用 scripts/generate_id.py 创建唯一的节点 ID:
python3 scripts/generate_id.py 5 # Generate 5 unique IDs
或者使用 Python/JavaScript 生成:
# Python
import time
node_id = str(int(time.time() * 1000))
// JavaScript (used in Dify frontend)
const nodeId = `${Date.now()}`
容器节点的特殊 ID 模式:
- 迭代/循环开始节点:
${parentNodeId}start - 示例:如果迭代节点 ID 为
1736668800000,其开始节点 ID 为1736668800000start
步骤 4:构建工作流
创建完整的 YAML 结构,包括:
- 顶层元数据(kind、version、app)
- App 部分(名称、描述、图标)
- 包含 features 和 graph 的 Workflow 部分
- 包含位置的节点数组
- 用于连接节点的边数组
使用的模板:从 assets/simple_llm_workflow.yml 开始构建基本流程
步骤 5:验证
检查工作流结构是否存在常见问题:
- 所有节点都有唯一 ID
- 所有边都引用现有节点 ID
- 开始和结束节点都存在
- 必需字段均已填写
- 变量引用使用正确的语法:
{{#node_id.field#}}
常见工作流模式
模式 1:简单 LLM 流程
开始 → LLM → 结束
使用场景:基础问答、文本生成
模板:assets/simple_llm_workflow.yml
模式 2:错误处理流程
开始 → 代码(带失败分支)→ [成功 → 聚合器] / [失败 → LLM 恢复 → 重试 → 聚合器] → 结束
使用场景:通过错误恢复实现可靠的数据处理
模板:assets/error_handling_workflow.yml
要点:
- 在代码节点上设置
error_strategy: fail-branch - 失败分支提供
error_message和error_type变量 - 使用变量聚合器合并成功和失败分支
- 在结束节点中引用聚合器输出
模式 3:条件路由
开始 → If-Else → [真 → 处理器 A] / [假 → 处理器 B] → 聚合器 → 结束
使用场景:根据内容/类型路由请求
模板:assets/conditional_workflow.yml
要点:
- If-else 有
true和falsesourceHandles - 使用比较运算符:contains、starts_with、is_empty 等
- 使用 logical_operator: "and" 或 "or" 组合条件
模式 4:循环处理
开始 → 循环 → [处理项目] → 循环结束 → 结束
使用场景:通过中断条件进行迭代处理
要点:
- 设置
loop_count以指定最大迭代次数 - 定义
break_conditions以提前退出 - 循环会在各次迭代之间保留状态
编辑现有工作流
添加节点
- 读取现有工作流文件
- 生成新的唯一节点 ID
- 将节点添加到
workflow.graph.nodes数组中,并包含:- 唯一 ID 和位置
- 节点类型和配置
- 正确的 sourcePosition/targetPosition
- 添加边,将新节点连接到
workflow.graph.edges - 更新任何依赖节点(例如结束节点的输出)
删除节点
- 确定要删除的节点 ID
- 从
workflow.graph.nodes中删除节点 - 删除所有引用该节点 ID 的边(作为源或目标)
- 更新引用了已删除节点输出的下游节点
修改连接
- 根据源节点和目标节点 ID 查找边
- 更新边的
source、target、sourceHandle或targetHandle - 更新边的
data.sourceType和data.targetType,使其与实际节点类型匹配 - 更新边的
id,遵循命名约定:{source_id}-{handle}-{target_id}-target
变量引用语法
变量由集中式的 VariablePool 管理,格式为:{{#node_id.field_name#}}
变量类型(VarType)
Dify 支持以下变量类型,以实现类型安全的数据流:
基本类型:
string:文本数据number:浮点数integer:整数boolean:true/false 值secret:加密的敏感数据(API 密钥、密码)
复杂类型:
object:JSON 对象file:单个文件引用array:通用数组array[string]:字符串数组array[number]:数字数组array[object]:对象数组array[boolean]:布尔值数组array[file]:文件数组array[any]:混合类型数组any:任意类型(请谨慎使用)
特殊类型:
contexts:知识检索结果iterator:迭代输入变量loop:循环输入变量
文件上传配置
使用文件输入类型(file、files、file-list)时,可以配置上传设置:
默认文件上传设置:
allowed_file_upload_methods: ['local_file', 'remote_url']
max_length: 5 # Maximum number of files
allowed_file_types: ['image'] # Options: image, document, audio, video, custom
allowed_file_extensions: [] # e.g., ['.pdf', '.docx']
上传方式:
local_file:从本地系统直接上传文件remote_url:从 URL 上传文件
文件类型类别:
image:图像文件(JPG、PNG、GIF 等)document:文档文件(PDF、DOCX、TXT 等)audio:音频文件(MP3、WAV 等)video:视频文件(MP4、AVI 等)custom:自定义文件类型(指定扩展名)
输入变量类型(InputVarType)
开始节点使用以下输入类型作为面向用户的变量:
text-input:单行文本输入paragraph:多行文本输入select:下拉选择number:数字输入checkbox:布尔复选框url:带验证的 URL 输入files:多文件上传file:单文件上传file-list:多文件列表json:JSON 输入(对象或数组)json_object:带模式验证的 JSON 对象contexts:知识检索上下文iterator:迭代变量loop:循环变量
变量选择器模式
变量模式正则表达式:{{#[a-zA-Z0-9_]{1,50}(?:\.[a-zA-Z_][a-zA-Z0-9_]{0,29}){1,10}#}}
选择器结构:[node_id, variable_name, ...optional_nested_keys]
- 第一个元素:生成该变量的节点 ID
- 第二个元素:变量名称或输出字段
- 其他元素:嵌套对象键或数组索引(适用于 FileSegment/ObjectSegment)
ValueSelector:DSL 中使用的数组格式(例如,['1732007415808', 'text'])
- 在 YAML 中表示为数组:
value_selector: ['node_id', 'field_name'] - 在提示词中转换为模板语法:
{{#node_id.field_name#}}
系统变量
可通过 sys 节点 ID 使用:
{{#sys.query#}}- 用户查询/输入{{#sys.files#}}- 上传的文件{{#sys.conversation_id#}}- 当前对话 ID{{#sys.user_id#}}- 用户标识符{{#sys.dialogue_count#}}- 对话轮数{{#sys.app_id#}}- 应用 ID{{#sys.workflow_id#}}- 工作流 ID{{#sys.workflow_run_id#}}- 当前执行 ID{{#sys.timestamp#}}- 当前时间戳
按节点类型划分的常见输出字段
LLM 节点:
{{#node_id.text#}}- 生成的文本响应(类型:string){{#node_id.usage#}}- Token 使用信息(类型:object){{#node_id.reasoning_content#}}- 模型推理内容(如已启用)(类型:string)
Agent 节点:
{{#node_id.usage#}}- Token 使用信息(类型:object)
代码节点:
{{#node_id.output_name#}}- 节点配置中定义的命名输出{{#node_id.error_message#}}- 错误消息(仅失败分支)(类型:string){{#node_id.error_type#}}- 错误类型(仅失败分支)(类型:string)
开始节点:
{{#node_id.variable_name#}}- 开始节点中定义的输入变量
条件分支节点:
{{#node_id.condition_result#}}- 布尔条件结果
循环节点:
{{#node_id.output#}}- 循环输出数组{{#node_id.iteration#}}- 当前迭代次数
HTTP 请求节点:
{{#node_id.body#}}- 响应正文(类型:string){{#node_id.status_code#}}- HTTP 状态码(类型:number){{#node_id.headers#}}- 响应标头(类型:object){{#node_id.files#}}- 响应为文件时下载的文件(类型:array[file])
工具节点:
{{#node_id.text#}}- 工具输出文本(类型:string){{#node_id.files#}}- 工具输出文件(类型:array[file]){{#node_id.json#}}- 工具输出 JSON(类型:array[object])
知识检索节点:
{{#node_id.result#}}- 检索到的知识片段(类型:array[object])
模板转换节点:
{{#node_id.output#}}- 转换后的输出(类型:string)
问题分类器节点:
{{#node_id.class_name#}}- 分类结果(类型:string){{#node_id.usage#}}- Token 使用信息(类型:object)
参数提取器节点:
{{#node_id.__is_success#}}- 提取成功标识(类型:number){{#node_id.__reason#}}- 提取失败原因(类型:string){{#node_id.__usage#}}- Token 使用信息(类型:object)- 以及节点配置中定义的自定义提取参数
变量聚合器:
{{#node_id.output#}}- 合并分支的聚合输出
文件对象结构(使用文件类型时):
name- 文件名(类型:string)size- 文件大小,单位为字节(类型:number)type- 文件类型类别(类型:string)extension- 文件扩展名(类型:string)mime_type- MIME 类型(类型:string)transfer_method- 使用的传输方式(类型:string)url- 文件 URL(类型:string)related_id- 相关资源 ID(类型:string)
知识检索结果结构:
{
"content": "",
"title": "",
"url": "",
"icon": "",
"metadata": {
"dataset_id": "",
"dataset_name": "",
"document_id": [],
"document_name": "",
"document_data_source_type": "",
"segment_id": "",
"segment_position": "",
"segment_word_count": "",
"segment_hit_count": "",
"segment_index_node_hash": "",
"score": ""
}
}
环境变量和对话变量
环境变量(在应用级别定义):
- 通过特殊节点 ID 访问:
env - 示例:
{{#env.API_KEY#}}
对话变量(会话状态):
- 通过特殊节点 ID 访问:
conversation - 示例:
{{#conversation.user_context#}}
变量用法示例
# In LLM prompt template
prompt_template:
- role: system
text: "You are a helpful assistant."
- role: user
text: "Process this input: {{#1732007415808.user_input#}}"
# In code node
variables:
- ["1732007415808", "user_input"]
- ["1732007420123", "processed_data"]
# Accessing nested object fields
text: "File name: {{#upload_node.files.name#}}"
text: "API response status: {{#http_node.status_code#}}"
节点定位
在画布上定位节点,确保视觉清晰:
布局常量(来自 Dify 前端):
NODE_WIDTH:240 像素X_OFFSET:60 像素(水平间距)NODE_WIDTH_X_OFFSET:300 像素(节点宽度 + 间距)Y_OFFSET:39 像素START_INITIAL_POSITION:{ x: 80, y: 282 }NODE_LAYOUT_HORIZONTAL_PADDING:60 像素NODE_LAYOUT_VERTICAL_PADDING:60 像素NODE_LAYOUT_MIN_DISTANCE:100 像素
容器节点内边距:
- 迭代/循环容器:
- 上:65,右:16,下:20,左:16
- 迭代/循环的 Z-index:1(容器),1002(子节点)
水平间距:相连节点之间为 300-400 像素
垂直间距:
- 同一层级:y 坐标相同
- 分支:偏移 150-200 像素
位置示例:
Start: x=80, y=282 # Initial position
LLM: x=380, y=282 # Start + NODE_WIDTH_X_OFFSET
Code: x=680, y=282
End: x=980, y=282
分支示例:
If-else: x=380, y=300
True branch: x=680, y=200
False branch: x=680, y=450
Aggregator: x=980, y=300
容器节点(迭代/循环):
- 容器内的起始节点:{ x: 24, y: 68 }(相对于容器)
- 子节点的
parentId设为容器 ID - 子节点的 Z-index(1002)高于容器(1)
详细布局模式和公式请参阅 references/node_positioning.md。
可视化编辑器集成
你创建的 DSL 会在基于 React Flow 构建的 Dify 可视化工作流编辑器中渲染。
DSL 如何映射到 UI
节点 → 画布上的可视化块,包括:
- 图标和标题(来自
type和title字段) - 连接手柄(根据节点类型和 error_strategy)
- 配置面板(右侧栏中的节点专属表单)
- 状态指示器(运行中、成功、失败)
边 → 连接节点的贝塞尔曲线,包括:
- 根据状态设置视觉样式(悬停、选中、运行中)
- 分支路径标签(true/false、分类标签)
- 成功/失败分支的颜色编码
视口 → 画布视图设置:
viewport:
x: 0 # Pan offset X
y: 0 # Pan offset Y
zoom: 1.0 # Zoom level (0.1 to 2.0)
前端组件架构
将 DSL 加载到编辑器时:
- WorkflowContextProvider 使用节点/边初始化 Zustand 存储
- ReactFlow 使用自定义节点组件渲染画布
- BaseNode 为每个节点封装通用 UI(连接手柄、标题栏)
- 面板系统 在选中节点时显示配置表单
- Hook 系统 管理草稿自动保存和执行
DSL 中不包含的 UI 功能
这些仅限 UI 的属性由前端管理(不要包含在 DSL 中):
_hovering、_connectedNodeIsHovering:鼠标交互状态_connectedSourceHandleIds、_connectedTargetHandleIds:根据边计算得出_runningStatus、_singleRunningStatus:运行时执行状态_isCandidate:连接拖动过程中的临时虚拟节点selected:节点选中状态
重要:DSL 中只包含持久化属性(id、type、title、position、configuration)。运行时 UI 状态由编辑器计算。
错误处理策略
错误策略
Dify 支持在节点配置中定义多种错误处理策略:
1. fail-branch(推荐用于代码/HTTP 节点):
- 出错时创建备用执行路径
- 提供
error_message和error_type变量 - 在边配置中使用
sourceHandle: "fail-branch" - 成功路径使用
sourceHandle: "success-branch" - 需要使用变量聚合器在继续到结束节点之前与成功路径合并
- 支持平稳恢复错误和自定义错误处理逻辑
2. default-value:
- 出错时返回预定义的默认值
- 继续主执行路径,不进行分支
- 比 fail-branch 简单,但可靠性较低
- 适用于可接受回退值的非关键操作
3. abort(默认):
- 失败时停止整个工作流的执行
- 无需额外配置
- 用于无法恢复的错误
4. retry:
- 可配置重试逻辑,包括最大重试次数和间隔
- 在节点的
retry_config部分定义 - 适用于暂时性故障(网络问题、速率限制)
- 支持的节点:仅限 LLM、工具、HTTP 请求和代码节点
重试配置结构:
retry_config:
max_retries: 3 # Maximum retry attempts (default: 3)
retry_interval: 100 # Interval between retries in ms (default: 100)
实现 fail-branch 错误处理
在节点配置中:
error_strategy: fail-branch
在边数组中:
# Success path
- id: code_node-success-branch-next_node-target
source: code_node_id
target: aggregator_id
sourceHandle: success-branch
targetHandle: target
# Failure path
- id: code_node-fail-branch-error_handler-target
source: code_node_id
target: error_handler_id
sourceHandle: fail-branch
targetHandle: target
fail-branch 中可用的错误变量:
{{#node_id.error_message#}}- 人类可读的错误说明{{#node_id.error_type#}}- 错误类型分类
验证清单
在完成工作流之前,请验证:
结构验证
- 所有节点 ID 均唯一且格式正确(数字字符串或有效标识符)
- 工作流恰好有一个根节点(开始、数据源或触发器节点)
- 工作流至少有一个结束节点
- 所有边均引用节点数组中存在的有效源节点和目标节点 ID
- 不存在会造成无限循环的循环依赖(有意使用的循环节点除外)
- 根节点已正确识别且可访问
边和连接验证
- 所有边 ID 均唯一
- 边的
sourceHandle值与节点类型相匹配:- 标准节点:
"source"(默认) - If-else/问题分类器:
"true"、"false"或分类标签 - 带错误处理的代码/HTTP 节点:
"success-branch"或"fail-branch" - 循环节点:用于继续执行的
"loop"
- 标准节点:
- 对于大多数节点,边的
targetHandle通常为"target" - 边的
data.sourceType与实际源节点类型相匹配 - 边的
data.targetType与实际目标节点类型相匹配 - 分支路径(来自 if-else、问题分类器)均为所有可能结果配置了边
- 使用
error_strategy: fail-branch时,存在 fail-branch 边
变量和数据流验证
- 变量引用使用正确语法:
{{#node_id.field#}} - 所有引用的变量均存在于上游节点(在当前节点之前执行的节点)中
- 变量选择器与引用节点的实际输出字段相匹配
- 系统变量使用正确的
sys前缀:{{#sys.query#}} - 如有需要,环境变量使用
env前缀 - 不存在会导致运行时错误的未定义变量引用
错误处理验证
- 使用
error_strategy: fail-branch的节点同时具有成功边和失败边 - 分支路径在到达结束节点之前通过变量聚合器合并
- 变量聚合器接收来自所有分支路径的输入
- 使用
error_strategy: default-value时,已提供默认值 - 使用重试策略时,重试配置有效(最大重试次数、间隔)
节点配置验证
- 每种节点类型都包含必填字段(参见 node_types.md)
- 设置节点位置以进行可视化布局(x、y 坐标)
- LLM 节点具有有效的模型配置(provider、name、mode)
- Code 节点指定了有效的语言(python3 或 javascript)
- HTTP 请求节点具有有效的 URL 和方法
- Loop 节点具有有效的
loop_count和中断条件 - If-else 节点具有结构正确且运算符有效的条件
工作流执行验证
- 没有不可达节点(所有节点都能从根节点到达)
- 所有执行路径最终都会到达 end 节点或 answer 节点
- 容器节点(iteration、loop)具有正确的开始/结束节点对
- 人工输入节点使用得当(工作流会暂停以等待输入)
- Trigger 节点(webhook、schedule)不能与标准 start 节点混用
节点执行类型
Dify 根据节点的执行行为对其进行分类。了解这些类型有助于设计正确的工作流:
EXECUTABLE(标准逻辑节点)
执行逻辑并生成输出。最常见的节点类型。
- 示例:llm、code、http-request、knowledge-retrieval、template-transform
- 行为:满足所有输入依赖项后执行
- 源句柄:
"source"(或在错误处理中使用"success-branch"/"fail-branch") - 输出:由节点类型定义(参见“变量参考”部分)
BRANCH(条件路由节点)
根据条件在多条路径中进行选择,以控制流程。
- 示例:if-else、question-classifier
- 行为:评估条件并激活一条或多条输出边
- 源句柄:
- If-else:
"true"、"false" - Question-classifier:分类标签(自定义)
- If-else:
- 重要提示:未选中的路径会标记为“skipped”,其下游节点不会执行
CONTAINER(子图管理)
通过迭代或循环管理嵌套执行上下文。
- 示例:iteration、loop
- 行为:多次执行内部子图
- 组件:
- 父容器节点
- 内部开始节点(iteration-start、loop-start)
- 内部结束节点(iteration-end、loop-end)
- 源句柄:
"loop",用于继续迭代/循环 - 状态管理:维护循环变量和迭代次数
RESPONSE(输出流)
实时向用户流式传输输出。
- 示例:answer、end
- 行为:输出结果,并可能完成工作流
- 用法:Answer 节点可以出现在工作流中途;End 节点会终止执行
ROOT(入口点)
作为工作流的入口点。
- 示例:start、datasource、trigger-webhook、trigger-schedule、trigger-plugin
- 行为:第一个执行的节点;没有入边
- 重要提示:每个工作流只能有一个根节点
- 约束:标准 start 节点和 Trigger 节点不能共存
支持输出变量的节点
以下节点类型可以生成供其他节点引用的输出变量:
- Start、TriggerWebhook、TriggerPlugin
- LLM、Agent
- KnowledgeRetrieval
- Code
- TemplateTransform
- HttpRequest
- Tool
- VariableAssigner、VariableAggregator
- QuestionClassifier
- ParameterExtractor
- Iteration、Loop
- DocumentExtractor(DocExtractor)
- ListFilter(list-operator)
- DataSource
注意:不在此列表中的节点(如 if-else、end、answer)通常不会生成可复用的输出变量,不过其中一些节点可能具有有限的内部状态。
工作流执行模型
执行流程
- 初始化:GraphEngine 将根节点加入 ReadyQueue
- 工作线程执行:工作线程从 ReadyQueue 拉取节点并执行
- 事件发出:工作线程将事件(started、succeeded、failed)推送到 event_queue
- 边处理:Dispatcher 处理事件并识别下游节点
- 依赖解析:依赖满足时,将下游节点加入 ReadyQueue
- 并行执行:多个工作线程并发执行互不依赖的节点
- 完成:End 节点执行完毕或执行失败时,工作流结束
边状态
执行期间,边可能处于以下三种状态:
- UNKNOWN:初始状态,尚未评估
- TAKEN:边已遍历(条件满足或路径已选定)
- SKIPPED:边未遍历(条件不满足或选择了替代路径)
工作流执行状态
工作流会经历以下状态:
- SCHEDULED:已排队但尚未启动
- RUNNING:正在执行
- SUCCEEDED:已完成且无错误
- FAILED:因未处理的错误而终止
- PARTIAL_SUCCEEDED:已完成,但存在已处理的错误(通过 fail-branch 或 default-value)
- STOPPED:已手动停止或中止
- PAUSED:正在等待人工输入(human-input 节点)
节点运行状态
单个节点会通过以下状态跟踪其执行状态:
- NOT_START:节点尚未开始执行
- WAITING:节点已排队,正在等待执行
- LISTENING:节点正在监听事件(触发器节点)
- RUNNING:节点正在执行
- SUCCEEDED:节点已成功完成
- FAILED:节点因未处理的错误而失败
- EXCEPTION:节点执行失败,但错误已得到处理
- RETRY:节点在失败后重试
- STOPPED:节点执行已停止
重要的 UI 状态属性(仅运行时,不在 DSL 中):
_runningStatus:当前执行状态_singleRunningStatus:运行单个节点时的状态_waitingRun:节点已排队等待执行_retryIndex:当前重试次数_isSingleRun:节点处于单次运行调试模式
执行最佳实践
- 并行与顺序:互不依赖的节点会自动并行执行。需要时使用边强制按顺序执行。
- 错误边界:在关键节点上使用 fail-branch,防止工作流中止
- 合并点:在分支汇合前,始终使用 variable-aggregator 合并分支
- 循环安全性:设置合理的
loop_count限制和明确的中断条件 - 人工输入:使用 human-input 节点时,应考虑工作流暂停状态
资源
scripts/
generate_id.py- 为工作流生成唯一的节点 IDvalidate_workflow.py- 验证工作流 DSL 语法(需要 PyYAML)
references/
node_types.md- Dify 所有节点类型的完整参考及示例workflow_structure.md- DSL 结构和格式规范详解
assets/
simple_llm_workflow.yml- 基本的 start→LLM→end 模板error_handling_workflow.yml- 包含 fail-branch 错误处理的模板conditional_workflow.yml- 包含 if-else 分支的模板
成功提示
- 从简单开始:先构建基本流程,再逐步增加复杂性
- 使用模板:改造现有模板,而不是从头开始
- 尽早验证:添加大量节点前先检查结构
- 规划错误处理:考虑可能发生的错误以及如何处理
- 清晰命名:使用描述性节点标题,便于维护
- 参考文档:查阅 node_types.md,了解字段要求
- 逐步测试:逐步构建并测试工作流