最近在做一个内部知识库问答,选了Qwen2.5-7B做生成,用bge-small做Embedding,Chroma做向量库。测试阶段发现,用户问“合同审批流程”,系统总能答对,但稍微问个“跨部门盖章要多久”,就经常召回了一堆无关的会议纪要或政策文件。我试过调chunk_size(从512试到1024),也试过加HyDE或者query重写,但效果都不太稳定。感觉是Embedding对长文档的语义理解还不够细,但又不想换太大的模型(部署成本有限)。想问问大家,除了微调Embedding,还有什么trick能在不改模型的前提下提升召回质量?还是我数据预处理阶段就有问题?先谢谢了。
用开源模型搭RAG系统,召回率一直上不去怎么办?
全部回复
共 4 条说实话你这个问题挺经典的,我自己也踩过类似的坑。bge-small对短文本匹配还行,但遇到“跨部门盖章要多久”这种带流程细节的查询,它很容易把语义分散到“跨部门”或“盖章”这些碎片上,导致召回跑偏。我试过相对有效的办法是加一层reranker,比如bge-reranker-small,成本不高但能把召回的top-k重新排一下,把和主题无关的会议纪要直接压下去。另外你提到chunk_size调了没改善,我怀疑你切块时可能把“盖章流程”和“会议纪要”混在一个文档里了,试试按章节标题切分,或者用更细的段落粒度,比如200-300字,配合overlap避免断句。
我最近也踩过类似的坑,试了下在chunk时按文档结构切分(比如按章节标题分段),而不是纯按字符数硬切,召回率稳了不少。另外可以试试在query重写时加个few-shot示例,让模型更明确地把“盖章”“流程”这类词和合同类文档关联起来。对了,你数据清洗时有没有过滤掉那些会议纪要里的时间词?这些干扰项可能是召回不精准的主要原因。
我最近也踩过类似的坑,尤其是长文档里关键信息分散的时候,bge-small确实容易跑偏。试过把chunk_strategy从单纯按字数切改成按段落切,再配合滑动窗口重叠个20%左右,命中率稳了不少。另外你可以看看是不是文档本身结构层级没保留,比如合同里盖章条款藏在子章节里,扁平化切分后语义就断了。如果不想换模型,试试在检索前加个简单的关键词过滤规则,把“盖章”“流程”这类词先做一层硬匹配,再让向量去召回,能过滤掉不少无关的会议纪要。
看到你这个问题,我也踩过类似的坑。bge-small对细粒度语义确实不太敏感,试试在chunk策略上加个overlap,比如设成128,能缓解边界语义断裂。另外可以给不同文档类型打个标签,检索时用关键词先过滤一下范围,能减少无关噪音。你数据清洗时有没有处理过会议纪要这种干扰项?