AI Agent开发框架中的Dify。你将学习Dify的低代码可视化编排、Prompt管理、RAG集成、模型支持、工作流设计、与LangChain对比,以及如何利用Dify快速构建和部署LLM应用,适合AI应用开发者学习。

岗位关联

需要学习Dify,了解AI技术趋势才能规划前沿课程。本篇涵盖LangChain/RAG/Agent、API集成、向量数据库,帮助你构建AI应用系统能力。

目录
  1. 可视化演示
  2. Dify平台总览与低代码LLM应用定位
  3. 可视化工作流编排与节点类型设计
  4. Prompt管理与版本控制体系
  5. RAG集成与知识库管理体系
  6. 多模型支持与部署架构设计
  7. Dify与代码框架对比及选型建议
  8. AI 应用场景
  9. Python 演示
  10. 常见问答
  11. 常见误区
  12. 参考来源

可视化演示

展示可视化工作流编排、RAG知识库流水线与多模型抽象层。

本节配有交互动效(进入视口后自动加载,约 3KB)。

可视化工作流编排(DAG) 拖拽节点连线,数据单向流动 LLM、知识库、工具调用等节点 Workflow = DAG(Start→Nodes→End) 低代码可视化构建复杂LLM应用

Dify平台总览与低代码LLM应用定位

Dify是一个开源的低代码LLM应用开发平台,它的核心理念是让不懂编程的人也能快速搭建AI应用。和LangChain这类代码框架不同,Dify提供了一个可视化的Web界面,你只需要拖拽节点、连线、配置参数,就能把大模型、知识库、工具调用串起来,形成一个完整的AI应用。打个比方:LangChain像是给你一堆积木和说明书,你得自己动手拼;Dify像是给你一个模块化的拼插玩具台,模块都做好了,你只管组合搭配就行。

Dify的核心价值在于降低了LLM应用的开发门槛。以前做一个AI客服应用,你需要会写Python、懂LangChain、会接向量数据库、能部署服务,门槛很高。现在有了Dify,产品经理、运营人员甚至业务人员,都可以直接在界面上拖拽编排工作流,快速做出一个能用的AI应用。这大大缩短了从想法到原型的时间,也让非技术团队能参与到AI应用的构建中来。

但Dify不只是给非开发者用的玩具,它同时也为专业开发者提供了强大的扩展能力。你可以通过API接口把Dify应用集成到自己的系统里,可以写自定义代码节点来实现复杂逻辑,可以接入自己的向量数据库和模型服务。也就是说,Dify走的是低代码+Pro-code融合的路线——简单的需求用可视化搞定,复杂的需求用代码扩展,两者可以无缝结合。

从产品形态上看,Dify支持多种类型的LLM应用。最基础的是聊天助手,也就是对话式应用。然后是文本生成应用,比如写文案、写报告、做翻译。还有工作流类型的应用,可以编排多步骤的复杂流程。更高级的是Agent模式,可以让模型自主选择工具、规划任务。Dify还内置了知识库管理和RAG能力,不需要自己搭向量数据库就能做知识问答。这些能力覆盖了大多数企业级LLM应用的常见场景。

可视化工作流编排与节点类型设计

Dify最有特色的功能就是可视化工作流编排。简单说,就是把一个复杂的LLM应用拆成一个个节点,每个节点做一件事,然后用连线把它们串起来,数据从一个节点流向下一个节点,就像流水线一样。整个工作流是一个DAG(有向无环图)——数据单向流动,不会形成循环(当然Dify也支持循环节点,但基础流程是无环的)。你在界面上拖拽节点、连线、配置参数,整个应用的逻辑就一目了然,比读代码容易理解多了。

Dify提供了丰富的节点类型,基本覆盖了LLM应用的常见需求。最核心的是LLM节点,也就是调用大模型生成文本的节点,你可以选模型、设参数、写Prompt模板。然后是知识检索节点,用来从知识库中查找相关文档,配合LLM节点做RAG问答。条件分支节点就像编程语言里的if-else,可以根据中间结果动态选择走哪条路径,比如置信度低的时候转人工。

还有几个非常实用的节点类型。代码执行节点允许你运行Python或JavaScript代码,用来做数据处理、格式转换、复杂计算等,这是Dify扩展能力的关键——当可视化节点不够用时,可以用代码补。HTTP请求节点可以调用外部API,比如调用天气接口、查询数据库、触发第三方服务等,这让Dify应用可以和外部系统互联互通。模板输出节点用来格式化最终的输出结果,支持变量插值。还有变量聚合节点、迭代节点等等,满足不同的流程控制需求。

节点之间的数据传递是通过变量引用来实现的。每个节点都有输入和输出变量,你可以在下游节点中用变量名的方式引用上游节点的输出。比如LLM节点的输出是llm.text,知识检索节点的结果是retrieval.docs,你可以在后续节点的Prompt或参数中直接引用这些变量。这种变量传递机制让数据流非常清晰,每个节点的输入输出都明明白白,调试起来也很方便——你可以查看每个节点的输入输出,快速定位问题出在哪一步。

Prompt管理与版本控制体系

很多人以为Prompt管理就是存几段文本,其实远不止这么简单。Dify把Prompt当成一等公民来对待,提供了一整套的管理体系。最基础的是变量插值——你可以在Prompt模板中嵌入动态变量,运行时再把实际数据填进去。这样Prompt模板就不是写死的字符串,而是可以根据不同输入动态变化的模板,复用性很高。

版本控制是Dify Prompt管理的一大亮点。每次修改Prompt模板,Dify都会自动保存一个新版本,你可以随时查看历史版本、对比不同版本的差异、一键回滚到之前的版本。这就像代码的Git版本管理一样,只不过是专门为Prompt设计的。有了版本控制,你就可以放心大胆地改Prompt,不用担心改坏了找不回来。而且每个版本的效果数据都有记录,哪个版本效果好一目了然。

A/B测试是Prompt管理中非常实用的功能。你可以同时运行多个版本的Prompt,Dify会自动把流量分配给不同版本,然后统计对比各个版本的效果指标,比如用户满意度、回答准确率、完成率等。这样你就不用靠感觉来判断哪个Prompt好,而是用数据说话。A/B测试对于优化Prompt效果非常有价值,因为很多时候你以为改好了,但实际效果可能反而下降了,只有通过真实用户的对比测试才能得出可靠的结论。

Dify的Prompt管理还支持团队协作和跨应用复用。一个Prompt模板可以在多个应用中共享使用,不用每个应用都重复写一遍。团队成员可以对Prompt模板发表评论、提出修改建议,有审核流程的团队还可以设置审批机制,确保上线的Prompt经过充分评审。这样一来,Prompt就不再是存在某个开发者脑子里的个人经验,而是变成了团队的可管理、可复用、可迭代的知识资产。这对于团队化运营LLM应用来说非常重要。

RAG集成与知识库管理体系

RAG(检索增强生成)是当前LLM应用最常用的技术之一,Dify内置了完整的RAG流水线,不需要你自己搭向量数据库、写检索逻辑,开箱就能用。整个流程是这样的:你上传文档到知识库,Dify自动做文本切分、向量化、存储索引;在工作流中加一个知识检索节点,配置好用哪个知识库、检索多少条结果;然后把检索结果传给LLM节点,让模型基于检索到的内容来回答问题。三步就能搭起一个RAG问答应用,非常方便。

文档处理方面,Dify支持多种格式的文档上传,包括PDF、Word、Excel、PPT、纯文本、网页等等。上传后自动进行文本切分,你可以自定义切分策略和chunk大小——比如按固定大小切、按段落切、按语义切等等。不同类型的文档适合不同的切分策略:产品手册可能适合按段落切,法律合同可能适合更小的chunk粒度。Dify还支持多种Embedding模型,你可以选用效果最好的那个来做向量化。

检索策略也很丰富。Dify支持三种检索模式:语义检索(按向量相似度匹配)、全文检索(按关键词匹配)和混合检索(同时用语义和全文,再融合排序)。不同场景适合不同的检索策略——比如纯事实性问答用语义检索就够了,涉及精确术语和编号的可能全文检索更准,复杂问题用混合检索效果最好。检索回来的结果还可以做重排序,用重排序模型进一步提升相关性,确保最相关的内容排在最前面。

知识库管理方面,Dify支持多租户隔离和细粒度的权限管理。大企业里不同部门的知识库要分开,不能让A部门看到B部门的机密文档,Dify的多租户和权限体系就能满足这种需求。你可以设置哪些人能管理知识库、哪些人能查看、哪些人能使用。知识库还支持分类标签,方便管理大量文档。总的来说,Dify的RAG能力不是玩具级的,而是可以满足企业级知识管理需求的完整方案。

多模型支持与部署架构设计

Dify不绑定任何一家大模型厂商,而是通过统一的模型抽象层支持多种LLM提供商。目前已经支持的模型包括OpenAI的GPT系列、Anthropic的Claude系列、Google的Gemini、国内的通义千问、文心一言、智谱AI等等,还支持通过Ollama或本地部署的开源模型。你只需要在配置里填入API密钥,就能切换使用不同的模型。切换模型不需要改工作流逻辑,同一个应用可以随时换底层模型试效果,非常灵活。

为什么多模型支持很重要?因为不同模型擅长的事情不一样。写文案可能GPT-4效果最好,做中文任务可能国产模型更合适,简单问答用便宜的模型就能搞定,敏感数据的场景需要用本地部署的开源模型。Dify让你可以根据任务类型选择最合适的模型,还能做模型级别的A/B测试——同样的工作流,用不同的模型跑,看哪个效果更好、性价比更高。这种灵活选型的能力,在模型快速迭代的今天特别有价值。

部署架构上,Dify采用Docker Compose微服务架构,主要包含几个核心组件:API服务负责处理后端逻辑,Worker服务负责异步任务(比如文档处理、批量推理),Web前端提供可视化界面,还有数据库存业务数据、向量数据库存知识库向量。你可以一键用Docker Compose把整套服务拉起来,也可以部署在Kubernetes上做横向扩展。对于有数据安全要求的企业,Dify支持完全私有化部署,所有数据都在企业内部,不出外网。

高可用方面,Dify提供了模型负载均衡和故障转移能力。你可以配置多个模型提供商作为备份,当主模型服务不可用时(比如API挂了、限流了),Dify会自动切换到备用模型,保证服务不中断。还可以做负载均衡——把请求分摊到多个模型账户或多个模型实例上,提高吞吐量和稳定性。这些企业级特性对于生产环境来说非常重要,毕竟谁也不想因为某家模型服务出问题导致自己的应用挂掉。

Dify与代码框架对比及选型建议

经常有人问:Dify和LangChain到底选哪个?这个问题没有绝对答案,要看你的具体需求。先说说Dify的优势:第一是门槛低,可视化编排上手快,非技术人员也能用;第二是开箱即用,RAG、Prompt管理、知识库、多模型支持这些都内置了,不用自己从零搭;第三是可视化调试,每个节点的输入输出都能看到,排查问题比读代码容易;第四是团队协作,非开发人员也能参与应用构建和运营。这些优势总结起来就是一个字:快。

再说说LangChain这类代码框架的优势。第一是灵活性强,你想怎么写就怎么写,想集成什么库就集成什么库,完全不受平台限制;第二是可控性高,每一行代码都是你自己写的,性能优化、错误处理都能精确控制;第三是生态丰富,LangChain社区大、集成多、教程多,遇到问题容易找到解决方案;第四是深度定制,当应用逻辑非常复杂的时候,代码框架的自由度是低代码平台比不了的。简单说,代码框架的优势是灵活和可控。

那到底怎么选?可以从几个维度来判断。第一看团队:如果团队里非技术人员多、需要运营和产品直接参与,选Dify;如果全是资深开发者、追求极致控制,选LangChain。第二看需求复杂度:如果是标准的RAG问答、文本生成、简单工作流,Dify完全够用还更快;如果是非常定制化的复杂Agent、需要深度集成到现有系统、有特殊性能要求,代码框架更合适。第三看阶段:快速验证想法、做MVP、做原型,用Dify效率最高;确定了方向、要做大规模生产级部署,可能需要用代码框架深度开发。

其实两者不是非此即彼的关系,很多时候可以互补。一个常见的模式是:先用Dify快速验证想法和原型,几天就能跑起来给用户试用,验证产品价值;确认方向没问题后,再用LangChain等代码框架做深度定制和性能优化,开发生产版本。还有一种模式是:主体流程用Dify搭,复杂的特殊逻辑用自定义代码节点或外部API来实现,低代码和Pro-code结合。最关键的是选对工具做对事,不要为了技术而技术,哪种方式能更快更好地解决问题,就用哪种。

AI 应用场景

企业知识库问答应用快速搭建

阶段:模型部署

解决的问题:企业需要快速搭建内部知识库问答系统但缺乏LLM开发经验,代码框架学习成本高且开发周期长

具体案例:使用Dify在3天内搭建企业知识库问答应用:运营人员上传200份产品手册和FAQ文档到知识库,Dify自动完成文本切分和向量化。拖拽编排工作流:知识检索节点(混合检索模式)→LLM节点(GPT-4基于检索结果生成答案)→条件分支(置信度低于0.7时转人工)。通过Prompt管理界面调整系统提示词并A/B测试两个版本。应用发布后通过Dify内置的API对外提供服务,员工可通过Web界面或API集成到内部系统使用。相比用LangChain代码开发,搭建周期从3周缩短至3天,且运营人员可自主维护知识库和Prompt。

多模型内容生成工作流

阶段:模型部署

解决的问题:内容生成需要结合多个模型能力(文本生成、图像描述、翻译),单一模型难以满足多语言多模态需求,代码编排多模型调用复杂度高

具体案例:使用Dify构建多模型内容生成工作流:开始节点接收中文内容→LLM节点1(GPT-4优化中文文案)→LLM节点2(Claude翻译为英文)→HTTP请求节点(调用DALL-E API生成配图)→模板输出节点(组合文案和图片URL输出最终内容)。工作流中每个LLM节点可独立配置不同模型和参数,当某模型不可用时通过Dify的故障转移自动切换备用模型。内容团队通过可视化界面监控每次生成的中间结果,发现翻译质量不稳定时在Prompt管理中调整翻译模板的A/B测试版本。整个多模型编排无需编写集成代码,内容生产效率提升3倍。

Python 演示

python181 行
import jsonfrom typing import List, Dict, Any  class SimpleDifyWorkflow:    """简化版Dify工作流引擎演示(模拟核心节点类型)"""        def __init__(self):        self.nodes = {}        self.edges = []        self.variables = {}        def add_node(self, node_id: str, node_type: str, config: Dict):        """添加工作流节点"""        self.nodes[node_id] = {            "type": node_type,            "config": config        }        def add_edge(self, from_node: str, to_node: str):        """添加节点连线(有向边)"""        self.edges.append((from_node, to_node))        def _get_next_nodes(self, current_node: str) -> List[str]:        """获取当前节点的下游节点"""        return [to for frm, to in self.edges if frm == current_node]        def _execute_llm_node(self, config: Dict, inputs: Dict) -> Dict:        """模拟LLM节点执行"""        prompt_template = config.get("prompt", "")        model = config.get("model", "gpt-4")        prompt = prompt_template        for key, value in inputs.items():            prompt = prompt.replace("{{" + key + "}}", str(value))        simulated_response = f"[{model}响应] 基于输入生成的回答...(Prompt: {prompt[:50]}...)"        return {"text": simulated_response, "model": model, "prompt_used": prompt}        def _execute_retrieval_node(self, config: Dict, inputs: Dict) -> Dict:        """模拟知识检索节点执行"""        query = inputs.get("query", "")        knowledge_base = config.get("knowledge_base", "default")        top_k = config.get("top_k", 3)        mock_docs = [            {"title": "文档1", "content": f"关于{query}的相关内容片段A...", "score": 0.92},            {"title": "文档2", "content": f"关于{query}的相关内容片段B...", "score": 0.85},            {"title": "文档3", "content": f"关于{query}的相关内容片段C...", "score": 0.78},        ]        return {            "query": query,            "knowledge_base": knowledge_base,            "documents": mock_docs[:top_k],            "context": "\n\n".join([d["content"] for d in mock_docs[:top_k]])        }        def _execute_conditional_node(self, config: Dict, inputs: Dict) -> Dict:        """模拟条件分支节点执行"""        variable = config.get("variable", "")        operator = config.get("operator", ">")        threshold = config.get("threshold", 0)        value = inputs.get(variable, 0)        try:            if operator == ">":                result = float(value) > float(threshold)            elif operator == "<":                result = float(value) < float(threshold)            elif operator == "==":                result = value == threshold            else:                result = True        except (ValueError, TypeError):            result = False        branch = "true_branch" if result else "false_branch"        return {"condition_met": result, "branch": branch, "value": value}        def _execute_code_node(self, config: Dict, inputs: Dict) -> Dict:        """模拟代码执行节点(安全沙箱)"""        result = {"processed": True, "input_keys": list(inputs.keys())}        if "text" in inputs:            result["text_length"] = len(str(inputs["text"]))            result["text_upper"] = str(inputs["text"]).upper()        return result        def _execute_http_node(self, config: Dict, inputs: Dict) -> Dict:        """模拟HTTP请求节点"""        url = config.get("url", "")        method = config.get("method", "GET")        return {            "status_code": 200,            "url": url,            "method": method,            "response": {"success": True, "data": f"模拟{url}的返回结果"}        }        def execute(self, start_node: str, initial_inputs: Dict) -> Dict:        """执行工作流(简化版拓扑排序执行)"""        self.variables = dict(initial_inputs)        executed = set()        execution_order = []        queue = [start_node]        while queue:            node_id = queue.pop(0)            if node_id in executed:                continue            node = self.nodes.get(node_id)            if not node:                continue            node_type = node["type"]            config = node["config"]            if node_type == "llm":                result = self._execute_llm_node(config, self.variables)            elif node_type == "retrieval":                result = self._execute_retrieval_node(config, self.variables)            elif node_type == "conditional":                result = self._execute_conditional_node(config, self.variables)            elif node_type == "code":                result = self._execute_code_node(config, self.variables)            elif node_type == "http":                result = self._execute_http_node(config, self.variables)            elif node_type == "output":                result = {"output": self.variables}            else:                result = {}            for key, value in result.items():                self.variables[f"{node_id}.{key}"] = value            for key, value in result.items():                if key not in self.variables:                    self.variables[key] = value            executed.add(node_id)            execution_order.append(node_id)            next_nodes = self._get_next_nodes(node_id)            queue.extend(next_nodes)        return {            "execution_order": execution_order,            "final_variables": self.variables,            "nodes_executed": len(executed)        }  def demo_workflow():    """演示一个简单的RAG问答工作流"""    wf = SimpleDifyWorkflow()    wf.add_node("start", "output", {"desc": "开始节点,接收用户输入"})    wf.add_node("retrieval", "retrieval", {        "knowledge_base": "product_faq",        "top_k": 3,        "search_mode": "hybrid"    })    wf.add_node("llm", "llm", {        "model": "gpt-4",        "prompt": "你是客服助手,请根据以下上下文回答用户问题。\n\n上下文:{{context}}\n\n用户问题:{{query}}\n\n回答:",        "temperature": 0.7    })    wf.add_node("conditional", "conditional", {        "variable": "score",        "operator": "<",        "threshold": 0.7,        "desc": "置信度低于0.7转人工"    })    wf.add_node("output", "output", {"desc": "输出最终回答"})    wf.add_edge("start", "retrieval")    wf.add_edge("retrieval", "llm")    wf.add_edge("llm", "conditional")    wf.add_edge("conditional", "output")    print("=== Dify工作流演示 ===")    print("\n工作流节点:")    for nid, node in wf.nodes.items():        print(f"  {nid}: {node['type']}")    print(f"\n连线数: {len(wf.edges)}")    print()    result = wf.execute("start", {"query": "怎么申请退款?", "score": 0.85})    print("执行顺序:", " → ".join(result["execution_order"]))    print(f"执行节点数: {result['nodes_executed']}")    print()    print("=== 关键输出 ===")    print(f"检索结果: {result['final_variables'].get('retrieval.documents', 'N/A')}")    print(f"LLM输出: {result['final_variables'].get('llm.text', 'N/A')[:80]}...")    print(f"条件判断: 置信度0.85 {'满足' if result['final_variables'].get('conditional.condition_met') else '不满足'}阈值要求")  if __name__ == '__main__':    demo_workflow()
目的:实现简化版Dify工作流引擎,模拟可视化节点编排和数据流传递,演示LLM节点、知识检索节点、条件分支节点等核心类型的执行逻辑
  1. class SimpleDifyWorkflow:简化版Dify工作流引擎主类,管理节点和连线
  2. def add_node(self, node_id: str, node_type: str, config: Dict):向工作流中添加节点,指定节点类型和配置参数
  3. def add_edge(self, from_node: str, to_node: str):添加节点间的连线,定义数据流向
  4. def _execute_llm_node(self, config: Dict, inputs: Dict) -> Dict:执行LLM节点,做变量插值后调用大模型生成文本
  5. def _execute_retrieval_node(self, config: Dict, inputs: Dict) -> Dict:执行知识检索节点,从知识库查找相关文档(模拟向量检索)
  6. def _execute_conditional_node(self, config: Dict, inputs: Dict) -> Dict:执行条件分支节点,根据阈值判断走哪条路径
  7. prompt = prompt.replace("{{" + key + "}}", str(value))变量插值,把变量名替换为实际值,这是Prompt模板的核心机制
  8. result = wf.execute("start", {"query": "怎么申请退款?", "score": 0.85})从start节点开始执行工作流,传入初始输入变量
  9. print("执行顺序:", " → ".join(result["execution_order"]))打印节点执行顺序,展示可视化工作流的数据流走向

常见问答

Dify作为低代码平台只能做简单聊天机器人吗?
不是。Dify的工作流引擎支持条件分支、代码执行节点、HTTP请求节点和循环等复杂逻辑,可以构建多步骤数据流管道和工具调用Agent。其Agent模式还支持ReAct推理和工具自主选择,复杂度不亚于代码框架实现的应用。低代码不等于功能简单。
Dify的Prompt管理和在代码里写字符串有什么区别?
区别很大。Dify的Prompt管理提供变量插值、多版本管理、A/B测试和团队协作审核等能力,将Prompt从代码中的静态字符串升级为可迭代、可对比、可协作的可管理资产。这些系统化管理能力是代码中写Prompt字符串无法实现的。
Dify私有化部署后数据就完全安全了吗?
不是。私有化部署确保数据不外传,但仍需配置API密钥加密存储、模型调用日志审计、知识库访问权限和工作流执行隔离等安全措施。特别是涉及代码执行节点时,需限制执行权限防止恶意代码。安全是多层防护的,部署方式只是其中一层。

常见误区

误区认为Dify作为低代码平台只能做简单的聊天机器人,无法构建复杂Agent应用

正解Dify的工作流引擎支持条件分支、代码执行节点、HTTP请求节点和循环等复杂逻辑,可以构建多步骤数据流管道和工具调用Agent,其Agent模式还支持ReAct推理和工具自主选择,复杂度不亚于代码框架实现的应用

为何常见:学习者将低代码等同于简单化,忽略了Dify工作流引擎的节点类型和编排能力足以支撑复杂应用逻辑

误区认为Dify的Prompt管理只是保存Prompt文本的简单功能,与代码中写字符串没有本质区别

正解Dify的Prompt管理提供变量插值、多版本管理、A/B测试和团队协作审核等能力,将Prompt从代码中的静态字符串升级为可迭代可对比可协作的可管理资产,这是代码框架中写Prompt字符串无法实现的系统化管理能力

为何常见:学习者将Prompt管理简单等同于文本保存,忽略了版本控制、A/B测试和协作审核等系统化管理能力

误区认为Dify私有化部署后数据完全安全不需要额外的安全措施

正解Dify私有化部署确保数据不外传,但仍需配置API密钥加密存储、模型调用日志审计、知识库访问权限和工作流执行隔离等安全措施,特别是涉及代码执行节点时需限制执行权限防止恶意代码

为何常见:学习者将私有化部署等同于绝对安全,忽略了应用层面的API密钥管理、权限控制和代码执行安全等防护需求

参考来源