好,这道题其实是在问一件事:怎么让大模型在不知道答案的时候,能自己去查资料,然后给出靠谱的回答。[[RAG]]就是干这个的,它本质上不是让模型学会新知识,而是给它配一个外挂知识库。
先说整体流程,我习惯把它拆成三段。第一段是索引,把知识文档切成小块,大概几百个token一段,然后用编码模型转成向量,存到[[向量数据库]]里。第二段是检索,用户问一个问题,同样用编码模型转成向量,去库里做近邻搜索,召回最相关的几段。第三段是生成,把问题和召回文档拼在一起,喂给大模型,让它基于这些信息回答。
这里有个关键组件就是编码模型,它决定了检索质量。我重点说说两种典型方案。DPR是有监督的,训练时用标注好的正例和负例,通过对比学习让正例距离近、负例远。它的优点是检索精度高,在特定场景下Recall能做得很好,但缺点也很明显,就是依赖标注数据,换一个领域就得重新标,成本很高。Contriever则走了另一条路,无监督,它利用语料里相邻句子天然语义相关这一特点,把连续句子对当正样本,随机采样当负样本。好处是训练数据零成本,通用性强,几乎不用调就能用,但坏处是在垂直领域,比如医疗、法律,效果可能不如有监督的DPR。
那么落地的时候怎么选呢?我的经验是,如果业务场景比较固定,数据标注成本能接受,DPR是首选;如果场景多变,或者刚起步没什么标注数据,先用Contriever快速验证,等数据积累够了再切到DPR。真正上线时,我几乎一定会把向量检索和关键词检索结合起来,也就是 [[Hybrid Search]],因为向量擅长语义匹配,但精确匹配比如订单号、政策条款号,还是[[BM25]]更靠谱。
怎么评估编码模型的检索能力?RAG场景下,我最看重的是 Recall@K,比如Recall@5。为什么?因为生成阶段能容忍一些噪声,你给大模型十段文档,哪怕其中两三段不相关,它也能挑出有用的信息。但如果你漏掉了关键文档,大模型就真不知道,那它就可能会瞎编,也就是 [[Hallucination]]。所以召回完整性是第一位的。MRR和NDCG这些排序指标,在RAG里优先级可以放低一点。
这里有个常见的失败场景,就是知识库频繁更新。比如企业客服的退款政策经常变,如果向量索引不支持增量更新,每次全量重建不仅耗时耗资源,还会造成服务中断。我的做法是维护一个base索引和一个delta索引,新文档直接插到delta里,查询时合并结果,然后定时异步把delta合并到base。如果文档删除或修改,我不用原地操作,而是软删除加版本号过滤。上线前我一定用一批历史query回放,对比新旧索引的Recall@K和延迟,达标才原子切换,不达标就回滚。 所以我会把编码模型看成RAG的入口守门员,它的召回能力决定了整个系统的天花板,而生成模型只是在这个天花板下做文章。