← 返回文章列表

Dify 中级实验(04):迭代进阶——如何批量处理数据并守住性能边界?

1. 业务场景

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

一家做产品的公司,用户反馈散落在多个渠道:App Store 评论、Google Play 评论、官方论坛帖子。产品团队每周要汇总分析一次,反馈里还混着大量垃圾内容——一句话灌水、纯标点、重复字符,直接送进情感分析会把结论带偏。人工逐条看,几百条评论看到眼瞎。

我们第一次接这类需求时,第一反应也是「在代码节点里写个 for 循环,一次跑完」。真正动手才发现——循环好写,逐条分流、嵌套遍历、输出收集全要自己造,数组一大还撞上限。后来翻 Dify 的节点列表才发现:平台原生的 Iteration(迭代) 就是干这个的——输入数组自动逐条处理,支持嵌套迭代、逐条条件分流、输出结构设计。

这不是个例。任何「拿到一个数组、逐条处理」的业务场景都是这个模式:批量取数、逐条审核、分页采集、批处理流水线——数组进来了,每条都要过一道,还要控制每条的走向。

2. 场景痛点

这个流程的痛点,在产品团队身上体现得最直接:

本质上,批量数据处理的核心不是「能不能循环」,而是「循环的边界和每一条的质量」——这两点控制不住,批处理就是灾难

3. 方案:为什么是迭代节点

选迭代节点的理由,我们实际对比过:

这篇文章我们就用它搭一个「多源反馈批量分析器」:外层迭代遍历数据源,内层迭代逐条做质量过滤,只有合格的评论才送 LLM 做情感分析。

4. 整体架构

graph TD start["开始:sources JSON"] parse["解析数据源配置:Code json.loads + 截断 [:20]"] subgraph iter_outer["外层迭代:遍历数据源(iter_sources)"] fetch["模拟获取数据源评论:Code 按 limit 生成 mock + 0.2s 延迟"] subgraph iter_inner["内层迭代:逐条质量过滤与分析(iter_reviews)"] filter["质量过滤:Code quality_ok 判定"] rule{"质量合格判断:IF-ELSE"} sentiment["情感分析:LLM"] collect["汇聚分析结果:Code"] end end summary["汇总统计:Code"] end1["结束"] start --> parse --> iter_outer iter_outer --> fetch --> iter_inner iter_inner --> filter --> rule rule -- "case_ok" --> sentiment --> collect rule -- "case_bad" --> collect collect --> summary --> end1

链路很清晰:入口收数组 → 外层迭代遍历数据源 → 内层迭代逐条过滤与分析 → 汇总统计。两级迭代是架构核心,质量过滤卡在 LLM 之前,保证分析只吃高质量数据。

5. 模块设计

5.1 开始节点变量

variables:

- label: 数据源配置(JSON 数组,每项含 name/url/limit)

  required: true

  type: paragraph        # 长 JSON 粘贴,paragraph 而非 text-input

  variable: sources

5.2 外层迭代容器

迭代输入数组有 30 个元素上限,解析节点先截断留余量:

def main(sources_text: str) -> dict:

    import json

    try:

        data = json.loads(sources_text or "[]")

        if not isinstance(data, list):

            data = []

    except Exception:

        data = []

    data = data[:20]              # 迭代上限 30,提前截断

    return {"source_items": data, "total": len(data)}

外层迭代容器配置(节选):

- data:

    error_handle_mode: terminated

    is_parallel: false

    iterator_selector: [cd_parse, source_items]

    output_selector: [iter_reviews, output]   # 内层迭代的输出

    output_type: array[string]

    parallel_nums: 10

    start_node_id: itstart0

    title: 外层迭代:遍历数据源

    type: iteration

  id: iter_sources

5.3 质量过滤(Code)

低质判定逻辑输出 quality_ok——注意布尔值展平为字符串:变量选择器看不到 boolean 类型,下游 if-else 也只用字符串比较:

def main(review: dict) -> dict:

    import re

    review = review or {}

    content = str(review.get("content", "") or "")

    quality_issues = []

    if len(content) < 3:

        quality_issues.append("内容过短")

    if re.match(r"^[!!.。??,,。]+$", content):

        quality_issues.append("无实质内容")

    if len(set(content)) <= 2 and len(content) > 1:

        quality_issues.append("疑似垃圾评论")

    return {

        "quality_ok": "true" if len(quality_issues) == 0 else "false",  # 字符串,不是布尔

        "quality_issues": quality_issues,

        ...

    }

5.4 内层分支与 LLM

IF-ELSE 用 is 比较字符串(不能用 =):

cases:

- case_id: case_ok

  conditions:

  - comparison_operator: is

    value: "true"

    variable_selector: [cd_quality, quality_ok]

  logical_operator: and

- case_id: case_bad

  conditions:

  - comparison_operator: is

    value: "false"

    variable_selector: [cd_quality, quality_ok]

  logical_operator: and

迭代内 LLM 引用当前元素用 {{#iter_reviews.item.字段#}},且必须显式 reasoning_format: separated——否则思考过程混入 text,整个迭代输出数组都被污染:

prompt_template:

- id: p_analyze

  role: system

  text: |

    分析以下用户评价:

    平台:{{#iter_reviews.item.platform#}}

    用户:{{#iter_reviews.item.user#}}

    评分:{{#iter_reviews.item.rating#}}/5

    评价内容:{{#iter_reviews.item.content#}}

    输出分析结论(50字以内):

    1. 情感倾向(正面/中性/负面)

    2. 核心关注点

    3. 可采取的行动建议

reasoning_format: separated

6. 运行验证

输入上方 sources 测试数据,观察:

检查项 预期 实测
外层迭代次数 3(3 个数据源) 3
内层迭代总次数 9(3+2+4) 9
质量过滤拦截 低质评论被拦,不走 LLM 与预期一致
汇总输出 扫描 9 条 / 有效 N 条 / 拦截 M 条 与预期一致

进阶对比:把外层迭代 is_parallel 打开(并行数 3)再跑一次,对比串行/并行耗时——本实验 mock 延迟 0.2s,数据量小看不出差距,数据量大了差异明显。

7. 实战坑

现象 修复
迭代输入数组超 30 个 运行报 then length of var "item" must be less than 30 elements 上游代码节点 data[:20] 提前截断留余量
output_selector 选 array[object] 迭代输出为空数组,下游取不到 内部代码节点 json.dumps 序列化为 string,output_type: array[string]
布尔输出给下游判断 变量选择器看不到 boolean,取不到值 输出 "true"/"false" 字符串,if-else 用 is 比较
嵌套迭代内部节点 parentId 写错层级 校验报「parentId=None 不是 iteration 节点」 parentId 是节点外层字段(与 id 同级),不是 data 内
迭代内 LLM 缺 reasoning_format 思考过程混入 text,判断逻辑全乱 显式 reasoning_format: separated

💡 嵌套迭代格式本身能通过校验,但 Dify 运行层对「迭代套迭代」支持有限——如果你的场景不需要逐源再逐条的两级结构,优先用「串联迭代 + 展平代码节点」更稳。

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

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

微信二维码

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