最近在做一个企业内部知识库的问答系统,用了Milvus+OpenAI的embedding模型(text-embedding-3-small),数据是几千篇技术文档。按说向量检索应该比关键词搜索更智能,但实际测试发现,很多用户问“打印机卡纸怎么办”,向量检索出来的结果反而没有Elasticsearch直接搜“卡纸”来得准。我怀疑是不是我分块策略有问题,目前是按段落切分,每个块512 token,有没有大佬指点一下?或者是不是embedding模型对中文长尾问题支持不够好?
向量数据库做RAG时,为什么检索准确率还不如直接用关键词搜索?
全部回复
共 138 条你这情况我也踩过坑,512 token对技术文档来说太长了,很多关键信息被稀释了,试试按标题或语义段落切,块越小越精准。另外embedding对中文里的具体故障词确实不敏感,“卡纸”这种强信号词,向量反而抓不住重点,混合检索加个BM25权重会好很多。还有个思路,把用户问题先做实体抽取再拿去匹配,比直接裸向量靠谱。
试试把512token改小到256甚至128,按标题和语义段落切,别死磕embedding,先看召回再调重排。
这问题我调过一阵子,其实不是embedding不够好,而是512token的段落对技术文档太长了,一个段落里可能混了故障现象、原因、解决步骤好几层意思,向量平均完就糊了。建议先按标题或者小节切,实在不行用滑动窗口重叠切,我这边切成128token后效果明显提升。至于关键词搜索,它本质是精确匹配,你文档里正好有“卡纸”这个字眼当然占便宜,向量检索强在语义泛化但最怕query本身信息量太碎。另外你可以试试过滤掉停用词再加权重,或者用BM25和向量结果做RAG融合,别指望单一召回吃遍天。
你这情况我也踩过坑,问题八成出在分块和query意图的错位上。“打印机卡纸”这种故障类问题,关键词本身信息密度极高,而512token的段落会把很多无关上下文卷进向量里,反而稀释了核心语义。建议试试把分块缩小到128-256token,或者干脆按句子切,再配合BM25做混合检索,用RRF融合排序,效果一般会立竿见影。另外text-embedding-3-small对中文专有名词和短指令确实偏弱,有条件可以换bge-m3或试下重排序模型。
说实话你这个现象挺典型的,向量检索擅长语义相似但有时候会忽略精确的关键词匹配,而“卡纸”这种词本身就是强信号,ES直接命中反而更合理。分块策略我觉得可以试试按标题和章节来切,别死守512token,另外中文场景下可以考虑混合检索,把BM25和向量结果做个rerank,效果通常会有明显提升。至于text-embedding-3-small,它对中文长尾词确实有点弱,有条件可以换bge或m3e这类中文优化模型对比一下。
512 token切太碎了,试试按语义切块,另外纯向量确实容易丢关键词,混合检索效果会好很多。
你这个情况挺常见的,我一开始用RAG也踩过类似的坑。text-embedding-3-small对中文短查询其实还行,但512token整段切分容易把关键信息稀释掉,尤其技术文档里“卡纸”这种词可能只占一两句,embedding反而被大段无关内容带偏了。你可以试试按语义或标题层级做小块切分,再配合BM25做混合检索,很多场景下效果比纯向量好不少。另外几千篇文档不算多,先别急着换模型,调分块和加关键词召回可能就够用了。
512切分确实容易把关键词上下文切散,试试小块加重叠,再把ES和向量做混合检索,效果会好很多。
我踩过一模一样的坑,几千篇文档场景下关键词搜索有时确实能打。后来发现512token按段落切,经常把“卡纸”这种关键词和它所在的操作步骤切散了,向量反而抓不到重点。可以试试把块切小一点,比如256,再带点overlap,另外在检索后面加个BM25混合排序,效果会稳很多。text-embedding-3-small对中文长尾确实一般,换成bge-m3或者加个query改写可能也有帮助。
分块太大确实容易稀释语义,512 token对短问题偏长了,先试试256带重叠看看效果。
这个问题我踩过类似的坑,后来发现很多时候不是向量检索不行,而是混合检索才是正解。你试试BM25加向量召回做个RRF融合,卡纸这种关键词明确的query交给关键词通道,语义模糊的长问题再靠向量兜底。另外512 token按段落切对中文技术文档其实偏碎了,上下文一断embedding抓不住重点,可以试试按标题层级做父子块。text-embedding-3-small中文确实一般,换成bge-m3或者qwen的embedding你会看到明显差别。
这个现象挺常见的,别急着怀疑embedding模型。text-embedding-3-small对中文短查询确实偏弱,但更关键的是你拿短query去匹配512token的长块,语义向量容易被稀释,关键词信号反而被淹没了。我之前也踩过这坑,后来改成小块(128-256token)+重叠窗口,再加上用Elasticsearch做混合检索,BM25和向量分数加权融合,卡纸这种具体问题召回立马就上来了。另外可以在query侧做点手脚,比如把用户问题先扩写成一句完整描述再embedding,效果也会好不少。
这问题太常见了,我一开始用RAG也踩过这个坑,后来发现很多时候不是向量检索本身不行,而是查询和文档块之间的语义鸿沟被高估了。你拿“打印机卡纸怎么办”去检索,embedding会把“怎么办”这种意图也编码进去,反而稀释了“卡纸”这个核心关键词的权重,而BM25这类关键词算法对稀有词的命中就是很直接。几千篇文档、512token的段落切分,其实块偏大了,里面可能混了好几个主题,向量被平均之后区分度就下来了,可以试试256甚至更小的块,再配上重叠。另外text-embedding-3-small对中文长尾确实一般,尤其技术文档里那些专有名词和缩写,它未必见过,换成bge-m3或者微调过的中文模型会好不少。最实用的做法其实是混合检索,向量加BM25各召回一批再做rerank,我这边切到这套之后准确率提升非常明显,纯向量在垂直领域真没想象中那么神。
这种情况其实挺常见的,不一定是你分块策略的问题。text-embedding-3-small 对中文的语义表征能力确实一般,尤其是技术文档里那种“卡纸”“进纸异常”“纸张堵塞”混着写的场景,它不见得能把这几层意思都压到同一个向量邻域里。而关键词搜索在这种场景下反而有优势,因为“卡纸”这个词本身就是一个强信号,ES 的 BM25 直接命中,不会有语义漂移。
你按段落切 512 token 也有点风险,技术文档的段落有时候很长,一段里可能前半截讲故障现象后半截讲解决方案,切完向量就被平均掉了,检索时反而不如一个短小精准的 chunk 来得直接。可以试试把 chunk 缩到 200 到 300 token,并且加一点重叠,让关键句别被切断。
另外几千篇文档这个量级其实不算大,完全可以用混合检索,ES 先召回 top50,再用向量做重排,或者反过来,两边各取一部分做 RRF 融合。纯向量检索在垂直领域本来就容易输给 BM25,这不是你一个人的问题。如果非要纯向量,换个 bge-m3 或者 multilingual-e5 这类中文更强的模型,效果会明显不一样。
512 token切太碎了,中文长尾问题确实容易丢语义,试试加大到1024再叠个BM25混合检索。
试试混合检索加重排序,纯向量对短查询本来就不占优,ES先召回再语义排效果会好很多。
这个现象其实挺常见的,不一定是你分块或模型的问题。向量检索和关键词检索本质上解决的是不同层面的匹配,前者靠语义相似度,后者靠字面命中,遇到“打印机卡纸”这种专有名词加具体故障的场景,关键词反而更稳,因为embedding容易把“卡纸”泛化成某种“设备故障”的语义空间,结果就召回一堆泛泛的设备维护文档。你可以先做个对照实验,把同一批query分别跑向量和BM25,看看badcase里有多少是向量把“卡纸”匹配成了“纸张处理”这类近义但不对口的文档。另外512 token按段落切,如果一段里混了好几个主题,embedding会被平均掉,关键信息就稀释了,试试按语义或标题层级切,或者把小块拼回去做rerank。text-embedding-3-small对中文长尾确实一般,尤其技术术语,换bge-m3或者用多语言版会好一些。实际生产里很少有人纯靠向量,基本都是hybrid检索加rerank,先用关键词保底召回,再用向量补语义,最后交叉编码器精排,这样准确率会明显上来。
512切分太碎了,试试按语义切或者加个标题上下文,中文长尾确实得调调embedding。