最近在搭一个本地知识库问答,用的bge-m3做embedding,向量库是Milvus。文档是那种技术手册,有标题、段落和代码块。我目前按固定512字符切块,重叠64——但查起来经常召回一些不相关的内容,比如问“如何配置超时时间”,返回的却是某个函数参数说明里带“timeout”的代码块。我怀疑是不是纯按长度切块把语义割裂了,但换语义切块又不知道怎么处理代码和表格混排的情况。有没有老哥指点下,RAG的分块策略一般怎么根据文档结构来定?或者有没有好用的库能自动识别标题层级来切?感谢!
RAG检索老召回不相关片段,是不是我分块方式有问题?
全部回复
共 50 条纯按长度切确实容易把语义切碎,尤其是技术手册里一个参数说明可能横跨好几段。你问超时配置却召回带 timeout 的代码块,大概率是 chunk 里代码和解释混一起了,embedding 抓到的只是关键词。可以试试按标题层级切,再用小模型对每个 chunk 做摘要或加标题前缀,召回会准不少。代码块和表格最好单独成块,别和正文硬拼。LangChain 的 MarkdownHeaderTextSplitter 能识别标题层级,但混排文档还是得自己写点规则兜底。
按标题层级切确实更靠谱,代码块单独拎出来别混进正文,不然timeout老被误召回。
可以试试按标题层级切,代码块和表格单独拎出来别硬切,llama_index的HierarchicalNodeParser能自动识别结构。
有没有更详细的教程推荐?
这个思路不错,收藏了。
刚入门,这个对我帮助很大。
学到了,感谢分享!
固定长度切块确实容易把代码和上下文割开,尤其技术手册里标题层级本身就是天然语义边界。可以试试按markdown标题递归切分,代码块和表格用fence保护起来整块保留,langchain的MarkdownHeaderTextSplitter或者unstructured都能识别层级。另外召回不准不一定全是分块的锅,bge-m3对短查询和长片段的匹配本来就有偏差,加个rerank模型过滤一下效果会明显不少。
学到了,感谢分享!
固定512切块确实容易把语义切碎,尤其技术手册里标题和正文分开后,embedding就丢了上下文。我一般先用标题层级做粗切,再把代码块和表格单独拎出来不参与语义切分,正文段落再用语义切块,效果会好不少。库的话可以看看langchain的MarkdownHeaderTextSplitter,或者unstructured能识别文档结构,配合bge-m3用还挺省事。