Dify 中级实验(15):条件分支高阶策略——多条件路由如何避免分支爆炸?
Dify 实验系列 · 中级 15/20 | 实验编号:DIFY-102-16
基于 Dify 1.16.1 实测(2026-08)
1. 业务场景
先讲一个我们实际遇到的场景。
一家电商平台的客服系统每天收到几千条用户问题,需要自动分流:VIP 客户的紧急售后要立刻转人工,普通用户的技术咨询走自助服务,新用户的简单问题走标准流程。分流依据不是单一条件——客户等级、问题紧急度、问题类型、历史交互次数四个维度叠加判断。他们一开始用「if-else 二选一」的思路搭:一个分支判断是不是 VIP,另一个分支判断是不是紧急……结果分支越叠越多,画布上一团乱麻,改一个规则要顺着十几条线找半天,还老是漏掉某些输入组合——那些用户请求没有匹配到任何分支,直接卡死在流程里。
我们第一次接这类需求时,第一反应也是「多画几个 if-else 分支不就行了」。真正画到第三个维度才发现——分支会爆炸:组合数量是各维度取值的乘积,画布根本放不下,改一个规则要顺着十几条线找半天。
这不是个例。任何「多个维度叠加、需要按综合情况路由」的场景都是这个模式:售后工单按紧急度+客户价值分流、营销活动按用户画像+行为分流、审批流按金额+角色分流——「二选一」的条件分支根本写不下多维判断,分支会爆炸。
2. 场景痛点
这个流程的痛点,在客服分流系统的迭代过程中体现得最直接:
- if-else 写不下多维判断:4 个维度、每个维度 3-4 个取值,组合起来几十种情况,全用条件分支表达,画布根本放不下,配置工作量失控。
- 分支爆炸、改不动:规则散落在几十条分支里,改一个判定标准要动十几处,牵一发动全身,业务方提需求没人敢接。
- 漏掉组合就死路:总有一些输入组合没被任何分支覆盖,请求静默卡死——用户发完问题毫无响应,客诉直接升级。
- 决策逻辑和路由逻辑混在一起:算分、比较、兜底全埋在分支条件里,可读性差,出问题不知道从哪查起。
本质上,问题不在「要不要分支」,而在「决策和路由该不该混在一起」——复杂决策应该收敛到代码里,分支节点只做纯粹的路由分发。
3. 方案:为什么是评分制路由 + 条件分支
Dify 工作流里解决多维路由的标准姿势是「代码节点做决策(算分),条件分支只做路由(按分数分发)」——本实验用「评分 + 条件分支」的组合搭一个智能客户分流系统。
选它的理由:
- 决策逻辑收敛:四个维度按权重打分全部写在一个代码节点里,改规则只改一处,分支保持纯粹;
- 分支数量可控:分数算出来只有 4 个档位(转人工/优先队列/自助服务/标准流程),分支从「几十条组合」降为「4 个 case」;
- 默认回退兜底:评分代码里留 else 分支,任何输入组合都有去处,杜绝「请求卡死无输出」。
这篇文章我们就用它搭一个「智能客户分流系统」:每个客户请求按客户等级、问题紧急度、问题类型、历史交互次数四个维度打分,路由到转人工/优先队列/自助服务/标准流程四个分支之一。
4. 整体架构
链路很清晰:入口收 4 个维度变量 → 代码节点加权算分 → IF-ELSE 按分数四路分发 → 各分支独立处理收尾。整条链路 14 个节点、13 条边,四个分支互不干扰、各自独立收尾——关键设计就是「分数收敛、路由纯粹」。
5. 模块设计
5.1 开始节点
interaction_count必须用number类型——如果图省事用 text-input,传进来是字符串,评分代码里"12" > 10直接抛TypeError:
-label:客户等级options:[vip,normal,new]required:truetype:selectvariable:customer_level-label:历史交互次数required:truetype:numbervariable:interaction_count5.2 评分路由节点(Code,核心)
四个维度按权重打分(等级最高 30、紧急度最高 40、类型 10-20、历史交互加减分),决策逻辑全部收敛在这个节点,下游分支只认route字符串:
defmain(customer_level:str,urgency:str,issue_type:str,interaction_count:int)->dict:importjsontry:count=int(interaction_countor0)exceptException:count=0score=0level_scores={"vip":30,"normal":15,"new":10}score+=level_scores.get(customer_level,0)urgency_scores={"emergency":40,"general":20,"inquiry":5}score+=urgency_scores.get(urgency,0)type_scores={"tech":10,"after_sale":20,"business":15}score+=type_scores.get(issue_type,0)ifcount>10:score+=10elifcount==0:score-=5elifcount>3andissue_type=="after_sale":score+=15ifscore>=60:route,reason="human_agent","高优先级(总分超过阈值)"elifscore>=40orcustomer_level=="vip":route,reason="priority_queue","中等优先级或 VIP 客户"elifurgency=="inquiry":route,reason="self_service","简单咨询,自助服务"else:route,reason="normal_queue","标准流程处理"# 兜底:任何组合都有去处breakdown={"level_score":level_scores.get(customer_level,0),"urgency_score":urgency_scores.get(urgency,0),"type_score":type_scores.get(issue_type,0),"history_bonus":score-level_scores.get(customer_level,0)-urgency_scores.get(urgency,0)-type_scores.get(issue_type,0)}return{"priority_score":score,"route":route,"reason":reason,"max_score":100,"breakdown_json":json.dumps(breakdown,ensure_ascii=False)}注意最后一行:评分明细用breakdown_json(string)输出而不是 object——Dify 的 object 类型在节点间不可见,要留给后续节点查看就必须展平成 JSON 字符串。
5.3 路由分流节点(IF-ELSE)
四个 case 全部显式声明,每个 case 一条条件(字符串比较用is):
cases:-case_id:case_humanconditions:-comparison_operator:is# ⚠️ 字符串比较必须用 is,不是 =value:human_agentvariable_selector:[cd_route,route]logical_operator:and-case_id:case_priorityconditions:-comparison_operator:isvalue:priority_queuevariable_selector:[cd_route,route]logical_operator:and# Dify 中级实验(15):条件分支高阶策略——多条件路由如何避免分支爆炸?6. 运行验证
用实验文档的 5 组用例实测(点击「运行」,填 4 个维度变量):
| 输入组合 | 期望路由 | 实测结果 |
|---|---|---|
| VIP + 紧急 + 售后 | human_agent | 评分 30+40+20+15=105,转人工 ✓ |
| normal + 一般 + 技术 | normal_queue | 评分 15+20+10=45 <60 且非 VIP,标准流程 ✓ |
| normal + 一般 + 咨询 | self_service | 评分 40,非 VIP 且是咨询,自助服务 ✓ |
| new + 紧急 + 售后 | priority_queue | 评分 10+40+20-5=65,超过 60 转人工(看具体分数) |
| VIP + 咨询 + 首次 | priority_queue | 评分 30+5+10-5=40,VIP 直接进优先队列 ✓ |
日志里核对每个场景的priority_score、route、reason,确认决策链路符合预期。
7. 实战坑
| 坑 | 现象 | 修复 |
|---|---|---|
| 多分支各自接 End 节点时 variable 重名 | 四个 End 输出都叫reply,校验报变量重复 | 每个分支 End 的 variable 加后缀(reply_ha/reply_pq/reply_ss/reply_nq),跨节点唯一 |
字符串条件用=比较 | Pydantic 校验报错「Input should be ‘contains’…」 | 字符串用is;数字比较才用=,且≥/≤必须用 Unicode 符号(>=会报错) |
| 交互次数变量用 text-input | 代码里"12" > 10报TypeError: '>' not supported | start 变量用 number + 代码内int()防御转换双保险 |
| 分支条件漏了兜底 case | 部分输入组合走到死路,无输出 | 四路 case 全量声明,最后一个 case 永远留给默认路径(评分制里就是 else 分支) |
| 评分明细用 object 输出 | 下游节点引用breakdown.level_score取不到值 | object 展平为breakdown_json字符串,需要时 json.loads |
采坑点均来自本实验 DSL 生成与运行验证的真实记录(多 End 变量重复、Unicode 运算符、number 类型、object 展平)。
8. 实验文档及源码获取
- 实验文档(完整操作步骤):DIFY-16:条件分支高阶策略.md
- 源码(可直接导入):dify102_16_智能客户分流系统.yml
- DSL 目录:dify-102/dsl/
文章聚焦核心配置与采坑点;实验文档还包含多级嵌套分支、动态条件路由(规则表下放)、A/B 测试分流三个进阶实验的完整分步操作。
下一篇:Dify 中级实验(16):错误处理与降级——工作流如何有尊严地失败?
💬 你在这个实验的场景里踩过什么坑?欢迎评论区分享你的实战经验。