最近在搭一个基于本地知识库的RAG问答系统,用的bge-large-zh做embedding,chunk_size试了256和512,结果中文长文本经常把完整句子或者逻辑段落切碎,比如“根据《数据安全法》第二十一条”被拆成两半,检索时匹配率很低。试过加overlap,但感觉治标不治本。想问下大家,有没有针对中文语义的chunk策略?或者用递归字符分割器时,separators怎么设比较合理?顺便求推荐对中文友好的分块工具,感谢!
部署RAG时中文分块总是切碎语义,大家怎么调chunk参数的?
全部回复
共 145 条中文分块确实不能照搬英文那套按token硬切,我也踩过这个坑。你试下用LangChain的RecursiveCharacterTextSplitter,把separators改成["\n\n", "\n", "。", ";", ",", ""],让它在句子边界优先断,实在不行再往逗号甚至字级别退。不过说实话,光靠分隔符还不够,中文法律条文、技术文档这种结构化文本,最好先按标题或条款正则预切一层,再用递归分割。chunk_size我一般建议300到400之间配bge-large-zh,512容易把两三个语义段混一起,检索时噪声反而大。overlap设成chunk的10%到15%就行,别太多,否则重复内容会挤占召回名额。另外你可以试试semantic-text-splitter或者chonkie这类按语义相似度动态切的库,对中文比纯字符递归友好不少。如果预算允许,用一个小模型先做句子级embedding再合并相邻高相似句,效果比调参明显。
我之前也踩过这个坑,光调chunk_size真不够,中文得从分隔符下手。你可以把separators设成 ["\n\n", "\n", "。", "!", "?", ";", ","],优先按句号问号切,实在超长再降级到逗号,这样基本不会把“第二十一条”那种切断。另外建议试试LangChain的ChineseRecursiveTextSplitter或者直接用语义分块,按embedding相似度找断点,比死磕字符数靠谱多了。
我一般按中文标点切,句号问号优先,再不行才切逗号,效果比死磕chunk_size好很多。
我也踩过这个坑,256和512切中文确实容易断句。后来我换成按标点递归切,separators设成["\n\n", "\n", "。", "!", "?", ";", ","],优先在句号问号这些地方断开,效果好了不少。overlap我一般设成chunk_size的10%到15%,别太大不然冗余检索很烦。另外你可以看看langchain的ChineseRecursiveTextSplitter,或者干脆按段落先粗分再控长度,比硬切强。
中文分块确实头疼,我一般会先用标点做一级切分,再按语义段落合并,别死磕固定size。separators里把“。!?”和“;”放前面,再配合“\n\n”做段落边界,效果会好不少。另外langchain的ChineseRecursiveTextSplitter可以试试,对中文标点更友好。overlap其实调成chunk的10%-15%就够了,太大反而检索噪声多。