Dify 企业级实验(01):多应用编排——如何让多个 Dify 应用协同完成一条业务链?
Dify 实验系列 · 企业级 01/12 | 实验编号:DIFY-104-01
1. 实验目的
掌握系统级应用编排:把多个独立的 Dify 应用(客服分流、订单质检、工单、周报)通过Workflow as Tool组合成一个完整的订单业务系统。这是中级实验 08「子工作流」思想的企业级放大——从「一个工作流调用子工作流」升级为「多个独立应用互调」。
适合:已有多个独立 Dify 应用(可能是不同团队维护),需要把它们组装成端到端业务流程的场景。核心能力是职责边界划分:编排应用只做调度、不做业务。
2. 场景设计
电商订单全流程:用户咨询 → 自动分流 → 订单质检 → 异常工单 → 周报汇总。传统做法是 4 个独立应用 + 人工衔接;本实验用 1 个编排应用(主 workflow)调用 4 个能力应用,端到端自动化。
输入:customer_message(用户消息)、order_id(订单号,可选)。
输出:分类结果 + 质检结论;命中「投诉/售后」或「高风险」时追加工单号。周报应用独立定时触发,汇总本周订单质量。
3. 节点拓扑
编排应用(dify104_01_05_订单编排) 开始(customer_message / order_id) → 客服分流引擎(tool,调 dify104_01_01) → 订单质检引擎(tool,调 dify104_01_02) → 是否需要工单(if-else:分类=投诉/售后 或 风险=high) ├─ 是 → 工单创建引擎(tool,调 dify104_01_03) └─ 否 → 直接组装结果 → 组装结果(code)→ 结束 能力应用(各自独立,发布为工具后被编排应用调用) 客服分流(01_01):开始 → 问题分类(question-classifier,4 类)→ 结束 订单质检(01_02):开始 → 订单信息提取(PE)→ 风险校验(code)→ 结束 工单创建(01_03):开始 → 生成工单(code)→ 结束 周报汇总(01_04):开始 → 模拟数据采集 → 解析数据 → 周报模板 → 结束(定时触发)4. 关键配置
4.1 能力应用发布为工具
每个能力应用先「发布为工具」,拿到provider_id后在编排应用 DSL 中引用。注意:重新发布后 provider_id 会变,运行前需按 app_id 动态查询最新值(102-08 实测教训的延续)。
4.2 编排应用的 tool 节点(tool5a 客服分流引擎)
tool 节点参数必须双写:tool_parameters与tool_configurations同值(UI 显示与运行兼容):
-id:tool5adata:type:tooltitle:客服分流引擎provider_type:workflowprovider_id:2af54f30-b1e6-4cd6-bc7b-bebaf5818353tool_name:dify104_fenliutool_parameters:customer_message:type:mixedvalue:'{{#start.customer_message#}}'tool_configurations:# 与 tool_parameters 同值,缺了 UI 面板显示空customer_message:type:mixedvalue:'{{#start.customer_message#}}'4.3 是否创建工单(if5)
三个条件用or组合——分类是投诉、分类是售后、质检风险为 high,任一命中即建单:
-id:if5data:type:if-elsetitle:是否需要工单cases:-case_id:need_ticketlogical_operator:orconditions:-comparison_operator:isvalue:投诉variable_selector:[tool5a,category]-comparison_operator:isvalue:售后variable_selector:[tool5a,category]-comparison_operator:isvalue:highvariable_selector:[tool5b,risk_level]4.4 组装结果(cd5d)
tool 返回的是 JSON 字符串,必须用 code 节点解析后再拼装,不能直接给下游:
defmain(category:str,quality_report:str,ticket_no:str,ticket_summary:str)->dict:parts=[f"分类:{category}",f"质检:{quality_report}"]ifticket_no:parts.append(f"工单:{ticket_no}")return{"final_result":"\n".join(parts)}4.5 质检风险校验(01_02 的 cd2,能力应用内)
命中负面关键词即标记高风险(negative_keywords = ["坏", "损坏", "破损", "退款", "退货", "投诉", "太差", "失望", "无法使用", "质量"]),并输出quality_report与risk_reasons;订单号缺失只提示不阻断。
4.6 周报模板(01_04 的 tt4)
template-transform 用 Jinja2 取数组最后两条做环比,sales|length判空兜底:
{% set sales = sales if sales else [] %} {% set cur = sales[-1] if sales|length > 0 else {} %} {% set prev = sales[-2] if sales|length > 1 else {} %} - 订单量:{{ cur.get('orders', 0) }}(上周 {{ prev.get('orders', 0) }})5. 运行验证
| 输入 | 预期 | 结果 |
|---|---|---|
| 含异常关键词的订单咨询(如「东西坏了,我要退款」) | 分流=投诉 → 质检风险=high → 建单,输出「分类:投诉 / 质检:…风险等级 high / 工单:WO-…」 | 通过(实测编排调 3 工具) |
| 普通咨询(如「订单多久能到?」) | 分流=咨询、风险=low,不建单,只输出分类 + 质检 | 通过 |
| 定时触发周报(report_week=本周) | 输出订单周报(订单量/营收/投诉数,含上周环比) | 通过 |
6. 采坑点
| 坑 | 现象 | 修复 |
|---|---|---|
| 重新发布工具后 provider_id 变化 | 编排应用调用报工具引用失效 | 运行前按 app_id 动态查询最新 provider_id 并同步 DSL(实测,102-08 教训延续) |
| tool 参数只写 tool_parameters | UI 面板显示空、手动调试报「不能为空」 | tool_parameters与tool_configurations双写同值(实测,102-08) |
| tool 返回 JSON 字符串直接拼给下游 | 下游 LLM 拿到字符串乱用、字段取不到 | 先用 code 节点解析再拼装(实测,102-08) |
| code 节点沙箱禁写文件 | 报PermissionError: /tmp | 存储统一走 http + 外部 KV 服务(实测,本批) |
| 编排应用里写业务逻辑 | 系统难维护,能力应用失去复用性 | 编排只做调度,业务逻辑留在能力应用(实验文档设计约束) |
7. 实验文档及源码获取
- 实验文档(完整操作步骤):DIFY-104-01:多应用编排系统——订单全流程协同.md
- 源码(可直接导入,一个应用一个 DSL):
- 源码一(客服分流):dify104_01_01_客服分流.yml
- 源码二(订单质检):dify104_01_02_订单质检.yml
- 源码三(工单创建):dify104_01_03_工单创建.yml
- 源码四(周报汇总):dify104_01_04_周报汇总.yml
- 源码五(订单编排,主流程):dify104_01_05_订单编排.yml
- 全部源码目录:dify-104/dsl
文章聚焦核心配置与采坑点;实验的完整分步操作(节点搭建/参数表/调试指引)见实验文档原文。
下一篇:Dify 企业级实验(02):跨应用状态传递——多轮对话的状态如何跨应用不丢?
💬 你在这个实验的场景里踩过什么坑?欢迎评论区分享你的实战经验。