RAG 系统上线 90 天复盘检索质量没有想象中那么高一、上线时信心满满Top-5 召回率 92%一个月后用户反馈搜不准RAG 系统在公司知识库上线时用人工标注的 500 条测试集测出来 Top-5 召回率 92%Top-1 精确率 85%。所有人都觉得够了。但上线一个月后来自用户的真实反馈是搜项目文档经常搜不到同样的问题问三次能搜到不同的答案。把用户的真实查询捞出来一看召回率只有 68%。差距在哪测试集和真实查询之间存在系统性偏差。测试集是产品经理和工程师精心构造的措辞规范、关键词明确。而用户的真实查询是口语化的、模糊的、带拼写错误的。这个鸿沟是 RAG 系统上线后最大的期望差距。二、真实查询 vs 测试集的差距分析找到差距后做了系统性的改进将真实召回率从 68% 提升到 87%。以下是四个关键改进。三、四个关键改进改进一查询改写Query Rewriting用户的查询那个回归的怎么做非常模糊。加入查询改写后先用 LLM 将模糊查询扩展为完整查询def rewrite_query(raw_query: str, history: List[Dict] None) - str: 将用户口语化查询改写为规范检索查询 prompt f 将以下用户查询改写为一个清晰的检索查询。 要求 1. 补全指代词那个这个等 2. 展开缩写和专业术语 3. 保持原意不变 对话历史: {history[-3:] if history else 无} 用户查询: {raw_query} 改写后的查询: # 实际调用 LLM 获取改写结果 rewritten llm_call(prompt) return rewritten # 效果: 那个回归的怎么做 → 多元线性回归分析的实现方法改进二多路召回 结果融合单一的向量召回对专有名词不敏感。改为 BM25 向量双路召回def hybrid_search(query: str, top_k: int 20): # 路1: 关键词检索对专有名词友好 bm25_results bm25_index.search(query, top_k * 2) # 路2: 向量检索对语义友好 query_embedding encoder.encode(query) vector_results vector_db.search(query_embedding, top_k * 2) # RRF倒数排名融合 fused reciprocal_rank_fusion(bm25_results, vector_results, k60) return fused[:top_k] # 效果: 专有名词Kubernetes pod 调度召回率从 56% → 89%改进三分块策略从定长改为语义切分原来的分块是 512 字符固定切分导致重要信息的首尾被切断。改用基于 Markdown 标题的语义切分# 原来的分块定长512无视文档结构 [chunk1] ## 一、背景 本项目旨在解决...512字符截断 [chunk2] ...数据质量问题。具体的方案是...后半段脱离标题 # 改进的分块按 Markdown 标题边界 [chunk1] ## 一、背景 本项目旨在解决企业数据质量问题。 [chunk2] ## 二、技术方案 采用 Flink Kafka 构建实时数据校验通道。效果Top-1 精确率从 72% 提升到 83%。因为 LLM 拿到的 chunk 是语义完整的不会出现前半段有标题、后半段没内容的情况。改进四用户反馈闭环加了两个隐藏的产品功能这个答案有帮助吗赞/踩按钮每周自动分析踩的查询找出 Top-10 召回失败的 case人工排查原因缺少文档、分块策略问题、向量相似度阈值。四、90 天后还存在的问题问题一多轮对话的上下文丢失。用户问上个月呢RAG 不知道上个月指的是什么因为向量检索没有对话记忆。这需要将对话历史也编码到检索查询中Query Rewriting 的部分功能。问题二时效性检索仍不理想。用户搜最新版本RAG 返回了三个月前的文档只是因为那段文档里最新这个词出现了多次。这需要在文档入库时打时间戳标签检索时对旧文档自动降权。问题三跨文档信息融合。用户问A 项目和 B 项目的技术栈对比这需要同时检索两篇文档并做对比RAG 目前做不到。这需要多跳检索Multi-hop Retrieval或 Agent 模式。五、总结RAG 系统的真实召回率通常比测试集低 20-30%。这不是模型的问题是测试集的构造偏差问题。四个关键改进查询改写补全模糊查询、多路召回BM25 向量融合、语义分块按标题边界切分、反馈闭环用户行为驱动持续优化。上线后最重要的指标不是Top-K 召回率那是技术指标而是用户踩率那是业务指标。如果踩率超过 15%RAG 在用户眼中的可信度就已经崩了——不管你测出来的召回率是多少。