一、节点介绍
Dify的模板转换节点,是基于Jinja2模板引擎,为用户提供灵活的数据转换能力。借助Jinja2,可以在Dify工作流中快速完成文本拼接、格式转换、数据结构重组等操作,实现”多源数据的无缝衔接与随心转换”。
本文将展开介绍Dify模版转换节点的设计引擎——Jinja2,同时,也将展示介绍Dify模版转化节点的8种典型应用场景,包括:多源文本合成、知识检索结构化、动态表单生成、动态数据报告、智能邮件生成、API数据转换、多语言内容渲染、系统告警模板。
二、核心引擎Jinja2
介绍Dify模版转换节点8种应用场景之前,我们先来了解一下Dify模版转换节点的设计引擎——Jinja2。
1. Jinja2定义与核心目的
- 是什么?
Jinja2 是一款成熟、功能丰富、安全且高效的 Python 模板引擎。它通过优雅的语法、强大的模板继承和宏系统、丰富的过滤器以及良好的可扩展性,完美地实现了业务逻辑与展示逻辑的分离。
- 核心目的:
它的主要作用是分离应用程序逻辑(通常是 Python 代码)和展示逻辑(HTML、XML、配置文件等)。实现将动态内容嵌入到静态的文本模板中。
- 核心思想:
遵循 “Don’t Repeat Yourself” 原则,提供强大的工具(如模板继承、宏)来避免代码重复,使模板更易于维护和重用。
2. Jinja2主要特性与优势
- 直观的语法:Jinja2 的语法清晰、简洁,借鉴了 Django 模板,但通常被认为更强大、更灵活。
- {{ … }}
- 用于输出变量或表达式的结果(会进行自动转义)。
- {% … %}
- 用于控制语句(如循环、条件判断)、宏定义、块定义、模板继承等。
- {# … #}
- 用于添加注释。
- 强大的模板继承:
- 这是 Jinja2 的杀手锏之一。
- 你可以定义一个基础模板 (base.html),在其中使用 {% block block_name %} … {% endblock %} 标记出可被子模板覆盖的区域。
- 子模板
- 使用 {% extends “base.html” %} 声明继承关系,然后使用 {% block block_name %} … {% endblock %} 来覆盖或扩展父模板中对应的块。
- 极大提高了模板结构的组织性和可维护性,避免了重复的布局代码。
- 灵活的宏:
- 类似于编程语言中的函数。
- 使用 {% macro macro_name(arg1, arg2) %} … {% endmacro %} 定义。
- 在其他地方使用 {{ macro_name(val1, val2) }} 调用。
- 封装可重用的 HTML 片段或逻辑,减少重复代码。
- 丰富的过滤器:
- 用于在模板中修改变量的显示格式。
- 语法: {{ variable | filter_name }} 或 {{ variable | filter_name(arg) }}。
- 内置大量过滤器:capitalize, lower, upper, trim, striptags, safe (标记字符串为安全,不转义), default, length, join, format, date, tojson 等等。
- 可以轻松自定义过滤器。
- 自动 HTML 转义:
- 出于安全考虑(防止 XSS 攻击),Jinja2 默认会对 {{ … }} 中输出的变量进行 HTML 转义(将 <, >, &, “ 等字符转换为实体)。如果你确定内容是安全的 HTML,可以使用 | safe 过滤器关闭转义。
- 控制结构:
- 支持完整的编程逻辑:
- 条件判断:{% if condition %} … {% elif condition2 %} … {% else %} … {% endif %}
- 循环:{% for item in sequence %} … {% endfor %} (支持 loop 变量访问索引、是否首次/末次等状态)
- 变量赋值:{% set variable_name = value %}
- 模板包含:
- 使用 {% include ‘template_name.html’ %} 将另一个模板的内容包含进来。适用于复用小的、独立的组件(如页眉、页脚)。
- 可扩展性:
- 自定义过滤器:
- 通过 Python 函数轻松扩展。
- 自定义测试:
- {% if variable is test_name %},用于检查变量是否符合某种条件(如 defined, even, odd, none 等,也可自定义)。
- 自定义全局函数/变量:
- 在模板上下文中注入自定义的函数或常量。
- 自定义扩展:
- 可以编写更复杂的扩展来修改解析器行为或添加新标签。
- 沙箱环境:
- 可以在受限环境中执行模板,增强安全性(尤其当模板内容来自不可信来源时)。
- 高性能:
- Jinja2 将模板编译为 Python 字节码进行缓存,后续渲染速度非常快。虽然可能不是绝对最快的(如 Mako),但其易用性和功能丰富性在性能上做了很好的平衡。
3. Jinja2主要应用场景
- Web 开发:
- 这是最经典的用法。作为 Flask 框架的默认模板引擎,也广泛用于 Django(作为 Django Templates 的替代选择)、Bottle、Pyramid 等其他 Python Web 框架。用于生成动态 HTML 页面。
- 配置管理:
- 在 DevOps 和基础设施即代码 (IaC) 中非常流行。工具如 Ansible、SaltStack 的核心模板引擎就是 Jinja2。用于根据变量和环境动态生成配置文件(如 Nginx, Apache, systemd, 各种应用的 .conf 文件等)。
- 文档生成:
- 结合静态网站生成器(如 Pelican)或自定义脚本,动态生成报告、文档、邮件内容等。
- 代码生成:
- 自动化生成重复性代码片段或基于模板的结构化代码。
- 任何需要文本动态化的场景:
- 生成 XML、JSON(需要 | tojson 过滤器)、CSV、纯文本邮件等。
4. 安装与使用
- 安装:
- 通过 pip 安装非常简单:pip install Jinja2
- 核心组件:
- Environment:
- 核心类,存储配置(如加载器、过滤器、测试、全局变量等)、编译模板。
- Template:
- 表示一个编译好的模板对象,通过 render(**context) 方法渲染,传入一个字典作为上下文(包含模板中可用的变量)。
- FileSystemLoader / PackageLoader 等:
- 用于从文件系统或 Python 包中加载模板。
- 官方文档:
- Jinja2 的官方文档(https://jinja.palletsprojects.com/)非常详尽且清晰,是学习的最佳资源。强烈建议阅读。
三、8种典型应用场景
Dify模版转化节点的8种典型应用场景,包括:多源文本合成、知识检索结构化、动态表单生成、动态数据报告、智能邮件生成、API数据转换、多语言内容渲染、系统告警模板。
场景1:多源文本合成
将分散的标题、摘要、正文内容组合成完整文档:
代码实例:
{{ title }}
{{ intro }}
{{ body }}
场景2:知识检索结构化
将知识检索节点获取的信息及其相关的元数据,整理成一个结构化的 Markdown 格式:
代码实例:
{% for item in chunks %}
### 知识片段 {{ loop.index }}
**相关度**: {{ item.metadata.score | default(‘未评分’) }}
#### {{ item.title | trim }}
{{ item.content | replace(‘\n’, ‘\n\n’) }}
—
{% endfor %}
代码解释:
{% for item in chunks %}
- 循环开始
- 遍历名为chunks的列表,每次迭代将当前元素赋值给item变量
### 知识片段 {{ loop.index }}
- 三级标题
- 使用Markdown的###创建标题
- loop.index
- Jinja2内置变量,表示当前循环的索引(从1开始计数)
- 输出示例
- ### 知识片段 1
**相关度**: {{ item.metadata.score | default(‘未评分’) }}
- 加粗文本
- 显示”相关度”标签
- item.metadata.score
- 访问当前知识片段的评分值
- | default(‘未评分’)
- 过滤器,如果评分为空则显示”未评分”
- 输出示例
- **相关度**: 85 或 **相关度**: 未评分
#### {{ item.title | trim }}
- 四级标题
- 使用Markdown的####创建子标题
- item.title
- 知识片段的标题
- | trim
- 过滤器,去除标题两端的空白字符
- 输出示例
- #### 人工智能发展简史
{{ item.content | replace(‘\n’, ‘\n\n’) }}
- 内容显示
- 输出知识片段的主体内容
- | replace(‘\n’, ‘\n\n’)
- 过滤器,将单换行符\n替换为双换行符\n\n
- 目的
- 在Markdown中,单换行符不会产生新段落,双换行符会创建段落分隔
- 效果
- 保留原文换行结构的同时确保正确分段
{% endfor %}
- 循环结束
- 标记循环结构结束
最终输出示例:
### 知识片段 1
**相关度**: 92
#### 机器学习基础
监督学习需要标注数据…
无监督学习发现数据内在结构…
—
### 知识片段 2
**相关度**: 未评分
#### 神经网络原理
神经元模拟生物神经细胞…
反向传播算法优化权重…
—
场景3:动态表单生成
创建支持多种数据格式的交互式表单:
代码实例:
<form data-format=”json”>
<label>用户登录</label>
<input type=”text” name=”username” placeholder=”请输入账号”>
<input type=”password” name=”password” placeholder=”请输入密码”>
<label>内容编辑</label>
<textarea name=”content”></textarea>
<div class=”datetime-group”>
<input type=”date” name=”schedule_date”>
<input type=”time” name=”schedule_time”>
</div>
<button data-variant=”primary”>提交</button>
</form>
场景4:动态数据报告生成
将数据库查询结果转换为可视化报告:
代码实例:
# 销售报告 {{ date.today() | date_format(“%Y-%m-%d”) }}
**总销售额**: ¥{{ total_sales | round(2) | thousands_separator }}
## 区域表现
{% for region in regions %}
– {{ region.name }}:
– 完成率: {{ (region.actual/region.target*100) | round(1) }}%
– 同比增长: {{ region.growth_rate | percent }}
{% endfor %}
代码解释:
1. 报告标题和日期
# 销售报告 {{ date.today() | date_format(“%Y-%m-%d”) }}
- # 销售报告
- Markdown格式的一级标题
- {{ … }}
- Jinja2动态表达式
- date.today()
- 调用日期对象获取当前日期
- date_format(“%Y-%m-%d”)
- 使用过滤器格式化日期%Y-%m-%d,输出格式如2023-10-05
- 最终输出
- # 销售报告 2023-10-05
2. 总销售额显示
**总销售额**: ¥{{ total_sales | round(2) | thousands_separator }}
- **总销售额**:
- Markdown加粗文本
- {{ total_sales … }}
- 动态变量
- 双重过滤器处理:
- round(2)
- 四舍五入保留2位小数(如123456.789 → 123456.79)
- thousands_separator
- 添加千位分隔符(如123456.79 → 123,456.79)
- 最终输出
- **总销售额**: ¥123,456.79
3. 区域数据循环
{% for region in regions %}
– {{ region.name }}:
– 完成率: {{ (region.actual/region.target*100) | round(1) }}%
– 同比增长: {{ region.growth_rate | percent }}
{% endfor %}
循环结构:
- {% for region in regions %}
- 遍历regions列表中的每个区域对象
- {% endfor %}
- 循环结束标记
每项输出内容:
- {{ region.name }}
- 区域名称,列表项格式(如- 华东地区)
- 完成率:{{ (region.actual/region.target*100) | round(1) }}%
- 实际值/目标值)×100,结果保留1位小数(如85.714% → 85.7%)
- 同比增长: {{ region.growth_rate | percent }}
- 增长率格式化,小数转为百分比(如0.15 → 15%)
完整输出示例:
假设数据为:
regions = [
{“name”: “华东”, “actual”: 85, “target”: 100, “growth_rate”: 0.15},
{“name”: “华北”, “actual”: 42, “target”: 50, “growth_rate”: 0.08}
]
生成的报告内容:
# 销售报告 2023-10-05
**总销售额**: ¥1,234,567.89
## 区域表现
– 华东:
– 完成率: 85.0%
– 同比增长: 15%
– 华北:
– 完成率: 84.0%
– 同比增长: 8%
场景5:智能邮件生成
根据用户行为生成个性化邮件内容:
代码实例:
尊敬的{{ user.name }}:
{% if last_login_days > 30 %}
我们注意到您已有{{ last_login_days }}天未登录,为您准备了专属回归礼包!
{% elif unpaid_orders %}
您的订单#{{ unpaid_orders[0].id }}尚未支付,点击完成支付:
{{ unpaid_orders[0].pay_link }}
{% else %}
根据您的浏览记录,为您推荐以下商品:
{% for item in recommended_items %}
– {{ item.name }}(同类用户评分:{{ item.rating }}/5)
{% endfor %}
{% endif %}
场景6:API数据转换
将内部数据结构转换为标准API响应:
代码实例:
{
“status”: “success”,
“data”: {
“userInfo”: {
“userId”: “{{ user.uid | string }}”,
“displayName”: “{{ user.first_name }} {{ user.last_name[:1] }}.”,
“membershipLevel”: “{{ ‘VIP’ if user.points > 1000 else ‘普通’ }}”
},
“features”: [
{% for feature in enabled_features %}
{
“name”: “{{ feature.name }}”,
“config”: {{ feature.config | tojson }}
}{{ “,” if not loop.last }}
{% endfor %}
]
}
}
场景7:多语言内容渲染
根据区域设置动态切换展示内容:
代码实例:
{% set lang = request.headers.get(‘Accept-Language’, ‘en’)[:2] %}
{% if lang == ‘zh’ %}
欢迎回来,{{ user.name }}!您有{{ notification_count }}条未读消息
{% elif lang == ‘ja’ %}
{{ user.name }}様、未読通知が{{ notification_count }}件あります
{% else %}
Welcome back, {{ user.name }}! You have {{ notification_count }} unread messages
{% endif %}
{{ _(‘current_balance’) }}:
{{ balance | currency(locale=lang) }}{{ _(‘current_balance’) }}: {{ balance | currency(locale=lang) }}
场景8:系统告警模板
生成可定制的监控告警信息:
代码实例:
[{{ alert.level | upper }}] 系统告警
**触发时间**: {{ alert.timestamp | datetimeformat(‘%Y-%m-%d %H:%M:%S’) }}
**影响服务**: {{ alert.services | join(‘, ‘) }}
{% if alert.metrics %}
## 监控指标
{% for metric in alert.metrics %}
– {{ metric.name }}:
– 当前值: {{ metric.value }}
– 阈值: {{ metric.threshold }}
– 持续时间: {{ metric.duration }}分钟
{% endfor %}
{% endif %}
{% if alert.suggestions %}
## 处理建议
{{ alert.suggestions | bulleted_list }}
{% endif %}
文章来自于“耳东AI”,作者“耳东AI”。