一、RAG文本分割
????????RAG(Retrieval-Augmented Generation,檢索增強生成)模型是一種結合了檢索 和生成能力的自然語言處理模型。 它通過檢索相關的文檔片段,并將這些信息作為生成過程的上下文,以提高生成質量 和準確性。
????????在RAG模型中,文本分割是一個非常關鍵的步驟。合理地分割文檔文本, 不僅能夠提高檢索的效率,還能更有效地將檢索到的信息提供給生成模型,使生成內 容更加連貫和準確。
文本分割優點:?
????????提升檢索效率: 文本分割的首要原因是為了提高檢索的效率。對于較長的文檔,直接檢索整篇文 檔可能會導致信息冗余或者重要信息丟失。因此,合理的文本分割將長文檔分成 多個段落或片段,這樣每個片段可以單獨進行檢索,從而提高檢索的精度和速 度。
????????更好的信息匹配: 當文檔被合理地分割后,檢索算法可以更加精確地匹配用戶查詢和文檔片段。這 樣不僅能夠減少噪聲,還可以確保檢索到的內容更加相關,生成模型在使用這些 片段進行回答時能夠生成更加相關和有意義的內容。
????????增強生成質量: 檢索增強生成模型依賴檢索到的內容作為生成輸入的一部分。如果檢索到的文檔 片段不準確或上下文不完整,生成的結果可能會偏離用戶的期望。文本分割可以 確保每個文檔片段足夠獨立,且能夠提供完整的上下文信息,從而提高生成的準 確性和上下文連貫性。
????????降低計算復雜度: 長文本的直接處理會大大增加模型的計算量和時間開銷,甚至有些大模型并不支 持超長文本的輸入。通過將文本分割成多個較小的片段,可以只針對特定的片段 進行處理,從而減少計算量,提高響應速度。這不僅優化了模型的性能,還減少 了生成結果時的延遲。?
二、文本分割方法?
2.1、字符分割
????????字符分割是最基礎的文本分割方式,按照指定的分隔符進行分割。chunk_size 指的 是每個分割片段(chunk)的長度。chunk_overlap 指的是每個分割片段之間的重疊 部分。
注意: split_text 和 split_documents 不同:
????????split_text:處理單純的字符串。
????????split_documents:處理包含元數據的文檔對象。?
# 導入LangChain的字符文本分割器
from langchain.text_splitter import CharacterTextSplitter# 定義要分割的中文文本
text = "在西天取經的幾百年前黑風山上有一只黑熊精占山為王,自稱黑風大王。"# 創建字符文本分割器實例
# 參數說明:
# chunk_size=15: 每個文本塊的最大字符數
# chunk_overlap=2: 相鄰文本塊之間的重疊字符數
# separator="": 分割符設為空字符串(按字符分割)
splitter = CharacterTextSplitter(chunk_size=15,chunk_overlap=2,separator=""
)# 執行文本分割
chunks = splitter.split_text(text)# 打印分割結果
print(chunks)
['在西天取經的幾百年前黑風山上有', '上有一只黑熊精占山為王,自稱黑', '稱黑風大王。']
2.2、遞歸字符文本分割
????????遞歸字符文本分割是字符分割的升級版,它以字符分割為基礎,但在分割時引入了遞 歸的機制。 在初步分割之后,再對一些不完整或冗長的片段進行進一步細分,從而獲得更加細粒 度的分割。
????????這個方法比簡單的字符分割更加靈活,可以通過遞歸深度來控制分割的粒度。 RecursiveCharacterTextSplitter不設置separators時,默認的separators參數為 ["\n\n", "\n", " ", ""]:將按不同的字符遞歸地分割(按照這個優先級["\n\n", "\n", " ", ""]),文本分割器首先在"\n\n"處嘗試分割,如果分出的塊過大(大于 chunk_size),則找到"\n"處嘗試分割以此類推,若都不滿足則按照字符劃分。
# 導入LangChain的遞歸字符文本分割器
from langchain.text_splitter import RecursiveCharacterTextSplitter# 定義要分割的中文文本
text = "在西天取經的幾百年前黑風山上有一只黑熊精占山為王,這里只是為了占位沒什么用,自稱黑風大王。"# 創建遞歸字符文本分割器實例
# 參數說明:
# chunk_size=15: 每個文本塊的最大字符數
# chunk_overlap=3: 相鄰文本塊之間的重疊字符數
# separators=[...]: 分割符優先級列表(按順序嘗試分割)
splitter = RecursiveCharacterTextSplitter(chunk_size=15, # 每個分塊最大15個字符chunk_overlap=3, # 分塊間重疊3個字符separators=["\n\n", # 雙換行(最高優先級)"\n", # 單換行" ", # 空格".", # 英文句號",", # 英文逗號",", # 中文逗號"。", # 中文句號"" # 最后按字符分割(最低優先級)]
)# 執行文本分割
chunks = splitter.split_text(text)# 打印分割結果
print(chunks)
['在西天取經的幾百年前黑風山上有', '山上有一只黑熊精占山為王', ',這里只是為了占位沒什么用', ',自稱黑風大王。']
遞歸分割機制:
????????會按照
separators
列表中的順序,優先嘗試用高級別的分隔符????????如果高級別分隔符無法滿足
chunk_size
要求,會降級使用更低級別的分隔符
參數特點:
????????
chunk_overlap=3
確保分塊之間有3個字符的重疊,保持上下文連貫????????中文標點","和"。"被明確列為分隔符,確保在標點處自然分割
分割策略:
????????優先在段落(\n\n)、句子(。)級別分割
????????其次在短語(,)和詞語(空格)級別分割
????????最后才會按單個字符分割
中文適配:
????????專門添加了中文標點作為分隔符
????????確保中文文本能在語義合理的邊界處分割
2.3、特定文檔分割(以markdown為例):
????????特定文檔分割是基于文檔結構對文本進行分割的一種方式。不同的文檔類型通常有各 自的結構化信息,例如書籍中的章節和段落、網頁中的HTML標簽等。 利用這些預定義的結構化信息,可以更加自然地分割文本,保證片段的上下文連貫 性。
# 導入Markdown標題文本分割器
from langchain.text_splitter import MarkdownHeaderTextSplitter# 定義包含Markdown標題的文本內容
text = """
# 第一章
在西天取經的幾百年前,黑風山上。\n\n在西天取經的幾百年前,黑風山上。在西天取經的幾百年前,黑風山上。在西天取經的幾百年前,黑風山上。在西天取經的幾百年前,黑風山上。在西天取經的幾百年前,黑風山上。在西天取經的幾百年前,黑風山上。在西天取經的幾百年前,黑風山上。
# 第二章
測試。
"""# 定義需要分割的標題級別和對應的元數據名稱
# 格式: [(標題標記, 元數據字段名), ...]
headers_to_split_on = [("#", "Header 1"), # 一級標題,保存到Header 1元數據字段("##", "Header 2"), # 二級標題,保存到Header 2元數據字段
]# 創建Markdown標題分割器實例
splitter = MarkdownHeaderTextSplitter(headers_to_split_on=headers_to_split_on # 傳入標題配置
)# 執行文本分割
chunks = splitter.split_text(text)# 打印分割結果
print(chunks)
# 預期輸出結構:
# [
# {
# 'content': '在西天取經的幾百年前...', # 正文內容
# 'metadata': {'Header 1': '第一章'} # 標題元數據
# },
# {
# 'content': '測試。',
# 'metadata': {'Header 1': '第二章'}
# }
# ]
[Document(metadata={'Header 1': '第一章'}, page_content='在西天取經的幾百年前,黑風山上。 \n在西天取經的幾百年前,黑風山上。在西天取經的幾百年前,黑風山上。在西天取經的幾百年前,黑風山上。在西天取經的幾百年前,黑風山上。在西天取經的幾百年前,黑風山上。在西天取經的幾百年前,黑風山上。在西天取經的幾百年前,黑風山上。'), Document(metadata={'Header 1': '第二章'}, page_content='測試。')]
2.4、實例
# 導入必要的庫
from langchain_community.document_loaders import TextLoader # 文本加載器
from langchain.text_splitter import RecursiveCharacterTextSplitter # 遞歸字符分割器# 1. 加載TXT文檔
# 創建TextLoader實例,指定文件路徑和編碼格式
text_loader = TextLoader("黑悟空.txt", encoding="UTF-8")
# 加載文檔內容,返回Document對象列表
documents = text_loader.load()# 2. 定義遞歸字符分割器
text_splitter = RecursiveCharacterTextSplitter(chunk_size=200, # 每個分塊的最大字符數chunk_overlap=20, # 相鄰分塊間的重疊字符數separators=["\n\n", "\n", " ", ".", ",", ",", "。", ""] # 分割符優先級列表# 分割符優先級說明:# 1. 首先嘗試用雙換行符(\n\n)分割# 2. 然后嘗試單換行符(\n)# 3. 接著是空格、英文標點# 4. 最后是中文標點# 5. 如果以上都不適用,則按單個字符分割
)# 3. 執行文檔分割
# 對加載的文檔進行分割,返回分割后的Document對象列表
splits_docs = text_splitter.split_documents(documents)# 4. 打印分割結果
# 遍歷所有分塊,打印序號和內容
for i, chunk in enumerate(splits_docs):print(f"分塊 {i+1}: \n{chunk}\n") # 打印分塊編號和內容# 每個chunk是一個Document對象,包含page_content和metadata屬性# 補充說明:
# 1. 適合處理包含中文標點的文本
# 2. 會盡量在段落、句子邊界處進行分割
# 3. 重疊部分(chunk_overlap)確保上下文連貫性
# 4. 輸出結果保留了原始文檔的結構信息