要在dify中实现提示词响应上下文、条件分支与模块复用,必须采用jinja2高级渲染:通过模板继承统一结构、宏封装高频逻辑、条件判断动态路由、过滤器链保障安全。
☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 多模态理解力帮你轻松跨越从0到1的创作门槛☜☜☜

要在Dify中让提示词真正响应上下文变化、支持条件分支与模块复用,必须突破基础变量替换,进入Jinja2高级渲染阶段——这一步直接决定提示词能否承载复杂业务逻辑,而非仅做字符串拼接。
用模板继承统一工作流结构
当你在多个节点(如意图识别→RAG检索→最终回复)中重复写时间格式化、错误兜底、安全转义时,就该引入模板继承了。它不是锦上添花,而是避免后期改一处漏十处的根本解法。
第一步:在任意一个节点的Jinja2代码区顶部,定义基础块结构:
{% block pre_processing %}{% endblock %}
{% block main_content %}{% endblock %}
{% block post_processing %}{% endblock %}
第二步:在需要复用该结构的其他节点中,用{% extends "base_template.jinja" %}声明继承关系——注意,【Dify不实际读取文件系统,这里的"base_template.jinja"是逻辑引用名,必须与你当前节点中定义的块名完全一致】。
第三步:只覆盖你需要定制的部分,例如在RAG节点中写:
{% extends "base_template.jinja" %}
{% block main_content %}
请基于以下检索结果回答用户问题:
{% for doc in rag_results %}
- {{ doc.title | truncate(80) }}: {{ doc.content | escape }}
{% endfor %}
{% endblock %}
用宏(macro)封装高频逻辑
当某段逻辑(如会员等级加权、多语言fallback、敏感词过滤)在3个以上节点反复出现,宏就是你的代码压缩包。
方法一:在单个节点内定义并调用
{% macro format_user_profile(user) %}
{{ user.name }}({{ user.level | upper }}会员,注册{{ user.join_days }}天)
{% endmacro %}
欢迎回来,{{ format_user_profile(context.user) }}!
方法二:跨节点复用——把宏定义放在最上游节点(如“会话初始化”节点),然后在下游节点通过context对象传递已渲染结果,【不要在下游重复定义同名宏,否则会覆盖上游逻辑】。
用条件判断实现动态提示路径
用户问“退货”,和问“查物流”,提示词结构完全不同;硬编码两条提示词会失控,用if/elif/else才能守住边界。
① 先判断核心意图:
{% if context.intent == "return" %}
您正在申请退货,请确认订单号{{ context.order_id }},并说明退货原因:
{% elif context.intent == "tracking" %}
正在为您查询订单{{ context.order_id }}的物流状态,请稍候……
{% else %}
请明确您的需求:退货、查物流,还是其他服务?
{% endif %}
② 嵌套判断处理权限差异:
{% if context.user.level == "vip" %}
作为VIP用户,您可享受优先审核与免运费退货。
{% elif context.user.level == "gold" %}
黄金会员退货需提供开箱视频。
{% else %}
普通用户退货需满足7天无理由条件。
{% endif %}
这一步不能省略context.key存在性检查——如果intent字段为空,整个if块会静默失败,返回空字符串,导致模型收不到任何指令。
用过滤器链强化输出可控性
Dify内置dify_前缀过滤器是安全阀,不用它们,就等于裸奔。
直接用{{ user_input }}风险极高——可能带XSS脚本、超长文本拖垮模型。必须链式过滤:
{{ user_input | trim | truncate(200) | escape | dify_sanitize }}
其中dify_sanitize是Dify专属过滤器,专清LLM注入类payload;而truncate(200)必须放在escape之前,否则HTML实体字符会被计入长度,导致截断失效。











