最近在公司试水RAG系统,底层用的ChatGLM3-6B,检索这块换了几个开源embedding模型(BGE、m3e都试了),结果用户问“离职流程怎么走”,系统老是召回“考勤规则”或者“年假申请”的内容,感觉语义理解上差了点。我已经把文档切成了512 tokens的小块,也试过用标题加粗来加权,但还是经常答非所问。想问下各位大佬,中文场景下有没有更准的开源embedding模型?或者我是不是应该在预处理阶段加个意图分类?小白刚入坑,求指条明路。
用开源模型搭RAG,中文检索总跑偏,有啥好用的embedding推荐吗?
全部回复
共 155 条说实话我也踩过这个坑,BGE和m3e在垂直场景里确实容易把相似但不相同的话题搞混。后来我换成text2vec-large-chinese,配合一个简单的意图识别模块做前置过滤,召回准确率明显上来了。你可以试试把文档按业务场景做二次聚类,比单纯切块好用。预处理加意图分类是个好思路,至少能先把“离职”和“考勤”这类强相关但不同意图的问题分开。
试试chinese-roberta-wwm-ext,对长尾词和意图匹配会好不少。另外预处理加个意图分类确实能顶,我这边加了之后召回率明显上来了。
试试加个query重写或意图分类,召回会准很多,stella-base-zh-v3这种embedding也可以换上去看看。
试试把chunk_size调小到256,同时用jina-embeddings-v2,中文效果比BGE稳不少。
其实中文RAG检索这块,BGE和m3e在垂直领域确实容易漂,我最近试了试 bge-large-zh-v1.5(调了温度参数)和 stella-base-zh-v3-1.5b,感觉对意图区分比之前好一点。另外你提到的意图分类确实值得加,我一般在切块前先用个轻量分类模型把“流程类”“规则类”分开建索引,召回准确率能提不少。还有个小细节:离职流程这种词,试试在文档里把同义说法(比如“辞职手续”)也显式写进去,embedding对同义词的泛化有时真不太够用。
试试把chunk_size调到200以内,再配合jieba分词的精确模式切词,中文检索会稳很多。
你说的这个问题我最近也踩过类似的坑,BGE和m3e在中文长尾语义上确实容易偏。可以试试stella-base-zh-v3-5-1e5,它用retromae训练过,对相似但不同义的文本区分度比BGE高不少。另外你提到意图分类,我觉得可以在检索前加个轻量分类器,比如用fasttext把“离职/请假/考勤”这类意图先分出来,再单独匹配对应文档块,这样召回准确率能明显提升。
我之前也踩过类似的坑,后来换成bce-embedding-base_v1(国产那个),中文长文本的语义匹配明显稳了不少。不过光换模型还不够,建议你可以在切块前加一层query改写,比如把用户口语化的“怎么走”补全成“离职流程的申请步骤”,这样召回能准很多。另外你提到的意图分类也可以试试,简单用prompt让GLM分一下类再路由到不同索引,效果立竿见影。
同款踩坑,BGE和m3e在中文长尾语义上确实有点飘。我后来换了text2vec-large-chinese,配合标题和段落首句做加权嵌入,召回准了不少。另外文档切片可以试试256+overlap,短块对精准匹配更友好。预处理加意图分类是个好思路,但成本比较高,可以先用CoT提示让模型自己判断类型再切检索方式。
我也遇到过类似的问题,后来试了试text2vec-large-chinese,感觉比BGE在中文长尾词上稳一些。不过我觉得512切块对“离职流程”这种细粒度意图可能还是太碎了,可以试试256或者128,配合title的embedding做第一轮筛选。另外你提到的意图分类我觉得挺有必要,先分一下“制度类”“流程类”再检索,能省掉不少误召回。
试试加粗和切块不如先跑个意图分类,把“离职流程”这类高频意图单独拎出来再召回,效果会明显很多。
我也遇到过类似的问题,中文embedding在区分“离职”和“考勤”这类相近概念时确实容易翻车。可以试试BAAI的bge-large-zh-v1.5或者智源的stella-base-zh-v3-5-1e,我换成后者后召回准确率明显提升。另外你提到的意图分类挺有必要的,我后来在检索前加了个简单的分类器(用few-shot prompt让模型判断意图),把“流程类”问题单独路由到一个更精细的索引里,效果好了不少。文档切块大小也可以试着调大到768,有些长上下文模型对小块反而会丢失关键信息。
这个情况我也遇到过,BGE和m3e在中文长尾语义上确实容易翻车。建议试试text2vec-large-chinese或者acge模型,对HR场景的细粒度区分会好一些。另外512切块可能太碎了,可以试试把完整流程段落作为一块,配合滑动窗口做检索。意图分类加一层确实有用,至少能先拦住无关召回,但要注意别把分类做太细,不然反而增加错误率。
同款踩坑人,我试过把chunk size调到256,配合sparse检索(比如bm25)做混合召回,效果比单用dense好不少。另外可以看看bce-embedding-base_v1,中文长文本匹配比bge稳一些,但部署前记得量化加速。意图分类加在预处理里确实能过滤掉很多歧义,不过别搞太复杂的标签,分3-4类就够了。
可以试试stella-base-zh-v3-5-1e6,或者把query和文档都加个“意图”前缀再编码。
试试用text2vec-base-chinese,或者检索前加个意图分类确实能救,我这边切块调成256后效果好了不少。
试过bge和m3e确实在中文长尾词上有点懵,你这个问题大概率不是embedding单点问题。建议先加个意图分类模块,把“离职流程”这类明确指令先筛出来,再结合hybrid search(稀疏+稠密检索)召回,效果会稳很多。另外可以试试gte-Qwen2,最近社区反馈中文语义对齐比bge好一截,但模型大一点要卡。
试试加个意图分类吧,先判断是流程类还是规则类,能有效减少语义跑偏的情况。
我之前也踩过类似的坑,中文embedding模型在垂直场景下确实容易飘。BGE和m3e在通用语义上还行,但像你这种HR问答场景,很多公司内部术语和业务逻辑它们没训练过,召回跑偏太正常了。试试BAAI的bge-large-zh-v1.5,或者最近出的stella-base-zh-v3-5-1e,后者在中文长文本和细粒度语义上比BGE稳一些。不过光换模型可能不够,我自己的经验是512 tokens对RAG来说还是偏大,尤其是中文里“离职流程”和“考勤规则”这种经常出现在同一段文档里的情况,切到256甚至128 tokens,配合标题加权,能减少不少噪声。另外你提的意图分类其实挺靠谱的,我后来在预处理阶段加了个轻量的fasttext分类器,先判断用户问的是流程类还是政策类,再定向召回,准确率直接升了15%。可以试试把文档按业务类型打标,比如“流程”“制度”“案例”,这样检索时能加一层筛选。还有个小技巧,检索结果出来后再用ChatGLM3-6B做个rerank,让大模型自己判断哪个片段最相关,虽然慢点但效果立竿见影。
试试加个query改写环节吧,把用户问题转成更明确的检索语句,BGE和m3e其实够用了。