Dify 企业级实验(02):跨应用状态传递——多轮对话的状态如何跨应用不丢?
Dify 实验系列 · 企业级 02/12 | 实验编号:DIFY-104-02
基于 Dify 1.16.1 实测(2026-08)
1. 业务场景
先讲一个我们实际遇到的场景。
企业客服最常见的对话长这样:用户第一轮说「我要退货」,第二轮补上订单号,第三轮才说清楚期望怎么处理。信息是分轮次到齐的——客服对话应用每轮只拿到一小块,但后台工单应用要的是一整份。
我们第一次接这类需求时,第一反应也是「状态嘛,存数据库不就行了」。真正动手才发现——Dify 的 chatflow 原生就有对话变量(conversation_variables),跨轮次保持,配合工具调用和变量写回就能组成状态闭环,根本不用自己搭存储。难的不是存,是「每一轮都在正确的时间把状态拿出来用」。
如果对话应用收集到的状态传不到后台,工单就建不起来;就算建起来了,用户第二天回来问「我的工单处理到哪了」,系统也得记得住、答得上。
这不是个例。任何「用户分步提供信息、后台分步处理」的场景都是这个模式:理赔资料收集、预约信息确认、多步表单填写——对话跨轮次,状态就必须跨轮次。
2. 场景痛点
这个流程的痛点,在客服团队身上体现得最直接:
- 状态随轮次丢失:用户第二轮补了订单号,第一轮的问题描述没存住,信息永远凑不齐,工单建不起来——用户重复描述,体验直线下降。
- 重复建单:用户再问一次,系统当成新单又建一张,后台被重复工单淹没,真实问题淹没在噪音里。
- 信息不全硬建单:缺订单号也创建工单,工单到后台无法处理,变成死单。
- 跨应用两张皮:对话应用记得、后台不记得,状态不同步,两边各说各话。
本质上,多轮对话的价值恰恰在「跨轮次记住」——状态没地方放、没人管,用户说过的话就等于白说。
3. 方案:为什么是对话变量 + 状态写回
Dify 的 chatflow 有一个原生状态容器——对话变量(conversation_variables),配合工具调用与变量写回,正好组成跨应用状态闭环。选它的理由:
- 平台原生:对话变量跨轮次保持(102-15/103 实测),天然就是「状态容器」,不用自己造;
- 写回闭环:工单应用返回工单号后,用 assigner 节点写回对话变量,用户下一轮能查到、系统也知道已建单,不重复创建;
- 可持久化可审计:工单记录落到外部 KV,工作流重启状态不丢。
这篇文章我们就用它搭一个「客服工单状态闭环」:客服对话应用收集状态、工单应用处理、工单号写回对话变量。
4. 整体架构
链路很清晰:每轮提取新信息 → 与对话变量合并 → 校验完整性 → 建单或追问 → 工单号写回。状态闭环的关键是「写回」——工单号回到对话变量,用户下一轮就能查到。
5. 模块设计
5.1 对话变量(状态容器)
chatflow 在conversation_variables里声明 4 个状态变量,跨轮次保持(102-15/103 实测)。id 必须是合法 UUID(非 UUID 会报 SQL 500):
conversation_variables:-description:已收集的订单号id:53ad6c85-cc60-4d1f-b8bf-06d7e6fb90a3name:order_idselector:[conversation,order_id]value:''value_type:string# issue_desc / expectation / ticket_no 同结构5.2 合并校验 code(cd_update)
PE 每轮只提取新信息,要和对话变量已有值合并,并输出两个字符串状态标志:
defmain(pe_order_id,pe_issue_desc,pe_expectation,cv_order_id,cv_issue_desc,cv_expectation,cv_ticket_no)->dict:order_id=pe_order_idorcv_order_idor""issue_desc=pe_issue_descorcv_issue_descor""expectation=pe_expectationorcv_expectationor""ticket_exist="true"ifcv_ticket_noelse"false"missing=[]ifnotorder_id:missing.append("订单号")ifnotissue_desc:missing.append("问题描述")ifnotexpectation:missing.append("期望结果")complete="true"ifnotmissingelse"false"ifticket_exist=="true":message="您的工单 "+str(cv_ticket_no)+" 正在处理中,请耐心等待…"elifcomplete=="true":message="已收集完整信息,正在为您创建工单…"else:message="请补充以下信息:"+"、".join(missing)+"。"return{"order_id":order_id,"issue_desc":issue_desc,"expectation":expectation,"complete":complete,"ticket_exist":ticket_exist,"message":message}5.3 触发条件(if5)
创建工单需要complete=true且ticket_exist=false——校验结果必须接 if-else 消费,否则状态不全也会触发下游(102-20 实测教训):
-id:if5data:type:if-elsetitle:是否创建工单cases:-case_id:createlogical_operator:andconditions:-comparison_operator:isvalue:'true'variable_selector:[cd_update,complete]-comparison_operator:isvalue:'false'variable_selector:[cd_update,ticket_exist]5.4 工单工具的参数模板
跨应用传递 = 工具调用参数。坑:chatflow 的 tool 节点参数模板引用 code 节点输出偶发为空(工具报参数 required);本实验状态本就存在对话变量,改用对话变量模板语义最贴合:
-id:tool5cdata:type:tooltitle:创建工单(工单应用)provider_type:workflowtool_name:dify104_02_gongdantool_parameters:order_id:type:mixedvalue:'{{#conversation.order_id#}}'issue_desc:type:mixedvalue:'{{#conversation.issue_desc#}}'expectation:type:mixedvalue:'{{#conversation.expectation#}}'tool_configurations:*tool_parameters# 双写同值5.5 写回工单号(状态闭环)
工具返回ticket_no后,用 assigner 节点写回对话变量(write_mode: over-write),用户下一轮就能查到工单号,且ticket_exist=true保证不重复建单。
6. 运行验证
| 输入 | 预期 | 结果 |
|---|---|---|
| ①「我要退货」 | PE 未提取到订单号 → 追问「请补充订单号」 | 通过(4 轮多轮对话实测) |
| ② 补订单号+问题描述 | 字段齐全 → 调用工单应用(Workflow as Tool)创建工单 → 返回工单号 | 通过 |
| ③④ 后续轮次问「我的工单处理到哪了」 | 对话变量已写回工单号 → 回复处理中,不重复建单 | 通过 |
| 检查 KV 工单记录 | 只有 1 条(不重复创建) | 通过 |
7. 实战坑
| 坑 | 现象 | 修复 |
|---|---|---|
| chatflow 工具参数模板引用 code 节点输出 | 偶发为空,工具报参数 required | 改用对话变量模板{{#conversation.x#}}(实测,本实验) |
| 工具重建时 parameters 传空数组 | 调用方传参校验失败 | parameters 必须 = 子工作流 start 变量(实测,本实验) |
code 字符串状态判断用elif complete: | 字符串 “false” 恒真,误触发「已收集完整」分支 | 必须== "true"显式比较(实测,本实验) |
| 对话变量 id 非 UUID | 报 SQL 500 错误 | 使用合法 UUID(实测,102-15) |
| 校验结果不接 if-else | 状态不全也触发下游(死代码) | if-else 消费 complete/ticket_exist(实测,102-20) |
| code 节点沙箱禁写文件 | 报PermissionError: /tmp | 工单记录改用本机 KV 模拟服务持久化(实测,本批) |
8. 实验文档及源码获取
- 实验文档(完整操作步骤):DIFY-104-02:跨应用状态传递——多轮对话状态跨应用不丢.md
- 源码(可直接导入,一个应用一个 DSL):
- 源码一(客服对话 chatflow):dify104_02_01_客服对话.yml
- 源码二(工单创建 workflow):dify104_02_02_工单创建.yml
- 全部源码目录:dify-104/dsl
文章聚焦核心配置与采坑点;实验的完整分步操作(节点搭建/参数表/调试指引)见实验文档原文。
下一篇:Dify 企业级实验(03):事件驱动流水线——Webhook 与定时触发如何组成异步处理链?
💬 你在这个实验的场景里踩过什么坑?欢迎评论区分享你的实战经验。