最近在搭一个RAG问答系统,用来回答公司内部的技术文档。用了llama-index默认的chunk设置(256 token,overlap 20),embedding用的bge-small,检索用的余弦相似度。结果发现,用户问一个稍微复杂点的问题,比如“怎么处理数据库连接超时”,经常召回不到核心段落,反而是一些无关紧要的配置说明。我试过把chunk调大到512,召回率是上去一点,但上下文变得很杂,回答也容易跑偏。想问下大家,这种场景下chunk大小和embedding模型一般怎么搭配?有没有什么经验或者trick能提高召回的精准度?先谢谢了。
RAG召回率上不去,chunk大小和embedding模型怎么调?
全部回复
共 164 条我之前也踩过差不多的坑,256 token 对技术文档来说确实太碎了,尤其像“数据库连接超时”这种问题,核心信息往往散在好几个段落里,切太细反而拼不出完整语义。后来我换成按语义切分加 400 到 500 token 左右,再配 10% 到 15% 的 overlap,召回明显稳一些。embedding 这块 bge-small 胜在快,但中文技术文档里专有名词和缩写多,换 bge-base 或者 bge-m3 通常能捞回不少漏掉的段落,代价就是索引慢一点。另外别只盯着 chunk 大小,检索策略也很关键,纯余弦 top-k 很容易被那种泛泛的配置说明抢位,可以试试 hybrid 检索,把 BM25 和向量结果融合一下。还有个我觉得挺管用的 trick,是给每个 chunk 加上它所属的标题层级或者文档路径当上下文前缀,再丢给 embedding,这样“配置说明”和“故障处理”就不会混在一起了。如果你们文档里有大量步骤性内容,也可以考虑按问答对或者按小节做 parent-child 检索,先粗召回再拿小 chunk 精排,效果比单纯调大 chunk 好。
bge-small换m3e-base试试,中文文档召回差别挺大的。chunk别光调大,试试按标题或段落切,比固定token好使。
试试用bge-large,再把chunk按文档结构切而不是死磕固定长度,效果会好很多。
你这个情况挺典型的,chunk调大召回确实会好一点,但噪声也跟着进来了,本质上是把“检索精度”和“上下文完整性”放在了对立面。我自己的经验是别只盯着chunk size,先看看你的文档结构,技术文档里很多答案其实是跨段落的,比如超时处理可能涉及配置项、代码示例和注意事项三块,硬切256肯定丢信息。可以试试按语义或标题层级切,llama-index里有semantic splitter或者markdown header splitter,比死磕token数管用。embedding那块bge-small对中文技术文档其实还行,但如果你们文档里缩写、代码符号多,可以换bge-m3或者用领域数据微调一下,效果比单纯换大模型明显。另外检索别只用余弦相似度,加个BM25做混合检索,再上rerank模型,召回精准度能提不少。还有一个容易忽略的点是query改写,用户问“怎么处理数据库连接超时”,你可以先让LLM扩成几个关键词再检索,比直接拿原句去搜强很多。