RAG 落地常见陷阱与优化策略

2026-06-10RAG优化工程实践

RAG 不是银弹:从原型到生产的差距

Demo 阶段的 RAG 通常表现完美,但上线后用户反馈"搜不准""搜不全""幻觉更严重了"。原因在于:原型用干净数据 + 简单查询,生产环境面临脏数据、模糊查询、多文档融合等真实问题。

陷阱一:分块策略不当

默认按固定长度分块(chunk_size=500)是最常见的错误。

文档类型推荐分块策略原因
产品文档/手册按章节/标题分块(语义分块)保持语义完整性
代码按函数/类分块代码上下文至关重要
FAQ/对话按 Q&A 对分块保持问答映射
长文章/论文重叠分块 (overlap=100)避免切断关键信息

核心原则:分块不是技术问题,是业务问题——理解文档结构后再决定如何切。

陷阱二:只用向量检索

纯向量检索的两个致命缺陷:(1) 对专有名词/代号/编号不敏感,(2) 短查询缺乏语义上下文。

解决方案:混合检索

# BM25(关键词)+ 向量(语义)双路召回
bm25_results = bm25_index.search(query, k=20)
vector_results = vector_db.search(embed(query), k=20)

# RRF (Reciprocal Rank Fusion) 融合
def rrf(results_a, results_b, k=60):
    scores = {}
    for rank, doc in enumerate(results_a):
        scores[doc.id] = scores.get(doc.id, 0) + 1 / (k + rank + 1)
    for rank, doc in enumerate(results_b):
        scores[doc.id] = scores.get(doc.id, 0) + 1 / (k + rank + 1)
    return sorted(scores.items(), key=lambda x: x[1], reverse=True)[:10]

陷阱三:检索了但没检索对(查询-文档不匹配)

用户问"怎么退款",文档里写的是"退货流程"——纯关键词或向量都匹配不上。

解决方案

  • 查询重写:用 LLM 把用户口语化问题转为接近文档风格的查询
  • HyDE:先让 LLM 生成假设答案,用假设答案的 embedding 去检索
  • 多轮改写:对话场景下将"那这个呢"改写为完整查询"那XX产品的退款流程呢"
# 查询重写示例
user_query = "怎么退款"
rewritten = llm.generate(
    "将用户问题改写为适合检索文档的查询语句:",
    user_query
)
# → "退款流程 退货申请 退款 操作步骤"

陷阱四:检索到但 LLM 用错了

检索返回了 5 个文档片段,LLM 可能:忽略关键信息、混淆多个文档、使用过时内容。

解决方案

  • 引用标注:在 Prompt 中要求 LLM 引用来源:"请引用具体的文档编号[1][2]"
  • Re-rank + 截断:只送 Top-3 给 LLM,避免信息过载
  • 时间衰减:旧文档降低权重,优先使用最新内容
  • 来源校验:LLM 回答后,用检索结果做事实核查

陷阱五:增量更新导致数据不一致

文档更新后,vector DB 中的旧 embedding 仍然存在,用户搜到过期内容。

解决方案

  • 文档版本管理:每条 chunk 带 doc_version,检索时过滤旧版本
  • 双写策略:先写新版本,验证无误后再删旧版本
  • 定时全量重建:定期重建索引(业务低峰期),清理脏数据

RAG 效果评估

不能只看"像不像",要量化评估:

指标含义如何计算
Hit RateTop-K 结果中包含正确答案的比例人工标注测试集
MRR正确答案的平均倒数排名正确答案排名越靠前 MRR 越高
FaithfulnessLLM 回答是否忠于检索到的文档LLM-as-Judge 逐句核对
Answer Relevance回答是否与用户问题相关Embedding 相似度

优化路线图

  1. Level 1 — 基础可用:语义分块 + 向量检索 + 基础 Prompt
  2. Level 2 — 召回优化:混合检索 + RRF + 查询重写
  3. Level 3 — 精度优化:Re-rank + HyDE + 引用标注
  4. Level 4 — 生产可靠:增量更新 + 效果评估 + A/B 实验
  5. Level 5 — 持续改进:用户反馈闭环 + 主动学习 + 自动评估
未标记