最近在用LangChain+OpenAI做一个内部文档问答的RAG demo,语料是混合型技术文档,有代码、有markdown表格、还有流程图。目前直接用固定长度chunk(500 tokens,overlap 50),检索出来的top5经常不相关,明明文档里就有答案。我试过调大chunk size,但跨段落语义割裂更严重;调小又觉得信息不完整。想请教下各位,大家生产环境里一般用什么切分策略?是按标题/段落结构切,还是用基于语义的递归切分?另外chunk之间overlap一般留多少比较合适?如果后续还要做rerank,chunk大小和检索结果topk之间要怎么配合?希望有踩过坑的大佬指点下,谢谢。
Chunking策略对RAG效果影响大吗?试了固定切分效果很差
全部回复
共 63 条固定长度切分对混合文档确实容易翻车,尤其代码和markdown表格这种结构信息强的,500token直接把语义切碎了。我生产里用的递归字符切分,优先按标题和代码块边界走,markdown表格单独识别成块,overlap大概留80-100token,这样检索命中率明显稳。rerank的话建议chunk别太小,800-1000token配top20召回,给重排留足上下文,不然重排模型也没法判断。你那个流程图是不是被当成普通文本切了?可以试试先按视觉块提取再拼回文本,不然内容再准也搜不出来。
混合型文档真别用固定长度切,代码和markdown表格的语义边界跟自然语言完全不一样。我生产环境里用LangChain的RecursiveCharacterTextSplitter按分隔符优先级递归切,代码块和表格基本能保住完整性,overlap设100左右效果还行。你试试按标题结构先分块再对长块递归切,检索topk可以先拉20,rerank后取5,这样即使前期召回有噪声也能靠重排兜底。另外流程图建议单独抽出来用多模态embedding,不然纯文本切碎后基本就是废数据。
固定长度切分在混合文档上基本就是碰运气,代码块和表格被拦腰截断后,语义直接碎成渣。我之前试过按标题结构切,但技术文档里标题层级经常不规范,反而把流程图拆得乱七八糟。后来改成递归切分,先按段落再按句子边界兜底,效果比固定长度稳不少,至少top5里能出相关结果了。
overlap我觉得不用太纠结,10%-15%就够,主要防止边界切断关键词,太大反而让重复内容干扰向量相似度。真正影响大的是chunk大小和embedding模型的适配性,比如bge或者text-embedding-3-small,对不同长度文本的区分度不一样,你可以拿自己的语料跑个曲线看看。
rerank的话,我建议chunk可以稍微大一点,保证上下文完整,但topk先拉高到20-30,让rerank去精排,不然top5里全是半截信息,rerank也救不回来。另外可以试试把代码和文本分开建索引,不同块走不同切分策略,虽然麻烦点但效果提升明显。
还有个坑,LangChain默认的text_splitter对markdown表格支持很差,你可以自己写个splitter,识别表格和代码块后整体保留。你现在的chunk size和overlap具体是多少?有没有试过检索前先做个query改写?有时候不是切分的问题,是query和文档的表述方式差异太大。