通过开放解析智能分块提高 RAG 性能

如果要使用大型语言模型 ()LLMs 实现生成式 AI 解决方案,则应考虑使用检索增强生成 (RAG) 的策略来生成上下文感知提示LLM。在启用 LLM RAG 的预生产管道中发生的一个重要过程是删除文档文本,以便仅将文档中最相关的部分与用户查询匹配并发送到用户查询以生成内容。LLM这就是 Open-Parse 可以提供帮助的地方。Open-Parse 超越了朴素的文本拆分,以确保相似的文本不会被拆分为两个单独的块。在这篇文章中,我将展示如何从 MinIO 存储桶中获取原始形式的文档,使用 Open-Parse 将它们分块,然后将它们保存到另一个可用于馈送向量数据库的存储桶中。可以在此处找到包含本文中显示的所有代码的 Jupyter 笔记本。

在介绍 Open-Parse 处理文档的功能之前,让我们先看一下 RAG 推理管道。请特别注意如何使用文档块来提高生成对用户查询的响应时的LLMs性能。

RAG 推理管道

下图显示了 RAG 推理管道。它还显示了文档处理管道,这将在后面的章节中讨论。

检索增强生成 (RAG) 是一种技术,它从用户请求(通常是问题)开始,使用向量数据库将请求与其他数据结合在一起,然后将请求和数据传递给 LLM an 以进行内容创建。使用 RAG,不需要任何培训,因为我们LLM通过从自定义文档语料库发送相关文本块来对其进行教育。如下图所示。它的工作原理是这样的,使用问答任务:用户在应用程序的用户界面中提出问题。您的应用程序将接受问题 - 特别是其中的单词 - 并使用向量数据库搜索与上下文相关的文本块。这些块和原始问题被发送到 LLM.整个包 - 问题加块(上下文)被称为提示。将LLM使用此信息来生成您的答案。这似乎是一件愚蠢的事情 - 如果您已经知道答案(片段),为什么还要为?LLM请记住,这是实时发生的,目标是生成文本 - 您可以复制并粘贴到您的研究中。您需要创建LLM包含自定义语料库中信息的文本。使用 RAG,可以实现用户授权,因为在推理时从向量数据库中选择文档(或文档片段)。文档中的信息永远不会成为模型参数参数的一部分。下面列出了RAG的主要优点。

优势

  • 从您的自定义语料库LLM中获取直接知识。

  • 可解释性是可能的。

  • 无需微调。

  • 幻觉显着减少,可以通过检查向量数据库查询的结果来控制。

  • 可以实现文档级授权。

文档处理管道

显然,RAG 的一个重要部分是在通过嵌入模型运行文档并将嵌入保存到向量数据库之前发生的文档处理。如果您有二进制格式的复杂文档,例如 PDF,这并非易事。例如,文档通常包含表格、图形、注释、编辑文本和对其他文档的引用。此外,LLMs对可以使用原始查询发送的上下文的大小进行限制。因此,发送整个文档不是一种选择。即使您可以发送整个文档,也可能无法产生最佳结果。来自多个文档的代码段集合可能是特定用户查询的最佳上下文。为了解决这个问题,许多解析库会根据所需的块长度拆分文档。一种暴力的方法是仅使用块长度来拆分文本。更好的方法是在句子或段落边界上拆分,该边界仍将块保持在限制范围内。虽然这样更好,但它可以将节标题放在它们自己的块和块表中,将它们拆分为几个块。

Open-Parse 是一个用于拆分 PDF 文件的开源库,它超越了朴素的文本拆分。它的设计灵活且易于使用。它通过分析布局和基于简单的启发式创建块来对文档进行分块,这些分块将相关文本保留在同一块中。下面是一个流程图,显示了 Open-Parse 逻辑。注意:文本节点将转换为 Markdown,而表节点将转换为 HTML。

来源: https://filimoa.github.io/open-parse/processing/overview/

让我们看几个简单的例子,看看这到底意味着什么。

使用 Open-Parse 对文档进行分块

在生产环境中,您需要将原始 PDF 和分块对象存储在具有性能和扩展能力的存储解决方案中。这就是 MinIO 的用武之地。本节中的代码假定您设置了两个存储桶,如下所示。

我已将 Open-Parse 存储库中说明书使用的一些示例文档上传到 original-corpus 存储桶。我还上传了我最喜欢的白皮书。

我们需要的第一件事是一个实用程序函数,用于将文件下载到临时目录,以便 open-parse 可以处理它。以下功能将连接到 MinIO,并将 PDF 下载到系统的临时文件夹。

import os
from dotenv import load_dotenv

load_dotenv()
MINIO_URL = os.environ['MINIO_URL']
MINIO_ACCESS_KEY = os.environ['MINIO_ACCESS_KEY']
MINIO_SECRET_KEY = os.environ['MINIO_SECRET_KEY']
if os.environ['MINIO_SECURE']=='true': MINIO_SECURE = True
else: MINIO_SECURE = False

import tempfile

from minio import Minio
from minio.error import S3Error


def get_pdf_from_minio(bucket_name: str, object_name: str) -> str:
   '''
   Retrieves an object from MinIO, saves it in a temp file and retiurns the
   path to the temp file.
   '''
   try:
       # Create client with access and secret key
       client = Minio(MINIO_URL,
                   MINIO_ACCESS_KEY, 
                   MINIO_SECRET_KEY,
                   secure=MINIO_SECURE)

       # Generate a temp file.
       temp_dir = tempfile.gettempdir()
       temp_file = os.path.join(temp_dir, object_name)
       # Save object to file.
       client.fget_object(bucket_name, object_name, temp_file)
      
   except S3Error as s3_err:
       raise s3_err
   except Exception as err:
       raise err

   return temp_file

使用下面的代码片段运行此函数后,我们将在当前系统的临时目录中有一个文件。

original_corpus_bucket_name = 'original-documents'
chunked_corpus_bucket_name = 'document-chunks'
object_name = 'Attention is all you need.pdf'

temp_file = get_pdf_from_minio(original_corpus_bucket_name, object_name)

接下来,让我们拆分 PDF。这就像几行代码一样简单。拆分文档后,可以显示节点。如下所示。

import openparse

parser = openparse.DocumentParser()
parsed_basic_doc = parser.parse(temp_file)

print('Number of chunks:', len(parsed_basic_doc.nodes))

for node in parsed_basic_doc.nodes:
   print(node)

每个节点都包含一个文本块和有关该块来源的其他信息。下面的屏幕截图显示了上述片段的输出,其中的信息相当丰富。

使用此显示技术有助于了解用于表示文档的基础对象模型。然而,Open-Parse 特别好的是它的可视化工具,它可以在原始文档上绘制一个边界框,显示每个块的来源。这只需两行代码即可完成。


pdf = openparse.Pdf(temp_file)
pdf.display_with_bboxes(parsed_basic_doc.nodes[0:4])

在此代码中,我要求 Open-Parse 绘制原始 PDF 以及围绕前四个文本块的边界框。显示如下。请注意,即使文本采用类似网格的格式,作者也被放置在一个块中。Open-Parse 还找出了页面左侧的垂直文本。

如果我们通过类似的代码运行另一个原始文档,我们可以看到 Open-Parse 如何处理部分标题和项目符号文本。

将块保存到 MinIO

一旦我们将文档分块,下一步就是将每个块保存到 MinIO。为此,我们将使用上面屏幕截图中所示的 document-chunks 存储桶。以下函数会将文件保存到 MinIO 存储桶中。我们将使用此函数将每个块保存为单独的对象。


def save_chunk_to_minio(bucket_name: str, object_name: str,
                       file_path: str, metadata: dict) -> None:
   '''
   Saves a doument chunk to MinIO.
   '''
   try:
       # Create client with access and secret key
       client = Minio(MINIO_URL,  # host.docker.internal
                   MINIO_ACCESS_KEY, 
                   MINIO_SECRET_KEY,
                   secure=MINIO_SECURE)

       client.fput_object(bucket_name, object_name, file_path, metadata=metadata)

   except S3Error as s3_err:
       raise s3_err
   except Exception as err:
       raise err
       

Open-Parse 提供了一种model_dump方法,用于将分块文档序列化为字典。下面的代码片段调用此方法并打印一些附加信息,以便您了解此字典的形成方式。


import json

chunks = parsed_basic_doc.model_dump_json()
chunks = json.loads(chunks)

print(chunks.keys())
print(chunks['nodes'][0])
print(type(chunks['nodes'][0]))
chunks

输出如下所示。


dict_keys(['nodes', 'filename', 'num_pages', 'coordinate_system', 'table_parsing_kwargs'])


{'variant': {'text'}, 'tokens': 140, 'bbox': [{'page': 0, 'page_height': 792.0, 'page_width': 612.0, 'x0': 116.68, 'y0': 436.19, 'x1': 497.21, 'y1': 558.54}], 'text': '...'}


<class 'dict'>


{'nodes': [{'variant': {'text'},
   'tokens': 140,
   'bbox': [{'page': 0,
     'page_height': 792.0,
     'page_width': 612.0,
     'x0': 116.68,
     'y0': 436.19,
     'x1': 497.21,
     'y1': 558.54}],
   'Text': ...

字典可以拆开,每个块都可以发送到 MinIO。如下所示。此代码还会将有关原始文档的元数据添加到每个对象。 将原始文件名与每个块一起保存有助于 Rag 推理管道中的可解释性。可解释性允许使用启用LLM的 RAG 的应用程序显示指向用于构建提示上下文的所有文档的链接。对于致力于提高推理管道性能的最终用户和工程师来说,这是一项强大的功能。

import json

temp_dir = tempfile.gettempdir()
temp_file = os.path.join(temp_dir, 'tmp.json')
print(temp_file)

metadata = {}
metadata['filename'] = chunks['filename']
metadata['num_pages'] = chunks['num_pages']
metadata['coordinate_system'] = chunks['coordinate_system']
metadata['table_parsing_kwargs'] = chunks['table_parsing_kwargs']
print(metadata)

chunk_num = 0
for node in chunks['nodes']:
   with open(temp_file, 'w') as f:
       f.write(json.dumps(node))
       #pickle.dump(node, f) # Serialize the node.
       chunk_name = os.path.splitext(object_name)[0]
       save_chunk_to_minio(chunked_corpus_bucket_name, f'{chunk_num} - {chunk_name}.json',
                           temp_file, metadata)
   chunk_num += 1

请注意,我们无法将数据转储到 JSON 文件。包含所有块的字典使用 Python “set” 对象,该对象无法序列化为 JSON。对于这种情况,Python pickle 格式工作得很好。完成上述代码后,我们的 document-chunks 存储桶将如下所示。

后续步骤

这篇文章介绍了 Open-Parse 的核心功能。但是,它还具有一些高级功能,在构建生产级推理管道之前应探索这些功能。

  • 解析表可能很棘手。如果默认功能在处理表时遇到问题,请在此处查看高级表解析功能。

  • RAG的主要优势之一是可解释性。它允许用户查看用于生成答案的所有文档的链接。使用 Open-Parse,这是通过与每个文档块一起保留的元数据实现的。当收集语义相关的块时,可以确定使用的所有文档,并且可以与生成的文本一起显示指向这些文档的链接。可以在此处观看此功能的简短视频演示。

  • 语义分块是一种高级技术,如果节点(块)在语义上相似,则它们会组合在一起。点击此处了解详情。

  • 如果希望进一步处理提取的数据,可以向 DocumentParser 类添加自定义处理函数。点击此处了解详情。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

论文:R语言数据分析之机器学习论文

欢迎大家关注全网生信学习者系列&#xff1a; WX公zhong号&#xff1a;生信学习者Xiao hong书&#xff1a;生信学习者知hu&#xff1a;生信学习者CDSN&#xff1a;生信学习者2 一、研究背景 全球范围内&#xff0c;乳腺癌是导致癌症发病率和死亡率的主要疾病之一。根据2018年…

BFS 解决最短路问题

例题一 解法&#xff08;bfs 求最短路&#xff09;&#xff1a; 算法思路&#xff1a; 利⽤层序遍历来解决迷宫问题&#xff0c;是最经典的做法。我们可以从起点开始层序遍历&#xff0c;并且在遍历的过程中记录当前遍历的层数。这样就能在找到出⼝的时候&#xff0c;得到起点…

会自动清除的文件——tempfile

原文链接&#xff1a;http://www.juzicode.com/python-tutorial-tempfile/ 在某些不需要持久保存文件的场景下&#xff0c;可以用tempfile模块生成临时文件或者文件夹&#xff0c;这些临时文件或者文件夹在使用完之后就会自动删除。 NamedTemporaryFile用来创建临时文件&…

教程:LVM操作讲解

LVM简介 在系统运维过程中&#xff0c;对磁盘扩缩容是常见的操作。如何高效的管理磁盘容量&#xff0c;lvm提供了很好的解决方案。 LVM将磁盘抽象成PV、VG、LV&#xff0c;方便用户进行磁盘管理&#xff0c;简单来讲&#xff0c;是由物理磁盘划分成PV&#xff0c;PV加入到具体…

探索Linux的奇妙世界:第二关---Linux的基本指令1

1. xshell与服务器的连接 想必大家在看过上一期视频时已经搭建好了Linux的环境了并且已经下好了终端---xshell了吧?让我来带大家看一看下好了是什么样子的: 第一次登陆会让你连接你的服务器,就是我们买的云服务器,买完之后需要把公网地址ip复制过来进行链接,需要用户名和密码连…

CNN神经网络猫狗分类经典案例

因为有猫和狗两类&#xff0c;所有在data/train目录下&#xff0c;再建两个目录data/train/dog和data/train/cat&#xff1a; 同理&#xff0c;其他的data/validation和data/test目录下&#xff0c;再建两个目录&#xff1a;cat和data/&#xff0c;在cat和dog目录下&#xff0c…

Large Language Model based Multi-Agents: A Survey of Progress and Challenges

目录 摘要简介背景单一智能体系统单智能体 vs .多智能体系统 剖析多智能体系统&#xff1a;接口、剖析、通信和能力智能体 - 环境接口智能体画像智能体通信能力获取 摘要 大型语言模型( Large Language Models&#xff0c;LLMs )在各种任务中都取得了令人瞩目的成功。由于LLMs…

你好,复变函数2.0

第一行&#xff1a;0 或 1 第二行&#xff1a;&#xff08;空格&#xff09;函数&#xff08;后缀&#xff09; #pragma warning(disable:4996) #include <easyx.h> #include <stdio.h> #include <math.h> #define PI 3.141592653589793 #define E 2.71828…

【ai】tritonserver 的测试sdk部署

HybrIKHybrIK 环境 conda create -n hybrik python=3.8 -y 虚拟环境 zhangbin@ubuntu-server:~/miniconda3/bin$ pip config set global.index-url https: …

make与makefile

目录 一、make的默认目标文件与自动推导 二、不能连续make的原因 执行原理 touch .PHONY伪目标 make指令不回显 makefile多文件管理 简写依赖方法 三、回车与换行 四、缓冲区 一、make的默认目标文件与自动推导 假设这是一个makefile文件&#xff0c;make的时候默认生…

Kubernetes Dashboard

Minikube 环境搭建 Kubernetes 的基本架构 Kubernetes 声明式语言 YAML YAML操作Kubernetes核心对象 CentOs搭建Kubernetes集群 Kubernetes进阶对象Deployment、DaemonSet、Service Kubernetes进阶对象Ingress、Ingress Class、Ingress Controller Kubernetes集群部署项目实践 …

XTDrone-无人机与无人船协同初步-配置教程

说明&#xff1a;配置该教程时所使用的是Ubuntu20.04 1 海洋与无人船仿真环境搭建 cp -r ~/XTDrone/sitl_config/usv/* ~/catkin_ws/src/ cd catkin_ws catkin build # or catkin_make 说明&#xff1a;由于官方所编写的脚本时几年之前的&#xff0c;所以很多东西不符合现在…

深入分析并可视化城市轨道数据

介绍 中国城市化进程加速中&#xff0c;城市轨道交通的迅速扩张成为提升城市运行效率和居民生活品质的关键。这一网络从少数大城市延伸至众多大中型城市&#xff0c;映射了经济飞跃和城市管理现代化。深入分析并可视化城市轨道数据&#xff0c;对于揭示网络特性、评估效率、理…

JavaScript学习笔记(二)

12、数字 常规用法和java的用法相似&#xff0c;就不再做详细的记录, JavaScript 数字 以下只记录特殊用法&#xff1a; 12.1 数字字符串运算 在所有数字运算中&#xff0c;JavaScript 会尝试将字符串转换为数字&#xff1a; var x "100"; var y "10"…

MySQL性能问题诊断方法和常用工具

作者介绍&#xff1a;老苏&#xff0c;10余年DBA工作运维经验&#xff0c;擅长Oracle、MySQL、PG数据库运维&#xff08;如安装迁移&#xff0c;性能优化、故障应急处理等&#xff09; 公众号&#xff1a;老苏畅谈运维 欢迎关注本人公众号&#xff0c;更多精彩与您分享。MySQL运…

python入门基础知识(错误和异常)

本文部分内容来自菜鸟教程Python 基础教程 | 菜鸟教程 (runoob.com) 本人负责概括总结代码实现。 以此达到快速复习目的 目录 语法错误 异常 异常处理 try/except try/except...else try-finally 语句 抛出异常 用户自定义异常 内置异常类型 常见的标准异常类型 语法…

每天写java到期末考试--接口1--基础--6.22

规则&#xff1a; 练习&#xff1a; 抽象类的抽象方法 动物类Animal package 期末复习;public abstract class Animal {private String name;private int age;//1.空构造public Animal(){}public Animal(String name,int age){this.ageage;this.namename;}public String getNa…

【Java毕业设计】基于JavaWeb的服务出租系统

本科毕业设计论文 题目&#xff1a;房屋交易平台设计与实现 系 别&#xff1a; XX系&#xff08;全称&#xff09; 专 业&#xff1a; 软件工程 班 级&#xff1a; 软件工程15201 学生姓名&#xff1a; 学生学号&#xff1a; 指导教师&#xff1a; 导师1 导师2 文章目录 摘…

C++入门 vector部分模拟实现

目录 vector大致框架 vector常见接口模拟实现 begin迭代器 & end迭代器 capacity( ) & size( ) reserve operator[ ] push_back( ) & pop_back( ) sort vector大致框架 vector的内部的成员变量大概有三部分构成&#xff1a; namespace bit {template<c…

java中的日志

springboot自带slf4j框架和logback&#xff0c;我们可以移除spring的logging&#xff0c;然后再带入自己的日志框架。 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusio…