6-5 文档分块:递归文本分块和语义智能分块
- 什么是文本分块: 文本分块指将长文本拆分成更小块的过程。在知识库构建中,把长文本分成小块,各小块经嵌入模型转化为嵌入向量,再存入向量数据库。所以,文本分块是技术构建的重要部分。
- 为什么要对长文本进行分块: 原因有三:
- 语义干扰:长文档内容可能包含多个不同语义信息,干扰构建嵌入语义向量,致使检索匹配精度下降。
- 无关信息:检索时,即便能精准匹配,长文本信息可能包含与检索问题不相关内容,增加RAG中大语言模型生成准确答案的难度。将长文档切割成较小独立块,可减少嵌入过程中引入的噪声,较小文本块能更精细匹配用户查询问题,提高检索精度。
- 模型限制:向量嵌入模型的输入长度有限制,对超过模型长度的输入会进行截取,造成信息缺失,因此必须对长文本进行分块。
- 文本分块的原则: 一个分块窗口只能表示一个完整且语义相关的上下文信息。正确分块对提高搜索结果的准确性和相关性至关重要。分块太小,会分割完整语义信息,导致各块上下文信息不完整,检索时错过真正相关内容;分块太大,一个块内可能包含多个不相关上下文信息,干扰检索,导致搜索结果不准确。
- 文本分块策略:
- 递归文本分块:
- 主要思想:根据特定分隔符对文档进行递归分割。分隔符常用来分隔段落或句子,一定程度保证语义完整性。
- 具体过程:
- 指定块大小:例如指定chunk size块大小为200,块大小一般不超过嵌入模型输入长度限制。
- 指定由粗到细的分隔符:如最大为段落,段落由句子组成,句子由单词组成,单词由字符组成。分割时,先用最初分隔符拆分文本,若拆分出的文档大小小于块大小,结束拆分;若有文档大小超过块大小,则依次使用更细分隔符拆分,直到每个分块大小符合块大小,即先按段落分,再按句子分,接着按单词分,最后按字母分,直至所有分块大小小于或等于预先设定的块大小。
- 实现过程:
- 引入递归文本分块方法。
- 声明递归文本分块实例。除块大小和分隔符外,还有重要参数“overlap”,即重叠文本长度。该参数使块与块之间保留一定长度重复文本,如长文本分为三个块,其中两个块之间有三个字符重复,如第一个块和第二个块之间重复文本为“OCH”,增加上下文信息连贯性。
- 通过实例的“create_document”方法进行文档分块。
- 分隔符选择:递归文本分块最重要的参数是分隔符,可为不同内容选择不同分隔符。例如,默认分隔符多针对英文语境,中文语境可增加逗号、句号等分隔符表示句子,更好适应中文语境。对于特殊文本格式如Markdown,因其层次结构清晰,可通过不同标题分隔,同一标题下还可按代码块、段落或列表更细粒度分隔。在LangChain中,可用“MarkdownTextSplitter”进行Markdown长文本分块,该类继承递归文本分块,但其分隔符根据Markdown文档层次结构设计,最初分隔符依据Markdown六个不同层次标题,接下来是代码块、分割线。若文档是Python代码,在LangChain中可通过“PythonCodeTextSplitter”进行分块,同样继承递归文本分块,将Python代码中的关键词作为分隔符,通过类、函数、内部函数等层级关系对Python代码分块。可根据文档固定格式设计分隔符对长文档分块。
- 基于语义的分块:
- 基于嵌入的语义分块:
- 原理:利用嵌入模型提取文本语义特征,通过嵌入向量判断段落中两句话是否表达同一语义,以此进行分块。
- 具体步骤:
- 将文档拆分成句子粒度。
- 设定滑动窗口长度,如长度为三表示包含三个句子,长度为一表示一个句子,目的是降低分块结果对设定阈值的敏感性。
- 计算前后两个窗口包含文本的嵌入相似度。
- 通过设定阈值判断如何分块,若前后两个窗口的嵌入相似度超过阈值,则在此点分割。
- 阈值选择策略:在LangChain中通过“SlidingWindow”类实现语义分块,需指定嵌入模型和阈值选取策略,策略基于统计信息,如基于百分位、标准差、四分位数。例如百分数设为95,程序会对所有相似度从小到大排序,选择第95%的相似度值作为阈值分块,即超过95%阈值处作为分割点,标准差和四分位过程类似。
- 补充说明:经嵌入语义分块后,各块大小可能不同,若块大小超过嵌入向量模型输入长度限制,通常会对超长块再进行一次递归文本分块。
- 端到端基于模型的语义分块:
- 原理:给定窗口内几个句子,模型直接判断每个句子是否为分割点,无需通过阈值判断。
- 以阿里达摩院模型为例:
- 思路:将基于嵌入向量分块的所有步骤囊括在模型中。
- 具体过程:给定窗口内N个句子,将每个句子的所有token送入编码器编码,得到每个token的嵌入向量,将每个token的嵌入向量求均值得到句子的嵌入向量,在句子嵌入向量后接二分类层,直接通过二分类判断句子是否为分割点,通过这些分割点将段落按语义分割成不同块。在阿里的ModelScope中有该模型开源版本,可通过pipeline实现语义分块调用,调用十分简单。
- 注意事项:运用到任务中时,需考虑模型泛化能力,因模型训练数据可能与任务数据不同,模型在测试集表现良好,但在任务中可能表现很差,所以需对模型进行测试验证,看是否符合要求。
- 基于嵌入的语义分块:
- 递归文本分块:
- 简短修订说明:
- 术语统一情况:将“evading模型”统一为“嵌入模型”,“embedding向量”统一规范表述为“嵌入向量” ,“大元模型”修正为“大语言模型”,统一相关专业术语,符合行业标准。
- 主要口误修正点:修正了如“鱼的缺失”应为“信息缺失”;“line”应为“LangChain”;“人群”应为“LangChain”;“认证”应为“LangChain” ;“mod”应为“Markdown” ;“monk到”应为“Markdown” ;“sport”应为“splitter” ;“基因模型”应为“基于模型” ;“models cope”应为“ModelScope” 等多处口误。同时,去除了冗余语气词和重复表述,使文本更流畅。梳理了实操相关内容,以条列式结构呈现。