Dify实战:如何用变量和Jinja2模板打造个性化AI客服(附完整代码)
最近和几个做SaaS产品的朋友聊天,他们都在头疼同一个问题:花大价钱接入了大模型,但做出来的客服机器人总像个“复读机”,对所有客户都说一样的话。VIP客户感觉不到尊贵,新用户又觉得过于机械。这让我想起去年我们团队用Dify重构客服系统时踩过的坑——真正让AI客服“活”起来的关键,往往不在模型本身,而在那些容易被忽略的“连接层”设计。
今天我想分享的,就是如何利用Dify平台提供的变量注入和Jinja2模板引擎,把一个标准化的AI客服改造成能识别用户身份、动态调整话术、甚至记住对话上下文的“智能体”。这不是简单的功能演示,而是我们从实际企业级项目中总结出的实战框架,包含完整的代码示例和配置思路。无论你是想快速上线一个差异化服务系统,还是希望优化现有机器人的交互体验,这些经验都能直接拿来用。
1. 从静态到动态:理解Dify中的变量系统
很多开发者第一次接触Dify时,会把Prompt当成一个静态的文本框——写一段指令,让AI照着执行。这种思路在Demo阶段没问题,但一旦放到真实商业场景里,立刻就会暴露局限性。比如你的电商客服无法区分普通用户和年消费百万的VIP,你的教育顾问对刚注册的学员和续费三年的老学员用同样的开场白。
Dify的变量系统,本质上是在Prompt和你的业务数据之间架起了一座桥。
1.1 基础变量注入:让AI“认识”用户
在Dify的控制台里,添加变量简单到只需要点击“输入变量”按钮。但我想强调的是命名规范和设计哲学。我们团队内部有个不成文的规定:所有业务变量名必须能清晰表达其数据来源和生命周期。
举个例子,下面是一个糟糕的变量设计:
{
{n}} // 用户名字?订单号?完全无法理解
{
{d}} // 日期?数据?设备?
而一个好的设计应该是这样的:
# 用户相关变量
{
{user_name}} # 用户姓名
{
{user_tier}} # 用户等级:'vip', 'regular', 'new'
{
{user_join_date}} # 用户注册日期
# 会话相关变量
{
{session_id}} # 当前会话ID
{
{conversation_count}} # 本月咨询次数
# 业务相关变量
{
{last_order_amount}} # 最近订单金额
{
{product_category}} # 咨询产品类别
为什么命名这么重要? 因为当你的应用发展到有几十个变量、多个开发者协作时,清晰的命名能极大降低维护成本。我建议采用snake_case(小写字母加下划线),并且为每个变量添加简短的描述注释——Dify的变量配置界面支持这个功能。
1.2 实战:构建一个带用户识别的欢迎模板
让我们看一个完整的例子。假设我们要为一家在线教育平台创建客服机器人,需要根据用户类型提供不同的欢迎语。
首先在Dify的“Prompt编排”中定义这些变量:
student_name(字符串):学生姓名student_level(字符串):'vip'、'regular' 或 'trial'course_progress(数字):课程完成百分比days_since_last_login(数字):距离上次登录的天数
然后在Prompt中使用这些变量:
{% if student_level == 'vip' %}
尊敬的VIP学员{
{student_name}},欢迎回来!
我是您的专属学习助手。看到您已经完成了{
{course_progress}}%的课程进度,真是令人钦佩!
{% if days_since_last_login > 7 %}
注意到您有一周没来学习了,需要我为您制定一个复习计划吗?
{% else %}
今天想继续学习哪个模块呢?
{% endif %}
{% elif student_level == 'regular' %}
您好{
{student_name}},欢迎回到学习平台!
您的课程进度是{
{course_progress}}%,继续保持这个学习节奏吧!
有什么问题我可以帮您解答?
{% else %}
欢迎{
{student_name}}!很高兴见到新朋友。
您正在体验我们的免费课程,如果对任何功能有疑问,随时问我。
想了解升级到正式会员的权益吗?
{% endif %}
前端调用时传入这样的JSON:
{
"student_name": "王小明",
"student_level": "vip",
"course_progress": 65,
"days_since_last_login": 3
}
AI就会生成针对性的回复。这个简单的模板实现了:
- 身份识别:VIP用户获得尊称和专属问候
- 进度感知:AI知道用户的学习进度
- 行为响应:对长期未登录的用户主动关怀
- 转化引导:对试用用户自然推荐升级
提示:在实际部署时,这些变量数据通常来自你的用户数据库或CRM系统。建议通过API网关统一处理,而不是让前端直接传递敏感信息。
2. Jinja2模板引擎:让AI拥有“判断力”
如果说基础变量是给AI“喂数据”,那么Jinja2模板就是给AI“装大脑”。这个轻量级的模板引擎支持条件判断、循环、过滤器等编程结构,让Prompt从静态文本变成可执行的逻辑代码。
2.1 条件逻辑:实现真正的差异化服务
企业客服最核心的需求之一就是“看人下菜碟”。不同客户价值不同,服务策略自然应该不同。用Jinja2的{% if %}语句,我们可以轻松实现这一点。
下面是一个电商客服的复杂模板示例:
{# 角色定义 - 根据业务线动态变化 #}
{% if business_line == 'electronics' %}
你是一名专业的数码产品客服专家,擅长解答手机、电脑、智能设备相关问题。
{% elif business_line == 'fashion' %}
你是一名时尚顾问,对服装搭配、潮流趋势有深入研究。
{% else %}
你是一名全能客服,服务态度热情专业。
{% endif %}
{# 服务策略 - 根据客户等级调整 #}
{% if customer_tier == 'platinum' %}
当前服务对象是我们的铂金会员,享有最高优先级服务。
请使用最尊重的语气,响应时间需在30秒内,可承诺特殊优惠。
可调用资源:专属客服经理、加急处理通道、最高折扣权限。
{% elif customer_tier == 'gold' %}
当前服务对象是黄金会员,提供优先服务。
请使用礼貌专业的语气,响应时间在1分钟内。
可调用资源:优先处理队列、会员专属优惠。
{% else %}
当前服务对象是普通客户,提供标准服务。
请使用友好耐心的语气,按正常流程处理。
{% endif %}
{# 对话历史处理 #}
{% if chat_history %}
以下是最近的对话记录:
{% for message in chat_history[-3:] %} {# 只保留最近3轮 #}
{
{message.role}}: {
{message.content}}
{% endfor %}
{% endif %}
{# 当前问题处理 #}
用户问题:{
{query}}
{# 根据问题类型添加特定指令 #}
{% if '退货' in query or '退款' in query %}
注意:处理退货退款问题时,请先确认订单状态和退货政策。
需要收集的信息:订单号、退货原因、商品状态。
{% endif %}
{% if '投诉' in query or '不满意' in query %}
注意:用户可能情绪不佳,请先表达理解和歉意。
安抚话术:"非常抱歉给您带来不好的体验..."
{% endif %}
这个模板展示了几个高级技巧:
- 多层条件嵌套:先判断业务线,再判断客户等级
- 历史对话截断:
chat_history[-3:]只保留最近3轮,避免token超限 - 关键词检测:在query中搜索特定词汇,动态添加处理指令
2.2 循环与过滤器:处理结构化数据
Jinja2的循环和过滤器功能在处理列表、字典等结构化数据时特别有用。假设你的客服需要处理订单咨询,而用户可能有多个订单。
{% if recent_orders %}
查询到您最近的{
{ recent_orders|length }}个订单:
{% for order in recent_orders %}
{
{ loop.index }}. 订单号:{
{ order.order_id }}
商品:{
{ order.product_name }}
金额:{
{ order.amount|float|round(2) }}元
状态:{% if order.status == 'shipped' %}已发货{% elif order.status == 'pending' %}待处理{% else %}已完成{% endif %}
下单时间:{
{ order.created_at|datetime_format('%Y-%m-%d %H:%M') }}
{% endfor %}
{% if recent_orders|length > 5 %}
(只显示最近5个订单,如需查看更早记录,请告诉我订单号)
{% endif %}
您想查询哪个订单的详情?
{% else %}
没有找到您最近的订单记录。
{% endif %}
这里用到的关键功能:
|length:获取列表长度|float|round(2):将字符串转为浮点数并保留两位小数|datetime_format:自定义日期格式化(需要注册自定义过滤器)loop.index:循环索引,从1开始
注意:Dify默认支持部分Jinja2过滤器,如果需要自定义过滤器(如上面的datetime_format),需要在后端进行扩展。我们团队的做法是封装一个Jinja2环境初始化函数,统一注册所有业务相关的过滤器。
2.3 宏定义:创建可复用的Prompt组件
当你的客服系统越来越复杂时,会发现很多Prompt片段被重复使用。Jinja2的宏(macro)功能类似于编程中的函数,可以定义一次,多次调用。
在Dify中,虽然不能直接使用{% macro %}标签,但我们可以通过“变量引用”的方式模拟类似效果。具体做法是:将常用的Prompt片段保存为知识库文档,然后在模板中通过{
{ retrieved_content }}动态引入。
不过更直接的方式是在代码层面实现复用。我们在项目中创建了一个prompt_components.py文件:
# prompt_components.py
def vip_welcome_template(customer_name, loyalty_years):
"""VIP欢迎模板"""
return f"""
尊敬的VIP客户{customer_name},您好!
感谢您{loyalty_years}年来的持续支持,您是我们的至尊会员。
今天有什么可以为您效劳的?我将为您提供最高优先级的服务。
"""
def order_status_template(order_list):
"""订单状态查询模板"""
if not order_list:
return "目前没有查询到您的订单信息。"
prompt = "查询到您的订单信息如下:\\n"
for i, order in enumerate(order_list, 1):
prompt += f"{i}. 订单号:{order['id']},状态:{order['status']},金额:{order['amount']}元\\n"
prompt += "\\n您需要了解哪个订单的详细信息?"
return prompt
def complaint_handling_template(

&spm=1001.2101.3001.5002&articleId=153159670&d=1&t=3&u=4667b15b115c4672a3a739cbcb9522ed)
2646

被折叠的 条评论
为什么被折叠?



