RAG文本拆分深入研究

在这里,我们将尝试全面深入地掌握成功实施 RAG 所必需的不同主题。以下是示例 RAG 架构。

NSDT工具推荐: Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 可编程3D场景编辑器 - REVIT导出3D模型插件 - 3D模型语义搜索引擎 - AI模型在线查看 - Three.js虚拟轴心开发包 - 3D模型在线减面 - STL模型在线切割

让我们从“文本拆分”的概念开始。

在这里,我们可能需要考虑根据某种类型的文本拆分方法将输入数据加载并转换为不同的块。让我们从不同的文本拆分方法开始,并比较所有这些方法的不同向量存储。

从高层次上讲,文本拆分器的工作原理如下:

  • 将文本拆分成小的、语义上有意义的块(通常是句子)。
  • 开始将这些小块组合成更大的块,直到达到一定的大小(由某个函数测量)。
  • 一旦达到该大小,就将该块作为自己的文本,然后开始创建具有一定重叠的新文本块(以保持块之间的上下文)。

这意味着你可以沿着两个不同的轴自定义文本分割器:

  • 如何分割文本
  • 如何测量块大小

1、使用 RAG 的实用代码示例

导入库:

import osfrom langchain.text_splitter import (CharacterTextSplitter,RecursiveCharacterTextSplitter,SentenceTransformersTokenTextSplitter,TextSplitter,TokenTextSplitter,
)
from langchain_community.document_loaders import TextLoader
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings

本节导入脚本所需的模块和类。这些包括文本分割器、文档加载器、向量存储和嵌入。langchain_community 和 langchain_openai 库用于加载文档、将其分割成可管理的块并创建嵌入。

目录设置:

# Define the directory containing the text file
current_dir = os.path.dirname(os.path.abspath(__file__))
file_path = os.path.join(current_dir, "books", "romeo_and_juliet.txt")
db_dir = os.path.join(current_dir, "db")

代码定义了脚本的当前目录、文本文件 (romeo_and_juliet.txt) 的路径以及将保存向量存储的目录 (db 目录)。

文件存在性检查:

# Check if the text file exists
if not os.path.exists(file_path):raise FileNotFoundError(f"The file {file_path} does not exist. Please check the path.")

代码检查指定的文本文件是否存在。如果不存在,它会引发 FileNotFoundError,从而停止脚本并提供错误消息。

加载文本内容:

# Read the text content from the file
loader = TextLoader(file_path)
documents = loader.load()

TextLoader 类用于将文本文件的内容加载到脚本中。此内容存储在 documents 变量中。

定义嵌入模型:

# Define the embedding model
embeddings = OpenAIEmbeddings(model="text-embedding-3-small"
)  # Update to a valid embedding model if needed

代码设置了嵌入模型,将文本数据转换为数值向量。此特定模型 (text-embedding-3-small) 用于嵌入文本数据,可根据需要进行更新。

创建和持久化向量存储的函数:

# Function to create and persist vector store
def create_vector_store(docs, store_name):persistent_directory = os.path.join(db_dir, store_name)if not os.path.exists(persistent_directory):print(f"\n--- Creating vector store {store_name} ---")db = Chroma.from_documents(docs, embeddings, persist_directory=persistent_directory)print(f"--- Finished creating vector store {store_name} ---")else:print(f"Vector store {store_name} already exists. No need to initialize.")

此函数检查指定目录中是否已存在向量存储。如果不存在,它将使用提供的文档和嵌入创建并保存一个新的向量存储。向量存储保存在 db_dir 目录中,名称由 store_name 提供。

2、拆分文本

现在,本文最重要的是如何拆分输入语料库数据。在这里,我们将研究拆分数据的不同方法,并检查它们的输出。

2.1 基于字符的拆分

# 1. Character-based Splitting
# Splits text into chunks based on a specified number of characters.
# Useful for consistent chunk sizes regardless of content structure.
print("\n--- Using Character-based Splitting ---")
char_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=100)
char_docs = char_splitter.split_documents(documents)
create_vector_store(char_docs, "chroma_db_char")

文本被拆分成 1000 个字符的块,块之间有 100 个字符的重叠。此方法可确保块大小一致,而不管文本的内容结构如何。生成的块存储在名为 chroma_db_char 的向量存储中。

2.2 基于句子的拆分

# 2. Sentence-based Splitting
# Splits text into chunks based on sentences, ensuring chunks end at sentence boundaries.
# Ideal for maintaining semantic coherence within chunks.
print("\n--- Using Sentence-based Splitting ---")
sent_splitter = SentenceTransformersTokenTextSplitter(chunk_size=1000)
sent_docs = sent_splitter.split_documents(documents)
create_vector_store(sent_docs, "chroma_db_sent")

文本根据句子被拆分成块,每个块最多包含 1000 个字符。此方法可确保块保持语义连贯性。生成的块存储在名为 chroma_db_sent 的向量存储中。

2.3 基于标记的拆分

# 3. Token-based Splitting
# Splits text into chunks based on tokens (words or subwords), using tokenizers like GPT-2.
# Useful for transformer models with strict token limits.
print("\n--- Using Token-based Splitting ---")
token_splitter = TokenTextSplitter(chunk_overlap=0, chunk_size=512)
token_docs = token_splitter.split_documents(documents)
create_vector_store(token_docs, "chroma_db_token")

根据标记(例如单词或子词)将文本拆分为块。此方法在使用具有严格标记限制的转换器模型时特别有用。生成的块存储在名为 chroma_db_token 的向量存储中。

2.4 基于字符的递归拆分

# 4. Recursive Character-based Splitting
# Attempts to split text at natural boundaries (sentences, paragraphs) within character limit.
# Balances between maintaining coherence and adhering to character limits.
print("\n--- Using Recursive Character-based Splitting ---")
rec_char_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=100)
rec_char_docs = rec_char_splitter.split_documents(documents)
create_vector_store(rec_char_docs, "chroma_db_rec_char")

此方法尝试在自然边界(例如句子或段落)处拆分文本,同时遵守字符限制。它在保持一致性和将块保持在指定大小之间取得平衡。生成的块存储在名为 chroma_db_rec_char 的向量存储中。

2.5 自定义拆分

# 5. Custom Splitting
# Allows creating custom splitting logic based on specific requirements.
# Useful for documents with unique structure that standard splitters can't handle.
print("\n--- Using Custom Splitting ---")class CustomTextSplitter(TextSplitter):def split_text(self, text):# Custom logic for splitting textreturn text.split("\n\n")  # Example: split by paragraphscustom_splitter = CustomTextSplitter()
custom_docs = custom_splitter.split_documents(documents)
create_vector_store(custom_docs, "chroma_db_custom")

本节定义了一个自定义文本分割器,可根据特定要求(在本例中为按段落)分割文本。此方法适用于标准分割器可能无法很好地处理的独特结构的文档。生成的块存储在名为 chroma_db_custom 的向量存储中。

3、查询

查询向量库:

# Function to query a vector store
def query_vector_store(store_name, query):persistent_directory = os.path.join(db_dir, store_name)if os.path.exists(persistent_directory):print(f"\n--- Querying the Vector Store {store_name} ---")db = Chroma(persist_directory=persistent_directory, embedding_function=embeddings)retriever = db.as_retriever(search_type="similarity_score_threshold",search_kwargs={"k": 1, "score_threshold": 0.1},)relevant_docs = retriever.invoke(query)# Display the relevant results with metadataprint(f"\n--- Relevant Documents for {store_name} ---")for i, doc in enumerate(relevant_docs, 1):print(f"Document {i}:\n{doc.page_content}\n")if doc.metadata:print(f"Source: {doc.metadata.get('source', 'Unknown')}\n")else:print(f"Vector store {store_name} does not exist.")

此函数使用用户定义的查询来查询特定的向量存储。它会检查向量存储是否存在,根据查询检索相关文档,然后显示结果以及任何元数据。

查询执行:

# Define the user's question
query = "How did Juliet die?"# Query each vector store
query_vector_store("chroma_db_char", query)
query_vector_store("chroma_db_sent", query)
query_vector_store("chroma_db_token", query)
query_vector_store("chroma_db_rec_char", query)
query_vector_store("chroma_db_custom", query)

代码定义了一个查询(“朱丽叶是怎么死的?”),并使用它来查询每个先前创建的向量存储。它为每个存储调用 query_vector_store 函数,检索并显示相关文档。

以下是完整的代码,供您参考。

import osfrom langchain.text_splitter import (CharacterTextSplitter,RecursiveCharacterTextSplitter,SentenceTransformersTokenTextSplitter,TextSplitter,TokenTextSplitter,
)
from langchain_community.document_loaders import TextLoader
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings# Define the directory containing the text file
current_dir = os.path.dirname(os.path.abspath(__file__))
file_path = os.path.join(current_dir, "books", "romeo_and_juliet.txt")
db_dir = os.path.join(current_dir, "db")# Check if the text file exists
if not os.path.exists(file_path):raise FileNotFoundError(f"The file {file_path} does not exist. Please check the path.")# Read the text content from the file
loader = TextLoader(file_path)
documents = loader.load()# Define the embedding model
embeddings = OpenAIEmbeddings(model="text-embedding-3-small"
)  # Update to a valid embedding model if needed# Function to create and persist vector store
def create_vector_store(docs, store_name):persistent_directory = os.path.join(db_dir, store_name)if not os.path.exists(persistent_directory):print(f"\n--- Creating vector store {store_name} ---")db = Chroma.from_documents(docs, embeddings, persist_directory=persistent_directory)print(f"--- Finished creating vector store {store_name} ---")else:print(f"Vector store {store_name} already exists. No need to initialize.")# 1. Character-based Splitting
# Splits text into chunks based on a specified number of characters.
# Useful for consistent chunk sizes regardless of content structure.
print("\n--- Using Character-based Splitting ---")
char_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=100)
char_docs = char_splitter.split_documents(documents)
create_vector_store(char_docs, "chroma_db_char")# 2. Sentence-based Splitting
# Splits text into chunks based on sentences, ensuring chunks end at sentence boundaries.
# Ideal for maintaining semantic coherence within chunks.
print("\n--- Using Sentence-based Splitting ---")
sent_splitter = SentenceTransformersTokenTextSplitter(chunk_size=1000)
sent_docs = sent_splitter.split_documents(documents)
create_vector_store(sent_docs, "chroma_db_sent")# 3. Token-based Splitting
# Splits text into chunks based on tokens (words or subwords), using tokenizers like GPT-2.
# Useful for transformer models with strict token limits.
print("\n--- Using Token-based Splitting ---")
token_splitter = TokenTextSplitter(chunk_overlap=0, chunk_size=512)
token_docs = token_splitter.split_documents(documents)
create_vector_store(token_docs, "chroma_db_token")# 4. Recursive Character-based Splitting
# Attempts to split text at natural boundaries (sentences, paragraphs) within character limit.
# Balances between maintaining coherence and adhering to character limits.
print("\n--- Using Recursive Character-based Splitting ---")
rec_char_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=100)
rec_char_docs = rec_char_splitter.split_documents(documents)
create_vector_store(rec_char_docs, "chroma_db_rec_char")# 5. Custom Splitting
# Allows creating custom splitting logic based on specific requirements.
# Useful for documents with unique structure that standard splitters can't handle.
print("\n--- Using Custom Splitting ---")class CustomTextSplitter(TextSplitter):def split_text(self, text):# Custom logic for splitting textreturn text.split("\n\n")  # Example: split by paragraphscustom_splitter = CustomTextSplitter()
custom_docs = custom_splitter.split_documents(documents)
create_vector_store(custom_docs, "chroma_db_custom")# Function to query a vector store
def query_vector_store(store_name, query):persistent_directory = os.path.join(db_dir, store_name)if os.path.exists(persistent_directory):print(f"\n--- Querying the Vector Store {store_name} ---")db = Chroma(persist_directory=persistent_directory, embedding_function=embeddings)retriever = db.as_retriever(search_type="similarity_score_threshold",search_kwargs={"k": 1, "score_threshold": 0.1},)relevant_docs = retriever.invoke(query)# Display the relevant results with metadataprint(f"\n--- Relevant Documents for {store_name} ---")for i, doc in enumerate(relevant_docs, 1):print(f"Document {i}:\n{doc.page_content}\n")if doc.metadata:print(f"Source: {doc.metadata.get('source', 'Unknown')}\n")else:print(f"Vector store {store_name} does not exist.")# Define the user's question
query = "How did Juliet die?"# Query each vector store
query_vector_store("chroma_db_char", query)
query_vector_store("chroma_db_sent", query)
query_vector_store("chroma_db_token", query)
query_vector_store("chroma_db_rec_char", query)
query_vector_store("chroma_db_custom", query)

一些查询的输出:

此代码提供了一种全面的文档处理、拆分、矢量化和查询方法。它允许尝试不同的文本拆分方法,并演示如何使用 Chroma 矢量存储来存储和查询文本嵌入。


原文链接:RAG文本拆分深入研究 - BimAnt

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

docker简述

1.安装dockers,配置docker软件仓库 安装,可能需要开代理,这里我提前使用了下好的包安装 启动docker systemctl enable --now docker查看是否安装成功 2.简单命令 拉取镜像,也可以提前下载使用以下命令上传 docker load -i imag…

单片机闪存,闪存缓冲取,闪存延迟

一、启用闪存预取缓冲区(FLASH_PrefetchBufferCmd (FLASH_PrefetchBuffer_Enable);) 闪存预取缓冲区的作用: 在微控制器中,闪存是用于存储程序代码和常量数据的非易失性存储器。当微控制器执行程序时,需要从闪存中读取…

62 加密算法

62 加密算法 三种加密算法分类: 对称加密:密钥只有一个,解密、解密都是这个密码,加解密速度快,典型的对称加密有DES、AES、RC4等非对称加密:密钥成对出现,分别为公钥和私钥,从公钥…

单细胞转录组 —— simpleaf 原始数据处理

单细胞转录组 —— 原始数据处理实战(simpleaf) 前言 Alevin-fry 是一个快速、准确且内存节约的单细胞和单核数据处理工具。 Simpleaf 是用 Rust 编写的程序,它提供了一个统一且简化的界面,用于通过 alevin-fry 流程处理一些最…

实现std::sort,replace,fill,accumulate,equal等函数

std::sort /// <summary>/// std::sort 是从小到大排列的/// </summary>/// <typeparam name"IteratorClass"></typeparam>/// <typeparam name"ComparingFunctions"></typeparam>/// <param name"itBegin&qu…

系统端口号被占用问题处理(WindowsLinux系统)

Windows 直接kill占用端口的进程 WinR 输入cmd 打开命令行窗口 1.查询本地已被占用的端口号&#xff1a; 下面以8080端口为例&#xff1a; netstat -aon|findstr "8080" 查看本地8080端口进程的PID 2.杀死"xxxx"端口号的进程 (下面的22868是 你查到…

java.lang.NoClassDefFoundError: kotlin/Result解决方案

问题 在控制窗口上虽然报错是找不到对应的class&#xff0c;但是呢在我们导入kotlin的后&#xff0c;还是报相同的异常&#xff0c;在网上查找了各种资料&#xff0c;都没有解决方案。 问题分析 在idea2021之后&#xff0c;kotlin都使用远程仓库&#xff08;kotlinx-coeouti…

多模态大语言模型(MLLM)-InstructBlip深度解读

前言 InstructBlip可以理解为Blip2的升级版&#xff0c;重点加强了图文对话的能力。 模型结构和Blip2没差别&#xff0c;主要在数据集收集、数据集配比、指令微调等方面下文章。 创新点 数据集收集&#xff1a; 将26个公开数据集转换为指令微调格式&#xff0c;并将它们归类…

鸿蒙开发(NEXT/API 12)【管理应用与Wear Engine服务的连接状态】手机侧应用开发

监测应用与Wear Engine服务的连接状态 华为运动健康App在后台停止服务&#xff08;如功耗过高&#xff09;&#xff0c;从而导致应用与Wear Engine服务的连接状态发生变化。对于类似这种不确定的断开情况&#xff0c;开发者可以通过本功能特性了解当前应用和Wear Engine的连接…

电池大师 2.3.9 | 专业电池管理,延长寿命优化性能

Battery Guru 显示电池使用情况信息&#xff0c;测量电池容量&#xff08;mAh&#xff09;&#xff0c;并通过有用技巧帮助用户改变充电习惯&#xff0c;延长电池寿命。支持显示电池健康状况&#xff0c;优化电池性能。 大小&#xff1a;9.6M 百度网盘&#xff1a;https://pan…

【SQL】换座位

目录 语法 需求 示例 分析 代码 语法 SELECT user_id, user_name, IF(user_age < 18, Minor, IF(user_age < 65, Adult, Senior)) AS age_group FROM users; 使用IF函数来根据user_age的值将用户分为不同的年龄组 在SQL中&#xff0c;IF语法主要用于在查询中根据条…

毕业设计项目-古典舞在线交流平台的设计与实现(源码/论文)

项目简介 基于springboot实现的&#xff0c;主要功能如下&#xff1a; 技术栈 后端框框&#xff1a;springboot/mybatis 前端框架&#xff1a;html/JavaScript/Css/vue/elementui 运行环境&#xff1a;JDK1.8/MySQL5.7/idea&#xff08;可选&#xff09;/Maven3&#xff08…

子弹生产线残次品检测系统源码分享

子弹生产线残次品检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer…

Golang | Leetcode Golang题解之第451题根据字符出现频率排序

题目&#xff1a; 题解&#xff1a; func frequencySort(s string) string {cnt : map[byte]int{}maxFreq : 0for i : range s {cnt[s[i]]maxFreq max(maxFreq, cnt[s[i]])}buckets : make([][]byte, maxFreq1)for ch, c : range cnt {buckets[c] append(buckets[c], ch)}an…

ATAM需求说明-系统架构师(七十六)

1体系结构权衡分析法ATAM(Architecture Trade Off Analyzer Method)是一种常见的结构权衡分析法&#xff0c;该框架主要关注系统的&#xff08;&#xff09;&#xff0c;针对性能、安全性、可用性和可修改性&#xff0c;在系统开发前进行分析、评价和这种。 A 需求说明 B 架构…

搭建企业级私有仓库harbor

华子目录 harbor简介实验环境准备下载软件包安装docker-cehosts解析 实验步骤配置https加密传输解压进入解压目录&#xff0c;修改文件配置启动harbor 测试客户端配置harbor本地加速器注意 通过docker compose管理harbor harbor简介 harbor是由wmware公司开源的企业级docker r…

uniapp自定义导航,全端兼容

我们在用uniapp 开发应用的时候&#xff0c;有的页面需要自定义导航&#xff0c; 1.如果普通的直接使用uni 扩展柜组件的 uni-nav-bar 也基本够用&#xff0c; 2.如果稍微带点自定义的这个值无法支持的&#xff0c;特别在小程序端&#xff0c;胶囊是会压住右边的按钮的 自定…

Debezium日常分享系列之:Debezium 3.0.0.Final发布

Debezium日常分享系列之&#xff1a;Debezium 3.0.0.Final发布 Debezium 核心的变化需要 Java 17基于Kafka 3.8 构建废弃的增量信号字段的删除每个表的详细指标 MariaDB连接器的更改版本 11.4.3 支持 MongoDB连接器的更改MongoDB sink connector MySQL连接器的改变MySQL 9MySQL…

九大排序之交换排序

1.前言 所谓交换&#xff0c;就是根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置&#xff0c;交换排序的特点是&#xff1a;将键值较大的记录向序列的尾部移动&#xff0c;键值较小的记录向序列的前部移动。 重点&#xff1a; 冒泡排序和快速排序 2.冒泡排…

【电子通识】TINA-TI 安装

TINA-TI是一个SPICE的模拟仿真程序&#xff0c;提供了 SPICE 所有的传统直流、瞬态和频域分析以及更多功能。 TINA 具有允许您按照希望的方式设置结果的格式。虚拟仪器允许选择输入波形、探针电路节点电压和波形。 下载链接&#xff1a;TINA-TI 模拟工具 | 德州仪器 TI.com.cn …