大模型(LLMs)RAG 版面分析——文本分塊面
-
一、為什么需要對文本分塊?
-
二、能不能介紹一下常見的文本分塊方法?
-
2.1 一般的文本分塊方法
-
2.2 正則拆分的文本分塊方法
-
2.3 Spacy Text Splitter 方法
-
2.4 基于 langchain 的 CharacterTextSplitter 方法
-
2.5 基于 langchain 的 遞歸字符切分 方法
-
2.6 HTML 文本拆分 方法
-
2.7 Mrrkdown 文本拆分 方法
-
2.8 Python代碼拆分 方法
-
2.9 LaTex 文本拆分 方法
-
致謝 一、為什么需要對文本分塊? 使用大型語言模型(LLM)時,切勿忽略文本分塊的重要性,其對處理結果的好壞有重大影響。 考慮以下場景:你面臨一個幾百頁的文檔,其中充滿了文字,你希望對其進行摘錄和問答式處 理。在這個流程中,最初的一步是提取文檔的嵌入向量,但這樣做會帶來幾個問題:
-
信息丟失的風險:試圖一次性提取整個文檔的嵌入向量,雖然可以捕捉到整體的上下文,但也 可能會忽略掉許多針對特定主題的重要信息,這可能會導致生成的信息不夠精確或者有所缺失。
-
分塊大小的限制:在使用如OpenAI這樣的模型時,分塊大小是一個關鍵的限制因素。例如, GPT-4模型有一個32K的窗口大小限制。盡管這個限制在大多數情況下不是問題,但從一開始 就考慮到分塊大小是很重要的。
因此,恰當地實施文本分塊不僅能夠提升文本的整體品質和可讀性,還能夠預防由于信息丟失或不 當分塊引起的問題。這就是為何在處理長篇文檔時,采用文本分塊而非直接處理整個文檔至關重要 的原因。
二、能不能介紹一下常見的文本分塊方法?
-
一般的文本分塊方法 如果不借助任何包,直接按限制長度切分方案:
-
正則拆分的文本分塊方法
-
動機:【一般的文本分塊方法】能夠按長度進行分割,但是對于一些長度偏長的句子,容易從 中間切開;
-
方法:在中文文本分塊的場景中,正則表達式可以用來識別中文標點符號,從而將文本拆分成 單獨的句子。這種方法依賴于中文句號、“問號”、“感嘆號”等標點符號作為句子結束的標志。
-
特點:雖然這種基于模式匹配的方法可能不如基于復雜語法和語義分析的方法精確,但它在大 多數情況下足以滿足基本的句子分割需求,并且實現起來更為簡單直接。 import re def split_sentences(text): # 使用正則表達式匹配中文句子結束的標點符號 sentence_delimiters = re.compile(u'[。?!;]|\n') sentences = sentence_delimiters.split(text) # 過濾掉空字符串 sentences = [s.strip() for s in sentences if s.strip()] return sentences text ="文本分塊是自然語言處理(NLP)中的一項關鍵技術,其作用是將較長的文本切割成更小、更易于處理的片段。這種分割通常是基于單詞的詞性和語法結構,例如將文本拆分為名詞 短語、動詞短語或其他語義單位。這樣做有助于更高效地從文本中提取關鍵信息。" sentences = split_sentences(text) print(sentences) >>> #output [ '文本分塊是自然語言處理(NLP)中的一項關鍵技術,其作用是將較長的文本切割成更 小、更易于處理的片段', '這種分割通常是基于單詞的詞性和語法結構,例如將文本拆分為名詞短語、動詞短語或其 他語義單位', '這樣做有助于更高效地從文本中提取關鍵信息' ] 在上面例子中,我們并沒有采用任何特定的方式來分割句子。另外,還有許多其他的文本分塊技術 可以使用,例如詞匯化(tokenizing)、詞性標注(POS tagging)等。
-
Spacy Text Splitter 方法
-
import spacy input_text = "文本分塊是自然語言處理(NLP)中的一項關鍵技術,其作用是將較長的文本切割成更小、更易于處理的片段。這種分割通常是基于單詞的詞性和語法結構,例如將文本拆分為名詞短語、動詞短語或其他語義單位。這樣做有助于更高效地從文本中提取關鍵信息。" nlp = spacy.load( "zh_core_web_sm" ) doc = nlp(input_text) for s in doc.sents: print (s) >>> [ '文本分塊是自然語言處理(NLP)中的一項關鍵技術,其作用是將較長的文本切割成更 小、更易于處理的片段。', "這種分割通常是基于單詞的詞性和語法結構,例如將文本拆分為名詞短語、動詞短語或其 他語義單位。", "這樣做有助于更高效地從文本中提取關鍵信息。" ] 介紹:Spacy是一個用于執行自然語言處理(NLP)各種任務的庫。它具有文本拆分器功能, 能夠在進行文本分割的同時,保留分割結果的上下文信息。
-
基于 langchain 的 CharacterTextSplitter 方法 from langchain.text_splitter import CharacterTextSplitter text_splitter = CharacterTextSplitter(chunk_size = 35, chunk_overlap=0, separator='', strip_whitespace=False) text_splitter.create_documents([text]) >>> [ Document(page_content='我是一個名為 ChatGLM3-6B 的人工智能助手,是基于清華大學'), Document(page_content='KEG 實驗室和智譜 AI 公司于 2023 年共同訓練的語言模型開發'), Document(page_content='的。我的目標是通過回答用戶提出的問題來幫助他們解決問題。 由于我是一個計'), Document(page_content='算機程序,所以我沒有實際的存在,只能通過互聯網來與用戶交 流。') ] 使用CharacterTextSplitter,一般的設置參數為:chunk_size、 chunk_overlap、separator和strip_whitespace。
-
基于 langchain 的 遞歸字符切分 方法 #input text input_text = "文本分塊是自然語言處理(NLP)中的一項關鍵技術,其作用是將較長的文本切割成更小、更易于處理的片段。這種分割通常是基于單詞的詞性和語法結構,例如將文本拆分為名詞短語、動詞短語或其他語義單位。這樣做有助于更高效地從文本中提取關鍵信息。" from langchain.text_splitter import RecursiveCharacterTextSplitter text_splitter = RecursiveCharacterTextSplitter( chunk_size = 100 , #設置所需的文本大小 chunk_overlap = 20 ) chunks = text_splitter.create_documents([input_text]) print (chunks) >>> [ Document(page_content='文本分塊是自然語言處理(NLP)中的一項關鍵技術,其作用是 將較長的文本切割成更小、更易于處理的片段。這種分割通常是基于單詞的詞性和語法結構, 例如將文本拆分為名詞短語、動詞短語或其他語義單位。這樣做有助'), Document(page_content='短語、動詞短語或其他語義單位。這樣做有助于更高效地從文本 中提取關鍵信息。')] 使用RecursiveCharacterTextSplitter,一般的設置參數為:chunk_size、 chunk_overlap。 與CharacterTextSplitter不同,RecursiveCharacterTextSplitter不需要設置分隔符,默認的幾個分隔 符如下: "\n\n" - 兩個換行符,一般認為是段落分隔符"\n" - 換行符 " " - 空格 "" - 字符 拆分器首先查找兩個換行符(段落分隔符)。一旦段落被分割,它就會查看塊的大小,如果塊太 大,那么它會被下一個分隔符分割。如果塊仍然太大,那么它將移動到下一個塊上,以此類推。
-
HTML 文本拆分 方法
-
介紹:HTML文本拆分器是一種結構感知的文本分塊工具。它能夠在HTML元素級別上進行文本 拆分,并且會為每個分塊添加與之相關的標題元數據。
-
特點:對HTML結構的敏感性,能夠精準地處理和分析HTML文檔中的內容。 <div> <h2>Mobot主要部分</h2> <p>有關Mobot的一些介紹文本。</p> <h3>Mobot第1小節</h3> <p>有關Mobot第一個子主題的一些文本。</p> <h3>Mobot第2小節</h3> <p>關于Mobot的第二個子主題的一些文字。</p> </div> <div> <h2>Mobot</h2> <p>關于Mobot的一些文字</p> </ div> <br> <p>關于Mobot的一些結論性文字</p> </div> </body> </html> """ headers_to_split_on = [ ( "h1" , "Header 1" ), ( "h2" , "標題 2" ), ( "h3" , "標題 3" ), ] from langchain.text_splitter import HTMLHeaderTextSplitter html_splitter = HTMLHeaderTextSplitter(headers_to_split_on=headers_to_split_on) html_header_splits = html_splitter.split_text(html_string) print(html_header_split) >>> [ Document(page_content='Mobot'), Document(page_content='一些關于Mobot的介紹文字。\nMobot主要部分 Mobot第1小節Mobot第2小節', metadata={'Header 1': 'Mobot'}), Document(page_content='有關Mobot的一些介紹文本。', metadata={'Header 1': 'Mobot', '標題 2': 'Mobot主要部分'}), Document(page_content='有關Mobot第一個子主題的一些文本。', metadata={'Header 1': 'Mobot', '標題 2': 'Mobot主要部分', '標題 3': 'Mobot第1小節'}), Document(page_content='關于Mobot的第二個子主題的一些文字。', metadata={'Header 1': 'Mobot', '標題 2': 'Mobot主要部分', '標題 3': 'Mobot第2小節'}), Document(page_content='Mobot div>', metadata={'Header 1': 'Mobot'}), Document(page_content='關于Mobot的一些文字 \n關于Mobot的一些結論性文字', metadata={'Header 1': 'Mobot', '標題 2': 'Mobot'}) ] 僅提取在header_to_split_on參數中指定的HTML標題。
-
Mrrkdown 文本拆分 方法
-
介紹:Markdown文本拆分是一種根據Markdown的語法規則(例如標題、Bash代碼塊、圖片和 列表)進行文本分塊的方法。
-
markdown_text = '# Mobot\n\n ## Stone\n\n這是python \n這是\n\n ## markdown\n\n 這是中文文本拆分' from langchain.text_splitter import MarkdownHeaderTextSplitter headers_to_split_on = [ ("#", "Header 1"), ("##", "Header 2"), ("###", "Header 3"), ] markdown_splitter = MarkdownHeaderTextSplitter(headers_to_split_on=headers_to_split_on) md_header_splits = markdown_splitter.split_text(markdown_text) print(md_header_splits) >>> [ Document(page_content='這是python\n這是', metadata={'Header 1': 'Mobot', 'Header 2': 'Stone'}), Document(page_content='這是中文文本拆分', metadata={'Header 1': 'Mobot', 'Header 2': 'markdown'}) ] 特點:具有對結構的敏感性,能夠基于Markdown文檔的結構特點進行有效的文本分割。 MarkdownHeaderTextSplitter 能夠根據設定的 headers_to_split_on 參數,將 Markdown 文本進行拆分。這一功能使得用戶可以便捷地根據指定的標題將 Markdown 文件分割成不同部分,從而提高編輯和管理的效率。
-
Python代碼拆分 方法 python_text = """ class Person: def init (self, name, age): self.name = name self.age = age p1 = Person("John", 36) for i in range(10): print (i) """ from langchain.text_splitter import PythonCodeTextSplitter python_splitter = PythonCodeTextSplitter(chunk_size=100, chunk_overlap=0) python_splitter.create_documents([python_text]) >>> [ Document(page_content='class Person:\n def init (self, name, age):\n self.name = name\n self.age = age'), Document(page_content='p1 = Person("John", 36)\n\nfor i in range(10):\n print (i)') ]
-
LaTex 文本拆分 方法
LaTex文本拆分工具是一種專用于代碼分塊的工具。它通過解析LaTex命令來創建各個塊,這些塊按照邏輯組織,如章節和小節等。這種方式能夠產生更加準確且與上下文相關的分塊結果,從而有 效地提升LaTex文檔的組織和處理效率。
#input Latex string
latex_text = """documentclass{article}begin{document}maketitlesection{Introduction} 大型語言模型 (LLM) 是一種機器學習模型,可以在大量文本數據上進行訓練,以生成類似人類的語言。近年來,法學碩士在各種自然語言處理任務中取得了重大進展,包括語言翻譯、文本生成和情感分析。subsection{法學碩士的歷史}最早的法學碩士是在 20 世紀 80 年代開發的和 20 世紀 90 年代,但它們受到可處理的數據量和當時可用的計算能力的限制。然而,在過去的十年中,硬件和軟件的進步使得在海量數據集上訓練法學碩士成為可能,從而導致subsection{LLM 的應用}LLM 在工業界有許多應用,包括聊天機器人、內容創建和虛擬助理。它們還可以在學術界用于語言學、心理學和計算語言學的研究。end{document}"""
from langchain.text_splitter import LatexTextSplitter
Latex_splitter = LatexTextSplitter(chunk_size= 100 , chunk_overlap= 0 )
latex_splits = Latex_splitter.create_documents([latex_text]) print (latex_splits)
>>> [
Document(page_content='documentclass{article}begin{document}maketitlesection{Introd uction}大型語言模型 (LLM)'),
Document(page_content='是一種機器學習模型,可以在大量文本數據上進行訓練,以生成 類似人類的語言。近年來,法學碩士在各種自然語言處理任務中取得了重大進展,包括語言翻譯、文本生成和情感分析。subsection{法學碩士的歷史'),
Document(page_content='}最早的法學碩士是在'),
Document(page_content='20 世紀 80 年代開發的和 20 世紀 90'),
Document(page_content='年代,但它們受到可處理的數據量和當時可用的計算能力的限制。然而,在過去的十年中,硬件和軟件的進步使得在海量數據集上訓練法學碩士成為可能, 從而導致subsection{LLM 的應用}LLM'),
Document(page_content='在工業界有許多應用,包括聊天機器人、內容創建和虛擬助理。 它們還可以在學術界用于語言學、心理學和計算語言學的研究。end{document}')
]
在上述示例中,我們注意到代碼分割時的重疊部分設置為0。這是因為在處理代碼分割過程中,任何重疊的代碼都可能完全改變其原有含義。因此,為了保持代碼的原始意圖和準確性,避免產生誤 解或錯誤,設置重疊部分為0是必要的。
當你決定使用哪種分塊器處理數據時,重要的一步是提取數據嵌入并將其存儲在向量數據庫
(Vector DB)中。上面的例子中使用文本分塊器結合 LanceDB 來存儲數據塊及其對應的嵌入。LanceDB 是一個無需配置、開源且無服務器的向量數據庫,其數據持久化在硬盤驅動器上,允許用戶在不超出預算的情況下實現擴展。此外,LanceDB 與 Python 數據生態系統兼容,因此你可以將其與現有的數據工具(如 pandas、pyarrow 等)結合使用。