Dify 中级实验(07):子工作流——如何把公共逻辑做成可复用积木?

📅 2026/8/15 22:15:47
Dify 中级实验(07):子工作流——如何把公共逻辑做成可复用积木?
Dify 中级实验07子工作流——如何把公共逻辑做成可复用积木Dify 实验系列 · 中级 07/20 | 实验编号DIFY-102-08基于 Dify 1.16.1 实测2026-081. 业务场景先讲一个我们实际遇到的场景。一家同时做客服、产品调研、舆情监控的公司客服要实时看客户情绪产品团队要分析用户反馈舆情部门要盯社区言论。三拨人各自开发了一套「情绪分析」——三份重复代码、三套维护成本、三个不一致的口径客服判「负面」的舆情可能判「中性」。我们第一次接这类需求时第一反应也是「把情绪分析的代码复制三份各改各的参数」。真正动手才发现——需求一样、代码三份改一处要改三处漏改一套口径就漂移。后来翻 Dify 的节点列表才发现模块化设计有原生手段——子工作流Sub-workflow把「情绪分析」这类公共逻辑抽成独立工作流一处定义、多处调用1.16 的真实做法是发布为工具调用。这不是个例。任何「多个业务线共用同一能力」的业务场景都是这个模式情绪分析、文本清洗、格式化输出……公共逻辑不做模块化就是在重复造轮子而且每个轮子还不太一样。2. 场景痛点这个流程的痛点在研发/业务团队身上体现得最直接同一逻辑重复开发三条线各写一份情绪分析需求一样、代码三份开发资源被重复消耗——重复的代码不是资产是负债每次升级都要连本带利还。改一处要改三处分析逻辑升级比如紧急度规则调整三套代码要同步改漏改一套口径就漂移——线上行为从此不一致。调用方被实现绑架每个调用方都要关心「怎么分析」——传什么参数、用什么模型、怎么解析输出而不是只关心「分析结果是什么」。输出格式不统一三条线产出的字段名、格式各异下游汇总统计对不上数据越攒越乱。本质上公共逻辑每多一个调用方重复成本就翻一倍——模块化的价值不在「少写代码」而在「一处定义、多处调用、接口即契约」。3. 方案为什么是子工作流选子工作流的理由我们实际对比过一处定义、多处调用情绪分析做成独立工作流两个主工作流消费它——客服看板逐条分析批量反馈迭代内逐条调用接口即契约输入text/language、输出 6 个结构化字段sentiment/score/confidence/keywords/brief/urgency边界清晰调用方只看接口不看实现1.16 的真实实现Dify 1.16 没有 sub-workflow 节点类型真实做法是发布子工作流为工具Workflow as Tool用 tool 节点调用——本实验完整演示这条路。这篇文章我们就用它搭「情绪分析引擎」子工作流 两个消费它的主工作流客服情绪看板 / 批量反馈分析。4. 整体架构主工作流 2批量反馈分析开始feedback_list JSON 数组解析反馈列表Code逐条情绪分析迭代 Tool 解析 Code汇总情绪分布Code结束主工作流 1客服情绪看板case_highcase_normal开始customer_message / agent_name调用情绪分析引擎Tool provider_type workflow解析情绪结果Code 从 json 数组展平字段紧急度分支IF-ELSE高优安抚回复LLM结束高优常规回复LLM结束常规子工作流情绪分析引擎开始text / language情绪分析LLM提取结构化字段PE结束链路很清晰子工作流定义能力主工作流消费能力——情绪分析引擎只做「分析并输出结构化字段」两个主工作流各自编排自己的业务逻辑看板按紧急度分流、批量分析走迭代。5. 模块设计5.1 子工作流枚举字段必须给显式规则LLM 输出的 JSON 里urgency是枚举字段——只写 low/medium/high 不给规则LLM 会随意输出实测负面投诉返回 low下游分支全走错prompt_template:-id:p_sentimentrole:systemtext:|你是一个专业情绪分析师。分析以下文本的情感输出 JSON 格式不要 Markdown 文本{{#start.text#}} { sentiment: positive/negative/neutral/mixed, score: 0.0 到 1.0 之间的浮点数, confidence: 0.0 到 1.0, keywords: [关键词1, 关键词2, ...], brief: 一句话情感总结, urgency: low/medium/high } 紧急度规则负面情绪/投诉/损坏/退款/愤怒类内容 → high中性咨询类 → medium正面/普通内容 → lowreasoning_format:separated参数提取器 6 个参数sentiment string / score number / confidence number / keywords array[string] / brief string / urgency stringreasoning_mode: function_call。5.2 主工作流发布子工作流为工具核心Dify 1.16.1没有 sub-workflow 节点类型运行时报No class mapping found for node type: sub-workflow必须「发布为工具」后用 tool 节点调用-data:provider_type:workflowprovider_name:dify102_08_01_情绪分析引擎provider_id:11e9699e-ffa8-448f-8278-e16799e5912a# 发布时的注册 ID重发会变tool_name:dify102_08_01tool_description:情绪分析引擎子工作流——输入文本输出结构化情绪字段type:tooltitle:调用情绪分析引擎tool_configurations:# ⚠️ 与 tool_parameters 双写同一份值UI 权威格式text:{type:mixed,value:{{#start.customer_message#}}}language:{type:mixed,value:中文}tool_parameters:text:{type:mixed,value:{{#start.customer_message#}}}language:{type:mixed,value:中文}paramSchemas:-name:textdefault:示例太棒了五星好评# default 决定 UI 面板显示值required:truetype:stringid:tool_sentiment5.3 输出不透传必须解析展平工具输出固定三件套textstring/filesarray[file]/jsonarray[object]——子工作流 end 的自定义字段名不透传下游直接引用{{#tool.sentiment#}}取不到。必须加代码节点从json数组提取defmain(sent_json:list)-dict:importjson data{}ifisinstance(sent_json,list):foriteminsent_json:ifisinstance(item,dict):data.update(item)return{sentiment:str(data.get(sentiment,未知)),brief:str(data.get(brief,无摘要)),urgency:str(data.get(urgency,low)),score:str(data.get(score,)),sentiment_json:json.dumps(data,ensure_asciiFalse),}紧急度分支用字符串比较is/is notcases:-case_id:case_highconditions:-comparison_operator:isvalue:highvariable_selector:[cd_parse_sent,urgency]varType:stringlogical_operator:and-case_id:case_normalconditions:-comparison_operator:is notvalue:highvariable_selector:[cd_parse_sent,urgency]varType:stringlogical_operator:and6. 运行验证输入预期实测正面太棒了客服很贴心五星好评sentimentpositiveurgencylow → 常规回复与预期一致负面东西收到就坏了联系客服三天没人理太失望了sentimentnegativeurgencyhigh → 安抚回复与预期一致中性周二下午三点可以安排配送吗sentimentneutralurgencymedium → 常规回复与预期一致批量3 条反馈 JSON迭代逐条分析汇总情绪分布与预期一致7. 实战坑坑现象修复用 sub-workflow 节点类型运行报No class mapping found for node type: sub-workflow1.16 必须「发布为工具」tool 节点 provider_type: workflow子工作流重导后 provider_id 失效主工作流调用报 workflow provider not found重发后从 tool-providers 动态查最新 provider_id 同步实测 2a6187e8 → 11e9699e下游直接引用工具的自定义字段{{#tool.sentiment#}}取不到值分支全走默认工具输出只有 text/files/json必须 code 解析 json 展平见 5.3tool 参数只写 tool_parametersUI 配置面板显示参数为空手动调试报「要分析的文本不能为空」tool_parameters与tool_configurations双写同一份值paramSchemas[].default填占位值让 UI 不空枚举字段不给规则负面投诉消息返回 urgencylow下游分支全走错prompt 给显式映射规则负面/投诉/退款→high咨询→medium正面→low迭代内 item 是字符串却传 item.content工具收到空文本全部判默认值字符串 item 直接传{{#iter.item#}} 什么时候该抽子工作流同一逻辑出现在 ≥2 个流程、接口稳定、输入输出边界清晰。接口即契约——改子工作流输出结构所有调用方都要跟着改这是模块化的真实成本。8. 实验文档及源码获取实验文档完整操作步骤DIFY-08子工作流——搭积木式模块化设计.md源码可直接导入先导子工作流再导主工作流dify102_08_01_情绪分析引擎.ymldify102_08_02_客服情绪看板.ymldify102_08_03_批量反馈分析.yml文章聚焦核心配置与采坑点实验的完整分步操作节点搭建/参数表/调试指引见实验文档原文。下一篇Dify 中级实验08代码节点进阶——如何用标准库处理文件与数据 你在这个实验的场景里踩过什么坑欢迎评论区分享你的实战经验。