我觉得[[RAG]]这道题本质上是在问:当你需要让模型回答它没训练过的新知识时,怎么在知识新鲜度和生成质量之间做平衡。说白了,RAG不是把检索和生成简单拼起来,而是要在信息密度、计算成本和[[幻觉]]风险之间反复取舍。
先说离线文档处理这一块。很多人上来就按固定长度[[切块]],比如512 token一刀切,这在通用场景还行,但遇到代码库或者论文,语义就被拦腰砍断了。我的做法是:先看业务文档的结构,代码按函数切,论文按章节切,普通文档按段落切,然后把零重叠、短窗口与较长窗口作为候选,用同一评测集验证哪种配置更能保留边界证据。这里有个坑:切得太细,检索时上下文不够,模型容易断章取义;切得太粗,一条chunk里塞进多个主题,检索噪声就大。所以上线前我会用一批典型query跑一遍,看召回是不是集中在正确段落上。
再一个就是向量索引和检索。[[Embedding]]模型选型上,通用域用BGE或者M3E就够了,但如果业务很垂直,比如金融合同或者医疗文献,我会考虑在领域数据上微调一下,否则相似度计算会偏。索引结构,百万级用[[HNSW]],内存够快;亿级就得用[[Faiss]]的[[IVF]]或者上分布式数据库。但纯向量检索有个问题:用户写个订单号或者错误码,向量相似度经常找不到,因为语义空间和字面匹配是两回事。所以我倾向做**[[混合检索]]**,把[[BM25]]关键词召回和向量召回两条路并行,再合并排序。这能明显提升召回率,尤其在客服退款、订单异常这类场景。
在线检索流程里,我特别看重精排这一步。粗召回我一般拉100到200条,然后用[[Cross-Encoder]][[重排]],只留前5到10条送进上下文。重排对最终答案质量影响非常大,它能把语义相关但不太匹配的文档压下去。但重排是计算密集的,延迟敏感场景下,我会考虑用[[ColBERT]]那种轻量级交互模型做近似,或者干脆砍掉精排,只依赖粗召回加阈值过滤。
上下文构建和生成优化是另一个容易翻车的地方。上下文窗口有限,检索出来的文档不能全塞进去,得按相关性排序,截断超长部分。如果文档本身很长,可以用摘要压缩,或者做多轮检索,第一次先找大概方向,第二次再精准定位。Prompt设计上,我明确告诉模型“基于以下参考信息回答,如果信息不足就说不知道”,并且要求输出引用标记,比如[doc_id],这样能溯源,也方便用户验证。还有一个关键点是拒答机制:如果所有检索结果的相关性都低于某个阈值,模型必须拒绝回答,不能胡编。这个阈值需要反复调,设太高容易拒答,设太低幻觉又冒出来。
最后说一个容易忽略的点:检索失败时的回退策略。比如用户问的问题在文档里确实没有,或者检索出来的内容自相矛盾,这时候模型该怎么做?我倾向引入一个自检环节,让模型先判断检索结果是否足够支持回答,如果不支持,就主动反问用户澄清意图,或者走一个备用知识库。这个思路其实已经有点[[Agentic RAG]]的味道了,模型不再是被动拼接,而是主动决策。
所以我的整体判断是:RAG落地最核心的不是某个模块做到极致,而是整个链路的一致性。检索、排序、生成、拒答,任何一个环节出问题,答案质量都会崩。我更倾向在离线阶段多花功夫做文档清洗和质量校验,而不是上线后靠prompt来救。