工作流节点设计理念:可组合性、人机交互、确定性节点与概率性节点并存
简介
Dify的Workflow不仅仅是一个“调用LLM的流程图”。其设计理念的核心是明确区分人工智能可以自主处理的领域和人类必须做出决策的领域,并使它们共存于单一流程中。
本文详细解释了支持 Dify Workflow 节点设计的四个设计原则:可组合性、人机交互 (HITL)、确定性和概率性节点的正确使用以及错误处理模式。
1. Workflow基本架构
1.1 节点和边缘配置
Dify Workflow 表示为有向无环图 (DAG):
graph LR
START((Start)) --> A[LLM Node]
A --> B{IF/ELSE}
B -->|条件A| C[Knowledge Base]
B -->|条件B| D[HTTP Request]
C --> E[LLM Node 2]
D --> E
E --> F[Human Review]
F -->|承認| G[HTTP Request<br/>外部API送信]
F -->|差し戻し| A
G --> END((End))
1.2 节点分类系统
Dify的Workflow节点根据其特点可以分为以下几类:
| 类别 | 节点类型 | 输出的性质 | 执行时间 |
|---|---|---|---|
| 概率节点 | LLM,问题分类器 | 非确定性(相同输入,不同输出) | 中长 |
| 确定性节点 | IF/ELSE、代码、模板、变量 | 确定性(相同输入,相同输出) | 短 |
| 外部联动节点 | HTTP 请求、工具 | 外部依赖 | 变量 |
| 数据节点 | 知识检索、变量聚合器 | 取决于搜索结果 | 中等 |
| 人工干预节点 | 人工输入(待机型) | 取决于人的判断 | 未定义 |
| 控制节点 | 开始、结束、迭代、参数提取器 | 流量控制 | 短 |
2. 可组合性:组合节点的可能性
2.1 设计原则
Dify Workflow 中的可组合性基于以下原则:
- 每个节点都有独立的输入/输出接口:节点之间唯一的依赖关系就是变量的传递。
- 无论节点类型如何,连接协议相同:LLM节点和HTTP节点可以采用相同的方式连接
- 嵌套和引用分离:变量引用是显式的,没有隐式的全局状态
graph TB
subgraph "コンポーザビリティの原則"
direction LR
subgraph "ノード A"
A_IN[入力変数] --> A_PROC[処理ロジック]
A_PROC --> A_OUT[出力変数]
end
subgraph "ノード B"
B_IN[入力変数] --> B_PROC[処理ロジック]
B_PROC --> B_OUT[出力変数]
end
A_OUT -->|"変数参照"| B_IN
end
2.2 变量范围模型
工作流中的变量遵循以下范围规则:
| 范围 | 描述 | 访问 |
|---|---|---|
| 节点本地 | 用于节点内部处理 | 仅在节点内 |
| 节点输出 | 节点处理结果 | 由下游节点 {{node_id.output}} 引用 |
| 工作流程输入 | Start 节点 | 中定义的输入参数由{{start.input_name}}从所有节点引用 |
| 环境变量 | 工作流程级别常量 | 从所有节点可见 |
| 对话变量 | 聊天型工作流程中跨对话保留 | 可以从所有节点引用和更新 |
通过这种设计,节点只需要知道“自己的输入和引用节点的输出”,而不需要知道整个工作流的状态。这是可组合性的基础。
2.3 迭代节点:迭代的可组合性
Iteration 节点对数组数据重复执行子流程。这使得无法用单个节点表达的复杂处理可以通过可组合的方式实现:
graph TB
START((Start)) --> SPLIT[Code Node<br/>文書を章ごとに分割]
SPLIT --> ITER[Iteration Node]
subgraph ITER[Iteration: 各章に対して]
I_LLM[LLM Node<br/>要約生成]
I_LLM --> I_QA[LLM Node<br/>QA 生成]
end
ITER --> AGG[Variable Aggregator<br/>結果統合]
AGG --> END((End))
3. Human-in-the-Loop (HITL):以人为本的设计理念
3.1 为何采用人机交互?
人工智能变得越自主,人类控制就变得越重要。这并不矛盾,而是风险管理的基本原则:
graph TB
subgraph "AI 自律性と人間制御のマトリクス"
direction TB
A["低リスク x 高自動化<br/>完全自動処理<br/>例: FAQ 自動回答"]
B["高リスク x 高自動化<br/>AI ドラフト + 人間承認<br/>例: 契約書レビュー"]
C["低リスク x 低自動化<br/>手動 + AI アシスト<br/>例: 創造的文書作成"]
D["高リスク x 低自動化<br/>人間主導 + AI 補助<br/>例: 法務判断"]
end
3.2 HITL的三种模式
根据公共文档,Dify 工作流程中的人机交互以三种模式运行:
审批模式
人类审查并批准或拒绝人工智能生成的结果:
graph LR
A[LLM Node<br/>回答ドラフト生成] --> B[Human Input<br/>承認/却下]
B -->|承認| C[HTTP Request<br/>顧客に送信]
B -->|却下| D[LLM Node<br/>再生成]
D --> B
适用场景:
- 自动为客户生成电子邮件后发送前确认
- 合同条款人工智能审核结果的法律确认
- 主管批准批准文件草案
####修正模式
人类可以直接编辑AI生成的结果:
graph LR
A[LLM Node<br/>レポート生成] --> B[Human Input<br/>内容修正可能]
B --> C[Template Node<br/>フォーマット適用]
C --> D[HTTP Request<br/>レポート保存]
适用场景:
- 更正了人工智能生成的报告中的数字和表达式
- 调整翻译结果的细微差别
- 修正技术文件中的术语
升级模式
如果人工智能的置信度较低,则自动升级为人类:
graph TB
A[LLM Node<br/>問い合わせ分類] --> B{IF/ELSE<br/>確信度チェック}
B -->|確信度 > 0.8| C[自動回答]
B -->|確信度 <= 0.8| D[Human Input<br/>担当者対応]
D --> E[回答送信]
C --> E
适用场景:
- 自动客户支持响应/升级判断
- 根据OCR识别结果的可靠性进行人工验证
- 自动/手动分类投诉
3.3 HITL 设计注意事项
| 注意事项 | 说明 | 建议行动 |
|---|---|---|
| 超时 | 没有收到人类响应时该怎么办 | 设置默认行为(升级或保留) |
| 并行处理 | 当多个审批队列同时发生时 | 审批队列管理和优先级设置 |
| 审计追踪 | 谁批准/修改了什么以及何时 | 操作日志持久化 |
| 权限管理 | 控制具有审批权限的用户 | 与工作区角色设置链接 |
| 服务水平协议 | 管理审批等待时间 | 配置警报通知 |
4.确定性节点和随机性节点并存
4.1 为什么这种区别很重要?
设计工作流时要认识到的最重要的一点是,输出的可预测性因节点而异:
| 节点类型 | 输出属性 | 测试方法 | 错误处理 |
|---|---|---|---|
| 确定性(代码,IF/ELSE) | 相同的输入,相同的输出 | 可进行单元测试 | 已修复错误 |
| 随机(LLM) | 相同输入有不同输出的可能性 | 需要统计评估 | 提示/参数调整 |
如果不了解这种区别,就会出现以下问题:
- 后续处理无法准确解析LLM节点的输出(格式不稳定)
- 它在测试期间有效,但在生产期间出现不同的输出(缺乏再现性)
- 无法确定错误原因是LLM 输出还是逻辑。
4.2 确定性节点的作用
确定性节点为工作流提供可预测性和可控性:
# Code ノードの例:LLM 出力の正規化
def main(llm_output: str) -> dict:
"""
LLM の確率的な出力を、確定的な構造に変換する。
これにより、後続ノードは安定したデータ形式に依存できる。
"""
import json
import re
# JSON ブロックの抽出(LLM が余分なテキストを付加する場合への対応)
json_match = re.search(r'\{[\s\S]*\}', llm_output)
if json_match:
try:
data = json.loads(json_match.group())
return {
"status": "success",
"category": data.get("category", "unknown"),
"confidence": float(data.get("confidence", 0)),
"summary": data.get("summary", "")
}
except (json.JSONDecodeError, ValueError):
pass
return {
"status": "parse_error",
"category": "unknown",
"confidence": 0.0,
"summary": llm_output[:200]
}
4.3 随机节点和确定性节点的合作模式
graph TB
subgraph "推奨パターン: 確率 then 確定 then 分岐"
A[LLM Node<br/>確率的: テキスト生成] --> B[Code Node<br/>確定的: 出力パース]
B --> C{IF/ELSE<br/>確定的: 条件分岐}
C -->|正常| D[次の処理]
C -->|パースエラー| E[エラー処理]
end
subgraph "アンチパターン: 確率の連鎖"
X[LLM Node 1] --> Y[LLM Node 2<br/>前段の出力形式に依存]
Y --> Z[LLM Node 3<br/>さらに不安定な入力]
end
style A fill:#f96,stroke:#333,color:#fff
style B fill:#69b,stroke:#333,color:#fff
style C fill:#69b,stroke:#333,color:#fff
style X fill:#f96,stroke:#333,color:#fff
style Y fill:#f96,stroke:#333,color:#fff
style Z fill:#f96,stroke:#333,color:#fff
设计原则:始终将代码(确定性)节点放置在LLM(概率性)节点之后,以规范化输出。这可以防止随机输出不稳定在整个 Workflow中传播。
5. 错误处理模式
5.1 工作流程中的错误类型
| 错误类型 | 来源 | 示例 | 对应图案 |
|---|---|---|---|
| 模型错误 | LLM节点 | 速率限制、超时和错误输出 | 重试/回退 |
| 外部 API 错误 | HTTP 请求 | 连接超时,5xx 错误 | 重试/备用端点 |
| 数据错误 | 知识检索 | 0 条搜索结果,数据格式无效 | 默认值/升级 |
| 逻辑错误 | 代码 / IF/ELSE | 类型不匹配,NULL 引用 | 错误修复(在设计时修复) |
| 人工输入超时 | 人工输入 | 审批人未回复 | 升级/自动批准 |
5.2 重试模式
graph TB
A[LLM Node] -->|成功| B[次のノード]
A -->|エラー| C{リトライ回数<br/>< 上限?}
C -->|Yes| D[待機<br/>指数バックオフ]
D --> A
C -->|No| E{フォールバック<br/>モデルあり?}
E -->|Yes| F[代替 LLM Node<br/>別モデルで実行]
F --> B
E -->|No| G[エラー終了<br/>/ エスカレーション]
5.3 后备模式
与 Provider 抽象层结合,模型级回退是可能的:
graph LR
subgraph "フォールバックチェーン"
P1[GPT-4o<br/>Primary] -->|エラー| P2[Claude Sonnet<br/>Secondary]
P2 -->|エラー| P3[GPT-4o-mini<br/>Tertiary]
P3 -->|エラー| ERR[エラー処理]
end
5.4 优雅降级
服务持续但质量逐渐下降而不是完全失败的模式:
| 舞台 | 状态 | 回应 |
|---|---|---|
| 正常 | 所有节点工作正常 | 优质答案 |
| 轻微恶化 | 无法重新排名 | 仅使用矢量搜索回答(准确性略有下降) |
| 中度恶化 | 知识库无法搜索 | 仅使用LLM内部知识回答(带注释) |
| 严重恶化 | 初级LLM不可能 | 用后备模型回答 |
| 服务中断 | 所有型号均不可用 | 升级为人类 |
6. 工作流程设计最佳实践
6.1 节点设计原则
| 原理 | 说明 | 示例 |
|---|---|---|
| 单一责任 | 1 个节点 = 1 个责任 | 不要把“分类+总结”塞进一个LLM |
| 概率输出的即时归一化 | 将代码节点紧接在 LLM | 之后JSON解析验证 |
| 故障安全 | 在每条路径上放置错误处理 | 使用 IF/ELSE 设计错误分支 |
| 可观察性 | 记录中间结果 | 将重要的节点输出保留为变量 |
| 幂等性 | 使用相同输入重新运行时没有副作用 | 确保外部API调用的幂等性 |
6.2 实用工作流程模板
####客户询问自动回复
graph TB
START((Start<br/>問い合わせ受信)) --> CLASS[LLM Node<br/>問い合わせ分類]
CLASS --> PARSE[Code Node<br/>分類結果パース]
PARSE --> ROUTE{IF/ELSE<br/>カテゴリ判定}
ROUTE -->|FAQ| KB[Knowledge Retrieval<br/>FAQ検索]
ROUTE -->|技術問題| TECH[Knowledge Retrieval<br/>技術文書検索]
ROUTE -->|クレーム| HUMAN[Human Input<br/>担当者対応]
KB --> ANS[LLM Node<br/>回答生成]
TECH --> ANS
ANS --> CONF{IF/ELSE<br/>確信度チェック}
CONF -->|高| SEND[HTTP Request<br/>回答送信]
CONF -->|低| REVIEW[Human Input<br/>回答確認]
REVIEW -->|承認| SEND
REVIEW -->|修正| ANS
HUMAN --> SEND
SEND --> END((End))
6.3 反模式
| 反模式 | 问题 | 改进思路 |
|---|---|---|
| LLM链 | 随机节点链使输出不稳定 | 通过 |
| 整体LLM | 一位LLM有多重责任 | 将任务拆分到单独的节点 |
| 忽略错误 | 不要设计错误路径 | 在所有分支上放置错误处理 |
| 过度自动化 | 自动执行高风险操作 | 使用 HITL 节点设置检查点 |
| 硬编码 | 在提示中嵌入固定值 | 使用变量和环境变量 |
7. 日本企业的工作流程设计注意事项
7.1 与 Ringi 流程集成
日本企业特有的Ringi系统自然对应着HITL节点:
graph TB
A[AI ドラフト生成] --> B[Human Input<br/>起案者確認]
B --> C[Human Input<br/>課長承認]
C --> D{IF/ELSE<br/>金額判定}
D -->|100万円以上| E[Human Input<br/>部長承認]
D -->|100万円未満| F[処理実行]
E --> F
7.2 审计跟踪要求
日本企业合规性要求保留人工智能生成的内容和人工批准的记录:
| 记录项目 | 需保留的数据 | 预计保留期限 |
|---|---|---|
| AI生成日志 | 提示、模型名称、生成结果、时间戳 | 5-10年 |
| 人类判断日志 | 审批人ID、判断详情、时间戳 | 5-10年 |
| 外部API调用 | 请求/响应、端点 | 3-5年 |
| 错误日志 | 错误类型、发生时间、影响范围 | 1-3年 |
7.3 分阶段实施策略
| 相 | 自动化水平 | HITL 部署 | 风险管理 |
|---|---|---|---|
| 第一阶段 | AI打稿+人工验证全案 | 所有节点上的 HITL | 最小化风险/建立信任 |
| 第二阶段 | 自动(高置信度)+人工确认(低置信度) | 有条件的 HITL | 效率与安全的平衡 |
| 第三阶段 | 大多数情况下是自动+人工干预(仅在例外情况下)升级式HITL | 需要高效率和监控系统 |
8. 工作流节点设计的未来展望
8.1 与代理节点合并
Dify 正在进行 Workflow 节点和 Agent 功能的整合,预计会有以下演变:
- 代理作为节点:将代理作为节点嵌入到工作流中以实现自主任务执行
- 动态路由:LLM 动态决定工作流程的分支(超越传统 IF/ELSE 的灵活性)
- 多代理协作:多个代理在工作流程中协作解决问题
8.2 更高级的错误处理
- 自动恢复:当发生错误时,LLM分析错误原因并自动尝试修复。
- 学习回退:从过去的错误模式中学习最佳回退策略
- 主动检查:人工智能在运行节点之前预先验证输入数据的有效性
总结
Dify Workflow 的节点设计理念可以概括为四大支柱:
-
可组合性:每个节点都有独立的输入/输出接口,可以自由组合。变量作用域使节点之间的依赖关系保持明确且最小化。
-
人在环:人工智能自主与人类控制共存。可以根据风险级别使用批准、纠正和升级三种模式来设计人为干预。
-
使用确定性和概率性节点:立即用Code(确定性)节点对LLM(概率性)的输出进行归一化,以确保整个 Workflow的可预测性。
-
错误处理:通过多层错误处理(包括重试、回退、优雅降级和升级)实现生产环境的稳健性。
一个成熟的工作流并不是自动化比例很高,而是有一个清晰的边界设计,“哪里自动化,哪里部署人力,哪里放置错误处理”。 Dify 的节点设计理念提供了一个框架,允许您在 GUI 上直观地设计边界。
参考资料
-Human-in-the-Loop の概念を Dify に落とし込み、AI の暴走を防ぐ -Human-in-the-Loop の活用事例 Dify での具体的な運用パターン9選 -Human-in-the-Loop の活用事例 Dify での具体的な運用パターン