Dify系列(六):工作流与 Agent:可视化编排与自主决策实战
摘要:本文是 Dify 学习系列的第六篇,深入讲解工作流与 Agent 的核心概念、区别与适用场景,并通过两个完整的实战案例(工作流版智能内容安全审核助手、对话流版智能内容安全审核助手)带你掌握在 Dify 中设计复杂业务逻辑、实现多轮对话与自主决策的全流程。
1. 工作流与 Agent
1.1 工作流
工作流 = 业务逻辑的可视化执行
它将一个复杂的任务分解成一系列可管理的、按顺序或按条件执行的步骤,并通过图形化的界面将这些步骤连接起来。
- 单一任务 → 用插件 → 查询天气
- 复杂任务 → 工作流 → 旅游规划流程
1.2 Agent
Agent = 自主决策的 AI 助手
以 ReAct 形式运行:思考 → 行动 → 观察 → 再思考 ……
特点
- 自主规划:动态制定执行计划,根据环境反馈实时调整路径。
- 工具选择:灵活调用外部工具库(API、数据库、搜索等)完成任务。
- 推理能力:具备多轮思考与自我纠错能力,处理复杂逻辑。
- 灵活但贵:智能化程度极高,但 Token 消耗与响应延迟相对较高。
1.3 工作流和 Agent 的对比
工作流与 Agent 不是对立关系,而是演进关系。
核心观点:工作流是确定性的 Agent 实现方式。
| 维度 | 工作流 | Agent |
|---|---|---|
| 确定性 | 路径固定,按图执行 | 动态规划,自主选择路径 |
| 适用场景 | 流程明确的业务(如数据清洗、定时任务) | 开放复杂的任务(如客服、个人助理) |
| 成本 | 较低(Token 消耗可预估) | 较高(多轮推理、工具调用) |
| 可观测性 | 强(每一步清晰可见) | 弱(决策过程黑盒) |
2. Dify 工作流的两种类型
Dify 中工作流分为两种:
- 工作流(Workflow):面向单一任务流程,适合处理一次性输入、固定输出格式的场景。
- 对话流(Chatflow):面向多轮对话交互,支持上下文记忆和用户意图识别,适合构建聊天机器人。
| 类型 | 特点 | 典型场景 |
|---|---|---|
| 工作流 | 无状态,单次执行 | 内容审核、数据转换、报告生成 |
| 对话流 | 有状态,多轮对话 | 客服机器人、智能助手、问答系统 |
3. 创建工作流的标准流程
3.1 创建工作流
创建空白应用 → 选择 工作流 或 Chatflow。
设置内容:
- 工作流名称(清晰明确)
- 功能描述(帮助 AI 理解)
3.2 编排工作流
核心操作:
- 在可视化画布中添加节点
- 连接节点形成数据流
- 配置每个节点的输入输出参数
典型结构:开始节点 → LLM 节点 → 工具节点 → 结束节点
3.3 测试和发布
- 测试方法:点击“测试运行”,输入测试数据,检查各节点状态
- 发布流程:测试通过后点击“发布”,发布后其他用户即可使用该工作流
4. 工作流案例:智能内容安全审核助手(Workflow 版)
本项目基于 Dify Workflow 构建一个智能内容安全审核助手,用于对用户输入的文本内容进行自动安全审核。工作流包含敏感词初步检测、风险分流、知识库检索增强、大模型深度分析,最后通过输出节点输出审核结论。
下面是整体流程图:

4.1 开始节点
作用
接收用户输入的需要审核的文本内容。
节点展开详情
开始节点仅包含一个输入字段,由用户手动填写待审核文本。字段类型为“文本输入”,字段名设置为 content。



注意:输入字段
content需在工作流变量中手动创建并绑定。
4.2 敏感词初步检测(代码节点)
作用
对用户输入的文本进行快速敏感词匹配,标记命中词并计算初步风险等级。该节点能够过滤出明显违规内容,降低后续大模型节点的计算压力。
实现方式
使用“代码执行”节点,基于预定义的敏感词库进行匹配检测。
点击加号,添加代码节点:
节点展开详情
- 修改节点名称为“敏感词初步检测”
- 输入变量选择前一个节点用户输入的
content(脚本代码中函数接收content字段,字段名需一致) - 代码实现(直接复制)
- 输出变量按代码中的返回值字段名一一对应填写

代码实现
import re
def main(content: str) -> dict:
"""
敏感词检测,返回风险等级及高风险时的回复文本。
"""
# 预定义敏感词库
sensitive_words = [
"暴力", "色情", "赌博", "毒品", "诈骗", "违禁话题A", "极端内容B"
]
# 标准化文本:去除标点、转为小写
cleaned = re.sub(r'[^\w\u4e00-\u9fff]', '', content.lower())
# 匹配敏感词
hits = [w for w in sensitive_words if w in cleaned]
# 判定风险等级
if len(hits) >= 3:
risk_level = "高"
elif len(hits) >= 1:
risk_level = "中"
else:
risk_level = "低"
# 高风险时直接返回拒绝文本
if risk_level == "高":
response = "内容违规严重,已拒绝发布。"
else:
response = ""
return {
"risk_level": risk_level,
"response": response,
"hit_words": hits # 保留供大模型使用
}
输出变量
| 变量名 | 类型 | 说明 |
|---|---|---|
| risk_level | String | 风险等级(低/中/高) |
| response | String | 高风险时的直接回复文本,否则为空 |
| hit_words | Array | 命中的敏感词列表(供大模型参考) |
4.3 风险等级条件分支
作用
根据敏感词检测输出的 risk_level 决定后续流程。高风险内容直接送入大模型分析(无需知识库检索),中低风险内容先经过知识库检索增强后再送入大模型。
实现方式
添加“条件分支”节点,基于 risk_level 进行分流。
点击加号,选择条件分支节点:


节点展开详情
修改节点名称为“风险等级条件分支”,设置 if 条件:

- 分支逻辑
- 高风险分支
条件:{{#sensitive.risk_level#}} == "高"
下一步:连接到“高风险输出节点”。 - 中/低风险分支
条件:默认(即risk_level为“中”或“低”)
下一步:连接到“知识库检索节点”。
- 高风险分支
4.4 高风险输出节点
作用
当敏感词检测为高风险时,直接输出拒绝文案。
节点类型:输出节点(Output)

配置
- 输出变量:选择
{{#sensitive.response#}}(来自代码节点的response字段) - 无需添加额外变量,直接使用代码节点返回的文本
节点展开详情

4.5 知识库检索(中/低风险)
作用
当敏感词检测未命中高风险时,检索违规案例知识库,获取与当前文本相似的历史案例片段,为大模型分析提供参考依据,提升对隐晦或新型违规内容的识别能力。
实现方式
添加“知识检索”节点,关联已构建的违规案例知识库。

节点展开详情
修改标题,查询文本选择用户输入,知识库提前建立好。

检索参数
- 查询内容:用户输入的原始文本
content - 输出变量:
| 变量名 | 类型 | 说明 |
|---|---|---|
| result | Array[Object] | 检索到的相似案例片段 |
4.6 大模型综合分析(LLM 节点)
作用
综合用户文本、敏感词命中结果以及知识库检索上下文,输出最终审核结论(纯文本)。
实现方式
添加“LLM”节点,使用自定义系统提示词。

节点展开详情
修改节点昵称,上下文设置为上一个检索节点的 result,系统 Prompt 和用户 Prompt 如下。

系统 Prompt
# 角色
你是一名专业的内容安全审核专家。
## 输入信息
- 待审核文本:{{#content#}}
- 敏感词命中:{{#sensitive.hit_words#}}
- 知识库案例:{{#context#}}(可能为空)
## 任务
根据以上信息,判断文本是否违规,并输出明确的审核结论。结论只能是以下三种之一:
- “内容审核通过,允许发布。”
- “内容存在疑似违规,已转人工复审。”
- “内容违规严重,已拒绝发布。”
请直接输出结论文本,不要添加任何额外说明。
用户 Prompt
待审核文本:{{#content#}}
敏感词命中:{{#sensitive.hit_words#}}
知识库参考:{{#context#}}
输出变量
| 变量名 | 类型 | 说明 |
|---|---|---|
| text | String | 大模型输出的审核结论文本 |
4.7 中/低风险输出节点
作用
当文本经过知识库检索和大模型分析后,输出审核结论。
节点类型:输出节点(Output)

节点展开详情

配置
- 输出变量:选择
{{#llm.text#}}(来自 LLM 节点的text字段) - 直接引用大模型输出的结论文本
4.8 测试
作用
验证工作流在不同输入场景下的输出是否符合预期。测试用例覆盖敏感词直接拦截、知识库增强判断、大模型纯推理等路径。
点击右上角的“测试运行”,输入文本:

| 输入文本 (content) | 预期风险等级 | 输出 |
|---|---|---|
| 暴力 色情 赌博 毒品 全都有 | 高 | 内容违规严重,已拒绝发布。 |
| 加微信XXX,看高清无码视频。 | 高 | 内容违规严重,已拒绝发布。 |
| 昨晚好寂寞,有没有人陪陪我? | 中 | 内容存在疑似违规,已转人工复审。 |
| 昨天买了件衣服,质量特别好,推荐给大家。 | 低 | 内容审核通过,允许发布。 |
追踪可以查看到输入不同的文本运行的流程图,并能查看最后的输出。

5. 对话流案例:智能内容安全审核助手(Chatflow 版)
本项目基于 Dify Chatflow 构建一个智能内容安全审核助手,支持多轮对话交互。用户可输入单条文本或批量文本(换行/逗号分隔),系统通过知识库检索和大模型判断内容是否违规,并给出明确结论。
5.1 整体流程图

5.2 节点详细配置
5.2.1 开始节点
- 作用:接收用户输入的消息。
- 配置:默认即可,用户输入自动存入
userinput.query。

5.2.2 意图识别
- 节点类型:LLM
- 作用:判断用户意图是“审核文本”、“普通闲聊”还是“感谢/告别”。
- 系统提示词:
# 角色
你是一个意图识别助手。
## 任务
判断用户输入属于以下哪一类:
- "audit":用户要求审核一段文本(包含“帮忙审核”、“检查这句话”、“这条评论违规吗”等,或直接提供待审核文本)。
- "chat":普通聊天(如问候、询问天气、聊日常等)。
- "farewell":感谢、告别(如“谢谢”、“再见”、“拜拜”)。
## 输出格式
只输出一个单词:audit / chat / farewell,不要有其他内容。
- 用户提示词:
{{#userinput.query#}}


5.2.3 条件分支(意图分流)
- 节点类型:条件分支
- 分支逻辑:
| 分支 | 条件 | 下一步 |
|---|---|---|
| 审核 | {{#意图识别.text#}} == "audit" |
进入批量检测节点 |
| 闲聊 | {{#意图识别.text#}} == "chat" |
直接回复(闲聊回答) |
| 告别 | {{#意图识别.text#}} == "farewell" |
直接回复(感谢/告别语) |

闲聊直接回复
- 节点类型:直接回复(Answer)
- 回复内容:
我是内容安全审核助手,你可以发给我一段文本,我会判断它是否违规。例如:“暴力 色情”。

告别直接回复
- 节点类型:直接回复(Answer)
- 回复内容:
感谢使用,再见!有问题随时回来。

5.2.4 批量检测判断
- 节点类型:代码执行
- 作用:检查用户输入是否包含换行符、分号、逗号等分隔符,判断是否为批量请求。
- 代码:
def main(query: str) -> dict:
if "\n" in query or ";" in query or "," in query:
return {"is_batch": True}
# 如果文本较长且包含多个句号,也视为批量
if len(query) > 100 and query.count("。") >= 2:
return {"is_batch": True}
return {"is_batch": False}
- 输入变量:
query={{#userinput.query#}} - 输出变量:
is_batch(Boolean)

5.2.5 条件分支(单条/批量)
- 节点类型:条件分支
- 分支:
{{#is_batch#}} == true→ 批量处理路径- 默认 → 单条审核路径

5.3 单条审核路径
5.3.1 知识库检索
- 节点类型:知识检索
- 查询内容:
{{#userinput.query#}} - 关联知识库:内容安全审核知识库(需提前导入)

5.3.2 LLM 审核(单条)
- 节点类型:LLM
- 系统提示词:
# 角色
你是一名专业的内容安全审核专家。
## 输入
- 待审核文本:{{#userinput.query#}}
- 知识库案例:{{#context#}}(可能为空)
## 任务
判断文本是否违规,输出结论。结论只能是以下三种之一:
- “内容审核通过,允许发布。”
- “内容存在疑似违规,已转人工复审。”
- “内容违规严重,已拒绝发布。”
直接输出结论文本,不要额外说明。
- 用户提示词:可留空

5.3.3 直接回复(结论 + 询问继续)
- 节点类型:直接回复(Answer)
- 回复内容:
{{#LLM审核.text#}}
是否继续审核其他文本?请直接发送新的待审核内容,或回复“结束”。

5.4 批量审核路径
5.4.1 文本切分(代码节点)
- 节点类型:代码执行
- 作用:将用户输入按分隔符拆分成数组。
- 代码:
import re
def main(query: str) -> dict:
# 按换行、分号、中文逗号拆分
items = re.split(r'[\n;;,,]', query)
items = [item.strip() for item in items if item.strip()]
return {"texts": items}
- 输入:
query={{#userinput.query#}} - 输出:
texts(Array[String])

5.4.2 重置批量结果数组
- 节点类型:变量赋值(Variable Assigner)
- 作用:在迭代前将
batch_results重置为空数组,避免累积历史数据。 - 配置:
- 变量:
batch_results(类型 Array[String],需提前在会话变量中定义) - 操作:设置(Set)
- 值:
[]
- 变量:


5.4.3 迭代节点(Iteration)
- 节点类型:迭代
- 输入数组:
{{#文本切分.texts#}} - 迭代变量名:
item(每次循环的单个文本) - 内部节点:

知识库检索(迭代内)
- 节点类型:知识检索
- 查询内容:
{{#item#}}(重要:不能使用全局sys.query)

LLM 审核(迭代内)
- 节点类型:LLM
- 系统提示词:
# 角色
你是一名专业的内容安全审核专家。
## 输入
- 待审核文本:{{#current_text#}}
- 知识库案例:{{#context_inner#}}(可能为空)
## 任务
判断文本是否违规,输出结论。结论只能是以下三种之一:
- “内容审核通过,允许发布。”
- “内容存在疑似违规,已转人工复审。”
- “内容违规严重,已拒绝发布。”
直接输出结论文本,不要额外说明。
- 用户提示词:可留空

收集结果(变量赋值追加)
- 节点类型:变量赋值
- 作用:将本次审核结果追加到
batch_results数组中。 - 配置:
- 变量:
batch_results - 操作:追加(Append)
- 值:
LLM 审核(迭代内).text
- 变量:
注意:追加模式下,变量
batch_results必须已存在且类型为数组。

5.4.4 汇总 LLM(迭代结束后)
- 节点类型:LLM
- 作用:将
batch_results数组整理成易读的 Markdown 格式。 - 系统提示词:
# 角色
你是一个报告生成器。
## 输入
批量审核结果数组:{{#batch_results#}}
## 任务
将结果整理成有序的列表,每条结果独立一行。最后添加一句:“以上为批量审核结果,如需继续审核,请单独发送文本。”
直接输出整理后的文本,不要额外说明。

5.4.5 直接回复(批量结果)
- 节点类型:直接回复(Answer)
- 回复内容:
{{#汇总.text#}}

5.5 测试用例
| 用户输入 | 预期行为 | 预期回复 |
|---|---|---|
| 你好 | 闲聊 | “我是内容安全审核助手…” |
| 加微信XXX看高清视频 | 单条审核 | “内容违规严重,已拒绝发布。” |
| 昨晚好寂寞,有没有人陪陪我? | 单条审核 | “内容存在疑似违规,已转人工复审。” |
| 谢谢 | 告别 | “感谢使用,再见!” |
| 加微信XXX看高清视频 这个产品质量太差劲了,千万别买 这件衣服不错 | 批量审核 | 1.内容违规严重,已拒绝发布。 2.内容违规严重,已拒绝发布。 3.内容审核通过,允许发布。 |

小结
本篇通过工作流与对话流两个完整案例,展示了 Dify 在复杂业务场景下的强大编排能力。工作流适合确定性任务流程,对话流则适合多轮交互场景,两者可灵活组合,满足从自动化到智能化的各类需求。至此,Dify 学习系列六篇文章已全部完成,从安装部署到模型接入、提示词工程、RAG 应用、自定义工具,再到工作流与 Agent,希望你已掌握 Dify 的核心用法,并能用它搭建出属于自己的智能应用。
更多推荐



所有评论(0)