Dify 中级实验(05):并行执行——如何让多路任务同时跑?
1. 业务场景
先讲一个我们实际遇到的场景。
一家电商公司的客服/销售场景:用户问「这款产品怎么样,现在买划算吗?」——要完整回答,需要同时看三路信息:产品技术文档(功能怎么样)、库存价格(现在什么价、有没有货)、市场动态(同行怎么评价)。以前是人工分别查三个系统再拼答案,一次咨询要花好几分钟。
我们第一次接这类需求时,第一反应也是「串行跑吧,反正就三步」。真正动手才发现——文档查完查库存、库存查完查动态,串行是最省事的写法,也是最慢的写法,用户等得越久流失越快。后来翻 Dify 的节点列表才发现:平台原生支持并行分支(Parallel Branch)——从开始节点拉出多条独立路径同时执行,最后汇聚到同一个节点整合。
这不是个例。任何「一个综合问题需要多路取数才能回答」的业务场景都是这个模式:知识库 + API + 搜索三路取数、多源信息汇总、互不依赖的子任务并发——问题是一个,答案要拼三块。
2. 场景痛点
这个流程的痛点,在服务/销售团队身上体现得最直接:
- 串行太慢:三步依次跑,总耗时是各步之和——文档查完查库存、库存查完查动态,用户等得越久流失越快。
- 信息分散:文档、价格、动态各在一个系统,人工分别查再手动拼,漏一块答案就不完整——答一半,比不答更让人不放心。
- 来源不可追溯:回答说不清每条信息来自哪,用户没法判断可信度,错了也无从追责。
- 多路编排靠人肉:多路任务手工协调,一个分支挂了整条链干等,没人知道哪路失败了——失败不可怕,可怕的是失败了没人知道。
本质上,多路取数的瓶颈从来不是「能不能同时跑」,而是「跑完怎么合、怎么讲清楚来源」——并行只是手段,汇聚才是目的。
3. 方案:为什么是并行分支
选并行分支的理由,我们实际对比过:
- 平台原生并行:从开始节点直接拉多路,互不依赖的任务同时执行,不需要自己写并发逻辑;
- 收益明确:并行总耗时 ≈ 最慢分支耗时,而不是各分支之和——I/O 密集(API/检索)场景收益明显;
- 汇聚点可控:所有分支汇到一个 LLM 整合输出,带来源标注,信息可追溯。
这篇文章我们就用它搭一个「多源情报聚合器」:用户问一个综合问题,知识库/库存 API/互联网搜索三路并行取数,最后 LLM 整合带来源标注回答。
4. 整体架构
链路很清晰:入口收问题 → 三路并行取数 → 单一汇聚点整合。三条线互不依赖,从开始节点直接拉出三路;唯一汇聚点是最后的 LLM。
5. 模块设计
5.1 知识库分支
- data:
dataset_ids:
- 87e2a4af-3f5c-4fb4-8468-a42609c5834c # 导入后替换为你的知识库 ID
output_retrieval_result: true # 必须 true,否则 result 为空
query_variable_selector: [start, user_query]
retrieval_mode: single
top_k: 5
title: 产品知识库检索
type: knowledge-retrieval
id: kb_retrieval摘要 LLM 直接用三花括号引用检索结果——KB → LLM 用
{{#kb_retrieval.result#}},context 保持
enabled: false:
prompt_template:
- id: p_summary
role: system
text: |
根据以下产品文档信息,提取和问题相关的内容:
问题:{{#start.user_query#}}
文档:{{#kb_retrieval.result#}}
格式要求:用 2-3 句话概括核心信息。如果文档中没有相关信息,说明"文档中未找到相关信息"。
reasoning_format: separated5.2 模拟 API 与搜索分支
# 分支 B:模拟价格库存 API(0.5s 延迟)
def main(product_name: str) -> dict:
import time
time.sleep(0.5)
mock_data = {
"产品A": {"price": 99.9, "stock": 500, "discount": "新品9折"},
"产品B": {"price": 199.0, "stock": 23, "discount": "限时8折"},
"产品C": {"price": 59.9, "stock": 0, "discount": "无"},
}
data = mock_data.get(product_name, {"price": "未知", "stock": "未知", "discount": "无"})
status = "有货" if data.get("stock", 0) > 0 else "缺货"
text = "产品:{};价格:{}元;库存:{};状态:{};优惠:{}".format(
product_name or "未知", data.get("price"), data.get("stock"), status, data.get("discount"))
return {"price_text": text}5.3 合并 LLM
三路输出通过 variables 映射进
prompt,要求带来源标注:
prompt_template:
- id: p_merge
role: system
text: |
你是一个情报分析师。请整合以下三路信息,给用户一个全面、结构化的回答。
用户问题:{{#start.user_query#}}
━━━ 来源 A:[知识库] 产品文档摘要 ━━━
{{#lm_summary.text#}}
━━━ 来源 B:[库存API] 价格与库存信息 ━━━
{{#cd_price.price_text#}}
━━━ 来源 C:[搜索] 市场动态 ━━━
{{#cd_search.search_text#}}
要求:
1. 以「来源标注」标注每条信息的出处([知识库]/[库存API]/[搜索])
2. 如果不同来源信息冲突,明确指出
3. 最终给出综合建议
reasoning_format: separated⚠️ prompt 里引用上游字段一律写
{{#节点id.字段#}}三花括号——{{变量名}}双花括号在 1.16 里不会被替换,会字面传给模型(实测踩坑,见第 7 节)。
6. 运行验证
| 输入 | 期望行为 | 实测 |
|---|---|---|
| product: 产品A,query: 有什么优惠? | 三路并行,合并回答带 [知识库]/[库存API]/[搜索] 标注 | 与预期一致 |
| product: 产品C,query: 如何购买? | 知识库有信息,但库存为 0,回答指出缺货 | 与预期一致 |
耗时对比:单分支串行约 1.3s,并行约 0.8s——并行收益 = 最慢分支耗时,而不是所有分支之和。打开执行日志,展开并行分支看每路独立耗时与交叉的日志流。
7. 实战坑
| 坑 | 现象 | 修复 |
|---|---|---|
| 并行分支间互相引用变量 | 分支 B 想读分支 A 的中间结果,取不到 | 分支内变量互不可见,只能在下游汇聚节点消费各分支输出 |
prompt 用 {{变量名}}
双花括号 |
LLM 收到字面占位符,回答「参考资料为空」 | 一律 {{#节点id.字段#}}
三花括号(实测:同应用两个 LLM 对照验证) |
| KB 结果在 LLM 模板取不到 | 误以为必须开 context 模式 | {{#kb_retrieval.result#}}
直接引用 + context.enabled: false |
| 并行日志交叉难读 | 多分支日志混在一起,定位问题慢 | 单次只调试一个分支,或把每个分支的摘要打印到输出 |
| 以为并行必然更快 | CPU 密集型任务并行无收益,甚至更慢 | 并行只对 I/O 密集型(API/检索)有效;合并节点复杂度可能吃掉加速收益 |
💡 并行架构的设计顺序:先定汇聚点,再画分支。三条线最后都要在同一个 LLM/聚合节点汇合,分支越多,合并 prompt 的编排成本越高——这是并行方案真正的成本。
8. 实验文档及源码获取
- 实验文档(完整操作步骤):DIFY-06:并行执行——同时做三件事.md
- 源码(可直接导入):dify102_06_多源情报聚合器.yml
文章聚焦核心配置与采坑点;实验的完整分步操作(节点搭建/参数表/调试指引)见实验文档原文。
- Dify 中级实验(01):参数提取器实战——如何从自然语言中提取结构化数据?
- Dify 中级实验(02):问题分类器——智能路由引擎如何四路分发?
- Dify 中级实验(03):模板转换实战——如何用零 Token 完成文本加工?
- Dify 中级实验(04):迭代进阶——如何批量处理数据并守住性能边界?
- Dify 中级实验(05):并行执行——如何让多路任务同时跑?
- Dify 中级实验(06):变量聚合——如何确定性合并多路分支结果?
- Dify 中级实验(07):子工作流——如何把公共逻辑做成可复用积木?
- Dify 中级实验(08):代码节点进阶——如何用标准库处理文件与数据?
- Dify 中级实验(09):HTTP 节点进阶——如何搞定认证、分页与错误重试?
- Dify 中级实验(10):知识库深度调优——如何科学评估检索质量?
- Dify 中级实验(11):高级 RAG 流水线——如何搭建多路检索与精排?
- Dify 中级实验(12):Agent 深度配置——如何让智能体自主调用工具?
- Dify 中级实验(13):多 Agent 协作——如何编排多个智能体分工干活?
- Dify 中级实验(14):对话变量与状态管理——如何让工作流记住多轮对话的状态?
- Dify 中级实验(15):条件分支高阶策略——多条件路由如何避免分支爆炸?
- Dify 中级实验(16):错误处理与降级——工作流如何有尊严地失败?
- Dify 中级实验(17):调试监控与性能优化——响应慢和 Token 超支如何定位?
- Dify 中级实验(18):插件开发入门——如何把工作流变成 Agent 可调用的工具?
- Dify 中级实验(19):综合实战——如何把 19 个实验串成一条生产级流水线?
- Dify 中级实验(20):综合实战——自动化报告生成流水线如何从数据到周报一步到位?