RAG检索质量差?这5种分块策略帮你解决70%的问题

简介: RAG效果关键在于文档分块:固定、递归、语义、结构化与延迟分块各有优劣。合理选择能显著提升检索质量,减少幻觉,增强上下文理解,是构建高效RAG系统的核心环节。

RAG 的关键其实就在检索这一步:检索质量好不好,很大程度上取决于怎么切分和存储文档——也就是分块(Chunking)这个看起来不起眼的环节。

固定分块、递归分块、语义分块、结构化分块、延迟分块,每种方法在优化上下文理解和检索准确性上都有各自的价值。用对了方法,检索质量能提升一大截,幻觉问题也会少很多。

RAG 的效果很依赖文档拆分的方式。这篇文章会先过一遍 RAG 的基本流程,然后重点讲分块在里面扮演什么角色,接着深入聊聊固定、递归、语义、基于结构和延迟这五种分块技术的定义、平衡点和实现思路,方便你根据实际场景选择合适的方案。

RAG 工作流程概览

标准流程是这样的:

文档摄取和分块 拿到大文档(PDF、HTML、纯文本)→ 切分成小块 → 算嵌入向量 → 扔进向量数据库。

查询检索 用户提问 → 把问题转成向量 → 用余弦相似度找出最相关的 top-k 个块

上下文增强 把检索到的块和元数据塞进 LLM 的 prompt 里,通常会用模板做些处理和筛选。

答案生成 LLM 根据检索内容加上自己的知识生成回答。

生成器只能看到你喂给它的东西,所以检索质量直接决定了最终效果。块切得不好或者根本检索不到相关内容,再强的 LLM 也救不回来。这也是为什么业内普遍认为 RAG 大概 70% 靠检索,30% 靠生成。

在讲具体技术之前,得先明白为什么分块这么重要:

嵌入模型和 LLM 都有上下文长度限制,没法直接塞整个文档进去;块必须语义完整。要是在句子中间或者一个完整意思的中间切断,嵌入向量就会带噪声甚至产生误导;块太大的话,相关的细节信息容易被淹没;反过来块太小或者重叠太多,就会存大量冗余内容,浪费算力和存储。

下面按从简单到复杂的顺序,聊聊五种主流的分块方法。

1、 固定分块

最直接的做法:按固定长度(token、词或字符)切文本,块与块之间留一些重叠部分。

这是 RAG 项目的常见起点,特别适合文档结构未知或者内容比较单调的场景(比如日志、纯文本)。算是一个不错的 baseline。

代码实现示例:

 def fixed_chunk(text, max_tokens=512, overlap=50):  
    tokens = tokenize(text)  
    chunks = []  
    i = 0  
    while i < len(tokens):  
        chunk = tokens[i : i + max_tokens]  
        chunks.append(detokenize(chunk))  
        i += (max_tokens - overlap)  
     return chunks

2、递归分块

先按高层级的边界拆(段落或章节),如果某个块还是超长了,就继续往下拆(比如按句子),直到所有块都符合大小限制。

适合有一定结构的文档(带段落、章节的那种),既想保持语义边界完整,又要控制块的大小。

好处是能尽量保留段落这种逻辑单元,不会在奇怪的地方切断,而且能根据内容自动调整块的大小。

用 LangChain 实现递归分块:

 from langchain.text_splitter import RecursiveCharacterTextSplitter  

# Sample text
text = """  
Input text Placeholder...  
"""  

# Define a RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(  
    chunk_size=200,           # target size of each chunk
    chunk_overlap=50,         # overlap between chunks for context continuity
    separators=["\n\n", "\n", " ", ""]  # order of recursive splitting
)  

# Split the text
chunks = text_splitter.split_text(text)  

# Display results
for i, chunk in enumerate(chunks, 1):  
     print(f"Chunk {i}:\n{chunk}\n{'-'*40}")

这样做能确保后续做嵌入和检索的时候,不会在边界处丢失关键上下文。

3、语义分块

根据语义变化来切分文本。用句子级别的嵌入来判断哪里该结束一个块,哪里该开始下一个。相邻句子如果语义相近就放一起,相似度明显下降了就切开。

在检索精度要求高的场景特别有用(法律文本、科研论文、技术支持文档之类的)。不过计算嵌入和相似度有成本,而且相似度阈值的设定需要反复调试。

代码实现:

 from sentence_transformers import SentenceTransformer, util  

model = SentenceTransformer("all-MiniLM-L6-v2")  

def semantic_chunk(text, sentence_list, sim_threshold=0.7):  
    embeddings = model.encode(sentence_list)  
    chunks = []  
    current = [sentence_list[0]]  
    for i in range(1, len(sentence_list)):  
        sim = util.cos_sim(embeddings[i-1], embeddings[i]).item()  
        if sim < sim_threshold:  
            chunks.append(" ".join(current))  
            current = [sentence_list[i]]  
        else:  
            current.append(sentence_list[i])  
    chunks.append(" ".join(current))  
     return chunks

4、基于结构的分块

利用文档本身的结构——标题、子标题、HTML 标签、表格、列表这些——作为天然的分块边界。比如每个章节或标题自成一块(必要时也可以继续递归拆分)。最适合处理 HTML 页面、技术文档、维基类内容,或者任何有明确语义标记的材料。

从实际经验来看,这种策略效果最好,尤其是配合递归分块一起用的时候。

但前提是得先解析文档格式,而且对于特别长的章节,可能还是会超出 token 限制,这时候就需要混合使用递归拆分了。

实现要点:

  • 用专门的库解析 HTML / Markdown / PDF 结构
  • 把章节标题(<h1><h2> 之类的)当作块的根节点
  • 某个章节太长的话,退回到递归拆分
  • 表格和图片可以单独成块,或者做一下摘要处理

5、延迟分块(也叫动态分块或查询时分块)

什么是延迟分块:把文档拆分这件事推迟到查询时再做

不是一开始就把所有东西切碎,而是存储比较大的片段甚至整份文档。等查询来了,只对相关部分做动态拆分或筛选。核心思路是在做嵌入的时候保留完整上下文,只在确实需要的时候才切分。

Weaviate 的说法是把这叫做"反转传统的嵌入和分块顺序"。

先用支持长上下文的模型对整个文档(或大段落)做嵌入。然后基于 token 范围或边界标记,池化生成块级别的嵌入。

具体流程

  1. 在索引里存储大段落或完整文档。
  2. 查询来了,先检索出 1-2 个最相关的大段。
  3. 在这些段落内部,围绕匹配查询的部分动态切分(可以用语义或重叠的方式)成更细的块。
  4. 对这些细块做过滤或排序,最后喂给生成器。

有点像编程里的延迟绑定,等有了更多上下文信息再做决定。

适用场景

  • 大型文档集(技术报告、长文)里,跨段落的上下文关联很重要的情况。
  • 文档经常更新的系统,不用每次都完整重新分块,能省不少时间。
  • 高精度要求或高风险的应用(法律、医疗、监管类),代词或引用理解错了代价很大的那种。

听起来挺理想,但代价也摆在那。嵌入整个文档或大段内容,计算开销相当大,而且需要支持长 token 的模型。查询时的计算成本也会增加,可能影响响应速度。

写在最后

分块这件事看着不起眼,但实际上直接决定了 RAG 系统的上限。固定分块简单粗暴适合快速验证;递归分块在保持语义完整性上更有优势;语义分块精度高但成本也高;结构化分块对特定类型文档效果最好;延迟分块则是在计算资源充足时的高级玩法。

没有哪种方法是银弹。实际项目里往往需要根据文档类型、查询特点、资源限制来组合使用。比如技术文档用结构化分块打底,长篇报告考虑延迟分块,日常问答系统可能固定或递归分块就够了。

https://avoid.overfit.cn/post/aa5e48e682a746bba4b22af0a2257775
作者:Ahmed Boulahia

目录
相关文章
|
3月前
|
存储 机器学习/深度学习 人工智能
RAG系统嵌入模型怎么选?选型策略和踩坑指南
嵌入是RAG系统的核心,直接影响检索质量。本文详解嵌入原理,解析稠密/稀疏、长上下文、多向量等类型,梳理选型关键:领域匹配、上下文长度、维度与成本,并结合MTEB基准给出实用建议,助你为业务挑选高效稳健的嵌入方案。
601 2
RAG系统嵌入模型怎么选?选型策略和踩坑指南
|
3月前
|
存储 机器学习/深度学习 人工智能
​​解锁AI检索的7大Embedding技术:从稀疏到多向量,一文掌握!​
本文系统解析七种主流文本嵌入技术,包括 Sparse、Dense、Quantized、Binary、Matryoshka 和 Multi-Vector 方法,结合适用场景提供实用选型建议,助你高效构建文本检索系统。
454 0
|
3月前
|
人工智能 运维 API
高级RAG优化手册:3招解决检索不准和查询模糊
本文深入解析RAG(检索增强生成)技术的核心优化方法,涵盖背景、架构与实践。RAG通过整合外部知识库,弥补大语言模型在实时性、准确性和专业性上的不足,广泛应用于企业场景。文章系统讲解RAG如何解决知识静态、生成幻觉与专业深度不足等问题,并剖析其离线索引与在线生成的闭环流程。此外,还介绍了高级优化策略,如查询重写、混合检索与结果重排序,助力突破RAG应用瓶颈。
763 1
|
3月前
|
机器学习/深度学习 人工智能 机器人
文本分块大揭秘,五种境界让你的RAG系统从菜鸟变大神
如果你的AI应用程序返回的答案总是不着边际,问题可能出在文本分块上!本文用轻松幽默的方式,带你玩转从基础到高级的五种文本分块策略,让你的RAG系统检索效率提升10倍。无论你是RAG新手还是老手,这篇文章都能让你事半功倍!
|
6月前
|
存储 自然语言处理 算法
RAG系统文本分块优化指南:9种实用策略让检索精度翻倍
本文深入探讨了RAG系统中的九种文本分块策略。固定大小分块简单高效,但可能破坏语义完整性;基于句子和语义的分块保留上下文,适合语义任务;递归与滑动窗口分块灵活控制大小;层次化和主题分块适用于结构化内容;特定模态分块处理多媒体文档;智能代理分块则通过大语言模型实现动态优化。开发者需根据文档类型、需求及资源选择合适策略,以提升RAG系统的性能和用户体验。作者Cornellius Yudha Wijaya详细分析了各策略的技术特点与应用场景。
1324 1
RAG系统文本分块优化指南:9种实用策略让检索精度翻倍
|
4月前
|
人工智能 自然语言处理 算法
提升LangChain开发效率:10个被忽视的高效组件,让AI应用性能翻倍
LangChain作为主流大语言模型应用框架,其高级组件常被忽视。本文详解10个高价值但低使用率的核心组件,如语义检索、多模板路由、智能查询转换等,结合技术原理与实践案例,助开发者构建更高效、智能、适应性强的AI系统,提升应用性能与业务价值。
359 0
|
2月前
|
存储 人工智能 搜索推荐
LangGraph 记忆系统实战:反馈循环 + 动态 Prompt 让 AI 持续学习
本文介绍基于LangGraph构建的双层记忆系统,通过短期与长期记忆协同,实现AI代理的持续学习。短期记忆管理会话内上下文,长期记忆跨会话存储用户偏好与决策,结合人机协作反馈循环,动态更新提示词,使代理具备个性化响应与行为进化能力。
537 10
LangGraph 记忆系统实战:反馈循环 + 动态 Prompt 让 AI 持续学习
|
1月前
|
机器学习/深度学习 人工智能 自然语言处理
构建AI智能体:十二、给词语绘制地图:Embedding如何构建机器的认知空间
Embedding是一种将词语、图像等信息转化为低维稠密向量的技术,使计算机能捕捉语义关系。不同于传统One-Hot编码,Embedding通过空间距离表达语义相似性,如“国王-男人+女人≈王后”,广泛应用于NLP、推荐系统与大模型中,是AI理解世界的基石。
539 13
|
2月前
|
安全 API
LlamaIndex检索调优实战:分块、HyDE、压缩等8个提效方法快速改善答案质量
本文总结提升RAG检索质量的八大实用技巧:语义分块、混合检索、重排序、HyDE查询生成、上下文压缩、元数据过滤、自适应k值等,结合LlamaIndex实践,有效解决幻觉、上下文错位等问题,显著提升准确率与可引用性。
304 8
|
2月前
|
存储 自然语言处理 测试技术
开源嵌入模型对比:让你的RAG检索又快又准
嵌入是RAG系统的核心,将文本转化为语义向量,实现基于含义的检索。本文详解嵌入原理、关键参数及主流开源模型,助你根据分块大小、语言需求和性能约束,选择最合适的嵌入方案,提升RAG效果。
824 4
开源嵌入模型对比:让你的RAG检索又快又准