返回顶部
热门问答 更多热门问答
技术文章 更多技术文章

您应该为您的 RAG 系统使用哪种分块技术?

[复制链接]
链载Ai 显示全部楼层 发表于 2 小时前 |阅读模式 打印 上一主题 下一主题

在人工智能领域迅猛发展的今天,检索增强生成(RAG)系统已成为构建可靠且上下文感知应用的基石,这些应用由大型语言模型(LLM)驱动。RAG 系统通过检索外部知识库(如向量数据库)中的相关信息,来弥合 LLM 与外部知识之间的差距,从而提升模型的响应质量。然而,在实现高效 RAG 系统时,一个最关键却常常被忽略的步骤是“分块”(chunking)——即将大型文档分解成更小、更易消化的片段的过程。



为什么分块如此重要?LLM 的上下文窗口有限,通常限制了一次能处理的文本量。糟糕的分块策略可能导致上下文不完整、检索无关信息,甚至生成幻觉输出。相反,精心选择的分块策略能显著提升检索准确性、响应相关性和整体系统性能。事实上,分块对 RAG 效果的影响往往大于嵌入模型或向量存储的选择。

本文将探讨八种流行的分块策略,借鉴行业最佳实践。我们将涵盖每种策略的描述、优缺点、理想使用场景,以及适用的代码示例。最后,我们提供一个决策框架,帮助您为 RAG 系统选择合适的技术。

    ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;padding-left: 1em;margin-left: 0px;color: rgb(63, 63, 63);margin-top: 0px;" class="list-paddingleft-1">
  1. ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;display: block;margin: 0.2em 8px;color: rgb(63, 63, 63);">
    1. 固定大小分块(基于令牌或字符)

ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;margin: 1.5em 8px;letter-spacing: 0.1em;color: rgb(63, 63, 63);">固定大小分块是最简单的方法,将文本分割成预定义长度的块(例如 512 个令牌),并可选地添加重叠(10-20%)以保持边界间的上下文连续性。

ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;margin: 1.5em 8px;letter-spacing: 0.1em;color: rgb(63, 63, 63);">优点:实现简单、计算高效,适合快速原型开发。

ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;margin: 1.5em 8px;letter-spacing: 0.1em;">缺点:忽略语义结构,可能在句子或想法中间截断,导致上下文碎片化。

ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;margin: 1.5em 8px;letter-spacing: 0.1em;color: rgb(63, 63, 63);">何时使用:适用于统一的无结构数据,如日志、短笔记,或在实时应用中优先考虑速度而非精度。

ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;margin: 1.5em 8px;letter-spacing: 0.1em;color: rgb(63, 63, 63);">代码示例(Python):

ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;overflow-x: auto;border-radius: 8px;margin: 10px 8px;padding: 0px !important;">


fromtypingimportList



importre





defword_splitter(source_text:str) ->List[str]:



source_text = re.sub("\s+"," ", source_text)



returnre.split("\s", source_text)





defget_chunks_fixed_size_with_overlap(text:str, chunk_size:int, overlap_fraction:float=0.2) ->List[str]:



text_words = word_splitter(text)



overlap_int =int(chunk_size * overlap_fraction)



chunks = []



foriinrange(0,len(text_words), chunk_size):



chunk_words = text_words[max(i - overlap_int,0): i + chunk_size]



chunk =" ".join(chunk_words)



chunks.append(chunk)



returnchunks


ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;display: table;padding: 0px 0.2em;margin: 4em auto 2em;color: rgb(255, 255, 255);background: rgb(15, 76, 129);">2. 递归分块

ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;margin: 1.5em 8px;letter-spacing: 0.1em;color: rgb(63, 63, 63);">这种方法使用分隔符的层次结构(例如,双换行符分段落,然后单换行符分句子),递归地分割文本,直到块符合所需大小。

优点:比固定大小更尊重文档结构,减少了不自然的断点。

缺点:仍基于规则,可能无法捕捉深层语义;编码稍复杂。

何时使用:适用于半结构化文本,如博客文章、新闻或研究论文,这些文本存在逻辑断点。

代码示例(Python):




fromtypingimportList





defrecursive_chunking(text:str, max_chunk_size:int=1000) ->List[str]:



iflen(text) <= max_chunk_size:



return[text.strip()]iftext.strip()else[]



separators = ["\n\n","\n",". "," "]



forseparatorinseparators:



ifseparatorintext:



parts = text.split(separator)



chunks = []



current_chunk =""



forpartinparts:



test_chunk = current_chunk + separator + partifcurrent_chunkelsepart



iflen(test_chunk) <= max_chunk_size:



current_chunk = test_chunk



else:



ifcurrent_chunk:



chunks.append(current_chunk.strip())



current_chunk = part



ifcurrent_chunk:



chunks.append(current_chunk.strip())



final_chunks = []



forchunkinchunks:



iflen(chunk) > max_chunk_size:



final_chunks.extend(recursive_chunking(chunk, max_chunk_size))



else:



final_chunks.append(chunk)



return[chunkforchunkinfinal_chunksifchunk]



return[text[i:i + max_chunk_size]foriinrange(0,len(text), max_chunk_size)]


3. 内容感知分块

内容感知分块基于自然内容单元(如句子、段落或章节)进行分割,使用分隔符或 NLP 工具。

优点:保持逻辑完整性,提升检索相关性。

缺点:依赖一致的格式;对结构不良的数据无效。

何时使用:适用于格式化文档,如报告、书籍或法律文本。

代码示例:使用 NLTK 库进行句子分割:




importnltk



nltk.download('punkt')





defsentence_chunking(text:str) ->List[str]:



sentences = nltk.sent_tokenize(text)



returnsentences # 如需进一步组合以达到所需大小


4. 语义分块

这种高级技术使用嵌入来分组语义相似的句子或段落,通常通过余弦相似度阈值实现。

优点:确保块在上下文中连贯,提升 RAG 准确性。

缺点:嵌入计算导致高计算成本。

何时使用:适用于密集的技术内容,如科学论文或代码库,其中含义优先于结构。

代码示例:使用 sentence-transformers:




fromsentence_transformersimportSentenceTransformer, util





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





defsemantic_chunking(sentencesist[str], similarity_threshold:float=0.7) ->List[str]:



embeddings = model.encode(sentences)



chunks = []



current_chunk = [sentences[0]]



foriinrange(1,len(sentences)):



sim = util.cos_sim(embeddings[i-1], embeddings[i])



ifsim > similarity_threshold:



current_chunk.append(sentences[i])



else:



chunks.append(' '.join(current_chunk))



current_chunk = [sentences[i]]



chunks.append(' '.join(current_chunk))



returnchunks


5. 代理分块

利用 LLM 作为“代理”来智能确定块边界,基于提示进行操作。

优点:高度适应性且语义感知,无需固定规则。

缺点:因 LLM 调用而昂贵且缓慢;可能不一致。

何时使用:高价值场景,如自定义企业数据,精度至关重要。

代码示例:通过 OpenAI API 提示 LLM:




importopenai





defAgentic_chunking(text:str, max_chunk_size:int) ->List[str]:



response = openai.ChatCompletion.create(



model="gpt-4",



messages=[{"role":"user","content":f"将此文本分割成不超过{max_chunk_size}个字符的连贯块:{text}"}]



)



chunks = response.choices[0].message.content.split('\n\n') # 假设块由双换行符分隔



returnchunks


6. 滑动窗口分块

通过在文本上滑动窗口创建重叠块,确保连续上下文。

优点:捕捉边界间信息,减少信息丢失。

缺点:因冗余而增加存储和检索开销。

何时使用:叙事或序列数据,如故事、转录或时间序列日志。

代码示例:类似于固定大小,但步长可调:




defsliding_window_chunking(text:str, window_size:int, step:int) ->List[str]:



words = text.split()



chunks = []



foriinrange(0,len(words), step):



chunk =' '.join(words[i:i + window_size])



ifchunk:



chunks.append(chunk)



returnchunks


7. 层次分块

构建多级结构(例如,文档 > 章节 > 段落 > 句子),用于分层检索。

优点:启用灵活的多分辨率搜索。

缺点:设置和索引复杂。

何时使用:大型层次文档,如手册、维基或学术论文。

代码示例:表示为树状结构(简化):




# 使用 BeautifulSoup 等库解析 HTML 或自定义解析器处理层次



defhierarchical_chunking(document:dict) ->dict:



# 假设文档已解析成章节



hierarchy = {'sections': []}



forsectionindocument['sections']:



chunks = {'title': section['title'],'paragraphs': [pforpinsection['content'].split('\n\n')]}



hierarchy['sections'].append(chunks)



returnhierarchy


8. 延迟分块

一种新颖方法,首先在长上下文中生成嵌入,然后在嵌入后派生块,以保留完整上下文。

优点:更好地处理长依赖;对某些模型成本效益高。

缺点:需要兼容的嵌入模型;不普遍适用。

何时使用:与长上下文 LLM 一起使用,或处理相互连接的叙事,如小说或法律合同。

代码示例:使用专用 API(例如 Cohere):




importcohere





co = cohere.Client('your-api-key')





deflate_chunking(text:str) ->List[str]:



# 嵌入长文本,然后基于嵌入簇进行分割



response = co.embed(texts=[text], model='embed-english-v3.0')



embeddings = response.embeddings[0]



# 使用聚类(例如 KMeans)定义块



# 简化:假设后处理分割



return[text] # 实际实现的占位符


选择分块技术的决策框架

选择合适的分块策略取决于几个因素:

  • •文档类型和结构:无结构数据使用固定大小或递归;结构化数据使用内容感知或层次。
  • •计算资源:预算有限时从简单方法如固定大小开始;高性能设置选择语义或代理。
  • •性能要求:复杂查询的准确性优先语义或延迟分块;速度优先递归。
  • •数据量:大规模语料库适合层次;重叠上下文适合滑动窗口。
  • •评估:使用指标如检索召回率、精度或端到端 RAG 基准(例如 RAGAS 框架)测试策略。迭代实验——A/B 测试不同块大小和重叠是关键。

总之,没有一种分块技术适用于所有场景——最佳选择取决于您的数据和用例。通过理解这些策略并应用决策框架,您可以优化 RAG 系统以实现卓越性能。

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

链载AI是专业的生成式人工智能教程平台。提供Stable Diffusion、Midjourney AI绘画教程,Suno AI音乐生成指南,以及Runway、Pika等AI视频制作与动画生成实战案例。从提示词编写到参数调整,手把手助您从入门到精通。
  • 官方手机版

  • 微信公众号

  • 商务合作

  • Powered by Discuz! X3.5 | Copyright © 2025-2025. | 链载Ai
  • 桂ICP备2024021734号 | 营业执照 | |广西笔趣文化传媒有限公司|| QQ