当前位置: 首页 > news >正文

Github 上 Star 数最多的大模型应用基础服务 Dify 深度解读(一)

背景介绍

接触过大模型应用开发的研发同学应该都或多或少地听过 Dify 这个大模型应用基础服务,这个项目自从 2023 年上线以来,截止目前(2024-6)已经获得了 35k 多的 star,是目前大模型应用基础服务中最热门的项目之一。这篇文章对 Dify 中核心的基础模块 RAG 服务进行深入解读,后续可能会更新其他模块的内容。

Dify 简介

Dify 是一个 LLMOps 服务, 涵盖了大语言模型(如GPT系列)开发、部署、维护和优化的一整套实践和流程。可以大幅简化大模型应用的开发。

基于 Dify 可以在不需要太多开发的情况下,快速搭建一个大模型应用。应用中可以调用 Dify 中内置的大量基础能力,比如知识库检索 RAG,大模型调用。通过可插拔式的组合构建大模型应用。一个典型的应用如下所示:
请添加图片描述

上面的场景中使用分类场景,RAG 服务以及大模型调用的基础模块,组合生成一个大模型应用。

RAG 核心流程

RAG 服务的基础流程在之前的 搭建离线私有大模型知识库 文章中已经介绍过了。RAG 服务的开源框架 有道 QAnything 和 Ragflow 也都解读过基础的 RAG 流程了,这部分就不详细展开了。一般情况下,RAG 服务会包含如下所示的功能模块:

  • 文件加载的支持;
  • 文件的预处理策略;
  • 文件检索的支持;
  • 检索结果的重排;
  • 大模型的处理;

因为 RAG 服务只是 Dify 中的一个基础模块,官方没有过多强调 RAG 服务的独特设计,但是依旧可以看到一个独特点:

  1. 支持 Q&A 模式,与上述普通的「Q to P」(问题匹配文本段落)匹配模式不同,它是采用「Q to Q」(问题匹配问题)匹配工作;
  2. 丰富的召回模式,支持 N 选 1 召回多路召回

下面的部分会对独特之处进行详细展开。

核心模块解读

之前介绍过来自中科院的 RAG 服务 GoMate 采取的是模块化设计,方便进行上层应用的组合。从目前的实现来看,Dify 的 RAG 设计也是采用模块化设计,RAG 的代码实现都在 api/core/rag 中,从代码结构上也很容易理解各个模块的作用:

请添加图片描述

深入来看代码的实现质量也比较高,对 RAG 的模块化设计感兴趣的可以深入了解下实现细节。

文件加载

Dify 的文件加载都是在 api/core/rag/extractor/extract_processor.py 中实现的,主要的文件解析是基于 unstructured 实现,另外基于其他第三方库实现了特定格式文件的处理

比如对于 pdf 文件,会基于 pypdfium2 进行解析,html 是基于 BeautifulSoup 进行解析,这部分代码实现都比较简单,就不展开介绍了。

文件预处理

加载的模型中的内容可能会存在一些问题,比如多余的无用字符,编码错误或其他的一些问题,因此需要对文件解析的内容进行必要的清理,这部分代码实现在 api/core/rag/cleaner 中。实际的清理都是基于 unstructured cleaning 实现的,Dify 主要就是将不同的清理策略封装为同样的接口,方便应用层自由选择。这部分实现也比较简单,感兴趣可以自行了解下。

Q&A 模式

Q&A 分段模式功能,与上述普通的「Q to P」(问题匹配文本段落)匹配模式不同,它是采用「Q to Q」(问题匹配问题)匹配工作,在文档经过分段后,经过总结为每一个分段生成 Q&A 匹配对,当用户提问时,系统会找出与之最相似的问题,然后返回对应的分段作为答案,实际的流程如下所示:

请添加图片描述

从上面的流程可以看到,Q&A 模式下会根据原始文档生成问答对,实现实现是在 api/core/llm_generator/llm_generator.py 中:

# 构造 promptGENERATOR_QA_PROMPT = ('<Task> The user will send a long text. Generate a Question and Answer pairs only using the knowledge in the long text. Please think step by step.''Step 1: Understand and summarize the main content of this text.\n''Step 2: What key information or concepts are mentioned in this text?\n''Step 3: Decompose or combine multiple pieces of information and concepts.\n''Step 4: Generate questions and answers based on these key information and concepts.\n''<Constraints> The questions should be clear and detailed, and the answers should be detailed and complete. ''You must answer in {language}, in a style that is clear and detailed in {language}. No language other than {language} should be used. \n''<Format> Use the following format: Q1:\nA1:\nQ2:\nA2:...\n''<QA Pairs>'
)def generate_qa_document(cls, tenant_id: str, query, document_language: str):prompt = GENERATOR_QA_PROMPT.format(language=document_language)model_manager = ModelManager()model_instance = model_manager.get_default_model_instance(tenant_id=tenant_id,model_type=ModelType.LLM,)# 拼接出完整的调用 promptprompt_messages = [SystemPromptMessage(content=prompt),UserPromptMessage(content=query)]# 调用大模型直接生成问答对response = model_instance.invoke_llm(prompt_messages=prompt_messages,model_parameters={'temperature': 0.01,"max_tokens": 2000},stream=False)answer = response.message.contentreturn answer.strip()

可以看到就是通过一个 prompt 就完成了原始文档到问答对的转换,可以看到大模型确实可以帮助实现业务所需的基础能力。

文件检索

知识库的检索是在 api/core/workflow/nodes/knowledge_retrieval/knowledge_retrieval_node.py 中实现的,与常规的 RAG 存在明显不同之处在于支持了丰富的召回模式。

丰富的召回模式

用户可以自由选择所需的召回模式:

请添加图片描述

  • N 选 1 召回:先根据用户输入的意图选择合适的知识库,然后从知识库检索所需的文档,适用于知识库彼此隔离,不需要互相联合查询的场景;
  • 多路召回:此时会同时从多个知识库检索,然后进行重新排序,适用于知识库需要联合查询的场景。

常规的 RAG 服务需要先手工选择知识库,然后从对应的知识库进行检索,无法支持跨库检索。相对而言,Dify 的这个设计还是要更方便一些。下面以 N 选 1 召回 为例介绍下文件的检索,对应的流程如下所示:

请添加图片描述

N 选 1 召回 的知识库选择是基于用户问题与知识库描述的语义匹配性来进行选择,存在 Function Call/ReAct 两种模式,实现代码在 api/core/rag/retrieval/dataset_retrieval.py 中,具体如下所示:

tools = []
# 根据用户输入的意图,使用知识库的描述构造 promptfor dataset in available_datasets:description = dataset.descriptionif not description:description = 'useful for when you want to answer queries about the ' + dataset.namedescription = description.replace('\n', '').replace('\r', '')message_tool = PromptMessageTool(name=dataset.id,description=description,parameters={"type": "object","properties": {},"required": [],})tools.append(message_tool)# 支持 ReAct 模式if planning_strategy == PlanningStrategy.REACT_ROUTER:react_multi_dataset_router = ReactMultiDatasetRouter()dataset_id = react_multi_dataset_router.invoke(query, tools, model_config, model_instance,user_id, tenant_id)
# 支持 Function Call 模式elif planning_strategy == PlanningStrategy.ROUTER:function_call_router = FunctionCallMultiDatasetRouter()dataset_id = function_call_router.invoke(query, tools, model_config, model_instance)
  • Function Call 模式就是构造了一个 prompt,让大模型根据描述选择合适的知识库,实现比较简单
  • ReAct 模式则是基于 ReAct , 通过推理 + 任务的结合选择正确的知识库

知识库检索

在前面根据模式选择了对应的知识库之后,就可以在单个知识库内进行检索,目前支持的检索方式包含下面三种:

  • 向量检索,通过生成查询嵌入并查询与其向量表示最相似的文本分段。
  • 全文检索,索引文档中的所有词汇,从而允许用户查询任意词汇,并返回包含这些词汇的文本片段。
  • 混合检索,同时执行全文检索和向量检索,并附加重排序步骤,从两类查询结果中选择匹配用户问题的最佳结果。

从实际的代码来看,还有一个 关键词检索 的能力,但是没有特别介绍,不确定是否是效果上还不够稳定,可以关注下后续的进展。混合检索的流程如下所示:

请添加图片描述
实际的实现在 api/core/rag/datasource/retrieval_service.py

# 关键词检索if retrival_method == 'keyword_search':keyword_thread = threading.Thread(target=RetrievalService.keyword_search, kwargs={'flask_app': current_app._get_current_object(),'dataset_id': dataset_id,'query': query,'top_k': top_k,'all_documents': all_documents,'exceptions': exceptions,})threads.append(keyword_thread)keyword_thread.start()# 向量检索(混合检索中也会调用)if RetrievalMethod.is_support_semantic_search(retrival_method):embedding_thread = threading.Thread(target=RetrievalService.embedding_search, kwargs={'flask_app': current_app._get_current_object(),'dataset_id': dataset_id,'query': query,'top_k': top_k,'score_threshold': score_threshold,'reranking_model': reranking_model,'all_documents': all_documents,'retrival_method': retrival_method,'exceptions': exceptions,})threads.append(embedding_thread)embedding_thread.start()# 文本检索(混合检索中也会调用)if RetrievalMethod.is_support_fulltext_search(retrival_method):full_text_index_thread = threading.Thread(target=RetrievalService.full_text_index_search, kwargs={'flask_app': current_app._get_current_object(),'dataset_id': dataset_id,'query': query,'retrival_method': retrival_method,'score_threshold': score_threshold,'top_k': top_k,'reranking_model': reranking_model,'all_documents': all_documents,'exceptions': exceptions,})threads.append(full_text_index_thread)full_text_index_thread.start()for thread in threads:thread.join()# 混合检索之后会执行向量和文本检索结果合并后的重排序if retrival_method == RetrievalMethod.HYBRID_SEARCH:data_post_processor = DataPostProcessor(str(dataset.tenant_id), reranking_model, False)all_documents = data_post_processor.invoke(query=query,documents=all_documents,score_threshold=score_threshold,top_n=top_k)
检索结果重排

检索结果的重排也比较简单,就是通过外部模型进行打分,之后基于打分的结果进行排序,实际的实现在 api/core/model_manager.py 中:

def invoke_rerank(self, query: str, docs: list[str], score_threshold: Optional[float] = None,top_n: Optional[int] = None,user: Optional[str] = None) \-> RerankResult:self.model_type_instance = cast(RerankModel, self.model_type_instance)# 轮询调用重排序模型,获得重排序得分,并基于得分进行排序return self._round_robin_invoke(function=self.model_type_instance.invoke,model=self.model,credentials=self.credentials,query=query,docs=docs,score_threshold=score_threshold,top_n=top_n,user=user)

总结

本文主要介绍了 Dify 的知识库 RAG 服务,作为完整 Agent 中一个基础模块,Dify 没有特别强调 RAG 独特之处,但是依旧存在一些独特的亮点:

  1. 多种召回模式,支持根据用户意图自动选择合适的知识库,也可以跨知识库进行检索,弥补了常规的 RAG 服务需要用户手工选择知识库的不便之处;
  2. 独特的 Q&A 模式,可以直接根据文本生成问答对,可以解决常规情况下用户问题与文本匹配度不够的问题,但是应该只适用于特定类型的场景,否则可能会因为转换导致的信息损耗导致效果更差;

总体而言,Dify 中的 RAG 服务是一个设计完备的服务,模块化的设计方便组合与拓展,一些独特的设计也可以提升易用性,代码质量也很高,感兴趣的可以深入研究下。

相关文章:

Github 上 Star 数最多的大模型应用基础服务 Dify 深度解读(一)

背景介绍 接触过大模型应用开发的研发同学应该都或多或少地听过 Dify 这个大模型应用基础服务&#xff0c;这个项目自从 2023 年上线以来&#xff0c;截止目前&#xff08;2024-6&#xff09;已经获得了 35k 多的 star&#xff0c;是目前大模型应用基础服务中最热门的项目之一…...

XStream导出xml文件

最终效果 pom依赖 <dependency><groupId>com.thoughtworks.xstream</groupId><artifactId>xstream</artifactId><version>1.4.11.1</version></dependency>代码 XStreamUtil 这个直接复制即可 import com.thoughtworks.xst…...

陪诊小程序搭建:构建便捷医疗陪诊服务的创新实践

在当今快节奏的社会&#xff0c;医疗服务与人们的生活息息相关。然而&#xff0c;在医疗体系中&#xff0c;患者往往面临着信息不对称、流程繁琐、陪伴需求得不到满足等问题。为了解决这些问题&#xff0c;我们提出了一种创新的解决方案——陪诊小程序&#xff0c;旨在为患者提…...

0139__TCP协议

全网最详细TCP参数讲解&#xff0c;再也不用担心没有面试机会了_tcp的参数-CSDN博客 TCP协议详解-腾讯云开发者社区-腾讯云 TCP-各种参数 - 简书...

家政小程序的开发,带动市场快速发展,提高家政服务质量

当下生活水平逐渐提高&#xff0c;也增加了年轻人的工作压力&#xff0c;同时老龄化也在日益增加&#xff0c;使得大众对家政的需求日益提高&#xff0c;能力、服务质量高的家政人员能够有效提高大众的生活幸福指数。 但是&#xff0c;传统的家政服务模式存在着效率低、用户与…...

JavaScript高级程序设计(第四版)--学习记录之对象、类与面向对象编程(下)

类 ES6新引入class关键字具有正式定义类的能力。 类定义&#xff1a;类声明和类表达式。 // 类声明 class Person {} // 类表达式 const Animal class {}; 类定义与函数定义的不同&#xff1a; 1&#xff1a;函数声明可以提升&#xff0c;类定义不能 2&#xff1a;函数受函数…...

PDF 生成(5)— 内容页支持由多页面组成

当学习成为了习惯&#xff0c;知识也就变成了常识。 感谢各位的 关注、点赞、收藏和评论。 新视频和文章会第一时间在微信公众号发送&#xff0c;欢迎关注&#xff1a;李永宁lyn 文章已收录到 github 仓库 liyongning/blog&#xff0c;欢迎 Watch 和 Star。 回顾 在本篇开始…...

day 51 115.不同的子序列 583. 两个字符串的删除操作 72. 编辑距离

115. 不同的子序列 给你两个字符串 s 和 t &#xff0c;统计并返回在 s 的 子序列 中 t 出现的个数&#xff0c;结果需要对 109 7 取模。 示例 1&#xff1a; 输入&#xff1a;s "rabbbit", t "rabbit" 输出&#xff1a;3 解释&#xff1a; 如下所示,…...

http包详解

http包的作用及使用 go的http包是go的web编程的核心内容&#xff0c;go的web框架本质上都是基于http提供的组件进行再度封装。我们来看一下http基本的使用&#xff1a; func main() {http.Handle("/get", GetVal())http.Handle("/hello", Hello())http.H…...

Reqable实战系列:Flutter移动应用抓包调试教程

Flutter应用网络请求调试一直是业内难题&#xff0c;原因在于Dart语言标准库的网络请求不会走Wi-Fi代理&#xff0c;常规通过配置Wi-Fi代理来抓包的方式行不通。这给我们日常开发测试造成了很大的阻碍&#xff0c;严重降低工作效率。因此写一篇教程&#xff0c;讲解如何使用Req…...

乾元通渠道商中标吴忠市自然灾害应急能力提升项目

近日&#xff0c;乾元通渠道商中标宁夏回族自治区吴忠市自然灾害应急能力提升项目&#xff0c;乾元通作为设备厂家&#xff0c;为项目提供通信指挥类装备&#xff08;多链路聚合设备&#xff09;QYT-X1。 青岛乾元通数码科技有限公司作为国家应急产业企业&#xff0c;深耕于数据…...

护网蓝队面试

一、sql注入分类 **原理&#xff1a;**没有对用户输入项进行验证和处理直接拼接到查询语句中 查询语句中插⼊恶意SQL代码传递后台sql服务器分析执行 **从注入参数类型分&#xff1a;**数字型注入、字符型注入 **从注入效果分&#xff1a;**报错注入、布尔注入、延时注入、联…...

【高考志愿】金融学

目录 一、金融学类专业概述 二、主要课程 三、就业前景与方向 四、适合人群 五、金融学学科排名 六、总结 高考志愿选择金融学&#xff0c;无疑是一个既充满挑战又极具前景的决策。金融学&#xff0c;作为经济学门类下的重要分支&#xff0c;不仅涵盖了广泛的金融领域知识…...

返利App的用户行为分析与数据驱动决策

返利App的用户行为分析与数据驱动决策 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天我们将深入探讨返利App中的用户行为分析与数据驱动决策的技术细节和实…...

python基础:高级数据类型:集合

1、集合的定义 集合是一个无序且无重复元素的列表。其定义与数学定义一致。其无序和不重复和字典特征类似&#xff0c;但是无“值”。 2、集合的创建 集合一般由列表创建&#xff0c;在初始化列表时保证其元素唯一性&#xff0c;即为集合。 创建方法&#xff1a;x set(list…...

idk17配置

只需要把zip包解压&#xff0c;然后配置环境变量&#xff1a; bin目录路径粘到path里面就好了 然后打开cmd窗口分别输入 java javac java -version 验证...

Java实现日志全链路追踪.精确到一次请求的全部流程

广大程序员在排除线上问题时,会经常遇见各种BUG.处理这些BUG的时候日志就格外的重要.只有完善的日志才能快速有效的定位问题.为了提高BUG处理效率.我决定在日志上面优化.实现每次请求有统一的id.通过id能获取当前接口的全链路流程走向. 实现效果如下: 一次查询即可找到所有关…...

你敢相信吗,AI绘画正在逐渐取代你的工作!

前言 在当今信息技术高速发展的时代&#xff0c;AI绘画技术的崛起已引起了广泛关注和讨论。许多人开始担心AI技术是否会逐渐取代传统绘画师的工作。人类无疑是感性的动物&#xff0c;创作出来的艺术作品常常带有浓郁的个人风格和情感。但AI绘画在某些方面的突破&#xff0c;使…...

博途PLC轴工艺对象随动误差监视功能

S7-1200PLC和V90总线伺服通过工艺对象实现定位控制时在组态工艺对象里有这样的随动误差监视功能介绍,关于这个功能,今天我们解读下,工艺对象组态编程可以参考下面文章链接: S7-1200PLC和V90总线伺服通过工艺对象实现定位控制(标准报文3应用)_v90工艺对象3号报文-CSDN博客文…...

《昇思25天学习打卡营第24天 | 昇思MindSporeResNet50图像分类》

24天 本节学习了使用ResNet50网络对CIFAR-10数据集进行分类。 步骤&#xff1a; 1.数据集准备与加载 2.构建网络 残差网络结构(Residual Network)是ResNet网络的主要亮点&#xff0c;ResNet使用残差网络结构后可有效地减轻退化问题&#xff0c;实现更深的网络结构设计&#x…...

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...

Cesium1.95中高性能加载1500个点

一、基本方式&#xff1a; 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...

vue3 字体颜色设置的多种方式

在Vue 3中设置字体颜色可以通过多种方式实现&#xff0c;这取决于你是想在组件内部直接设置&#xff0c;还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法&#xff1a; 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

C++ 基础特性深度解析

目录 引言 一、命名空间&#xff08;namespace&#xff09; C 中的命名空间​ 与 C 语言的对比​ 二、缺省参数​ C 中的缺省参数​ 与 C 语言的对比​ 三、引用&#xff08;reference&#xff09;​ C 中的引用​ 与 C 语言的对比​ 四、inline&#xff08;内联函数…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现

摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序&#xff0c;以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务&#xff0c;提供稳定高效的数据处理与业务逻辑支持&#xff1b;利用 uniapp 实现跨平台前…...

汇编常见指令

汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX&#xff08;不访问内存&#xff09;XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...

06 Deep learning神经网络编程基础 激活函数 --吴恩达

深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...

全志A40i android7.1 调试信息打印串口由uart0改为uart3

一&#xff0c;概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本&#xff1a;2014.07&#xff1b; Kernel版本&#xff1a;Linux-3.10&#xff1b; 二&#xff0c;Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01)&#xff0c;并让boo…...

全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比

目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec&#xff1f; IPsec VPN 5.1 IPsec传输模式&#xff08;Transport Mode&#xff09; 5.2 IPsec隧道模式&#xff08;Tunne…...