在上一篇文章《大模型RAG:基于PgSql的向量检索》中,简单介绍了RAG概念和简要实现。在实际的应用中,技术方案远不会这样简单。
我们知道,大模型在预训练阶段获取的知识是有限的,一般需要数据增强模块引入外部知识库,通过知识检索的方式搜索于用户提问相关的知识,这也是RAG相关应用架构出现的原因。但这又引申出另一个问题,外部知识文档往往比较长,可能是包含几十页甚至数百页的内容,如果直接使用会存在以下问题
所以我们需要根据一定策略将文本切分为小块,以便适应大模型的上下文窗口,同时提高知识检索的精度。
文本分块不是盲目的切分,而是必须在不影响或尽量降低对整体效果影响的前提下进行。所以文本分块(chunk)最核心的目的就是把相同语义的token聚集在一起,不同语义的token互相分开,利于后续的retrieve和rerank。举个例子:我们有一个word文档,分为多个段落,每个段落都是一个问题的问答对。那么显然把一个问答对作为一个chunk划分是最理想的结果。
常见chunk方案有按照字符chunk、按token、按段落、递归划分、语义划分、代理划分等。Langchain作为一个 LLM 协调框架,内置了一些用于分块以及加载文档的工具,提供了很多可以开箱即用的chunk方法:
CharacterTextSplitter
RecursiveCharacterTextSplitter
Split by tokens
Semantic Chunking
HTMLHeaderTextSplitter
MarkdownHeaderTextSplitter
RecursiveJsonSplitter
Split Cod
由于相关的代码解说文章已经很多,这里不再赘述,只以RecursiveCharacterTextSplitter、SentenceSplitter和HTMLHeaderTextSplitter为例:
基于字符数来递归地分割文本。每个块都保持在指定的长度以下,这对于具有自然段落或句子间断的文档特别有用,确保了块的可管理性和易于处理性,而不会丢失文档的固有结构。
Langchain中的递归字符文本分割器方法根据字符数将文本分割成块,以确保每个块低于指定的长度。这种方法有助于保持文档中段落或句子的自然断开。
from langchain_text_splitters import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(
# 这里做初始化,块大小1k以及50个跨文本字符
separators=["\n\n", "\n", " ", ""],
chunk_size=1000,
chunk_overlap=50,
length_function=len,
is_separator_regex=False,
)
chunks = text_splitter.split_text(pages[0].page_content)
print(len(chunks))
# 打印输出
for chunk in chunks:
print(chunk)
SentenceSplitter是在句子边界上分割文本,这种方法能够保持文本的上下文完整性。句子通常代表完整的思想,这使得这种方法非常适合那些对内容有连贯理解的场景。
from langchain.text_splitter import SentenceSplitter
text = "long document text ..."
# 初始化SentenceSplitter ,每个块最多5个句子
splitter = SentenceSplitter(max_length=5)
chunks = splitter.split_text(text)
for chunk in chunks:
print(chunk)
HTMLHeaderTextSplitter是一个网页代码分块器,它根据 HTML 元素拆分文本,并将相关元数据分配给分块内的每个标头。它可以返回单个分块或将具有相同元数据的元素组合在一起,以保持语义分组并保留文档的结构上下文。此拆分器可与分块管道中的其他文本拆分器结合使用。
from langchain_text_splitters import HTMLHeaderTextSplitter
# 这里定义一段HTML网页内容代码
html_string = """
<!DOCTYPE html>
<html>
<body>
<div>
<h1>Foo</h1>
<p>Some intro text about Foo.</p>
<div>
<h2>Bar main section</h2>
<p>Some intro text about Bar.</p>
<h3>Bar subsection 1</h3>
<p>Some text about the first subtopic of Bar.</p>
<h3>Bar subsection 2</h3>
<p>Some text about the second subtopic of Bar.</p>
</div>
<div>
<h2>Baz</h2>
<p>Some text about Baz</p>
</div>
<br>
<p>Some concluding text about Foo</p>
</div>
</body>
</html>
"""
headers_to_split_on = [
("h1", "Header 1"),
("h2", "Header 2"),
("h3", "Header 3"),
]
html_splitter = HTMLHeaderTextSplitter(headers_to_split_on=headers_to_split_on)
html_header_splits = html_splitter.split_text(html_string)
html_header_splits
"""
[Document(page_content='Foo'),
Document(page_content='Some intro text about Foo. \nBar main section Bar subsection 1 Bar subsection 2', metadata={'Header 1': 'Foo'}),
Document(page_content='Some intro text about Bar.', metadata={'Header 1': 'Foo', 'Header 2': 'Bar main section'}),
Document(page_content='Some text about the first subtopic of Bar.', metadata={'Header 1': 'Foo', 'Header 2': 'Bar main section', 'Header 3': 'Bar subsection 1'}),
Document(page_content='Some text about the second subtopic of Bar.', metadata={'Header 1': 'Foo', 'Header 2': 'Bar main section', 'Header 3': 'Bar subsection 2'}),
Document(page_content='Baz', metadata={'Header 1': 'Foo'}),
Document(page_content='Some text about Baz', metadata={'Header 1': 'Foo', 'Header 2': 'Baz'}),
Document(page_content='Some concluding text about Foo', metadata={'Header 1': 'Foo'})]
"""
尽管LangChain和llamaIndex都已经提供了文本Chunk方法,但不幸的是这两者提取语义embedding用的都是openAI的接口,要收费不说,大陆地区还面临被封API的风险,更关键的是在很多企业内根本不允许使用。所以我们只能参考LangChain中各方法的实现原理,自行开发和调试文本chunk方法。
从文档角度出发,RAG流程中的各个主要环节如下:
关键概念说明:
RAPTOR:RAPTOR模型提出了一种创新的策略。它通过递归地进行文本片段的向量化、聚类和摘要生成,构建了一个树状索引结构。这种结构不仅捕捉了文档的高层次主题,还保留了低层次的细节,允许基于语义相似性而非仅仅是文本顺序对节点进行分组。这样的树状结构使得RAPTOR能够在不同的抽象层次上加载文档的上下文片段,从而有效地回答不同层次的问题。
GraphRAG:2024年4月微软推出GraphRAG,并于7月2日开源。GraphRAG仍然沿袭了RAG的思路,即通过检索来增强模型的准确性。不过,与RAG不同的是,GraphRAG还引入了“知识图谱”(Knowledge Graph)技术,以增强模型的“检索”能力,以实现对复杂信息的高效和可靠检索,从而提高LLM问答系统对于复杂信息的答案生成的准确性。GraphRAG示意图如下:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。