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

news2024/11/18 20:18:03

背景介绍

接触过大模型应用开发的研发同学应该都或多或少地听过 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 中:

# 构造 prompt

GENERATOR_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,
    )

    # 拼接出完整的调用 prompt

    prompt_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.content
    return 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 = []
# 根据用户输入的意图,使用知识库的描述构造 prompt

for dataset in available_datasets:
    description = dataset.description
    if not description:
        description = 'useful for when you want to answer queries about the ' + dataset.name

    description = 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 服务是一个设计完备的服务,模块化的设计方便组合与拓展,一些独特的设计也可以提升易用性,代码质量也很高,感兴趣的可以深入研究下。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1882365.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HEC-HMS水文模型教程

原文链接&#xff1a;HEC-HMS水文模型教程https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247607904&idx5&sn1a210328a3fc8f941b433674d8fe2c85&chksmfa826787cdf5ee91d01b6981ebd89deac3e350d747d0fec45ce2ef75d7cb8009341c6f55114d&token90645021…

智能驾驶系列报告:特斯拉智能驾驶方案简剖

不同于绝大多数国内车企在自动驾驶上采取多传感器融合方案&#xff0c;特斯拉FSD在发展初期就摒弃激光雷达、且不配备高清地图&#xff0c;成为在感知层以摄像头为核心的纯视觉解决方案代表;其依靠车身搭载的摄像头来捕捉周围的环境信息&#xff0c;并经过算法及神经网络模型处…

JOSEF约瑟 YHSJ-J打滑开关 使用带速0.3-5.0m/s

产品概述&#xff1a; YHSJ-J打滑开关是一种智能型超速打滑检测器&#xff0c;采用非接触式监测方式&#xff0c;自动采集设备正常运行时的转速&#xff0c;并通过监测转速变化量和相关控制参数进行比较&#xff0c;以判断是否存在打滑现象。 该产品已广泛应用于输送系统中&…

【智慧水利数字孪生解决方案】

在2024年全国水利工作重点会议上&#xff0c;水利部部长李国英发表重要讲话&#xff0c;强调&#xff1a;大力推进数字孪生水利建设。坚持需求牵引、应用至上、数字赋能、提升能力&#xff0c;加快构建数字孪生水利体系&#xff0c;为水利治理管理提供前瞻性、科学性、精准性、…

“论云上自动化运维及其应用”写作框架,软考高级论文,系统架构设计师论文

论文真题 云上自动化运维是传统IT运维和DevOps的延伸&#xff0c;通过云原生架构实现运维的再进化。云上自动化运维可以有效帮助企业降低IT运维成本&#xff0c;提升系统的灵活度&#xff0c;以及系统的交付速度&#xff0c;增强系统的可靠性&#xff0c;构建更加安全、可信、…

明星中药企业系列洞察(九)一手好牌打的稀烂!近500年老字号锁定退市,太安堂为何“塌房”了?

近日&#xff0c;太安堂发布公告称&#xff0c;公司已收到深交所下发的《关于广东太安堂药业股份有限公司股票终止上市的决定》&#xff0c;深交所决定终止公司股票上市&#xff0c;预计其最后交易日期为7月4日。太安堂曾作为国内知名的中成药上市公司之一&#xff0c;是国家级…

动捕系统如何解决“超出捕捉范围”的挑战

惯性运动捕捉系统改变了我们捕捉运动的方式&#xff0c;使艺术家、创作者和独立工作室能够摆脱动捕实验室和复杂设置的限制。通过身体上的传感器和无线连接&#xff0c;动捕演员可以自由移动和并作出各种高难度动作。然而具有高自由度的惯性动捕系统&#xff0c;经常面临着超出…

深入解析 androidx.databinding.BaseObservable

在现代 Android 开发中&#xff0c;数据绑定 (Data Binding) 是一个重要的技术&#xff0c;它简化了 UI 和数据之间的交互。在数据绑定框架中&#xff0c;androidx.databinding.BaseObservable 是一个关键类&#xff0c;用于实现可观察的数据模型。本文将详细介绍 BaseObservab…

雨量气象站:野外监测的得力助手

在广阔无垠的大自然中&#xff0c;雨量、风力、风向、温湿度以及大气压力等气象数据对于各种应用场景都至关重要。特别是在野外、森林防火、山洪监测等无市电供电的场合&#xff0c;一款高效可靠的监测设备更是不可或缺。雨量气象站正是为了满足这些需求而诞生的户外专用监测站…

昇思25天学习打卡营第8天|模型训练

昇思25天学习打卡营第8天|模型训练 前言模型训练构建数据集定义神经网络模型定义超参、损失函数和优化器超参损失函数优化器 训练与评估 个人任务打卡&#xff08;读者请忽略&#xff09;个人理解与总结 前言 非常感谢华为昇思大模型平台和CSDN邀请体验昇思大模型&#xff01;从…

剖析DeFi交易产品之UniswapV4:概述篇

本文首发于公众号&#xff1a;Keegan小钢 UniswapV4 与 UniswapV3 相比&#xff0c;算法上并没有什么改变&#xff0c;依然还是采用集中流动性模型&#xff0c;但架构上变化很大&#xff0c;包括功能架构&#xff0c;也包括技术架构。相比之前的版本&#xff0c;UniswapV4 最大…

光扩散微球市场增长空间大 我国已实现其产业化

光扩散微球市场增长空间大 我国已实现其产业化 光扩散微球是一种高性能微球材料&#xff0c;具有优异的光学和力学性能&#xff0c;且不含杂质&#xff0c;将其涂抹在光扩散膜&#xff08;板&#xff09;上&#xff0c;可以将点光源变成面光源&#xff0c;使显示面板的布光更加…

大型语言模型能否生成可信的事实核查解释?——通过多智能体辩论实现可信可解释的事实核查

Can LLMs Produce Faithful Explanations For Fact-checking? Towards Faithful Explainable Fact-Checking via Multi-Agent Debate 论文地址:https://arxiv.org/abs/2402.07401https://arxiv.org/abs/2402.07401 1.概述 在数字化时代,对于迅速传播的错误信息,其核实与明…

达梦数据库系列—19. 动态增加实时备库

目录 动态增加实时备库 1、数据准备 2 、配置新备库 2.1配置 dm.ini 2.2配置 dmmal.ini 2.3 配置 dmarch.ini 2.4 配置 dmwatcher.ini 2.5 启动备库 2.6 设置 OGUID 2.7 修改数据库模式 3、 动态添加 MAL 配置 4、 动态添加归档配置 5、 修改监视器 dmmonitor.ini…

windows离线安装显卡驱动解决方案

前言 我们说这个离线泛指计算机无公网环境&#xff0c;而我们需要将显卡驱动打上&#xff0c;既然没有公网&#xff0c;我们就无法使用联网的方式&#xff08;傻瓜式安装&#xff09;&#xff0c;受各种原因限制&#xff0c;也不可以把主机搬走连上互联网进行安装。总之…

导入tidb时将数据库表导出为多张csv格式

DBeaver&#xff1a; 步骤&#xff1a; 确定目标库——>工具——>创建新任务 NEXT Navicat&#xff1a;

AQS同步队列、条件队列源码解析

AQS详解 前言AQS几个重要的内部属性字段内部类 Node同步队列 | 阻塞队列等待队列 | 条件队列 重要方法执行链同步队列的获取、阻塞、唤醒加锁代码流程解锁 条件队列的获取、阻塞、唤醒大体流程 调用await()方法1. 将节点加入到条件队列2. 完全释放独占锁3. 等待进入阻塞队列4. …

智慧校园新气象:校园气象站

在数字化、智能化的浪潮下&#xff0c;传统校园正在迎来一场革命性的变革。在这场变革中&#xff0c;校园气象站以其独特的功能和魅力&#xff0c;成为推动校园气象科普教育、提升校园品质的重要力量。 一、校园气象站&#xff1a;智慧校园的“气象眼” 校园气象站&#xff0c…

UVa1321/LA2925 Dice contest

UVa1321/LA2925 Dice contest 题目链接题意分析测试数据AC 代码 题目链接 本题是2003年icpc欧洲区域赛中欧赛区的D题 题意 骰子的六面展开图如下&#xff0c;现在把骰子的六个面赋予一套权重 w i ( 1 ≤ w i ≤ 50 , 1 ≤ i ≤ 6 ) w_i(1\le w_i \le 50,1\le i\le 6) wi​(1≤…

如何选择适合您业务需求的多语言跨境电商系统源码

随着互联网技术的飞速发展和全球市场的日益融合&#xff0c;多语言跨境电商已经成为许多企业进军国际市场的重要战略。在这个竞争激烈的时代&#xff0c;拥有一个适合自己业务需求的多语言跨境电商系统源码至关重要。本篇文章将为您揭秘如何选择适合您业务需求的多语言跨境电商…