随着 GPT-3、GPT-4 和检索增强生成(RAG)系统等大型语言模型(LLM)的使用日益增多,有效处理文章、文档或代码等长篇内容成为一大挑战。LLM 通常有标记限制(如 GPT-3 中的 4096 个标记),从而限制了一次可处理的文本数量。为了解决这个问题,我们需要使用一种叫做分块的技术,将这些大型输入分解成较小的、可管理的片段。
本文将全面介绍分块技术在 LLM 和 RAG 中的应用,内容包括:
1. 什么是LLM和RAG背景下的分块?
LLM 中的分块是指将大型文档或文本分割成较小的片段,称为块。这一点很有必要,因为 LLM 有标记限制,这限制了它们一次能处理多少文本。例如,GPT-3 的标记限制为 4096,包括输入和输出标记。
在结合了检索模型(获取相关文本)和生成模型(生成响应)的 RAG 系统中,分块被用来确保大文档被分成可以被有效检索和处理的较小块。
2. 分块为何至关重要?
分块技术之所以重要,有以下几个原因:
3. LangChain 中的分块方法
LangChain 提供多种文本分块工具,适用于从简单文本到复杂代码等各种类型的内容。以下是你可以在 LangChain 中使用的分块方法:
3.1. 字符文本分割器
字符文本分块器(CharacterTextSplitter)是最简单的分块器,它根据固定的字符数对文本进行分块。这种方法非常适合结构化内容,在这种情况下,保留特定的语义可能并不重要。
代码示例
from langchain.text_splitter import CharacterTextSplitter
# Define the splitter
text_splitter = CharacterTextSplitter(
chunk_size=1000, # Each chunk will be 1000 characters
chunk_overlap=100 # There will be an overlap of 100 characters between chunks
)
# Sample text to split
text = "This is a very long document that needs to be split into smaller chunks."
# Perform the split
chunks = text_splitter.split_text(text)
# Print the chunks
for i, chunk in enumerate(chunks):
print(f"Chunk {i+1}:\n{chunk}\n")
用例:最适用于要根据字符数进行分割的结构化文档,如文章或不太强调保留段落或句子的纯文本。
3.2. RecursiveCharacterTextSplitter (语义分块法)
RecursiveCharacterTextSplitter 更为先进,它能根据句子和段落等语义单位分割内容。它非常适合文章、报告和博客等对语义的保留至关重要的文档。
代码示例
from langchain.text_splitter import RecursiveCharacterTextSplitter
# Define the splitter
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=1000, # Each chunk will be 1000 characters
chunk_overlap=100 # Overlap of 100 characters between chunks
)
# Sample text
text = "This is a long document divided into paragraphs and sentences."
# Perform the split
chunks = text_splitter.split_text(text)
# Print the chunks
for i, chunk in enumerate(chunks):
print(f"Chunk {i+1}:\n{chunk}\n")
用例:适用于需要保持句子和段落结构的文章、博客和其他自然语言内容。
3.3. PythonCodeTextSplitter(代码分块)
为了处理代码,LangChain 提供了一个名为 PythonCodeTextSplitter 的专用分割器。该分割器可确保函数或类不会被分割成块,从而保持代码的逻辑流。
代码示例
from langchain.text_splitter import PythonCodeTextSplitter
# Define the Python code splitter
splitter = PythonCodeTextSplitter(
chunk_size=500, # Each chunk will be 500 characters
chunk_overlap=50 # Overlap of 50 characters between chunks
)
# Sample Python code to split
code = """
def function_1():
print("Hello from function 1")
def function_2():
print("Hello from function 2")
"""
# Perform the split
chunks = splitter.split_text(code)
# Print the chunks
for i, chunk in enumerate(chunks):
print(f"Chunk {i+1}:\n{chunk}\n")
用例:适用于处理对保持函数和类的逻辑流至关重要的代码。
3.4. 用于 JavaScript 和其他语言的 RecursiveCharacterTextSplitter
LangChain 还允许对 JavaScript、HTML 和 Markdown 等其他编程语言进行分块。这是通过使用 RecursiveCharacterTextSplitter.from_language() 方法来实现的,在该方法中,你可以指定语言语法。
JavaScript 代码示例:
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.text_splitter import Language
# Define the JavaScript splitter
splitter = RecursiveCharacterTextSplitter.from_language(
language=Language.JS, # Choose JavaScript language
chunk_size=60, # Each chunk will be 60 characters
chunk_overlap=10 # Overlap of 10 characters
)
# Sample JavaScript code
js_code = """
function greet() {
console.log("Hello, World!");
}
greet();
"""
chunks = splitter.split_text(js_code)
# Print the chunks
for i, chunk in enumerate(chunks):
print(f"Chunk {i+1}:\n{chunk}\n")
用例:该方法在处理 JavaScript 或 HTML 等非 Python 代码时非常有用。
3.5. Mardown 文本分割器
Markdown 内容通常遵循层次结构(标题、段落、列表等),因此有必要根据这些语义单位进行分块。
代码示例
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.text_splitter import Language
# Define the Markdown splitter
splitter = RecursiveCharacterTextSplitter.from_language(
language=Language.MARKDOWN,
chunk_size=500,
chunk_overlap=100
)
# Sample Markdown document
markdown_text = """
# Heading 1
This is a paragraph under heading 1.
## Subheading
This is some more text under the subheading.
"""
# Perform the split
chunks = splitter.split_text(markdown_text)
for i, chunk in enumerate(chunks):
print(f"Chunk {i+1}:\n{chunk}\n")
4. 有效分块的最佳做法
以下是为 LLM 和 RAG 系统分块文本时需要考虑的一些最佳实践:
结论
分块是 LLM 和 RAG 系统中的一项关键技术,它能让模型高效处理长文本,同时保留上下文和含义。无论你处理的是自然语言内容还是复杂代码,LangChain 都能提供多种分割器,以满足不同的使用情况