最近在搭一个RAG问答系统,用的bge-large-zh,文档按512字硬切的chunk,向量库用的Milvus。测试时发现几个问题:一是问“某个接口怎么调用”,检索结果经常是文档里其他无关接口的内容;二是明明文档里有明确答案,但top-5召回里就是没有。调过top_k和相似度阈值,效果提升不大。目前有点怀疑是不是分块策略太粗暴了,还是说中文场景下bge系列其实不太够用?有没有人遇到过类似情况,一般先排查哪块?
RAG检索出来的东西不对,是分块粒度问题还是embedding模型选错了?
全部回复
共 63 条硬切512字太糙了,接口文档得按段落或标题切。先换个分块策略试试,bge-large-zh中文够用了。
我也踩过这个坑,512字硬切对接口文档来说基本是灾难级别的。你问“某个接口怎么调用”,答案可能就藏在一段代码示例或者参数说明里,硬切之后上下文直接断了,embedding出来的向量语义是残缺的,召回自然跑偏。bge-large-zh本身中文检索能力不差,问题多半不在模型上,先别急着换。可以试试按标题层级或者段落做递归切分,接口文档尤其适合按“接口名+说明+参数+示例”这种结构来切,再带一点overlap。另外Milvus里如果只存了纯文本向量,没有把接口名、路径这类关键词做成元数据过滤,也会导致无关接口混进来。我一般会先手动看几条badcase,把chunk原文和query摆一起对比,很快就能判断是切分把答案切没了,还是embedding压根没抓住语义。如果chunk里明明有答案但top-5还是召不回,那才轮到怀疑模型或者加个rerank。
512字硬切这个粒度确实容易出问题,尤其是接口文档这种结构化的内容,一个接口的说明可能就两三百字,硬切之后要么把两个接口混在一个chunk里,要么把关键参数说明切到隔壁去了。我自己踩过类似的坑,后来改成按标题层级切、再控制chunk在200-300字左右,召回准确率提升挺明显的。bge-large-zh本身中文语义能力不差,但如果你没加query指令前缀,效果会打折扣,bge系列检索时query端一般要加“为这个句子生成表示以用于检索相关文章”这类提示。另外你说的“文档里有答案但top5没有”,很可能是召回阶段就漏了,跟rerank没关系,建议先把chunk原文打出来看看答案是不是被切碎了或者跟别的接口混在一起。Milvus那边也顺便确认下距离度量用的是不是IP或COSINE,跟bge的输出匹配,用L2的话相似度排序会怪。排查顺序我一般先看chunk原文质量,再看query有没有加指令,最后才怀疑模型本身。实在不行可以拿bge-m3或者换个rerank模型兜一下,但根因大概率还是在切分上。