RAG 在线工作流:从用户提问到可信答案的完整工程链路
离线阶段把知识库“整理好”在线阶段把用户问题“查准、排好、拼稳、答得有依据”。RAG 的难点不在“把向量库接上”而在每一步是否能持续稳定地把正确证据送到模型面前。一、为什么不能只说“检索 生成”很多人第一次理解 RAG会把它简化成两步用户提问系统去知识库里查几段资料再把资料交给大模型回答。这个理解没错但只停留在最粗的轮廓。真正的在线 RAG 链路要处理的问题要复杂得多用户的问题可能口语化、带指代、带上下文向量检索可能召回相似但无答案的片段关键词检索能命中专有名词但不懂语义Rerank 能提纯结果但会增加延迟Prompt 拼得不好大模型依然可能脱离资料乱答。所以一个成熟的 RAG 在线流程通常不是“检索 - 生成”两步而是“改写 - 向量化 - 多路召回 - 融合 - 精排 - 组装 - 生成 - 溯源 - 评估”的工程链路。二、完整在线流程总览当用户输入一个问题后系统最好不要马上把原问题送进向量库。更稳妥的做法是先把问题变成“适合检索”的形式再通过多种召回方式找候选证据然后用精排模型筛掉噪音最后把证据、问题和约束指令组装成 Prompt交给大模型生成带引用的答案。Query 预处理补全上下文、消除指代、改写成独立检索句。Query Embedding用和建库一致的 Embedding 模型把问题转成向量。多路召回向量检索、BM25、元数据过滤等多通道并行找候选片段。结果融合用 RRF 等方式把不同通道的排名合成统一候选集。Rerank 精排用 Cross-Encoder 或 reranker 模型重新打分保留最有用证据。Prompt 组装按证据编号、Token 预算、拒答规则、引用格式构造输入。答案生成与溯源基于证据作答并给出来源引用必要时做后处理校验。三、第一步Query 预处理让问题变得“可检索”用户输入的原始问题往往不是一个干净的检索句。比如“上次那个方案有没有风险”“这个怎么收费”“为啥又扣钱了”人能看懂是因为人有上下文和常识但向量库只看到一串文本它不知道“那个”“这个”“又”指的是什么。Query Rewrite 的目标不是润色文字而是提高检索命中率。常见做法包括独立问题改写把多轮对话里的省略和指代补全让问题脱离上下文也能理解。HyDE让模型先生成一段“假设答案”再用假设答案去检索因为答案和真实资料的表达往往更接近。多角度扩写把同一个问题改写成多个表述分别检索后合并结果提高召回覆盖面。意图拆分如果用户同时问“查资料 写回复 生成方案”应拆成多个子任务不要用一个 Query 硬搜。注意Query Rewrite 不是越多越好。改写过度可能改变用户原意所以工程上常保留原始 Query并记录 rewrite_version方便回放和评估。代码示例一个简单的 Query Rewrite 约束模板rewrite_promptf 你是 RAG 检索问题改写器。 请把用户问题改写成适合知识库检索的独立问题。 要求1. 不改变用户原意2. 补全多轮对话里的指代3. 保留产品名、版本号、时间、地区等关键约束4. 如果问题已经清楚直接原样返回5. 输出 JSON不要输出解释。 对话上下文{chat_history}用户问题{user_query}输出格式{{rewritten_query:...,need_rewrite:true,reason:...}}四、第二步Query Embedding必须和建库模型保持一致Query 改写完成后需要把文本转成向量然后才能去向量数据库里做相似度搜索。这里最容易踩的坑是在线查询用的 Embedding 模型必须和离线建库时用的 Embedding 模型一致。原因很简单不同模型的向量维度、训练目标、向量空间分布都不同。用模型 A 建库再用模型 B 查询就像拿两套不同坐标系算距离结果没有意义。换 Embedding 模型通常意味着需要重建索引。五、第三步多路召回向量检索和关键词检索各有分工很多线上 RAG 系统不会只做向量检索。向量检索擅长找语义相近的内容比如“退款”和“退费”但它对产品型号、订单号、错误码、专有名词、精确短语不一定稳定。BM25 或全文检索正好能弥补这一点。典型的多路召回包括三类向量检索捕获语义相似适合问法多变、同义表达丰富的场景。BM25 / 全文检索捕获精确词、术语、编号、产品名、代码符号。元数据过滤按权限、租户、产品线、版本、时间范围、文档状态先过滤候选范围。RRF 融合为什么不能直接把分数相加向量检索的分数可能是 cosine similarityBM25 的分数是另一套统计分数两个分数没有天然可比性。RRFReciprocal Rank Fusion不直接比较分数而是比较“排名位置”一个片段如果在多个通道里都排得靠前它最终得分就更高。from collectionsimportdefaultdict def rrf_fusion(result_lists,k60): result_lists: 多个召回通道的结果列表例如[[doc_a, doc_b, doc_c],[doc_b, doc_d, doc_a]]返回按 RRF 得分排序后的文档 scoresdefaultdict(float)forresultsinresult_lists:forrank, doc_idinenumerate(results,start1): scores[doc_id]1.0/(k rank)returnsorted(scores.items(),keylambda x: x[1],reverseTrue)六、第四步Rerank 精排从“召回一堆”到“只留可用证据”多路召回解决的是“不要漏掉可能相关的片段”但召回越多噪音也越多。Rerank 的作用就是对候选片段重新排序把真正能回答问题的片段排到前面。常见做法是两阶段先用向量检索和 BM25 快速召回 Top-20 到 Top-50再用 Rerank 模型对这些候选进行深度匹配最终只保留 Top-3 到 Top-5 进入 Prompt。Rerank 的关键价值是“降噪”。它不是替代召回而是补上召回之后的质量控制。没有 RerankTop-K 里混入噪音模型就可能被错误片段带偏。七、第五步Prompt 组装让模型基于证据回答精排后的片段不能简单拼在一起就丢给模型。Prompt 组装要同时考虑四件事证据顺序、Token 预算、引用格式和拒答规则。一个可用的 RAG Prompt至少应该明确告诉模型只能基于资料回答资料不足时要拒答关键结论要带引用不要把参考资料里没有的信息编出来。def build_rag_prompt(question, contexts): evidence[]fori, ctxinenumerate(contexts,start1): evidence.append(f[{i}] 来源{ctx[source]} f片段{ctx[text]})returnf 你是一个严谨的知识库问答助手。 请只根据【参考资料】回答用户问题。 如果资料不足请回答“根据现有资料无法回答”。 关键结论后面必须标注引用编号例如[1][2]。 【参考资料】{chr(10).join(evidence)}【用户问题】{question}【回答】.strip()八、第六步生成答案与溯源可信度来自可回查大模型拿到 Prompt 后基于参考资料生成答案。到这里用户看到了结果但工程上还没结束。真正可上线的 RAG 系统最好能让用户看到答案来自哪篇文档、哪个 chunk、哪一页、哪一段。溯源有三个好处第一用户可以验证答案第二运营和研发可以定位错误第三当模型误读资料时可以通过源文档快速判断问题出在检索、Prompt 还是生成。九、在线 RAG 的延迟优化不要只盯向量库在线链路里向量检索通常不是最慢的环节。真正影响用户体感的往往是 Rerank 和大模型生成。工程上可以通过缓存、并行召回、精排限流和流式生成降低等待感。缓存高频 Query 的改写结果、召回结果和最终答案。向量检索和 BM25 并行执行避免串行叠加延迟。Rerank 限制候选数量超过阈值先粗筛。生成阶段使用流式返回让用户尽快看到首 token。对低置信度检索结果直接拒答或转人工而不是强行生成。十、常见失败点RAG 调优要先定位环节RAG 出错时不能一上来就换模型。你需要先判断问题出在哪一段是不是 Query 改写改错了是不是召回没找回来是不是 Rerank 把正确片段排掉了是不是 Prompt 太长、噪音太多还是生成阶段没有遵守引用约束十一、生产级在线架构可观测、可回放、可评测如果只是 Demo把所有逻辑写在一个 Python 函数里也能跑。但生产环境需要把每一层拆清楚入口层、Query 层、检索层、排序层、生成层和治理层。每次请求都要有 query_id每个 chunk 都要有 chunk_id / doc_id每个阶段都要记录耗时和分数。建议至少记录这些字段query_id一次问答请求的唯一编号用于链路追踪。raw_query / rewritten_query保留原问题和改写结果方便回放。retrieval_results各召回通道的候选片段、分数、排名。rerank_scores精排得分和最终入 Prompt 的片段。prompt_tokens / completion_tokens评估成本和延迟。citations答案中的引用与 chunk_id 的映射关系。十二、如何评估在线流程拆开看不只看答案评估 RAG 不应该只看最终答案像不像。更有效的方法是组件级评估召回阶段看有没有找回答案片段排序阶段看正确片段是否排在前面生成阶段看是否忠于证据。一套实用的离线评测集最好包含“用户问题、标准答案、标准证据片段”。这样你每次调整改写、召回、Rerank、Chunk 粒度时都能用同一批问题做回归测试而不是凭感觉判断效果。十三、面试回答模板如果面试官问“用户输入一个问题后RAG 系统是怎样工作的”可以这样回答我会把 RAG 在线流程拆成六步。第一步做 Query 预处理把口语化、多轮指代问题改写成独立检索句第二步用和建库一致的 Embedding 模型把 Query 向量化第三步做多路召回通常会并行跑向量检索、BM25 和元数据过滤第四步用 Rerank 精排从候选片段里筛出最有用的 Top-N第五步把证据、引用编号、拒答规则和用户问题组装成 Prompt第六步由大模型基于证据生成答案并标注来源方便用户回查。线上还会记录每一步耗时、召回结果、精排分数和引用映射用于评估和排障。

相关新闻