南京建设网站方案wordpress发音
2026/1/11 5:25:15 网站建设 项目流程
南京建设网站方案,wordpress发音,网站改版提交,做一网站APP多少钱尊敬的各位同仁#xff0c;欢迎来到今天的讲座。在人工智能#xff0c;特别是大型语言模型#xff08;LLM#xff09;飞速发展的今天#xff0c;我们正面临一个看似简单却又充满挑战的基础问题#xff1a;如何有效地处理海量的文本数据#xff0c;并将其以一种对AI模型友…尊敬的各位同仁欢迎来到今天的讲座。在人工智能特别是大型语言模型LLM飞速发展的今天我们正面临一个看似简单却又充满挑战的基础问题如何有效地处理海量的文本数据并将其以一种对AI模型友好的方式呈现。LLM的强大能力毋庸置疑但它们并非没有局限。其中最显著的便是“上下文窗口”的限制。这意味着模型一次能够处理的文本量是有限的。当我们需要向LLM提供一份长达数万甚至数十万字的文档例如一份技术手册、一本小说、或者一份复杂的法律合同我们不能简单地将整个文档一次性喂给模型。这就引出了一个核心需求文本切割Text Splitting或者更常用的术语文本分块Chunking。然而文本分块绝非简单地“剪切”文本。今天我们将深入探讨一个在LLM应用开发中至关重要的工具——RecursiveCharacterTextSplitter。我们将从最基础的问题出发为什么简单的长度切割会破坏段落的语义完整性接着我们将详细解析RecursiveCharacterTextSplitter如何以其巧妙的设计在满足长度限制的同时最大程度地保留文本的语义连贯性。一、语义完整性文本处理的基石在深入RecursiveCharacterTextSplitter之前我们必须先理解为什么“语义完整性”在文本处理中如此关键。想象一下你正在阅读一本关于量子物理学的教科书。如果你拿起一把剪刀随机地将书页剪成固定大小的小纸片然后试图从这些碎片中理解量子纠缠的复杂概念你会有何感受你可能会发现一个句子被截断了一个段落的开头和结尾分属不同的纸片甚至一个公式的一半在这一片另一半在那一片。这样的阅读体验无疑是灾难性的因为文本的“语义完整性”已经被彻底破坏了。对于人类尚且如此对于LLM而言这个问题则更为严峻。LLM通过分析文本中的词语、句子、段落之间的关系来理解语境、提取信息、生成回答。如果输入给模型的信息是零散的、不连贯的那么模型将难以理解上下文句子被切断段落被肢解模型无法建立起完整的语义图谱。提取关键信息核心论点、事实或实体可能被分散到不同的块中导致信息丢失或难以关联。生成高质量响应基于破碎的上下文模型容易产生不准确、不完整甚至“幻觉”的回答。进行有效检索在检索增强生成RAG系统中如果文本块不具备良好的语义边界检索到的块可能无法提供足够连贯的上下文来回答用户查询。简而言之一个好的文本切割策略其核心目标是在满足LLM上下文窗口限制的前提下尽可能地保持文本的语义连贯性将文本分解为最小的、仍能独立表达完整意义的单元。二、简单长度切割的陷阱现在让我们通过一个具体的例子看看最直观、最简单的文本切割方法——按固定长度切割——是如何破坏语义完整性的。假设我们有一段描述某个概念的文本大型语言模型LLM在自然语言处理领域取得了显著进展。它们能够理解、生成和处理人类语言应用场景广泛包括内容创作、智能客服、代码辅助等。然而LLM的上下文窗口是有限的这意味着它们一次性处理的文本量存在上限。为了克服这一限制文本分块成为一个关键预处理步骤它将长文档拆分为更小的、可管理的部分以便逐一输入到模型中进行处理。如果我们的目标是将这段文本切割成最大长度为50个字符的块并且我们采用最简单的字符计数方式进行切割代码可能如下def simple_char_splitter(text: str, chunk_size: int): chunks [] current_pos 0 while current_pos len(text): chunk text[current_pos : current_pos chunk_size] chunks.append(chunk) current_pos chunk_size return chunks text_to_split 大型语言模型LLM在自然语言处理领域取得了显著进展。它们能够理解、生成和处理人类语言应用场景广泛包括内容创作、智能客服、代码辅助等。然而LLM的上下文窗口是有限的这意味着它们一次性处理的文本量存在上限。为了克服这一限制文本分块成为一个关键预处理步骤它将长文档拆分为更小的、可管理的部分以便逐一输入到模型中进行处理。 chunk_size 50 simple_chunks simple_char_splitter(text_to_split, chunk_size) print(--- 简单长度切割结果 ---) for i, chunk in enumerate(simple_chunks): print(fChunk {i1} (长度: {len(chunk)}): {chunk})输出结果会是这样--- 简单长度切割结果 --- Chunk 1 (长度: 50): 大型语言模型LLM在自然语言处理领域取得了显著进展。它们能够理 Chunk 2 (长度: 50): 解、生成和处理人类语言应用场景广泛包括内容创作、智能客服、代 Chunk 3 (长度: 50): 码辅助等。然而LLM的上下文窗口是有限的这意味着它们一次性处理的文 Chunk 4 (长度: 50): 本量存在上限。为了克服这一限制文本分块成为一个关键预处理步骤它 Chunk 5 (长度: 50): 将长文档拆分为更小的、可管理的部分以便逐一输入到模型中进行处理。我们来分析一下这些块Chunk 1:大型语言模型LLM在自然语言处理领域取得了显著进展。它们能够理 —— 理解这个词被硬生生截断了。句子的主语和谓语被分开了。Chunk 2:解、生成和处理人类语言应用场景广泛包括内容创作、智能客服、代 —— 代码辅助的“代”字被截断。Chunk 3:码辅助等。然而LLM的上下文窗口是有限的这意味着它们一次性处理的文 —— 文本量的“文”字被截断。等等…这种切割方式的弊端显而易见词语被截断这是最直接的破坏导致词语失去意义。句子被截断一个完整的句子被一分为二使得模型的语法分析和语义理解变得困难。语义单元被破坏段落、论点、列表项等自然的语义边界完全被忽略。上下文碎片化各个块之间缺乏逻辑连接模型难以将它们拼接起来形成一个连贯的整体。在RAG系统中如果用户查询的是“LLM的局限性是什么”检索系统可能会返回Chunk 3但由于其开头和结尾都是不完整的模型很难从中准确地提取“上下文窗口有限”这一核心信息或者需要更多的推理才能补全。这就是为什么我们需要一个更智能、更精细的文本切割策略。三、RecursiveCharacterTextSplitter递归字符文本切割器RecursiveCharacterTextSplitter正是为了解决上述问题而设计的。它不是简单地按固定长度暴力切割而是采用一种“递归”的策略尝试在尽可能大的语义单位处进行切割如果切割后的块仍然过大则继续使用更小的语义单位进行切割直到所有块都满足长度限制。3.1 核心思想优先切割大的语义单元其核心思想在于它会尝试使用一组预定义的、按优先级排序的分隔符来切割文本。这些分隔符通常按从大到小的语义单位排序双换行符 (nn)通常代表段落之间的分隔。这是最大的语义单元优先尝试在此处切割。单换行符 (n)通常代表一行文本的结束或者列表项、代码行之间的分隔。空格 ()代表词语之间的分隔。空字符串 ()如果以上分隔符都无法将文本切割到指定长度最终的兜底策略按单个字符切割。3.2 “递归”的策略迭代尝试这里的“递归”并非指函数本身的递归调用而是指其处理逻辑的迭代性质。它的工作流程可以概括为给定一个长文本和一组分隔符列表[sep1, sep2, sep3, ..., sepN]。尝试使用第一个分隔符sep1切割文本。这会生成一系列子字符串。检查每个子字符串的长度。如果子字符串的长度小于或等于chunk_size则它是一个有效的块。如果子字符串的长度仍然大于chunk_size那么这个子字符串就需要进一步处理。对那些过长的子字符串使用下一个分隔符sep2再次进行切割。这就好像我们“递归”地对这些过长的部分应用了相同的切割逻辑只是使用了更细粒度的分隔符。这个过程会一直重复直到用尽所有的分隔符或者所有生成的块都满足chunk_size的要求。最终即使是单个字符的切割也会被应用到那些无法通过更高级别分隔符切分的超长“词语”上。通过这种方式RecursiveCharacterTextSplitter会优先在段落边界切割如果段落过长则在行边界切割如果行过长则在词语边界切割以此类推。这最大程度地保留了文本的语义单元。3.3 关键参数解析RecursiveCharacterTextSplitter有几个重要的参数它们共同决定了切割的行为chunk_size(int):每个文本块的最大长度。这是我们希望每个输出块能达到的上限。chunk_overlap(int):块与块之间的重叠字符数。这是一个非常重要的参数它有助于在相邻块之间保持上下文的连续性。当一个问题或概念横跨两个块时重叠可以确保模型在处理某个块时也能“看到”前一个块或后一个块的部分内容从而更好地理解上下文。separators(List[str]):一个字符串列表用于指定切割文本时尝试的分隔符。分隔符的顺序至关重要它定义了切割的优先级。默认值通常是[nn, n, , ]。length_function(Callable[[str], int]):一个函数用于计算文本块的长度。默认是Python内置的len函数它计算字符数。然而对于LLM我们通常更关心的是“token”数量因此可以传入一个基于tokenizer的长度函数。keep_separator(bool):是否在切割后的块中保留分隔符。默认为False。如果设置为True分隔符会出现在每个块的开头这在某些场景下有助于理解块的来源和结构。四、RecursiveCharacterTextSplitter的实际应用与代码示例现在让我们通过具体的代码示例来展示RecursiveCharacterTextSplitter的强大功能。我们将使用langchain库中的实现因为它是一个非常流行的LLM应用开发框架并且其文本切割器功能完善。首先确保你已经安装了langchainpip install langchain4.1 基本用法与语义优势展示我们将再次使用之前的长文本并应用RecursiveCharacterTextSplitter进行切割。from langchain.text_splitter import RecursiveCharacterTextSplitter text_to_split 大型语言模型LLM在自然语言处理领域取得了显著进展。它们能够理解、生成和处理人类语言应用场景广泛包括内容创作、智能客服、代码辅助等。nn然而LLM的上下文窗口是有限的这意味着它们一次性处理的文本量存在上限。为了克服这一限制文本分块成为一个关键预处理步骤它将长文档拆分为更小的、可管理的部分以便逐一输入到模型中进行处理。 # 为了更好地演示效果我们稍微调整文本让它有明确的段落分隔符 nn # 并设置一个较小的 chunk_size 和 chunk_overlap text_splitter RecursiveCharacterTextSplitter( chunk_size50, chunk_overlap10, separators[nn, n, , ] # 默认分隔符 ) recursive_chunks text_splitter.split_text(text_to_split) print(--- RecursiveCharacterTextSplitter 切割结果 ---) for i, chunk in enumerate(recursive_chunks): print(fChunk {i1} (长度: {len(chunk)}): {chunk})输出结果--- RecursiveCharacterTextSplitter 切割结果 --- Chunk 1 (长度: 47): 大型语言模型LLM在自然语言处理领域取得了显著进展。 Chunk 2 (长度: 46): 它们能够理解、生成和处理人类语言应用场景广泛 Chunk 3 (长度: 32): 包括内容创作、智能客服、代码辅助等。 Chunk 4 (长度: 48): 然而LLM的上下文窗口是有限的这意味着它们一次性 Chunk 5 (长度: 46): 处理的文本量存在上限。为了克服这一限制文本分块 Chunk 6 (长度: 45): 成为一个关键预处理步骤它将长文档拆分为更小的、 Chunk 7 (长度: 44): 可管理的部分以便逐一输入到模型中进行处理。对比简单切割我们可以看到显著的改进没有词语被截断所有切割都在词语之间进行保证了词语的完整性。段落优先第一个nn分隔符被优先处理将文本自然地分成了两大部分。虽然每个段落内部因长度限制仍需切割但切割点是在词语之间。可读性增强每个块都至少包含完整的词语更容易理解其含义。chunk_overlap效果虽然在这个例子中不明显但重叠会在内部处理时确保相邻块之间共享部分上下文例如如果Chunk 2和Chunk 3有重叠Chunk 3会包含Chunk 2末尾的一部分增加连贯性。4.2 自定义分隔符与优先级分隔符的顺序是RecursiveCharacterTextSplitter的灵魂。我们可以根据不同的文档类型和需求自定义分隔符列表。示例处理Markdown文档Markdown文档通常包含标题#、##等、列表项、代码块等结构。为了更好地保留这些语义单元我们可以将标题分隔符放在前面。from langchain.text_splitter import RecursiveCharacterTextSplitter markdown_text # 深入理解LLM分块策略 ## 为什么需要分块 大型语言模型LLM因其强大的自然语言处理能力而备受关注。 然而它们的上下文窗口限制了单次处理的文本量。 例如GPT-3.5-turbo 可能只有4k或16k token的上下文。 ## RecursiveCharacterTextSplitter 这是一种智能的文本分块器。 它优先在段落边界nn切割。 如果段落过长则尝试在行边界n切割。 最终如果必要会在单词边界 甚至字符边界切割。 ### 示例代码 python # 这是一个代码块 def hello_world(): print(Hello, world!)总结选择合适的分隔符至关重要。针对Markdown的自定义分隔符优先按一级标题然后二级标题然后段落然后行然后空格最后字符markdown_splitter RecursiveCharacterTextSplitter(chunk_size150, # 增大 chunk_size 以便看清结构chunk_overlap20,separators[nn#, nn##, nn###, nn, n, , ])markdown_chunks markdown_splitter.split_text(markdown_text)print(n— Markdown文档切割结果 —)for i, chunk in enumerate(markdown_chunks):print(fChunk {i1} (长度: {len(chunk)}): ‘{chunk}’)输出示例可能因 chunk_size 和内容略有不同但能体现结构— Markdown文档切割结果 —Chunk 1 (长度: 57): ‘# 深入理解LLM分块策略’Chunk 2 (长度: 60): ‘## 为什么需要分块’Chunk 3 (长度: 129): ‘大型语言模型LLM因其强大的自然语言处理能力而备受关注。n然而它们的上下文窗口限制了单次处理的文本量。n例如GPT-3.5-turbo 可能只有4k或16k token的上下文。’Chunk 4 (长度: 46): ‘## RecursiveCharacterTextSplitter’Chunk 5 (长度: 30): ‘这是一种智能的文本分块器。’Chunk 6 (长度: 132): ‘它优先在段落边界nn切割。n如果段落过长则尝试在行边界n切割。n最终如果必要会在单词边界甚至字符边界切割。’Chunk 7 (长度: 48): ‘### 示例代码’Chunk 8 (长度: 44): ‘pythonn# 这是一个代码块ndef hello_world(): Chunk 9 (长度: 20): print(Hello, world!)n‘Chunk 10 (长度: 22): ‘总结选择合适的分隔符至关重要。’注意观察 * 一级标题和二级标题都被保留在了独立的块中Chunk 1, Chunk 2, Chunk 4, Chunk 7。这是因为我们把 nn# 和 nn## 等放在了分隔符列表的前面。 * 代码块也被尽可能地作为一个整体保留。虽然这里因为 chunk_size 小代码块内部被分割了但它仍然试图在行级别分割而不是随机字符分割。 * 每个逻辑段落如“为什么需要分块”下的内容Chunk 3尽可能地保留在了一个块中。 这个例子清楚地展示了通过调整 separators 参数我们可以如何指导 RecursiveCharacterTextSplitter 更好地理解和尊重特定文档类型的结构。 #### 4.3 chunk_overlap 的作用 chunk_overlap 参数在RAG系统中尤为重要。它允许相邻的文本块之间共享一部分内容。这有助于在检索时即使检索到的主要块可能缺失某些上下文其重叠部分也能提供必要的线索。 让我们用一个简短的例子来演示重叠 python from langchain.text_splitter import RecursiveCharacterTextSplitter short_text 这是第一句话。这是第二句话。这是第三句话。这是第四句话。 # 无重叠 splitter_no_overlap RecursiveCharacterTextSplitter( chunk_size15, chunk_overlap0, separators[。] # 以句号切割 ) chunks_no_overlap splitter_no_overlap.split_text(short_text) print(n--- 无重叠切割 ---) for i, chunk in enumerate(chunks_no_overlap): print(fChunk {i1}: {chunk}) # 有重叠 splitter_with_overlap RecursiveCharacterTextSplitter( chunk_size15, chunk_overlap5, # 重叠5个字符 separators[。] ) chunks_with_overlap splitter_with_overlap.split_text(short_text) print(n--- 有重叠切割 (overlap5) ---) for i, chunk in enumerate(chunks_with_overlap): print(fChunk {i1}: {chunk})输出--- 无重叠切割 --- Chunk 1: 这是第一句话 Chunk 2: 这是第二句话 Chunk 3: 这是第三句话 Chunk 4: 这是第四句话 --- 有重叠切割 (overlap5) --- Chunk 1: 这是第一句话 Chunk 2: 第一句话。这是第二句话 # 注意 第一句话 重叠了 Chunk 3: 第二句话。这是第三句话 # 注意 第二句话 重叠了 Chunk 4: 第三句话。这是第四句话 # 注意 第三句话 重叠了在这个例子中因为我们以句号切割且句号在chunk_size范围内所以每个块都以句号结束。当chunk_overlap5时你会看到每个后续块的开头都包含前一个块的最后5个字符包括分隔符。。这种重叠对于模型理解相邻块之间的关系非常有益尤其是在 RAG 场景中。4.4length_function从字符到Token的度量默认情况下RecursiveCharacterTextSplitter使用len()函数计算字符长度。然而LLM的上下文窗口限制通常是以“token”为单位的。不同的tokenizer对相同文本的token计数可能大相径庭。因此使用一个基于LLM特定tokenizer的length_function是最佳实践。以OpenAI模型为例我们可以使用tiktoken库来计算token数。首先安装tiktokenpip install tiktoken然后我们可以这样定义一个基于token的长度函数import tiktoken from langchain.text_splitter import RecursiveCharacterTextSplitter # 假设我们使用 cl100k_base 编码这是GPT-3.5-turbo和GPT-4使用的编码 tokenizer tiktoken.get_encoding(cl100k_base) def tiktoken_len(text): return len(tokenizer.encode(text)) text_to_split 大型语言模型LLM在自然语言处理领域取得了显著进展。它们能够理解、生成和处理人类语言应用场景广泛包括内容创作、智能客服、代码辅助等。nn然而LLM的上下文窗口是有限的这意味着它们一次性处理的文本量存在上限。为了克服这一限制文本分块成为一个关键预处理步骤它将长文档拆分为更小的、可管理的部分以便逐一输入到模型中进行处理。 # 使用 tiktoken_len 作为长度函数 token_splitter RecursiveCharacterTextSplitter( chunk_size100, # 现在这个 chunk_size 是以 token 为单位 chunk_overlap20, # 重叠也是以 token 为单位 length_functiontiktoken_len, separators[nn, n, , ] ) token_chunks token_splitter.split_text(text_to_split) print(n--- 基于Token的切割结果 ---) for i, chunk in enumerate(token_chunks): token_count tiktoken_len(chunk) print(fChunk {i1} (字符长度: {len(chunk)}, Token长度: {token_count}): {chunk})输出示例chunk_size为100 tokenchunk_overlap为20 token--- 基于Token的切割结果 --- Chunk 1 (字符长度: 122, Token长度: 41): 大型语言模型LLM在自然语言处理领域取得了显著进展。它们能够理解、生成和处理人类语言应用场景广泛包括内容创作、智能客服、代码辅助等。 Chunk 2 (字符长度: 131, Token长度: 46): 辅助等。nn然而LLM的上下文窗口是有限的这意味着它们一次性处理的文本量存在上限。为了克服这一限制文本分块成为一个关键预处理步骤它将长文档拆分为更小的、可管理的部分以便逐一输入到模型中进行处理。可以看到尽管chunk_size设置为100 token但实际生成的块可能远小于100 token。这是因为RecursiveCharacterTextSplitter会优先使用分隔符进行切割如果在分隔符处切割后生成的块已经小于或等于目标chunk_size它就不会再进一步切割。例如上述例子中整个文本在nn处被分成两部分这两部分各自的token数都远小于100因此它们成为独立的块。这种行为是符合预期的因为它优先保持语义完整性。如果一个自然段落的token数超过了chunk_size那么RecursiveCharacterTextSplitter就会在其内部应用下一个分隔符如n直到满足长度限制。4.5 文档类型与分隔符选择建议选择合适的分隔符是优化RecursiveCharacterTextSplitter性能的关键。以下是一些常见文档类型及其推荐的分隔符策略文档类型推荐 Separators (示例)优先级与Rationale通用散文[nn, n, , ]高优先级:nn(段落) – 尽可能保持整个段落的完整性。中优先级:n(行) – 如果段落过长则按行切割。低优先级: (词) - 如果行过长则按词切割。br**最低优先级:** (字符) – 最终兜底确保任何超长字符串都能被切割。Markdown[nn#, nn##, nn###, nn, n, , ]高优先级:nn#,nn##,nn###(各级标题) – 优先将标题及其下的内容作为一个整体。这有助于保持文档的逻辑结构。次高优先级:nn(段落) – 保持段落完整性。中优先级:n(行) – 针对列表项、代码块等。低优先级: (词) - 确保词语完整。br**最低优先级:** (字符)。代码 (Python)[nnclass , nndef , nn, n, , ]高优先级:nnclass,nndef(类和函数定义) – 优先将整个类或函数作为一个块。这对于代码理解至关重要。次高优先级:nn(逻辑代码块) – 保持大的代码块完整。中优先级:n(代码行) – 如果函数或类过长则按行切割。低优先级: (标识符/关键词) - 保持代码元素的完整性。br**最低优先级:**(字符)。br*注意具体语言需要调整分隔符例如JavaScript可能用functionJava可能用class和public static等。*JSON/YAML[n, , , {, }, [, ], , ]高优先级:n(行) – JSON/YAML通常按行组织。中优先级:,(键值对分隔) – 保持键值对的完整性。低优先级:{,},[,](结构分隔) – 保持对象和数组的边界。最低优先级: (空格) 和 (字符)。目标是保持有效的JSON/YAML片段但对于非常长的嵌套结构可能需要更复杂的解析器。CSV/TSV[n, ,](CSV) 或[n, t](TSV)高优先级:n(行) – 保持每一行的完整性即每一条记录。中优先级:,或t(列分隔) – 如果行过长则按列切割但这通常意味着一行数据本身就超过了chunk_size可能需要更高级的处理例如将某些列合并或摘要。这个表格提供了一个起点实际应用中可能需要根据特定文档的特点进行微调和实验。五、高级场景与最佳实践5.1 链式切割与专门化切割器在某些复杂的场景下单一的RecursiveCharacterTextSplitter可能不足以满足需求。这时我们可以考虑链式切割或使用专门化的切割器。例如对于一份包含Markdown文本和嵌入式代码块的文档我们可以首先使用一个专门的Markdown切割器如LangChain中的MarkdownTextSplitter它在内部可能也使用了递归思想但更专注于Markdown结构将文档分解为Markdown块和代码块。然后对Markdown块使用RecursiveCharacterTextSplitter通用散文或Markdown分隔符。对代码块使用PythonCodeTextSplitter或JSCodeTextSplitter等针对代码的分隔符。LangChain提供了一系列开箱即用的专门化切割器它们通常是RecursiveCharacterTextSplitter的变体预设了针对特定格式的separators。from langchain.text_splitter import MarkdownTextSplitter, PythonCodeTextSplitter # 示例MarkdownTextSplitter md_splitter MarkdownTextSplitter(chunk_size500, chunk_overlap50) md_chunks md_splitter.split_text(markdown_text) # 使用之前的 markdown_text # 示例PythonCodeTextSplitter python_code class MyClass: def __init__(self, name): self.name name def greet(self): print(fHello, {self.name}) def main(): obj MyClass(World) obj.greet() if __name__ __main__: main() py_splitter PythonCodeTextSplitter(chunk_size100, chunk_overlap10) py_chunks py_splitter.split_text(python_code) print(n--- MarkdownTextSplitter 结果 ---) for i, chunk in enumerate(md_chunks): print(fChunk {i1} (长度: {len(chunk)}): {chunk}) print(n--- PythonCodeTextSplitter 结果 ---) for i, chunk in enumerate(py_chunks): print(fChunk {i1} (长度: {len(chunk)}): {chunk})这些专门化的切割器在内部往往已经预设了符合该文件类型的最佳分隔符策略使得我们无需手动构建复杂的separators列表。5.2 检索增强生成 (RAG) 中的应用在RAG系统中RecursiveCharacterTextSplitter是构建高质量检索索引的关键组件。良好的文本块能够提高检索精度语义完整的块更容易与用户查询匹配。改善LLM生成质量LLM接收到的上下文更连贯、更准确从而生成更相关的回答。一个常见的RAG策略是“父文档检索”Parent Document Retrieval或“小块检索大块合成”Small-to-Large Chunking创建小块用于检索使用较小的chunk_size和适当的chunk_overlap来生成用于向量数据库索引的块。这些小块的目标是包含足够的信息来匹配查询但又足够小以便在检索时提高效率。创建大块用于合成同时保留原始文档的较大、更具上下文的块或整个原始文档。当小块被检索到时我们可以用它来识别其对应的更大、更完整的父块。LLM上下文构建将检索到的小块作为触发器然后将对应的大块或父块提供给LLM作为上下文进行生成。这种策略兼顾了检索效率和LLM对完整上下文的需求。RecursiveCharacterTextSplitter非常适合生成这些不同粒度的块。5.3 评估与迭代没有“一劳永逸”的文本切割策略。最佳的chunk_size、chunk_overlap和separators组合取决于文档类型散文、代码、法律文本、技术手册等。下游任务摘要、问答、信息提取、代码生成等。LLM的上下文窗口大小不同的模型有不同的限制。性能要求检索速度、生成质量。因此实验和迭代是关键。手动检查生成一些文本块手动阅读它们判断它们的语义完整性。小规模测试在小数据集上运行RAG或LLM任务评估不同切割策略对结果质量的影响。指标评估如果有可用的评估指标如RAG中的召回率、准确率LLM的BLEU/ROUGE分数等可以使用它们来量化不同策略的效果。通过持续的调整和测试我们可以找到最适合特定应用场景的文本切割方案。六、与其他文本切割器的简要对比CharacterTextSplitterRecursiveCharacterTextSplitter实际上是CharacterTextSplitter的一个更智能的变体。CharacterTextSplitter也可以接受separator参数但它会一次性用一个分隔符进行切割。如果结果块仍然过大它不会“递归”地尝试用下一个分隔符。RecursiveCharacterTextSplitter的优势在于其迭代尝试不同分隔符的策略。TokenTextSplitterTokenTextSplitter严格按照token数量来切割通常不考虑语义边界除非结合自定义的separators。它更关注精确控制token数量而RecursiveCharacterTextSplitter则优先语义同时使用length_function来约束token数量。在实际应用中我们通常将RecursiveCharacterTextSplitter与一个基于token的length_function结合使用以兼顾语义和token限制。基于句子的分割器 (如NLTK/SpaCy的Sentence Splitter)这些工具擅长将文本分割成句子。它们在句子级别提供了非常好的语义完整性但它们不处理更高级别的结构如段落、章节也不直接支持按固定长度分块的需求。它们可以作为RecursiveCharacterTextSplitter的预处理步骤或者在separators中包含句号等标点符号。七、总结RecursiveCharacterTextSplitter是处理大型文本以适应LLM上下文窗口限制的强大而灵活的工具。它通过优先在自然的语义边界如段落、行、词语进行切割并迭代地尝试不同粒度的分隔符有效地解决了简单长度切割破坏语义完整性的问题。通过精心选择chunk_size、chunk_overlap和定制separators并结合基于token的length_function我们可以极大地提升LLM应用特别是RAG系统的性能和可靠性。理解其工作原理和最佳实践是构建高效、智能LLM应用的关键一步。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询