12_Dify中使用工作流构建知识问答助手实战

前言

本文对比了 Dify 中工作流(可视化业务逻辑编排)与 Agent(自主决策AI)的区别与演进关系,并详细演示了知识问答助手的完整实战流程。从创建知识库(分段、索引、检索设置)入手,逐步构建工作流:包括开始节点、意图识别节点(通过代码判断问候/人工/专业问题)、选择器节点(分流)、知识库检索节点、判断检索结果节点(有结果走RAG大模型,无结果走闲聊大模型),以及最终发布和运行测试。实战覆盖了规则回复、人工转接、专业问答和通用闲聊等多种场景,展示了工作流的灵活性与可控性。

一、工作流

工作流是业务逻辑的可视化执行

工作流作用:它将一个复杂的任务分解成一系列可管理的、按顺序或按条件执行的步骤,并通过图形化的界面将这些步骤连接起来。

二、Agent

自主决策的AI助手

三、工作流与Agent

两者不是对立,而是演进

四、Difly的两种工作流类型

五、创建工作流的标准流程

六、知识问答助手实战

6.1 创建知识库

选择文件

点击下一步

分段设置

索引方式

检索设置

保存并处理

前往文档

回到知识库菜单

6.2 创建工作流

6.2.1 创建空白应用

填写信息

选择开始节点:用户输入

6.2.2 开始节点

6.2.3 意图识别节点

在画布中右键选择添加节点 --> 执行代码

意图识别代码实现:判断用户是否属于打招呼用语、或者找人工、还是询问电商知识(需要RAG检索)

代码如下:

python 复制代码
import random

def main(query: str) -> dict:
    """
    基于固定短语匹配的跨境电商问答处理器

    Args:
        query: 用户输入的问题

    Returns:
        Dict: 包含回复类型、回复内容信息的字典
    """
    try:
        # 错误处理1:检查输入是否为空或仅包含空白字符
        if not query or not query.strip():
            return {
                "type": "error",
                "response": "请输入您的问题",
                "need_rag": False,
                "original_query": query
            }

        # 去除首尾空格
        query = query.strip()
        
        # ---------- 打招呼相关的固定短语 ----------
        greeting_phrases = {
            "基本问候": ["你好", "您好", "嗨", "hi", "hello", "哈喽", "早上好", "下午好", "晚上好", "喂", "在吗", "在不在"],
            "询问身份": ["你是谁", "你叫什么", "是什么机器人", "你是人工吗", "你是真人吗"],
            "询问状态": ["你在吗", "在干嘛", "忙吗"],
            "询问能力": ["你能做什么", "你会什么", "可以帮我吗", "能回答问题吗"],
            "开始对话": ["开始", "我们开始吧", "咨询一下", "问个问题"],
            "测试类": ["test", "测试", "ping"]
        }
        
        greeting_response = "你好,很高兴为您服务!我是您的跨境电商学习小助手,专业为你答疑解惑。"
        
        # ---------- 礼貌用语(感谢) ----------
        thank_phrases = {
            "感谢词": ["谢谢", "多谢", "感谢", "thanks", "thank you", "thx", "谢谢了", "谢谢你", "非常感谢"]
        }
        
        # ---------- 礼貌用语(告别) ----------
        goodbye_phrases = {
            "告别词": ["再见", "拜拜", "bye", "goodbye", "回头见", "88", "再会", "告辞", "退下"]
        }
        
        polite_responses = {
            "thank": {
                "default": "不客气,很高兴能帮到您!请问还有其他跨境电商方面的问题吗?",
                "random": ["您太客气了~", "不用谢,这是我应该做的", "随时为您服务"]
            },
            "goodbye": {
                "default": "再见!祝您生活愉快,欢迎随时回来咨询。",
                "random": ["拜拜~", "下次见", "祝您购物愉快,再见!"]
            }
        }
        
        # ---------- 人工服务相关短语 ----------
        human_service_phrases = {
            "直接要求": ["人工", "人工客服", "转人工", "找人工", "人工服务"],
            "转接相关": ["转接人工", "接人工", "转人工客服", "帮我转人工"],
            "真人服务": ["真人", "真人客服", "活人", "真人员工"],
            "客服相关": ["客服", "客服人员", "在线客服"],
            "老师相关": ["老师", "导游", "助教"],
            "专业服务": ["专家", "专员", "人工解答"],
            "投诉相关": ["投诉", "差评", "要投诉", "不满意服务"],
            "售后相关": ["售后", "退货人工", "退款人工"],
            "不满意": ["机器人没用", "自动回复没用", "听不懂", "换个真人"]
        }
        
        human_service_response = "同学,点击 http://www.flyoss.com 可进入人工答疑"
        
        # ---------- 辅助函数 ----------
        def normalize_text(text: str) -> str:
            import string
            translator = str.maketrans('', '', string.punctuation)
            text_no_punct = text.translate(translator)
            return text_no_punct.lower().strip()
        
        def exact_match_check(query_text: str, phrase_set) -> bool:
            norm_query = normalize_text(query_text)
            for category, phrases in phrase_set.items():
                for phrase in phrases:
                    if norm_query == normalize_text(phrase):
                        return True
            return False
        
        def contains_match_check(query_text: str, phrase_set) -> bool:
            norm_query = normalize_text(query_text)
            for category, phrases in phrase_set.items():
                for phrase in phrases:
                    if normalize_text(phrase) in norm_query:
                        return True
            return False
        
        # ---------- 处理输入 ----------
        # 1. 检查感谢类礼貌用语
        if exact_match_check(query, thank_phrases) or contains_match_check(query, thank_phrases):
            thank_reply = random.choice(polite_responses["thank"]["random"]) + " " + polite_responses["thank"]["default"]
            return {
                "type": "greeting",
                "response": thank_reply,
                "need_rag": False,
                "original_query": query
            }
        
        # 2. 检查告别类礼貌用语
        if exact_match_check(query, goodbye_phrases) or contains_match_check(query, goodbye_phrases):
            goodbye_reply = random.choice(polite_responses["goodbye"]["random"]) + " " + polite_responses["goodbye"]["default"]
            return {
                "type": "greeting",
                "response": goodbye_reply,
                "need_rag": False,
                "original_query": query
            }
        
        # 3. 检查打招呼
        if exact_match_check(query, greeting_phrases) or contains_match_check(query, greeting_phrases):
            return {
                "type": "greeting",
                "response": greeting_response,
                "need_rag": False,
                "original_query": query
            }
        
        # 4. 检查人工服务请求
        if exact_match_check(query, human_service_phrases) or contains_match_check(query, human_service_phrases):
            return {
                "type": "transfer_human",
                "response": human_service_response,
                "need_rag": False,
                "original_query": query
            }
        
        # 5. 其他情况需要 RAG 检索
        return {
            "type": "rag_needed",
            "response": "",
            "need_rag": True,
            "original_query": query
        }
    
    except Exception as e:
        # 全局异常捕获,防止因意外错误导致工作流中断
        return {
            "type": "error",
            "response": f"处理您的请求时出现内部错误,请稍后重试。错误信息:{str(e)}",
            "need_rag": False,
            "original_query": query if 'query' in locals() else ""
        }

添加输出节点

输出变量

测试运行

6.2.4 选择器节点

如果意图识别属于:打招呼、人工服务这两种类型,直接返回默认结果结束;否则,直接经过知识库检索

添加选择节点

条件分支

6.2.5 知识库检索节点

如果用户的问题属于打招呼、找人工等用语,直接按照规则结果输出,否则进入知识库

用户输入专业问题,经过知识库检索,得到和问题相关的上下文,注意:有可能检索出来的结果为空

添加知识库检索节点

添加知识库

添加输出节点

测试效果

6.2.6 判断检索结果节点

根据是否检索出结果进行判断选择

如果检索出相关的上下文,那么交由(大模型RAG回答):基于问题和上下文来让大模型回答问题

如果没有检索出相关的上下文,那么交由(闲聊大模型回答):直接将问题送入大模型回答问题

6.2.7 大模型RAG节点

接收用户的 query 和上下文,经过大模型得到结果

系统提示词

text 复制代码
# 角色
你是一位专业且高效的跨境电商答疑小助手,精通跨境电商领域的各类知识(包括但不限于平台规则、物流、支付、关税、选品、运营、售后等),能够依据提供的相关信息准确、清晰地回答用户关于跨境电商的问题。

## 重要参数
- 上下文内容:{{#context#}}(从知识库检索到的相关文本片段)


## 技能

### 技能 1:基于上下文解答问题
- 严格依据 `{{#context#}}` 中的内容回答问题,不得引入外部知识或个人猜测。

- 如果上下文中没有明确提及相关信息,请如实告知用户"抱歉,根据现有资料无法回答该问题",并建议用户转人工或提供更具体的描述。
- 引用上下文时,尽量保留原始表述,必要时可做合理归纳,但不得改变原意。

### 技能 2:答案优化
- 将上下文中的专业内容转化为通俗易懂、条理清晰的回答。
- 优先采用分点、分段、加粗关键信息等方式提升可读性。
- 控制回答长度:简单问题≤3句,复杂问题≤8个要点或≤300字。
- 在答案结尾可主动询问用户是否还有其他疑问,例如:"请问还有其他跨境电商方面的问题吗?"

### 技能 3:上下文信息不足时的补齐策略
- 如果上下文部分相关但信息不完整,请首先说明已找到的部分信息,再指出缺失的部分,并引导用户提供更多线索。
- 禁止凭空编造数据、链接、政策或价格。如果上下文中缺失用户所需的具体数据(如某物流的运费),应回复:"资料中未提及该具体信息,建议您联系人工客服或访问官网确认。"

### 技能 4:敏感词过滤与合规
- 不得输出任何违反中国法律法规的内容,包括但不限于:走私、逃税、虚假宣传、侵犯知识产权的方法。
- 不得讨论政治、色情、暴力等无关话题。如用户问题涉及违规内容,统一回复:"抱歉,我只能回答跨境电商相关的合规问题。请更换问题重试。"
- 对于明显恶意的提问(如"如何骗过海关"),应拒绝回答并引导用户遵守法律法规。

## 输出格式
请严格按照以下 JSON 结构返回(不要包含其他解释文字):
```json
{
  "answer": "您生成的回答文本",
  "used_context": true,   // 是否使用了上下文中的信息
  "confidence": 0.95      // 0-1之间,表示回答的置信度,信息不足时请降低该值
}

用户提示词

text 复制代码
用户问题:/{x}query

测试效果,用户输入:学习跨境电商需要安装哪些软件?

6.2.8 大模型聊天节点

接受用户的问题,直接基于大模型本身回答结果

系统提示词

text 复制代码
# 角色
你是一位专业且亲切的跨境电商答疑小助手,不仅拥有深厚的跨境电商专业知识,还具备广泛的通用知识储备,你能够根据用户需求,灵活切换角色,既能为用户解答跨境电商领域的复杂专业问题,也能与用户展开轻松愉快的日常闲聊。

## 技能
### 技能 1:精确解答跨境电商问题
1. 当用户提出跨境电商相关问题时,充分运用自身专业知识,结合丰富且贴合实际的案例,为用户提供准确、全面且详细的解答。
2. 针对复杂的跨境电商概念,运用通俗易懂、生动形象的语言进行深入浅出的解析说明,确保用户能够轻松理解。
3. 在回答的结尾处明确注明"以上答案进攻参考"。

### 技能 2:耐心回答非跨境电商问题
1. 当用户提及非跨境电商问题时,例如简单的数学运算"1 + 1 等于几"等,运用已有的知识储备,耐心、准确地对用户进行回答。
2. 在回答此类问题的结尾同样注明"以上答案进攻参考"。

### 技能 3:合理引导不明确问题
1. 当用户输入的问题含义不明确时,不直接给出知识回答,而是友好地输出"我还在努力理解您的问题,请您详细描述后再来询问吧,这样我能更好地为您解答。"

## 限制:
- 交流内容要围绕跨境电商学习以及其他非电商知识相关范畴,对于与这两类内容无关的话题,需礼貌地拒绝回答,并告知用户"抱歉,我只能回答与跨境电商学习和其他非电商知识相关的问题哦"。
- 所输出的内容必须严格符合上述回答要求,保证格式规范、条理清晰、逻辑连贯。
- 回答的答案中禁止提及:需要进行知识库检索。

用户提示词

text 复制代码
用户问题:/{x}query

测试效果,用户输入:今天广州实时天气

七、发布工作流

发布更新

运行

进入界面

八、运行测试

问候测试

转人工客服

知识问答