Dify 高级实验(06):自动化报告——如何让系统定时自动生成周报?

Dify 实验系列 · 高级 06/10 | 实验编号:DIFY-103-06

1. 实验目的

掌握自动化报告流水线的完整链路:并行数据采集 → 变量聚合 → 指标计算与异常检测 → LLM 分析结论 → 模板转换生成报告 → Webhook 推送。核心能力:

  • 三路并行采集:销售/客服/用户数据互不依赖,同时拉取(实验用 Code 模拟,真实场景换 HTTP 节点);
  • 变量聚合(variable-aggregator):把多分支输出确定性合并,替代手写代码拼接;
  • 模板转换双格式:同一个 Template Transform 按 output_format 输出 Markdown 或 JSON;
  • 可开关推送push_enabled 布尔开关控制是否推送到企业微信/飞书机器人。

适合:运营周报/日报、经营分析、定时报表自动化。前置要求:中级实验 03 模板转换、05 并行执行、06 变量聚合。

2. 场景设计

每周一早上要出上周运营周报,涉及销售、客服、用户三个维度。原来数据分析师要花半天,现在一键全自动:拉数据 → 算环比 → 检测异常 → 生成报告 → 推送。

输入report_week(报告周次,默认「上周」)、output_format(markdown/json 下拉)、push_enabled(checkbox 推送开关,演示时关掉)。
输出:完整周报(核心指标 + 趋势分析 + 异常预警),可选推送到企业微信机器人。

3. 节点拓扑

开始(report_week / output_format / push_enabled)
  ├─ 销售数据采集(Code)────┐
  ├─ 客服数据采集(Code)────┼→ 变量聚合(合并三路 JSON)
  └─ 用户数据采集(Code)────┘
  → Code 指标计算与异常检测(环比/满意度/活跃用户 + anomalies)
    → LLM 分析结论(300 字以内,直接输出正文)
      → 模板转换(Markdown/JSON 双格式报告)
        → Code Webhook 推送(模拟 HTTP 200)
          → 结束

4. 关键配置

4.1 三路采集(cd_sales / cd_customer / cd_support)

每个采集节点同时输出两份object 结构数据(sales)给下游代码节点与模板消费,json 字符串(sales_json)给变量聚合器合并:

def main():
    return {
        "sales": {"current": {"total_revenue": 1285000, "total_orders": 342, "avg_order": 3757},
                  "previous": {"total_revenue": 1150000, "total_orders": 310, "avg_order": 3709},
                  "daily": [{"date": "周一", "revenue": 185000, "orders": 48}]},
        "sales_json": '{"current": {...}, "previous": {...}}'   # json.dumps 序列化
    }

4.2 变量聚合(va_merge)

variables[[节点id, 字段], ...] 嵌套数组格式,output_type: string

- data:
    output_type: string
    title: 变量聚合(合并数据)
    type: variable-aggregator
    variables:
    - [cd_sales, sales_json]
    - [cd_customer, customer_json]
    - [cd_support, support_json]

4.3 指标计算与异常检测(cd_analyze)

环比计算必须除零保护has_anomaly 展平为字符串(boolean 在变量选择器不可见):

def main(sales, customer, support):
    issues = []
    sales = sales or {}; customer = customer or {}; support = support or {}
    cur = sales.get("current") or {}; prev = sales.get("previous") or {}
    prev_rev = prev.get("total_revenue") or 0
    rev_change = (cur.get("total_revenue", 0) - prev_rev) / prev_rev * 100 if prev_rev else 0
    if rev_change < -10:
        issues.append(f"营收环比下降 {abs(rev_change):.1f}%,需关注")
    # 客服满意度 < 4.0、活跃用户环比 < -5% 同理检测……
    return {"revenue_change_pct": round(rev_change, 1), "anomalies": issues,
            "has_anomaly": "true" if issues else "false", "summary": "...", "analysis": {...}}

4.4 分析结论 LLM(lm_analysis)

你是一个运营数据分析师。根据以下本周({{#start.report_week#}})运营数据,生成中文分析结论。
核心指标摘要:{{#cd_analyze.summary#}}
环比变化:营收 {{#cd_analyze.revenue_change_pct#}}%,客服工单 {{#cd_analyze.ticket_change_pct#}}%,活跃用户 {{#cd_analyze.user_change_pct#}}%
异常项列表:{{#cd_analyze.anomalies#}}
要求:
1. 分析营收、订单、客服、用户四个维度的环比变化趋势
2. 指出异常项(如有)
3. 给出 2-3 条可执行的行动建议
4. 控制在 300 字以内
5. 直接输出正文,不要输出任何解释性文字

4.5 模板转换(tmpl_report)

模板开头一组 {% set %} 做空值保护,计算处全部 if prev else 0 除零保护;所有输入走 variables 映射,模板内用 {{ var }} 引用:

{% set s = sales if sales else {} %}
{% set cur = s.current if s.current else {} %}
{% set prev = s.previous if s.previous else {} %}
{% set issues = analysis.anomalies if analysis and analysis.anomalies else [] %}
{% set rev_pct = analysis.revenue_change_pct if analysis and analysis.revenue_change_pct is defined else 0 %}
{% if output_format == 'json' %}
{ "report_week": "{{ report_week }}", "revenue": {{ cur.total_revenue | default(0) }},
  "anomalies": [{% for issue in issues %}"{{ issue }}"{% if not loop.last %}, {% endif %}{% endfor %}] }
{% else %}
# 运营周报({{ report_week }})
## 核心指标
- 营收:¥{{ cur.total_revenue | default(0) }}(环比 {{ rev_pct }}%)
- 订单:{{ cur.total_orders | default(0) }} 单
## 趋势分析
{{ llm_analysis }}
## 异常预警
{% if issues | length > 0 %}{% for issue in issues %}- ⚠️ {{ issue }}{% endfor %}
{% else %}- 无异常,各项指标正常 ✅{% endif %}
{% endif %}

4.6 推送(cd_push)

push_enabled 为 true 时模拟调用企业微信机器人(真实场景换 http-request 节点,URL 指向机器人 Webhook)。

5. 运行验证

输入 期望行为 实测
report_week=上周,output_format=markdown,push_enabled=关 输出完整 Markdown 周报(核心指标/趋势分析/异常预警三节) 与预期一致
output_format=json 输出 JSON 结构报告(report_week/revenue/anomalies/analysis 字段) 与预期一致
push_enabled=开 push_status = 已推送到企业微信机器人(模拟 Webhook 调用成功,HTTP 200) 与预期一致
三路数据置空(冒烟测试) 模板空值保护生效,输出空报告而不是运行报错 与预期一致({% set %} 兜底)

6. 采坑点

现象 修复
模板变量为 null/空时直接计算 {{ x | length }}x | map(...) | sum / (x | length) 运行报错(0/0 除零、None 切片),冒烟输入空数据直接崩溃 模板开头 {% set %} 兜底默认值 + 计算处 (sum / length) if (length) > 0 else 0(dify102 全量验证实测)
长报告 text 返回空字符串 DeepSeek 把内容写进思考部分,或思考与输出共享 max_tokens 预算被挤空 报告类节点 max_tokens 提到 4000-8000 + prompt 明确「直接输出正文,不要输出任何解释性文字」(dify103_09 lm_format 实测)
has_anomaly 用 boolean 类型输出 下游 LLM 模板 {{#cd_analyze.has_anomaly#}} 取不到值(boolean 变量选择器不可见) 代码输出 "true" if x else "false" 字符串,模板语义不变(2026-07-31 dify-103 实测)
模板里直接写 {{#node.field#}} 引用 code 的 object 字段 validate_dsl.py 模板正则扫描报错,或跨节点引用不可见字段 所有输入走 variables 映射(value_selector),模板内用 {{ var }} 引用(dify102-2 21 实证)

7. 实验文档及源码获取

文章聚焦核心配置与采坑点;实验的完整分步操作(节点搭建/参数表/调试指引)见实验文档原文。


下一篇:Dify 高级实验(07):智能审批——如何让机器自动完成流程审批?

💬 你在这个实验的场景里踩过什么坑?欢迎评论区分享你的实战经验。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐