RAG文本分块全解析:七种策略决定检索效果上限

发布时间:2026/9/10 19:53:32
RAG文本分块全解析:七种策略决定检索效果上限 做RAG落地时间长了你会发现一个反直觉的事实决定问答效果天花板的往往不是选哪个embedding模型也不是向量库用Milvus还是pgvector而是最开始那个看起来最简单的步骤——文本分块Chunking。我见过不少项目换了一个分块策略之后召回率直接从40%提到75%以上而模型和向量库一丁点都没动。这个投入产出比比调什么prompt都来得实在。这篇内容适合正在做RAG知识库、企业文档问答、Agent/工作流里接检索模块的开发者也适合刚接触RAG想系统理解分块原理的初学者。我会把目前工业界最常用的七种分块技术方案一次性梳理清楚包括每种方案的原理、最小可用实现、适合场景、典型缺陷以及我落在真实项目里的选型经验。1. 分块这件事为什么总被忽略但又决定RAG的上限1.1 分块本质检索单位与上下文完整性之间的天平先想清楚一个问题用户问一句“今年的报销流程和去年比有什么变化”系统要做的第一步不是让LLM去理解而是先从知识库里把“回答这个问题需要的内容”捞出来。捞出来的最小单位就是chunk。所以分块策略直接决定了两件事检索层能不能命中正确答案所在的位置以及命中的chunk里是否包含答案所需的完整上下文。这两个需求本质上是矛盾的。块切得小比如每块100个字符向量化之后语义聚焦召回相关文本的位置更精准但上下文容易被拦腰截断比如某个关键结论在前一块它的前提条件在后一块。块切得大比如每块2000个字符上下文相对完整但整体语义被平均化embedding出来的向量像“什么都说了又什么都没说”召回精度下降而且超出模型窗口后还得截断。这个矛盾就像你在图书馆里找资料索引卡片小块能精确定位“哪本书的哪一页讲了这件事”但你要真正读懂往往需要把前后几页一起借出来。分块方案的设计本质上就是在“精确定位”和“完整上下文”之间选一个平衡点。七种方案的区别只是这个平衡点落在哪里的问题。1.2 评价分块质量的三把尺子我在实际项目里评判一个分块方案好不好基本只看三个维度检索命中率。把一批已知答案的测试问题跑一遍检索看正确答案所在的chunk有没有被召回以及排在第几位。这个指标决定了分块方案的下限。上下文完整性。把召回的chunk交给LLM之后看生成结果是不是存在“信息缺失”或“回答片面”的情况。有些时候检索命中了但答案只给了一半就是因为关键约束写在chunk边界之外。工程成本。包括embedding的调用次数、向量库存储量、检索后的拼接逻辑复杂度以及是否需要额外维护父子映射这类后处理逻辑。方案越高级工程复杂度越高这个维度的代价愈发不能忽视。分块不是越复杂越好而是要看你的文档类型和预期效果这直接关系到后面每一种方案该怎么选。2. 基础分块方案固定大小与递归字符切分2.1 固定大小分块Fixed-size Chunking这是最原始的分块方式设定一个chunk_size按字符数或者token数硬切允许连续块之间有overlap重叠区避免句子的头尾信息被硬生生拆丢。def fixed_size_chunk(text, chunk_size500, overlap50): chunks [] start 0 while start len(text): end start chunk_size chunks.append(text[start:end]) start end - overlap return chunks注意这里有两个隐蔽的问题。第一个问题是chunk_size用token还是字符文本切分时默认用token更合理因为embedding模型的输入上限通常按token算但tokenizer会额外引入计算开销所以很多轻量实现直接用字符。第二个问题是overlap取多少overlap太小起不到衔接上下文的作用overlap太大又会让重复内容占据向量容量导致有效信息密度下降。固定大小分块的优势是简单、稳定、开销极低任何文本都能切。缺点是完全没有语义意识如果文档里正好在句子中间切断比如修饰关系和主谓宾被拆开检索效果就会明显缩水。我的建议是这种做法只适合日志、固定格式的票据文本或者你只是想快速跑通一个RAG基线系统时用一用正式项目基本不会拿它当最终方案。2.2 递归字符分块Recursive Character Text Splitter我默认的基线方案LangChain里有个RecursiveCharacterTextSplitter它和固定分块最大的不同在于它不是按固定长度硬切而是按分隔符的优先级递归地去找“尽量接近chunk_size”的切点。它内部维护了一个分隔符列表通常是[\n\n, \n, 。, , , ]切分逻辑是先用最粗粒度的段落分隔符\n\n把文本切成块如果某一块还是超过chunk_size就降级用\n继续切再不行用句号、逗号、空格最后才用字符级别硬切。from langchain.text_splitter import RecursiveCharacterTextSplitter text_splitter RecursiveCharacterTextSplitter( chunk_size500, chunk_overlap50, separators[\n\n, \n, 。, , , ], length_functionlen, ) chunks text_splitter.split_text(document)这套顺序的逻辑很强它的本质是“优先保住段落完整再保句子完整实在不行才牺牲语义”。所以在绝大多数没有专门结构标记的通用文本上递归字符分块是性能最稳、适用面最广的baseline。我统计过自己经手的十几个RAG项目初期用递归分块跑出来的效果基本都能达到最终调优方案的70%到80%。但注意它仍然是一种“纯文本结构”的分块不是“语义”的分块。它认为\n\n和句号是语义边界实际上很多语义转折发生在连续段落之间或者同一个自然段内部这种情况它就无能为力了。2.3 chunk_size和overlap该怎么调很多人以为chunk_size越大越好因为“放进去的上下文多”这其实是个误区。embedding模型在计算长文本向量时会把整个句子的语义压成一个向量文本越长信息被“平均化”得越严重关键词的语义可能被稀释掉。而LLM生成答案时又需要看到足够多的上下文所以要在这两者之间找一个平衡。不同场景下我常用的起始值可以参考这张表文本类型起始chunk_sizetoken口径overlap短问答、FAQ条目12816通用文章、技术文档51250长报告、政策文件800-1000100代码仓库文档40040注意这里说的是token口径中文场景下一个token大约对应0.6到1个汉字所以如果你用字符数来写chunk_size500字符大约等价于300多个token。调参的正确步骤是先固定一个方案按这个表试3到4组不同的chunk_size把检索命中率记录下来再决定要不要继续往细调。不要一开始就在overlap上花时间overlap只是微调手段chunk_size才是主要杠杆。3. 结构感知分块让文档自己的骨架来帮你切3.1 Markdown和HTML标题层级天然就是chunk边界如果你处理的是带标题结构的文档Markdown笔记、HTML页面、Wiki、企业知识库里导出的富文本那再傻乎乎地用固定长度切就太浪费了。这类文档本身就有章节结构标题就是天然的语义边界按标题层级切分出来的块几乎和人类划分的“主题块”完全吻合。LangChain里提供了MarkdownHeaderTextSplitter它的工作方式是先把Markdown文档按标题级别H1到H4解析成一棵树然后根据你指定的标题层级组合来决定哪些内容合到同一个chunk里。from langchain.text_splitter import MarkdownHeaderTextSplitter headers_to_split_on [ (#, H1), (##, H2), (###, H3), ] splitter MarkdownHeaderTextSplitter(headers_to_split_onheaders_to_split_on) splits splitter.split_text(markdown_document)最终每个chunk还自带metadata包含它所属的H1/H2/H3标题路径。这段metadata非常有用后面检索的时候可以把它拼进重排结果里也可以当成文档范围的筛选条件。类似的逻辑在HTML文档里就变成了按h1、h2、section、p标签来切PDF则有一些工具能识别段落和页眉页脚。总的思路是先按文档自身的结构层级做粗切如果切出来的某个段落还是太长再下探到递归字符分块去处理。这种“结构优先文本兜底”的组合是我做知识库类项目最常用的策略之一。3.2 结构化文档分块的三个坑结构感知分块不是没有代价。第一个坑是文档结构质量参差不齐很多企业导出的Markdown标题层级混乱三级标题直接跳到一级或者PDF解析出来的是无结构文本流。这种情况必须先清洗再分块否则结构感知方案还不如递归分块稳定。第二个坑是表格内容。表格在Markdown和HTML里通常是一个整体如果按页面上某个标题切分表格很容易被拦腰截断。我的习惯是分块之前把表格提取出来独立成chunk或者把表格整体转换为文本描述比如“某表列包括XX行为XX”保证表格的语义作为一个整体参与embedding。第三个坑是过长的叶子节点。一个章节下面如果是一整篇上千字的论述单纯按标题切出来的块仍然会超长。所以我一般会在结构分块之后再加一道长度约束超过max_chunk_size的块再递归切一次确保每个块的长度可控。提示结构感知分块不是“识别标题”这么简单它真正的价值在于产出的metadata。检索阶段把这些metadata拼进重排特征里可以明显提升命中的准确率。4. 语义分块与句子窗口从语义转折点下手4.1 语义分块Semantic Chunking让embedding告诉你哪里该断前面的方案都是在“文本表面”上切语义分块则是直接计算相邻句子的向量相似度把相似度高语义连续的句子合并成一个块把相似度骤降语义转折的位置作为chunk边界。完整流程是这样的先把文档拆成句子用句号、问号、感叹号分句。按顺序取连续的句子用embedding模型算出每个句子的向量。计算相邻句子之间的余弦相似度。从similarity_threshold比如0.6往下滑相似度低于阈值的位置就是语义边界。合并边界之间的句子成为一个chunk。用伪代码表示就是sentences split_into_sentences(document) vectors [embedding_model.encode(s) for s in sentences] similarities [cosine_similarity(vectors[i], vectors[i1]) for i in range(len(sentences)-1)] threshold 0.6 chunks [] start 0 for i, sim in enumerate(similarities): if sim threshold: chunks.append(.join(sentences[start:i1])) start i1 chunks.append(.join(sentences[start:]))实现上唯一要留意的是阈值怎么定。阈值太高chunk会切得很碎导致上下文不完整阈值太低chunk会把几个主题不同的段落并到一起。我一般建议先用0.5到0.7之间的几个档位做快速实验拿一批标注过的问题看哪个阈值下命中率最高。另外句子粒度的embedding最好用专门针对短文本优化的模型通用embedding模型对短句子的分辨力参差不齐。语义分块是七种方案里“最符合直觉”的它以语义连贯性为依据而不是用字符数硬切。但它有两个硬伤调用embedding的次数大幅增加长文档的切分耗时是递归分块的几倍到十几倍而且边界位置对阈值非常敏感抖动比较明显。所以它更适合离线构建知识库的场景不适合实时流式进来的数据。4.2 句子窗口分块Sentence Window检索单句补全上下文句子窗口分块的核心思路是索引的时候以单句为最小检索单位但把每句话前后各N句的上下文一并存起来检索命中的时候把窗口内的句子都取出来拼给LLM。这种做法在LlamaIndex里叫SentenceWindowNodeParser参数就两个sentence_id和window_size。索引阶段每条记录包含一个句子本体和它周围的窗口句子检索阶段先找到最匹配的那个句子再把它所在窗口的完整内容输出给LLM。from llama_index.core.node_parser import SentenceWindowNodeParser node_parser SentenceWindowNodeParser.from_defaults( window_size3, window_metadata_keywindow, original_text_metadata_keyoriginal_text, )它的优势很明显单句的embedding向量非常聚焦能精确定位关键信息而窗口机制保证了LLM看到的不是孤零零的一句话而是带上下文的完整片段。它的短板是“窗口大小”仍然是个需要凭经验调的数窗口太大就失去了单句检索的精度优势窗口太小又回到上下文割裂的老问题上。我把句子窗口归到语义分块这一类的理由是它本质上承认了一个前提——连续句子之间的语义关联是理解上下文的关键它用“相邻即相关”这个假设近似了真正的语义相关性属于语义分块的轻量替代。实测下来它在FAQ和短文本问答场景的表现很好但对长文档跨段落的知识召回效果不如后面要说的父子分块。5. 父子分块Parent-Child / Small-to-Big检索精度与上下文完整度兼得5.1 双通道映射小片段用于检索大片段用于生成父子分块是目前工业界和学术界都普遍认可的一种“效果与复杂度兼顾”的方案。它的核心思路是用两个粒度的chunkchild块小做检索parent块大做上下文供给。具体流程是这样的先把文档切成较大粒度的parent块比如800 token。对每个parent块再细分成若干个child块比如200 token。给child块做embedding存入向量库parent块不参与检索匹配只存原始文本维护child_id到parent_id的映射关系。检索时query先匹配到child块然后通过映射找到对应的parent块把整个parent块内容拼进prompt传给LLM。这个方案的精妙之处在于它把“定位”和“理解”解耦了。小chunk的向量语义聚焦检索命中位置更准大chunk提供完整上下文LLM生成答案时信息足够。映射关系就是中间的桥梁。from llama_index.core.node_parser import HierarchicalNodeParser, get_leaf_nodes # 粗切父块 node_parser HierarchicalNodeParser.from_defaults( chunk_sizes[800, 400, 200], # 从父到子逐级切分 ) nodes node_parser.get_nodes_from_documents(documents) # 只把最底层的叶子节点child拿去embedding检索 leaf_nodes get_leaf_nodes(nodes)如果你用的是LangChain也有ParentDocumentRetriever可以帮你省掉手动建映射的步骤。我在项目里做过一次对比测试同一个知识库文档集递归分块的检索命中率约68%父子分块直接把命中率拉到82%左右。代价是索引阶段的embedding调用次数变多存储也有一些冗余但这点工程成本相比收益完全值得。5.2 父子分块工程化时容易被忽略的细节第一个细节是parent块的大小直接决定“上下文增益”够不够。parent切得太小补全上下文的意义就没了切得太大有可能把不相关的内容也塞进prompt反而干扰答案生成。我建议parent块设定在生成模型单次输入窗口的1/4到1/3比较合适比如模型窗口是4k tokenparent取800到1200 token。第二个细节是child块必须继承parent的metadata。比如parent块里有文档标题、章节路径这些信息要跟着child去走检索否则检索命中了child你也不知道它属于哪一篇文档在做一个跨文档的问答场景时就没法做来源回溯。第三个细节是检索hybrid化。父子分块本身已经解决了粒度的矛盾如果再叠加关键词检索BM25和向量检索的多路召回扛干扰能力会更强。我在政务类知识库项目里就是“父子分块BM25向量检索Rerank”的组合实测下来复杂问题的端到端准确率比单路向量检索高了12个百分点左右。6. 第七种方案让LLM参与断句的Agentic Chunking6.1 把断句权力交给模型七种方案里最后一种严格来说不算一个标准算法而是一种思路上的跃迁让LLM自己决定哪里是语义边界。有人管它叫“Agentic Chunking”或“LLM-based Chunking”理由是现在的语言模型已经能较好地理解文本结构那为什么不让模型来帮我们判断一个知识块从哪里开始、在哪里结束做法不复杂把一份长文档的若干段落一步步喂给LLM同时告诉模型当前已经累积了哪些内容让模型判断“如果继续累加下一个自然段语义主题是否发生了变化”。如果模型认为主题变了就在当前段落末尾断开生成一个新的chunk。整个流程类似一个“增量累积”的状态机def agentic_chunking(documents, llm): chunks [] cur_text for para in documents: prompt f当前内容块:\n{cur_text}\n\n下一个段落:\n{para}\n\n如果追加这个段落后内容主题发生了切换回答boundary否则回答continue。 resp llm(prompt) if resp.strip() boundary and cur_text: chunks.append(cur_text) cur_text para else: cur_text \n para if cur_text: chunks.append(cur_text) return chunks这个方案的理论上限很高因为它是真正站在“语义内容”而非“文本表面”的角度去切分特别适合那些自然段之间语义跳跃大、但又没有显式标题结构的文本比如演讲稿、访谈记录、论文的长段落。6.2 Agentic Chunking的代价与折中说实话我不建议大多数生产环境直接全量上Agentic Chunking。原因很现实切分一次文档要频繁调用LLM成本高、延迟明显而且结果有随机性同样的文档跑两次可能得到不同的chunk边界。我在一个知识库项目里试过对1000份政策文件做Agentic Chunking耗时比递归分块多了将近30倍花了几十块钱的token费用而评测集上的命中率提升并不显著——因为政策文件本身标题结构很完整结构感知分块已经能处理得很好。所以我的真实建议是Agentic Chunking更适合做“高价值文档”的精细化处理比如核心知识文档、法律合同、咨询报告这类需要严谨分块的内容可以走Agentic分块而日常的海量文档仍然用递归分块或结构感知分块兜底。同时可以设置一个缓存机制对已经分块过的文档直接复用结果避免重复调用。7. 七种分块方案的横向对比与决策路径7.1 一张表看完七种方案为了让你一眼看到差异我直接做个汇总方案原理依据优点缺点典型场景工程成本固定大小分块字符/token数简单、可控、零依赖语义断裂严重日志、流水文本、快速基线极低递归字符分块分隔符优先级通用性好、实现简单、保句完整无句法语义理解通用文本、技术文档默认选择低结构感知分块标题/标签层级符合人类阅读习惯、产出metadata依赖文档结构质量Markdown/HTML/企业知识库低语义分块句子向量相似度语义边界准确块内主题一致计算量大阈值敏感长文档离线库、内容主题变化大的文本中高句子窗口分块单句向量上下文窗口检索聚焦、上下文补全窗口大小需调、跨段落后劲不足FAQ、短文本问答中父子分块小块检索大块供给精度与上下文兼得、扩展性好索引耗时、需维护映射开放问答、长文档、企业知识库主力方案中Agentic ChunkingLLM语义判断接近人工分块质量成本高、延迟大、有随机性高价值文档精细化处理高7.2 我的选型决策路径在很多内部交流里总有人问“到底用哪种好”。我一般不给死答案而是给一条决策路径按顺序做判断先看文档类型。如果文档自带清晰标题结构直接上结构感知分块如果是一堆无结构长文先用递归分块跑通流程拿到召回评测数据。再判断问答形式。如果用户的问题是“某条款的具体内容是什么”这类需要有明确出处的父子分块基本是首选如果问题是“根据这几段话总结一下”这类要跨越多个部分结构感知或语义分块更合适。最后看成本约束。如果对索引实时性要求高比如文档不断上传、需要尽快完成向量化语义分块和Agentic分块就得往后放优先选递归分块或结构感知分块。8. 我在真实项目里的调优经验与验证方法8.1 没有评测集一切分块方案都是玄学这是我最想强调的一点分块选型必须用评测集验证不能靠感觉。我见过太多团队在这个环节拍脑袋定参数上线后效果靠运气。我的习惯是每次接到一个新的RAG项目先抽出30到100个真实用户问题人工标注好标准答案所在的文档位置跑一遍“检索命中率”的基线。然后在这套评测集上试不同分块方案和参数选出最优组。评测集怎么用呢具体操作是跑完检索后检查标准答案所在的那个chunk有没有出现在top-k结果里如果命中了再看它在top几。这个指标我一般记录成“Top1命中率”“Top5命中率”比单纯看LLM回答的对错更可靠——因为即使检索命中了LLM也可能因为prompt问题答错但你至少能定位到问题出在检索层还是生成层。8.2 分块之后的小数据调整比换方案更快在实际项目中同一个知识库往往是混合文档——有Markdown手册、有PDF合同、有爬取的网页正文。对这种情况我的建议是做“分层处理”先按文档类型各走各的分块方案再在入库时用统一的metadata标注来源类型。这样检索的时候既可以全局搜索也可以按来源类型过滤灵活度会高很多。另外一个很实用的小技巧是分块之前先做文档清洗。很多分块效果差不是分块方案的问题而是原始文本里有大量无意义的换行、空格、页面页脚重复内容导致分隔符优先级判断失误。我用递归分块之前通常会先用正则把多余空白行压缩掉把段内的人工换行替换成空格分块效果立刻就能提升一截。8.3 最后分享一个我自己项目的实测感受从去年到今年我把手头几个知识库项目的分块策略全部梳理了一遍最主要的体会是不要执念于找“最好”的分块方案而要建立“分块→评测→调参”这个闭环。分块本身就是一个信号压缩的过程无论多高级的方案都无法百分之百保留原文全部语义所以选题的核心其实是保证“这个块被召回的概率”和“这个块的上下文信息量”之间的最优配置。如果非要说一个通用结论我现在对新项目的默认策略是基线用递归字符分块配上父子分块的映射兜底文档结构可靠的场景叠加上结构感知分块评测集上表现不够再考虑语义分块或Agentic Chunking。这个策略让我在大多数项目里都能快速跑出一个效果不差的RAG系统剩下的时间基本都花在调chunk_size、overlap和重排策略这些真正的收尾环节上。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询