这道题问 [[RAG]] 的实现流程,其实本质是在问:怎么把外部知识以可控的方式注入到语言模型里,同时保证检索和生成的质量。这不是一个简单搭积木的过程,而是一连串的权衡决策。
先说文档处理。很多人一上来就固定切 512 tokens,但实际落地你会发现,[[分块]]粒度决定了检索的下限。固定长度切得快,但容易砍断语义,比如一段退款政策被切到两个块里,用户问“退款时效”时可能只召回一半。我更倾向做语义分块,按段落边界或标题层级切,再把零重叠、短窗口与较长窗口作为候选,用同一评测集验证边界信息、召回与成本。元数据一定要保留,比如文档来源、时间戳,后面过滤和溯源都用得上。
然后是[[向量化]]。Embedding 模型选型要看领域,比如电商客服场景,用 BGE 或 M3E 就比通用英文模型好。[[向量数据库]]的话,我会关注索引算法,[[HNSW]] 在中等规模下表现稳定,但数据到千万级就得考虑 [[IVF]] 分区了。这里有个前提:向量检索只能做语义相似,没法做精确关键词匹配,所以单纯靠向量容易漏掉那些带特定订单号或错误码的查询。
所以检索模块我一般走[[混合检索]]。粗排阶段,同时跑稠密向量和 [[BM25]] [[稀疏检索]],然后用 RRF 或者倒数排名融合把结果合并。举个例子,用户问“我的退款订单 AB123 处理到哪了”,向量可能把“退款”相关的文档都召回,但 BM25 能精准命中“AB123”,两者互补。Top-K 拿 100 个候选,再过一个 [[Cross-Encoder]] 做精排,这里[[重排]]是性价比很高的环节,能把相关性分数拉得更准。
生成模型集成这块,核心是上下文组装和 Prompt 设计。我会把检索结果按相关性排序,拼接成参考信息,开头加一句“基于以下内容回答,如果信息不足请说明”。窗口管理要控制总长度,优先塞高相关性文档,低分的直接舍弃。这里有个常见失败场景:如果检索到的文档本身就有矛盾,比如两个政策版本时间不同,模型可能会混淆。所以我会在 Prompt 里强调“优先参考时间最新的文档”。
结果融合上,我会做两步。一是引用溯源,让模型输出时带文档编号,方便验证。二是置信度判断,检索分数低于某个阈值的,直接回答“没有找到相关信息”,防止[[幻觉]]。再进阶一点,可以用 [[Self-RAG]] 让模型自己决定是否需要再检索一轮,逐步细化答案。
其实 RAG 还有一个经常被忽略的瓶颈,文档更新的实时性。比如商家满减政策改了,旧文档还在库里,向量索引没来得及更新,模型就会给出过时的回答。这个问题目前没有完美解法,我倾向用时间戳过滤加增量索引,但增量索引的图结构维护很麻烦,删除操作不能原地动图,否则召回质量会崩。
所以整体来看,我会把 RAG 看成一套系统工程,不是搭好就完事的。我更倾向根据业务场景做取舍:客服场景重召回率,宁可多召回再重排;而风控合同场景重精确性,宁可答不上也不乱答。如果面试官感兴趣,我可以再聊聊增量索引的具体实现。