← 返回文章列表

Dify 中级实验(15):条件分支高阶策略——多条件路由如何避免分支爆炸?

1. 业务场景

先讲一个我们实际遇到的场景。

一家电商平台的客服系统每天收到几千条用户问题,需要自动分流:VIP 客户的紧急售后要立刻转人工,普通用户的技术咨询走自助服务,新用户的简单问题走标准流程。分流依据不是单一条件——客户等级、问题紧急度、问题类型、历史交互次数四个维度叠加判断。他们一开始用「if-else 二选一」的思路搭:一个分支判断是不是 VIP,另一个分支判断是不是紧急……结果分支越叠越多,画布上一团乱麻,改一个规则要顺着十几条线找半天,还老是漏掉某些输入组合——那些用户请求没有匹配到任何分支,直接卡死在流程里。

我们第一次接这类需求时,第一反应也是「多画几个 if-else 分支不就行了」。真正画到第三个维度才发现——分支会爆炸:组合数量是各维度取值的乘积,画布根本放不下,改一个规则要顺着十几条线找半天。

这不是个例。任何「多个维度叠加、需要按综合情况路由」的场景都是这个模式:售后工单按紧急度+客户价值分流、营销活动按用户画像+行为分流、审批流按金额+角色分流——「二选一」的条件分支根本写不下多维判断,分支会爆炸

2. 场景痛点

这个流程的痛点,在客服分流系统的迭代过程中体现得最直接:

本质上,问题不在「要不要分支」,而在「决策和路由该不该混在一起」——复杂决策应该收敛到代码里,分支节点只做纯粹的路由分发

3. 方案:为什么是评分制路由 + 条件分支

Dify 工作流里解决多维路由的标准姿势是「代码节点做决策(算分),条件分支只做路由(按分数分发)」——本实验用「评分 + 条件分支」的组合搭一个智能客户分流系统。

选它的理由:

这篇文章我们就用它搭一个「智能客户分流系统」:每个客户请求按客户等级、问题紧急度、问题类型、历史交互次数四个维度打分,路由到转人工/优先队列/自助服务/标准流程四个分支之一。

4. 整体架构

graph TD start["开始:4 个维度变量"] --> score["优先级评分路由(Code:加权评分 → route/reason/priority_score)"] score --> route{"路由分流(IF-ELSE,4 个 case)"} route -- "case_human(转人工)" --> h1["通知客服并记录工单(Code)"] h1 --> h2["生成安抚回复(LLM)"] h2 --> end_human["结束"] route -- "case_priority(优先队列)" --> p1["VIP专属回复(LLM)"] p1 --> p2["排队信息计算(Code)"] p2 --> end_priority["结束"] route -- "case_self(自助服务)" --> s1["FAQ自助检索(知识库)"] s1 --> s2["自助回答(LLM)"] s2 --> end_self["结束"] route -- "case_normal(标准流程)" --> n1["标准回复(LLM)"] n1 --> end_normal["结束"]

链路很清晰:入口收 4 个维度变量 → 代码节点加权算分 → IF-ELSE 按分数四路分发 → 各分支独立处理收尾。整条链路 14 个节点、13 条边,四个分支互不干扰、各自独立收尾——关键设计就是「分数收敛、路由纯粹」。

5. 模块设计

5.1 开始节点

interaction_count 必须用 number 类型——如果图省事用 text-input,传进来是字符串,评分代码里 "12" > 10 直接抛 TypeError

- label: 客户等级

  options: [vip, normal, new]

  required: true

  type: select

  variable: customer_level

- label: 历史交互次数

  required: true

  type: number

  variable: interaction_count

5.2 评分路由节点(Code,核心)

四个维度按权重打分(等级最高 30、紧急度最高 40、类型 10-20、历史交互加减分),决策逻辑全部收敛在这个节点,下游分支只认 route 字符串:

def main(customer_level: str, urgency: str, issue_type: str, interaction_count: int) -> dict:

    import json

    try:

        count = int(interaction_count or 0)

    except Exception:

        count = 0

    score = 0

    level_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)

    if count > 10:

        score += 10

    elif count == 0:

        score -= 5

    elif count > 3 and issue_type == "after_sale":

        score += 15

    if score >= 60:

        route, reason = "human_agent", "高优先级(总分超过阈值)"

    elif score >= 40 or customer_level == "vip":

        route, reason = "priority_queue", "中等优先级或 VIP 客户"

    elif urgency == "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_human

  conditions:

  - comparison_operator: is      # ⚠️ 字符串比较必须用 is,不是 =

    value: human_agent

    variable_selector: [cd_route, route]

  logical_operator: and

- case_id: case_priority

  conditions:

  - comparison_operator: is

    value: priority_queue

    variable_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_scoreroutereason,确认决策链路符合预期。

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" > 10TypeError: '>' not supported start 变量用 number + 代码内 int() 防御转换双保险
分支条件漏了兜底 case 部分输入组合走到死路,无输出 四路 case 全量声明,最后一个 case 永远留给默认路径(评分制里就是 else 分支)
评分明细用 object 输出 下游节点引用 breakdown.level_score 取不到值 object 展平为 breakdown_json 字符串,需要时 json.loads

采坑点均来自本实验 DSL 生成与运行验证的真实记录(多 End 变量重复、Unicode 运算符、number 类型、object 展平)。

8. 实验文档及源码获取

文章聚焦核心配置与采坑点;实验文档还包含多级嵌套分支、动态条件路由(规则表下放)、A/B 测试分流三个进阶实验的完整分步操作。

本系列 · Dify 实验 · 中级
  1. Dify 中级实验(01):参数提取器实战——如何从自然语言中提取结构化数据?
  2. Dify 中级实验(02):问题分类器——智能路由引擎如何四路分发?
  3. Dify 中级实验(03):模板转换实战——如何用零 Token 完成文本加工?
  4. Dify 中级实验(04):迭代进阶——如何批量处理数据并守住性能边界?
  5. Dify 中级实验(05):并行执行——如何让多路任务同时跑?
  6. Dify 中级实验(06):变量聚合——如何确定性合并多路分支结果?
  7. Dify 中级实验(07):子工作流——如何把公共逻辑做成可复用积木?
  8. Dify 中级实验(08):代码节点进阶——如何用标准库处理文件与数据?
  9. Dify 中级实验(09):HTTP 节点进阶——如何搞定认证、分页与错误重试?
  10. Dify 中级实验(10):知识库深度调优——如何科学评估检索质量?
  11. Dify 中级实验(11):高级 RAG 流水线——如何搭建多路检索与精排?
  12. Dify 中级实验(12):Agent 深度配置——如何让智能体自主调用工具?
  13. Dify 中级实验(13):多 Agent 协作——如何编排多个智能体分工干活?
  14. Dify 中级实验(14):对话变量与状态管理——如何让工作流记住多轮对话的状态?
  15. Dify 中级实验(15):条件分支高阶策略——多条件路由如何避免分支爆炸?
  16. Dify 中级实验(16):错误处理与降级——工作流如何有尊严地失败?
  17. Dify 中级实验(17):调试监控与性能优化——响应慢和 Token 超支如何定位?
  18. Dify 中级实验(18):插件开发入门——如何把工作流变成 Agent 可调用的工具?
  19. Dify 中级实验(19):综合实战——如何把 19 个实验串成一条生产级流水线?
  20. Dify 中级实验(20):综合实战——自动化报告生成流水线如何从数据到周报一步到位?

联系我

15088711270

手机端点击号码可直接拨打 · 桌面端可复制

微信二维码

扫码加微信 · 备注「门户」更快通过