← 返回文章列表

Dify 中级实验(19):综合实战——如何把 19 个实验串成一条生产级流水线?

1. 业务场景

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

一家电商公司的客服团队每天收到几百条用户问题,从「API 报 502 了」到「我要退货退款」什么都有。原来全靠人工分拣:读一遍、判断类型、分给对应客服、记录工单、跟踪处理——一个工单的流转要经过五六双手。他们想用 Dify 把这条链路自动化:用户用自然语言提问题,系统自动完成质量检查、意图分类、路由分发、分派 Agent 处理、工单聚合、报告生成,出错还能兜底降级。

我们当时评估这个需求的第一反应是「这不就是把前面的节点串起来嘛」。真正动手才发现——串起来和设计好,是两回事。节点连起来只解决「正常路径」,而生产系统 90% 的复杂度都在异常路径上:输入太短怎么办?分类器认不出来怎么办?处理 Agent 挂了怎么办?

这不是个例。任何「用户用一句话描述问题、系统要全自动处理到底」的场景都是这个模式:工单系统、故障报修、投诉处理、审批流——把前面学过的参数提取、问题分类、条件分支、多 Agent 协作、错误处理、降级回退串进一个完整系统,就是「从会搭节点到会设计系统」的分水岭

2. 场景痛点

这个流程的痛点,在电商客服团队身上体现得最直接:

本质上,真正的系统设计能力 = 把每个环节的正确路径和异常路径都设计出来,而不是只会把节点连起来

3. 方案:为什么是「多 Agent 智能工单系统」

本实验是系列 1 的总检验:把参数提取、问题分类、条件分支、多 Agent 协作、错误处理、降级回退串进一个完整系统——多 Agent 智能工单系统。19 个节点、25 条边的全链路,跑通它,你就从「会搭节点」进化到了「会设计系统」。

选它的理由:

这篇文章我们就用它搭「多 Agent 智能工单系统」:用户用自然语言提问题,系统自动完成质量检查 → 意图分类 → 路由分发 → 分派 Agent 处理 → 工单聚合 → 报告生成 → 错误兜底。

4. 整体架构

graph TD start["开始:user_input / user_id / channel"] --> pe["工单参数提取(PE:issue_type/description/urgency_level/expected_action/related_entities)"] pe --> quality["输入质量检查(Code:valid/reask_message)"] quality --> qc_branch{"质量校验分支(IF-ELSE)"} qc_branch -- "case_invalid" --> end_reask["结束-重新询问(描述过短/敏感词提示)"] qc_branch -- "case_valid" --> qc["意图分类(QC:tech/after_sale/business/account/other)"] qc --> route["路由分发(Code:class_id 路由 + VIP/phone 特殊规则)"] route --> agent_branch{"Agent分支(IF-ELSE)"} agent_branch -- "case_tech" --> tech_agent["技术Agent处理(Code)"] agent_branch -- "case_after" --> after_agent["售后Agent处理(Code)"] agent_branch -- "case_business" --> biz_agent["商务Agent处理(Code)"] agent_branch -- "case_other" --> manual["未分类转人工(Code)"] tech_agent --> aggregate["工单聚合(Code:ticket_id/工单 dict)"] after_agent --> aggregate biz_agent --> aggregate manual --> aggregate aggregate --> report["生成工单报告(LLM)"] report --> err_capture["错误捕获(Code:has_errors/action)"] err_capture --> err_branch{"错误判定(IF-ELSE)"} err_branch -- "case_error" --> degrade_log["降级记录(Code)"] degrade_log --> end_degrade["结束-降级"] err_branch -- "case_ok" --> end_ok["结束"]

链路很清晰:入口收问题 → 参数提取 → 质量检查拦截模糊输入 → 意图分类 → 路由分发 → 四路 Agent 分支处理 → or-chain 聚合 → 生成报告 → 错误捕获兜底。19 个节点、25 条边,全链路的关键是「每个检查类节点都接一个消费它的 IF-ELSE」——否则校验、分类、错误处理全是死代码。

5. 模块设计

5.1 输入质量检查(Code)→ 必须接 IF-ELSE

这是本实验最容易踩的坑:检查类节点输出 valid 后,下游必须接一个消费它的 IF-ELSE,否则 reask 逻辑就是死代码:

def main(user_input: str, issue_type: str) -> dict:

    issues = []

    # 1. 空输入 / 描述过短

    if not user_input or len(user_input.strip()) < 5:

        return {"valid": "false", "has_warning": "false", "warnings": [],

                "sanitized": user_input, "action": "reask",

                "reask_message": "描述过于简短,请提供更多信息"}

    # 2. 意图不明确

    if not issue_type or issue_type == "other":

        issues.append("无法识别问题类型")

    # 3. 敏感内容检查

    for pattern in ["密码", "银行卡", "身份证", "验证码"]:

        if pattern in user_input:

            issues.append("包含敏感信息关键词: {}".format(pattern))

    has_warning = len(issues) > 0

    return {"valid": "true", "has_warning": "true" if has_warning else "false",

            "warnings": issues, "sanitized": user_input,

            "action": "continue" if not has_warning else "warn_and_continue",

            "reask_message": ""}

对应的 IF-ELSE 只有两个 case:case_valid → 意图分类case_invalid → end_reask。输入「有问题」这种模糊描述时,正确行为是提示补充,而不是一路走到「需人工审核」。

5.2 路由分发(Code)——只信 QC 的真实输出字段

问题分类器(QC)的输出只有 4 个字段:class_id / class_name / class_label / usage——没有 class_names、classes、confidence。路由代码只消费 class_id/class_name,置信度 0.9 是硬编码的演示值:

def main(class_id: str, class_name: str, urgency_level: str, user_id: str, channel: str) -> dict:

    route_id = class_id or "other"

    route_name = class_name or "未分类"

    confidence = 0.9  # QC 无 confidence 输出,硬编码演示回退逻辑

    is_vip = str(user_id or "").strip().lower().startswith("vip")

    if route_id not in ["tech", "after_sale", "business"]:

        route_id, route_name = "other", "未分类"

    priority = "high" if urgency_level == "high" else "normal"

    force_manual = "false"

    note = ""

    if is_vip and route_id in ["tech", "after_sale"]:

        priority, note = "high", "VIP 客户,优先处理"

    if channel == "phone" and route_id == "after_sale":

        force_manual, note = "true", "电话渠道售后,转人工处理"

    if confidence < 0.5:

        route_id, route_name = "other", "未分类"

        note = "置信度过低({}),由人工分类".format(confidence)

    return {"route": route_id, "route_name": route_name, "priority": priority,

            "force_manual": force_manual, "note": note}

QC 的 5 条类边(tech/after_sale/business/account/other)全部指向同一个路由代码节点是合法拓扑——分类器负责粗分,路由代码负责精算,这是「分类-路由」职责分离的标准写法。

5.3 多 Agent 分支与 or-chain 聚合

四个处理分支(技术/售后/商务 Agent、未分类转人工)各自输出 agent_response/agent_ok,汇聚到「工单聚合」代码节点——用 or-chain 语义取第一个有效结果(演示环境里 Agent 用代码节点模拟,接真实 Agent 时换成 HTTP 调用其 API):

agent_response = tech_resp or after_resp or business_resp or manual_resp

needs_human_review = "true" if route == "other" else "false"

聚合后再接「生成工单报告」(LLM)→「错误捕获」(Code 检查各节点是否有 error)→「错误判定」(IF-ELSE:case_error → 降级记录 + 友好提示;case_ok → 正常结束)。错误被处理了 ≠ 没事了——降级路径也要生成记录。

6. 运行验证

测试场景 输入 预期 实测结果
技术问题 「我们的 API 连续返回 502 错误,非常紧急」 分类 tech → 高优先级 → 技术 Agent → 生成工单 全链路走通,工单含分类/优先级/处理结果 ✓
售后问题 「上周买的商品有质量问题,我要退货退款」 分类 after_sale → 售后 Agent 处理 售后分支触发 ✓
模糊输入 「有问题」 质量检查 valid=false → 提示「描述过于简短」 走 reask 分支,未误入处理链路 ✓
VIP 客户 同售后问题 + user_id=vip1001 自动标记高优先级 路由代码识别 VIP,priority=high ✓
Agent 不可用 让 Agent 分支返回 error 错误捕获 → 降级提示「需人工审核」 降级链路生效,输出友好提示 ✓

7. 实战坑

现象 修复
检查类节点后没接 IF-ELSE cd_quality 直接连分类器,reask 逻辑成死代码——输入「有问题」走了「需人工审核」而不是提示补充 检查类 code(valid/reask 输出)必须接 if-else 消费其状态:valid→继续 / invalid→reask 出口(本实验 cond_quality 两个 case)
路由代码引用 QC 不存在的字段 class_names[0]/confidence 取不到值,路由全错 QC 只有 class_id/class_name/class_label/usage;路由只消费 class_id/class_name,置信度逻辑自行硬编码
PE 与 QC 查询字段名混用 参数提取节点配 query_variable_selector(那是 QC/KB 的字段) PE 用 query;QC/KB 用 query_variable_selector——两类节点字段名相反,极易混
boolean 直接输出 valid/has_warning/force_manual/agent_ok 判断不到 全部展平为 string "true"/"false"
多 End 节点 variable 重名 end / end_fallback / end_reask 输出变量重复,校验报错 每个 End 用不同 variable 名
兜底分支塞默认数据 未分类工单被「假装处理成功」 未分类走 cd_manual 转人工 + needs_human_review=true,诚实标记需人工

采坑点来自本实验 DSL 生成与运行验证的真实记录(死代码缺陷、QC 字段、PE/QC 字段名、多 End 变量)。

8. 实验文档及源码获取

文章聚焦核心配置与采坑点;实验文档还包含工单聚合完整代码、工单报告提示词模板、评估标准(分类准确率/工单完整性/错误恢复率)与后续扩展方向(工单数据库、自动回复、升级机制)。

本系列 · 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

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

微信二维码

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