Dify 中级实验(06):变量聚合——如何确定性合并多路分支结果?
1. 业务场景
先讲一个我们实际遇到的场景。
一家互联网公司的用户运营团队,要看一个用户的完整画像:身份信息(姓名/年龄/等级)、消费行为(订单数/客单价)、服务记录(工单数/满意度)——数据分散在用户档案、订单系统、客服工单三个系统里。运营每次看用户都要开三个后台、手工拼信息,看完还说不清全不全。
我们第一次接这类需求时,第一反应也是「把三路 JSON 丢给 LLM,让它合并成一份」。真正动手才发现——LLM 合并的字段偶尔丢、偶尔被改写,同名冲突谁覆盖谁全看运气,输出不可预测。后来翻 Dify 的节点列表才发现:平台原生的 Variable Aggregator(变量聚合) 就是干这个的——用确定性方式合并多路分支输出,零 Token、结果可预测。
这不是个例。任何「多源数据要精确合并成一份」的业务场景都是这个模式:多源数据拼装用户画像、配置合并、日志/结果收集——数据在多个地方,最终要合成一个对象。
2. 场景痛点
这个流程的痛点,在运营/数据团队身上体现得最直接:
- 三系统来回切:看一个用户要开三个后台,信息全凭脑内拼接,漏一块就误判——评估用户价值时少看一块数据,决策就偏了,而「少看」自己往往毫不知情。
- 合并规则不可控:用 LLM 合并,字段偶尔丢、偶尔被改写,同名冲突谁覆盖谁全看运气——输出不可预测,下游没法依赖。
- 每次合并都烧 Token:LLM 合并一次的成本,随着调用量线性上涨——为「结构拼接」付「语义生成」的钱。
- 报告生成慢:等 LLM 慢慢组织语言,数据量大时更久,运营等不起。
本质上,「合并」要的是精确、可预测、不烧 Token——这不是 LLM 的活,是确定性工具的活。LLM 负责把结构讲成人话,结构本身不该交给它。
3. 方案:为什么是变量聚合
选变量聚合的理由,我们实际对比过:
- 确定性合并:覆盖(后到者赢)、深合并(对象递归合并)、自定义(代码节点兜底)三种心智,结果可预测——本实验用深合并,三个分支字段互补、合并后零丢失;
- 零 Token:纯结构操作,不消耗 Token,毫秒级完成;
- 与 LLM 分工:聚合器负责结构(JSON 全字段保留),LLM 负责叙事(把 JSON 讲成人话)——两者不冲突。
这篇文章我们就用它搭一个「用户 360 报告生成器」:并行获取用户画像/订单/客服交互三路数据,聚合后生成完整报告。
4. 整体架构
链路很清晰:入口收用户名 → 三路并行取数 → 聚合器确定性合并 → LLM 生成报告。聚合器是架构核心——三个分支的数据结构同构、字段互补,深合并后零丢失,LLM 只负责把合并好的 JSON 讲成人话。
5. 模块设计
5.1 三个数据源分支(Code)
每个分支输出一个 object,字段刻意设计成同构互补:
# 分支 A:用户画像
def main(user_name: str) -> dict:
name = (user_name or "张三").strip() or "张三"
return {
"profile_data": {
"user": {"name": name, "age": 28, "level": "VIP"},
"metrics": {"login_count": 45, "last_active": "2026-07-21"},
}
}5.2 聚合节点(核心)
聚合器把三个 object 合并成一个,output_type: string
时输出合并后的 JSON 文本:
- data:
output_type: string
title: 聚合多源数据
type: variable-aggregator
variables:
- - cd_profile # 注意:variables 是 [[节点id, 字段], ...] 嵌套数组
- profile_data
- - cd_orders
- orders_data
- - cd_service
- service_data
id: agg_merge⚠️ aggregator 的
variables格式与 LLM 节点不同:LLM 是[{value_selector, variable}]对象数组,aggregator 是嵌套数组[[节点id, 字段], ...],别搞混。
5.3 消费聚合结果的 LLM
长报告输出把 max_tokens 提到 8000,prompt
加「直接输出正文」约束(DeepSeek 长输出被思考挤空 text 的坑):
model:
completion_params:
max_tokens: 8000
temperature: 0.7
mode: chat
name: deepseek-v4-flash
prompt_template:
- id: p_report
role: system
text: |
用户全景数据如下(JSON 格式,由用户画像/订单/客服交互三路数据源合并而来):
{{#agg_merge.output#}}
请生成一份用户 360 报告,包括:
1. 用户身份概览
2. 行为画像
3. 价值评估
4. 服务建议
直接输出报告正文,不要输出任何解释性文字。
reasoning_format: separated6. 运行验证
| 检查项 | 预期 | 实测 |
|---|---|---|
| 合并后的 user 对象 | 含 name/age/level/total_orders/avg_order_value/ticket_count/satisfaction 全部 7 字段 | 与预期一致 |
| 合并后的 metrics 对象 | login_count/last_active/return_rate/avg_response_time 全部保留 | 与预期一致 |
| LLM 报告 | 四段式:身份概览/行为画像/价值评估/服务建议 | 与预期一致 |
对比实验:把聚合策略换成「覆盖」再跑一次——后完成分支会覆盖先完成的同名字段,user
对象只剩最后一个分支的字段(数据丢失)。这一对比直观展示「深合并 vs
覆盖」的差异。
7. 实战坑
| 坑 | 现象 | 修复 |
|---|---|---|
| 同名冲突字段被覆盖 | 并行分支完成顺序不确定,「后到者覆盖」不可预测 | 设计阶段约定冲突策略:字段互补(本实验)或代码节点自定义合并加后缀 |
| 把聚合当数值累加 | 期望 total_orders 相加,实际是对象合并 | 合并 ≠ 累加:数值统计(求和/均值)必须走代码节点 |
| aggregator 的 variables 格式写错 | 用 LLM 的
[{value_selector, variable}] 格式,校验报错 |
用嵌套数组
[[节点id, 字段], ...] |
| 长报告输出 text 为空 | DeepSeek 把内容写进思考/解释部分,max_tokens 被挤空 | max_tokens 提到 8000 + prompt 明确「直接输出正文」 |
| 校验脚本在 aggregator 上崩 | check_dsls.py 报
AttributeError: 'list' object has no attribute 'get' |
脚本局限(已修),非 DSL 错误——aggregator 格式以本文为准 |
💡 选型心法:要「精确、可预测」→ variable-aggregator;要「理解语义、自由组织」→ LLM 合并。两者不冲突:聚合器负责结构(JSON 全字段保留),LLM 负责叙事(把 JSON 讲成人话)。
8. 实验文档及源码获取
- 实验文档(完整操作步骤):DIFY-07:变量聚合——多路分支结果合并.md
- 源码(可直接导入):dify102_07_多源数据合并器.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):综合实战——自动化报告生成流水线如何从数据到周报一步到位?