微信扫码
添加专属顾问
我要投稿
探索如何通过最佳分块策略优化大语言模型应用,提高语义搜索和Chatbot的效率和准确性。 核心内容: 1. 分块在大语言模型中的作用与重要性 2. 分块策略对语义搜索和Chatbot的影响 3. 选择合适的分块大小和方法的权衡因素
今天和大家讲一下Chunking(分块) 在构建LLM(大语言模型)相关应用中的重要性。
如果你经常接触LLM相关的项目,这里提到的“分块”就显得尤为重要了。简单来说,分块就是把一大段文本拆分成更小的部分。这个过程对于优化从向量数据库中检索到的内容的相关性非常关键,尤其是在我们用LLM对内容进行嵌入时。
我们都知道现在任何内容被索引之前,都需要先进行嵌入处理。而分块的主要目的就是为了确保我们在嵌入的时候,能够尽量减少噪声,同时让语义保持相关性。
举个例子,在语义搜索中,我们需要索引大量文档,每篇文档都包含某个特定主题的重要信息。通过有效的分块策略,我们可以确保搜索结果能精准地捕捉用户的查询意图。如果分块太小或太大,就会导致搜索结果不够精确,甚至会错过一些重要的相关内容。
一般的经验法则是:如果一段文本在没有上下文的情况下对人类是有意义的,那么它对语言模型也会有意义。因此,找到适合文档集合的最佳分块大小,是确保搜索结果准确性和相关性的关键。
当然,分块的策略不仅仅适用于语义搜索,还广泛应用于对话AI(Chatbot)。在Chatbot中,嵌入后的分块内容会被用来构建基于知识库的上下文,从而让ChatBot有可靠的依据去生成回答。在这种场景下,选择正确的分块策略非常重要,主要有两个原因:
第一,这决定了上下文是否真的与我们的提问相关;
第二,这也决定了我们能否在将文本发送给外部模型提供者(例如OpenAI)之前,将其适配到有限的token窗口内。
在某些情况下,比如使用GPT-4这种支持32k上下文窗口的模型时,适应大块文本可能不是问题。但我们仍然需要谨慎对待过大块的情况,因为这可能会影响检索到的结果的相关性。
在这篇文章里,我们会探讨几种不同的分块方法,并讨论在选择分块大小和方法时需要考虑的权衡因素。最后,会给出一些建议,帮助你为自己的应用选择最佳的分块大小和方法。
当我们对内容进行嵌入时,可以预见根据内容长短的不同,嵌入的表现也会有所区别。短内容(如句子)和长内容(如段落或整篇文章)的处理方式会有显著差异。
当一个句子被嵌入时,生成的向量主要聚焦于该句子的具体含义。比较也自然会在这样的粒度上进行。不过,这种方式可能会忽略掉段落或文档中更广泛的上下文信息。
相比之下,当整个段落或文档被嵌入时,嵌入过程会同时考虑整体上下文以及句子和短语之间的关系。这样得到的向量表示往往更加全面,能够捕捉到文本的宏观意义和主题。但另一方面,较大的输入文本可能会引入噪音,稀释个别句子或短语的重要性,从而使得在查询索引时难以找到精确匹配。
此外,查询的长度也会影响嵌入之间的关联性。较短的查询(如单句或短语)会更关注细节,因此更适合与句子级别的嵌入进行匹配。而较长的查询(如多句或多段)则可能更适合与段落或文档级别的嵌入进行匹配,因为它通常寻找的是更广义的上下文或主题。
索引也可能呈现非同质化的特点,即其中包含不同大小的分块嵌入。这种情况既带来挑战,也可能有一些积极的效果。一方面,由于长内容和短内容的语义表征存在差异,查询结果的相关性可能会波动。另一方面,非同质化的索引有可能捕捉到更广泛的上下文和信息,因为不同大小的分块代表了文本的不同粒度,这可以让系统更灵活地应对各种类型的查询。
有几个变量会影响最佳分块策略的选择,这些变量因应用场景而异。以下是一些需要注意的关键点:
回答这些问题将帮助你制定出一种既能平衡性能又能保证准确性的分块策略,从而使查询结果更加相关。
分块的方法有很多种,每种方法在不同情况下各有优劣。通过分析每种方法的利弊,我们要能够找出最适用自己场景的方法。
这是最常见的也是最直接的分块方法:我们只需决定每个分块包含的token数量,并且可以选择是否让它们之间有一定的重叠。一般来说,为了让语义上下文不会在分块之间丢失,我们会保留一些重叠部分。固定大小分块在大多数常见情况下都是最优路径。与其他形式的分块相比,这种方法计算成本低且易于使用,因为它不需要依赖任何NLP库。
下面是一个使用LangChain进行固定大小分块的例子:
text = "..." # 文本
from langchain.text_splitter import CharacterTextSplitter
text_splitter = CharacterTextSplitter(
separator = "\n",
chunk_size = 256,
chunk_overlap = 20
)
docs = text_splitter.create_documents([text])
这是一系列利用待分块内容特性并施加更复杂分块方法的策略。以下是几个例子:
正如前面提到的,许多模型在嵌入句子级别内容时表现优异。自然地,我们会使用句子分块,而且有许多方法和工具可以实现这一点,包括:
text = "..." # 文本
docs = text.split(".")
text = "..." # 文本
from langchain.text_splitter import NLTKTextSplitter
text_splitter = NLTKTextSplitter()
docs = text_splitter.split_text(text)
text = "..." # 文本
from langchain.text_splitter import SpacyTextSplitter
text_splitter = SpaCyTextSplitter()
docs = text_splitter.split_text(text)
递归分块以分层和迭代的方式将输入文本划分成更小的块,使用一组分隔符。如果最初的尝试未能产生所需大小或结构的块,该方法会递归调用自身,直到达到所需的块大小或结构为止。这意味着尽管块的大小不一定完全相同,但它们仍然会“趋向”于相似的大小。
以下是如何使用LangChain进行递归分块的示例:
text = "..." # 文本
from langchain.text_splitter import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(
# 设置一个非常小的块大小,只是为了展示。
chunk_size = 256,
chunk_overlap = 20
)
docs = text_splitter.create_documents([text])
Markdown和LaTeX是两种常见的结构化和格式化内容的例子。在这些情况下,可以使用专门的分块方法来在分块过程中保留原始结构。
from langchain.text_splitter import MarkdownTextSplitter
markdown_text = "..."
markdown_splitter = MarkdownTextSplitter(chunk_size=100, chunk_overlap=0)
docs = markdown_splitter.create_documents([markdown_text])
from langchain.text_splitter import LatexTextSplitter
latex_text = "..."
latex_splitter = LatexTextSplitter(chunk_size=100, chunk_overlap=0)
docs = latex_splitter.create_documents([latex_text])
这是一种新的分块方法,由Greg Kamradt首次提出。在他的代码示例中,Kamradt指出,全局分块大小可能过于简单,无法考虑到文档内各段落的含义。如果我们使用这种机制,就无法知道我们是否在组合那些彼此无关的段落。
这是代码示例地址:https://github.com/FullStackRetrieval-com/RetrievalTutorials/blob/main/tutorials/LevelsOfTextSplitting/5_Levels_Of_Text_Splitting.ipynb
这种语义分析可以用来创建围绕同一主题或话题的句子组成的块。
以下是使语义分块工作所需的步骤:
LangChain基于Kamradt的工作创建了一个语义分块分割器。
地址为:https://python.langchain.com/docs/modules/data_connection/document_transformers/semantic-chunker/
以下建议,可以帮助你在常见的分块方法(如固定分块)不适用时,确定最佳的分块大小。
分块没有一刀切的解决方案,所以适合一个用例的方法可能不适合另一个。希望这篇文章能帮助你更好地理解如何为你的应用选择合适的分块策略。
- END -53AI,企业落地大模型首选服务商
产品:场景落地咨询+大模型应用平台+行业解决方案
承诺:免费场景POC验证,效果验证后签署服务协议。零风险落地应用大模型,已交付160+中大型企业
2024-10-27
2024-09-04
2024-07-18
2024-05-05
2024-06-20
2024-06-13
2024-07-09
2024-07-09
2024-05-19
2024-07-07
2025-04-04
2025-04-03
2025-04-02
2025-04-01
2025-04-01
2025-03-30
2025-03-28
2025-03-27