深入 Dify 源码,洞察 Dify RAG 切片机制实现细节

news2024/11/28 2:54:12

背景介绍

最近测试时发现 Dify 的 RAG 分片效果一般,不管是使用之前 深入 Dify 源码,洞察 Dify RAG 核心机制 中有调研过的默认解析还是 Unstructured 解析。因此调研比较了 大量的开源框架 实现了特定格式的结构化解析方案,并与 Dify 现有解析流程进行了适配。

为了保证文件的解析能真正发挥出效果,需要保证预处理中其他环节也遵循前面的结构化方案进行处理,其中重要的一块就是文本的分片机制。深入了解 Dify 的实现细节后整理相关内容在这边,方便对 Dify RAG 实现机制感兴趣的同学。

Dify 切片简介

在前面的 深入 Dify 源码,洞察 Dify RAG 核心机制 已经大致了解到,Dify 的切片主要涉及的页面如下所示:
请添加图片描述

自动分段与清洗对应的就是 EnhanceRecursiveCharacterTextSplitter, 自定义对应的就是 FixedRecursiveCharacterTextSplitter,其实这两者实现机制的机制基本相同,主要差异是自定义机制将切片默认的参数提供给用户自由选择,并提供了一个额外的分段标识符。

Dify 切片机制

自动分段与清洗

Dify 的切片方案基本上是参考 langchain 实现,就是按照指定标识符列表进行递归切分,默认的切分的字符列表为 ["\n\n", "。", ". ", " ", ""],切分过程举例如下所示:
请添加图片描述

  1. 第一步按照第一个标识符 \n\n 进行切分;
  2. 如果切分后分片的大小依旧超过指定的分片阈值,此时按照下一个标识符 进行切分;
  3. 长度依旧超过阈值,接下来按照下一个字符 . 切分,递归处理直到切分到的分片长度不超过阈值;

对应的代码在 api/core/rag/splitter/text_splitter.py 中:

def _split_text(self, text: str, separators: list[str]) -> list[str]:
    final_chunks = []
    separator = separators[-1]
    new_separators = []

    # 依次从指定的标识符列表中寻找合适的标识符

    for i, _s in enumerate(separators):
        if _s == "":
            separator = _s
            break
        if re.search(_s, text):
            separator = _s
            new_separators = separators[i + 1:]
            break

    # 按照标识符进行切分

    splits = _split_text_with_regex(text, separator, self._keep_separator)

    _good_splits = []
    _separator = "" if self._keep_separator else separator
    for s in splits:
        # 长度没有超过阈值, 是一个较好的分割点

        if self._length_function(s) < self._chunk_size:
            _good_splits.append(s)
        else:
            if _good_splits:
                merged_text = self._merge_splits(_good_splits, _separator)
                final_chunks.extend(merged_text)
                _good_splits = []
            if not new_separators:
                final_chunks.append(s)
            else:
                # 长度超过阈值,递归按照后续的标识符进行切分

                other_info = self._split_text(s, new_separators)
                final_chunks.extend(other_info)
    # 合并文本,尽量保证文本长度接近阈值,避免过短的碎片文本

    if _good_splits:
        merged_text = self._merge_splits(_good_splits, _separator)
        final_chunks.extend(merged_text)
    return final_chunks

上面的实现也比较容易理解,就是从 separators 中依次选择标识符,递归执行切分,切分后的片段暂存在 _good_splits 中,为了避免切分后的文本长度过短,在加入最终的列表 final_chunks 之前会进行文本的合并。

文本的合并常规就是依次遍历切片产生的片段,依次合并并保留必要的重合区域,感兴趣可以查看 _merge_splits() 方法的实现。

自定义

自定义分片与自动分段类似,可以支持用户指定分片长度和重叠长度,这个与常规的自动分段基本类似,只是将默认参数提供给用户进行修改。除此之外可以支持用户指定分段标识符:
请添加图片描述

通过上面的自动分段可以看到文本切分是递归按照标识符列表进行切分的,那么这个自定义的分段标识符与默认的切分标识符列表是如何结合的呢?可以查看对应的实现:

def split_text(self, text: str) -> list[str]:
    # 额外指定分段标识符的情况下,会按照用户指定的分隔标识符先切分

    if self._fixed_separator:
        chunks = text.split(self._fixed_separator)
    else:
        chunks = list(text)

    final_chunks = []
    for chunk in chunks:
        # 按照用户执行的分段标识符切分后超过阈值,此时按照标识符列表依次递归切分

        if self._length_function(chunk) > self._chunk_size:
            final_chunks.extend(self.recursive_split_text(chunk))
        else:
            final_chunks.append(chunk)

    return final_chunks

可以看到自定义切分的主要差异是会先按照用户指定的分段标识符进行额外切分,但是要特别注意这部分目前的实现比较粗糙:

  1. 按照用户指定的分段标识符进行切分时,分段重叠参数是不生效的,Dify 会直接按照指定的分段标识符切分;
  2. 按照用户指定的分段标识符切分时,不会执行分段的合并,可能会产生大量的长度较小的碎片文本;
  3. 用户指定的分段标识符为空的情况下,执行的 chunks = list(text) 明显是有问题的,会按照单个字母切分字符串,最终完全不可用;

从目前来看,自定义的切片策略的实现坑有点多,需要慎用

总结

总结而言,Dify 的分片策略主要分为自动分段以及自定义策略,两者机制类似,依次按照字符列表进行递归的切片,但是自定义策略的实现目前坑有点多,建议谨慎选择。

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

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

相关文章

高通8255 Android Virtio Virtio-IIC 配置方法

目录 一&#xff1a;VirtIO和Passthrough的区别 方法一&#xff1a; passthrough 方法二&#xff1a;virtIO 二&#xff1a;配置逻辑 三&#xff1a;示例Virtio-I2C配置 Virtio-I2C框架 步骤一&#xff1a;QNX IIC资源配置 & 测试 配置 测试 步骤二&#xff1a;B…

干货整理: 什么软件能够监控电脑? 六大好用监控电脑软件抢手推荐

如何保障电脑的安全是许多企业用户关注的焦点。 除了常见的杀毒软件外&#xff0c;电脑监控软件也是一道重要的防线。 这些软件能够实时监控电脑的各项运行状况&#xff0c;及时发现并处理潜在的安全威胁&#xff0c;确保电脑的正常运行和用户数据的安全。 接下来&#xff0…

优思学院|防呆法的十大原理

防呆法&#xff08;Poka-Yoke&#xff09;&#xff0c;又称防错法&#xff08;Mistake-Proofing&#xff09;&#xff0c;是一种通过预防错误的发生来提高工作效率&#xff0c;也是精益管理、六西格玛中常用的管理工具。以下就是防呆法的十大原理&#xff1a; 1. 断根原理 断…

算法_链表专题---持续更新

文章目录 前言两数相加题目要求题目解析代码如下 两两交换链表中的结点题目要求题目解析代码如下 重排链表题目要求题目解析代码如下 合并K个升序链表题目要求题目解析 K个一组翻转链表题目要求题目解析代码如下 前言 本文将记录leetcode链表算法题解&#xff0c;包含题目有&a…

Why Memory Matters?(记忆力为何如此重要?)

What is memory? The general consensus is that memory is a multitude of cognitive systems which allow us to store information for certain periods of time so that we can learn from our past experiences and predict the future. 什么是记忆?人们普遍的共识是&am…

《PostgreSQL 数据库在国内的发展前景》

从DB-engines这张2024年8月的最新排名图上可以看出&#xff0c;PostgreSQL数据库的发展趋势还是非常好的&#xff0c;在国内&#xff0c;PostgreSQL数据库也展现出令人振奋的发展前景&#xff0c;非常明显的一种表现就是腾讯云、人大金仓、阿里云、华为等众多厂商都有基于Postg…

推荐一个uniapp选择文件上传的插件

插件地址&#xff1a;文件选择、文件上传组件&#xff08;图片&#xff0c;视频&#xff0c;文件等&#xff09; - DCloud 插件市场 支持 H5 / App / 微信小程序

警惕!SCI投稿也有“假网址”!3秒教你查询正确的期刊官网网址

【SciencePub学术】很多没有发表过SCI论文的学者&#xff0c;对于投稿是非常陌生的。首先第一步&#xff0c;对于寻找正确的SCI/SSCI期刊官网都是一项难题。 01 假网站泛滥 • 目前市面上很多假的期刊官网&#xff0c;甚至于界面都所差无几&#xff0c;但是网址仅仅相差一个“…

【两周年纪念日】我将竭尽全力,只为和最美丽的自己早日汇合

​ 您好&#xff0c;我是程序员小羊&#xff01; 存在有其原因&#xff0c;经历有其始终&#xff0c;年华有其始末&#xff0c;拼搏要有结果。 2023来去匆匆&#xff0c;2024奋斗始终&#xff0c;献出一份感情&#xff0c;收获一份心情&#xff0c;拼出一段经验&#xff0c;收获…

两个方法 搞定伦敦金涨跌预测

受美联储降息预期和地缘局势紧张的关系影响&#xff0c;近期伦敦金价格再次出现了强势的上涨&#xff0c;盘中攀升超过30美元。这波涨势的出现&#xff0c;实在是在很多人的意料之外&#xff0c;那么下一步投资者就要开始考虑伦敦金的上涨的终点在哪里&#xff1f;实际上这就是…

计算机组成原理 - 中央处理器

中央处理器 考纲内容 CPU的功能和基本结构指令执行过程数据通路的功能和基本结构控制器的功能和工作原理异常和中断机制 异常和终端的基本概念&#xff1b;异常和中断的分类&#xff1b;异常和中断的检测与响应指令流水线 指令流水线的基本概念&#xff1b;指令流水线的基本实…

动态规划:买卖股票系列

目录 1. 买卖股票的最佳时机1-只能买卖一次(LeetCode121) 解法1&#xff1a;暴力解法 解法2&#xff1a;贪心算法 解法3&#xff1a;动态规划 2. 买卖股票的最佳时机2-可以买卖多次(LeetCode122) 解法1&#xff1a;贪心算法 解法2&#xff1a;动态规划 3. 买卖股票的最…

【架构设计】软件设计原则中的7种耦合和内聚(详解)

文章目录 一、前言二、内聚1、定义2、7 种内聚类型及其描述3、设计要求 三、耦合1、定义2、7 种耦合类型及其描述3、设计要求 四、总结 一、前言 耦合&#xff08;Coupling&#xff09;和内聚&#xff08;Cohesion&#xff09;是衡量软件模块设计质量的两个非常重要的概念。高…

2024实验班选拔考试(热身赛)

比赛传送门 邀请码&#xff1a;2024wksyb A. 简单的数列问题 签到&#xff0c;记得开long long。 #include<bits/stdc.h> #define rep(i,a,b) for (int ia;i<b;i) #define per(i,a,b) for (int ia;i>b;--i) #define se second #define fi first #define endl …

linux进程篇总结——实战——自定义shell

前言&#xff1a;经过过去两章十二篇文章的学习&#xff0c;我们已经知道了进程的基本概念以及进程的控制方法。 本篇内容就是使用过去学习的内容自己写一个功能简单的shell外壳程序&#xff0c; 也就是我们使用的bash命令行。 本篇内容是过去进程知识的集大成者。 我们在这个实…

智慧能源管理:助力公共机构节能增效

一、背景&#xff1a; 在全球倡导绿色发展、节能减排的时代浪潮下&#xff0c;公共机构作为社会服务的重要提供者&#xff0c;能源消耗量大&#xff0c;特别是在照明方面能源消耗问题尤为突出。从政府办公楼的日常照明&#xff0c;到学校教室的学习照明&#xff0c;再到医院走…

计算机组成原理 - 存储系统

存储系统 考纲内容 存储器的分类层次化存储器的基本结构半导体随机存储器(RAM) SRAM、DRAM、Flash存储器主存储器 DRAM芯片和内存条、多模块存储器、主存储器和CPU之间的连接外部存储器 磁盘存储器、固态硬盘(SSD)高速缓冲存储器(Cache) Cache的基本原理&#xff1a;Cache和主…

解读智慧车间生产线的智慧大脑:ARMxy 工业计算机边缘控制器

在现代工业制造中&#xff0c;智慧车间生产线的建设已成为提高生产效率、降低成本、提升产品质量的关键。而 ARMxy 工业计算机边缘控制器作为智慧车间生产线的智慧大脑&#xff0c;正发挥着越来越重要的作用。 ARMxy 工业计算机边缘控制器是一种基于 ARM 架构的嵌入式工业计算机…

JavaWeb基础1:HTML/CSS/JS/HTTP

JavaWeb基础1&#xff1a;HTML/CSS/JS/HTTP (qq.com)

C-sharp-console-gui-framework:C#控制台应用程序的GUI框架

推荐一个.Net开源项目&#xff0c;方便我们基于控制台创建图形用户界面&#xff08;GUI&#xff09;应用程序。 01 项目简介 ConsoleGUI是一个简单的布局驱动.NET框架&#xff0c;用于创建基于控制台的GUI应用程序。 核心功能&#xff1a; **布局驱动&#xff1a;**与WPF或H…