先看翻车地图:90% 的 RAG 问题都在检索链路

这是 RAG 最常见的 6 类翻车地图,90% 的人都踩过:

翻车类型 表现症状 根本原因
纯向量检索硬条件失真 “三居"检索到"四居”、“600万以内"出来"650万” 向量只管语义,不管约束
TopK 越大越乱 加到 Top-100,噪声淹没证据,回答反而变差 没有精排,低质量文档混入
Rerank 万能论 以为加 Rerank 就能解决一切,结果延迟爆炸、成本爆炸 没有诊断"是召回错还是排序错"
HyDE 乱补条件 用户说"预算 600 万",生成的假设文档变成"900 万豪宅" 生成模型不理解硬约束
GraphRAG 当银弹 花 3 个月搭建知识图谱,收益还不如 Hybrid + Rerank 用错了场景,关系型问题其实很少
Agentic RAG 上来就开 QPS 崩、预算爆、延迟从 500ms 变成 5s 没有降级策略,把 Agent 当救命稻草

结论:90% 的 RAG 翻车,不是因为模型问题,而是检索链路没想清楚。


完整技术路线概览

这篇文章会给你一张"生产级 RAG 的完整地图"。不是堆砌技术名词,而是告诉你:

第一部分:4 个递进阶段(必须按顺序做)

阶段 1:Hybrid Retrieval
  ├─ 向量召回 + BM25 召回
  ├─ RRF 融合
  └─ 解决:硬条件失真

阶段 2:Rerank(精排)
  ├─ 两阶段检索
  ├─ Top-50 → Top-5
  └─ 解决:Top-1 不稳

阶段 3:Context Engineering(上下文工程)
  ├─ Evidence Table(证据表)
  ├─ 结论-证据绑定
  └─ 解决:幻觉 + 引用错误

阶段 4:Verification + Eval(验证 + 评估)
  ├─ 回答自检
  ├─ 固定测试集
  └─ 解决:上线后变差

第二部分:4 个增强模块(按需加)

增强模块 1:Query Rewrite
  └─ 口语 query 改写成"检索友好"表达

增强模块 2:HyDE
  └─ 生成假设文档,提升软偏好召回

进阶模块 3:GraphRAG
  └─ 关系型问题 + 多跳推理

进阶模块 4:Agentic RAG
  └─ 复杂任务 + 跨系统调用

核心建议:先把 4 个阶段做稳,再考虑增强模块。


第一部分:生产 RAG 的 4 个递进阶段

我把生产级 RAG 拆成 4 个阶段。这不是"高级功能"的堆砌,而是一条必须按顺序走的路线图

阶段 1:Hybrid Retrieval(召回不翻车)

问题:为什么纯向量检索很容易翻车?

向量检索擅长的是语义相似,不擅长的是必须满足

你会遇到这些典型事故:

  • “三居” → 检索到"四居"(语义接近,但硬条件错了)
  • “600万以内” → 出来"650万"(价格是数字,向量不理解)
  • “北京朝阳” → 出来"北京海淀"(地名相似,但位置错了)
  • “必须支持 API X” → 结果召回了一堆"类似的"文档

这不是你的 prompt 写得差,而是向量检索天然不是为"硬条件"设计的。

Hybrid 的核心价值:向量负责语义,关键词负责约束。

向量检索(Vector):找"意思接近的"
关键词检索(BM25):找"字面必须出现的"

什么时候必须用 Hybrid?

满足以下任意一条,就应该上 Hybrid:

  • Query 里包含数字/单位:3居、600万、100㎡、2023版
  • Query 里包含专有名词:产品名、接口名、政策条款编号
  • 业务里硬条件非常多:筛选类/推荐类/合规类系统

Hybrid 怎么落地(最小可行实现):

不用上来搞很复杂的融合,最小版本就够用:

# Stage 1: Hybrid Retrieval (伪代码)

def hybrid_retrieval(query, top_k=50):
    # Step 1: 向量召回
    vector_results = vector_search(query, top_k=top_k)
    
    # Step 2: BM25 召回
    bm25_results = bm25_search(query, top_k=top_k)
    
    # Step 3: 合并去重(使用 RRF)
    merged = merge_with_rrf(vector_results, bm25_results)
    
    # Step 4: 返回候选集
    return merged[:100]  # 返回 Top-100

融合方式建议用 RRF(Reciprocal Rank Fusion):

RRF 的思想很简单:不关心具体分数,只看排名。文档在多个召回源里排名越靠前,总分越高,最终更容易排到前面。

# RRF 合并伪代码(5 行)
def merge_with_rrf(results_a, results_b, k=60):
    scores = {}
    for rank, doc in enumerate(results_a, 1):
        scores[doc['id']] = scores.get(doc['id'], 0) + 1/(k + rank)
    for rank, doc in enumerate(results_b, 1):
        scores[doc['id']] = scores.get(doc['id'], 0) + 1/(k + rank)
    return sorted(scores.items(), key=lambda x: x[1], reverse=True)

这样就能稳定地融合多路召回结果。

升级信号:什么时候从 Hybrid 升级到 Rerank?

  • Top-5 准确率已经很高(>80%)
  • 但 Top-1 经常不对(<60%)
  • 说明召回对了,但排序错了

阶段 2:Rerank(让 Top-1 稳下来)

问题:Top-1 不稳定怎么办?

这是最关键的诊断:你到底是"召回错"还是"排序错"?

很多人优化 RAG 失败,就是因为方向错了。

最省时间的诊断方式:

看两个指标:

  • Top-5 准确率
  • Top-1 准确率

判断逻辑:

情况 A:Top-5 也很差(<60%)
  → 说明"召回错"
  → 优先改:embedding / chunk / query rewrite / Hybrid

情况 B:Top-5 很高(>80%),但 Top-1 低(<60%)
  → 说明"排序错"
  → 优先加:Rerank

举个最典型的排序瓶颈:你的系统 Top-5 准确率 = 88%,但 Top-1 准确率 = 55%。这说明正确答案其实已经被你召回了,只是排序把它压到了第二、第三甚至第五。这种情况下继续换 Embedding、调 chunk 往往收益很小,正确解法是加 Rerank。

Rerank 是什么?

一句话解释:Rerank 的本质不是"再算一遍相似度",而是用更强的相关性模型,把候选集合重新排序

标准做法是两阶段检索:

第一阶段:Retriever(快)→ Top-50
第二阶段:Rerank(准)→ Top-5

怎么落地(推荐默认参数):

# Stage 2: Recall + Rerank (伪代码)

def retrieve_and_rerank(query):
    # Step 1: Hybrid 召回 Top-50
    candidates = hybrid_retrieval(query, top_k=50)
    
    # Step 2: Rerank 精排
    reranked = rerank_model.rank(
        query=query,
        documents=candidates,
        top_k=5
    )
    
    # Step 3: 只把 Top-5 拼成 context
    context = format_context(reranked[:5])
    
    return context

工程经验:

  • Top-20 往往不够稳
  • Top-100 成本高但收益不明显
  • Top-50 是很常见的 sweet spot

Rerank 的代价是什么?

一句话:延迟上升明显

但现实是:你不想加 rerank,通常是因为怕慢;但你不加 rerank,系统通常就是不准。

所以生产上要做的是:

对高价值场景开启 rerank
对低价值或高 QPS 场景降级(不 rerank 或用轻量 rerank)

升级信号:什么时候从 Rerank 升级到 Context Engineering?

  • 检索已经对了(Top-5 准确率 >85%)
  • 但回答还是不稳定
  • 症状:幻觉多、引用错误、逻辑混乱
  • 说明问题不在检索,而在 Context 组织

阶段 3:Context Engineering(让答案不胡说)

问题:检索对了,为什么回答还是乱?

因为 LLM 不会自动做这些事:

  • 去重:同一事实重复 5 次
  • 消歧:A 文档和 B 文档冲突
  • 抽重点:10 段里哪句是关键证据
  • 结构化表达:让答案更可读

Context Engineering 的最小可行方案:

你不需要上来做 fancy 的压缩模型,最小落地就够用。

对比:为什么 Context 组织很关键?

❌ 拼 chunk 模式:
  5 段乱七八糟的文本 → LLM 自己归纳
  结果:容易幻觉、引用错误、逻辑混乱

✅ 证据表模式:
  结论-证据绑定 → 结构化输入
  结果:输出变稳、引用准确、幻觉减少

推荐 Context 模板:Evidence Table(证据表)

把 Top-5 证据整理成固定结构:

证据 1:
  来源:文档 A,第 3 段
  核心句:XXX
  支持点:支持结论 1、结论 2

证据 2:
  来源:文档 B,第 5 段
  核心句:YYY
  支持点:支持结论 3

...

然后再让 LLM 生成回答。

效果非常直接:

  • 回答更稳
  • 引用更准确
  • 幻觉显著减少

怎么落地:

# Stage 3: Context Engineering (伪代码)

def format_evidence_table(reranked_docs):
    evidence_table = []
    
    for idx, doc in enumerate(reranked_docs, 1):
        evidence = {
            "id": idx,
            "source": doc["source"],
            "core_sentence": extract_key_sentence(doc),
            "support_points": extract_key_points(doc)
        }
        evidence_table.append(evidence)
    
    # 格式化为 Markdown 表格
    formatted = format_as_table(evidence_table)
    
    return formatted

def generate_answer_with_evidence(query, evidence_table):
    prompt = f"""
    基于以下证据表,回答用户问题。
    
    {evidence_table}
    
    用户问题:{query}
    
    要求:
    1. 每条结论必须引用证据编号
    2. 如果证据不足,标注"信息不足"
    3. 不要编造证据中没有的内容
    """
    
    answer = llm.generate(prompt)
    return answer

升级信号:什么时候从 Context Engineering 升级到 Verification?

  • 回答已经很稳定了
  • 但你需要可追溯性可信度
  • 特别是在合规/医疗/金融场景

阶段 4:Verification + Eval(上线可控)

问题:怎么确保上线后系统不会变差?

这是最被忽视的一步,也是最关键的一步。

结论先说:没有评估体系的 RAG,本质是随机系统。

Verification 的工程动机:

Verification 不是为了让回答更长,而是为了防止:模型把"检索到的内容"合理化扩写成"看似正确但无证据的结论"

这是生产系统最常见的隐形 bug。

最小可行的验证方案:

两步就够:

  1. 回答时强制输出引用

    • 每条结论绑定证据编号
    • 格式:结论 [证据 1, 证据 3]
  2. 回答后让模型做一次自检

    • “这句话是否能被证据支持?”
    • “证据不足就标注不确定”
# Stage 4: Verification (伪代码)

def verify_answer(answer, evidence_table):
    verification_prompt = f"""
    检查以下回答是否被证据支持:
    
    回答:{answer}
    证据表:{evidence_table}
    
    对每条结论进行检查:
    1. 是否有对应证据?
    2. 是否有无证据的结论?
    3. 是否有矛盾?
    
    输出格式:
    - 结论 1:✓ 有证据 / ✗ 无证据
    - 结论 2:✓ 有证据 / ✗ 无证据
    """
    
    verification = llm.generate(verification_prompt)
    return verification

def generate_final_answer(query, evidence_table):
    # Step 1: 生成初始回答
    answer = generate_answer_with_evidence(query, evidence_table)
    
    # Step 2: 验证回答
    verification = verify_answer(answer, evidence_table)
    
    # Step 3: 如果有无证据结论,标注不确定
    final_answer = mark_uncertain_conclusions(answer, verification)
    
    return final_answer

评估体系怎么做(工程版):

最小落地只要做三件事:

1. 固定测试集(按类型分桶)

硬条件 query:20 个
  - 区域/户型/预算组合
  - 例:北京朝阳 3 居 600 万以内

强意图 query:20 个
  - 明确需求
  - 例:我想找一个通勤方便的房子

软偏好 query:20 个
  - 模糊需求
  - 例:我想住得安静点

边界 query:10 个
  - 容易混淆的
  - 例:三居 vs 三房一厅

总计 70 个,按类型分桶回归

2. 最小评分口径(可落地)

Retrieval@5:是否命中正确文档?(0/1)
Top-1 硬条件:是否满足硬条件?(0/1)
Answer 引用:是否引用正确证据?(0/1)
Answer 幻觉:是否出现无证据结论?(0/1)

3. 线上监控的 3 个关键指标

用户满意度:点赞率 / 追问率
召回为空率:检索不到的比例
延迟:p95 latency

升级信号:什么时候需要前沿技术?

  • 4 阶段都做稳了
  • 但还有特定场景不行
  • 比如:多跳推理、复杂任务、口语化 query

第二部分:增强模块(按需使用,别抢主线戏份)

前沿技术不是"更好",而是"更专"。只在特定场景用。

增强模块:Query Rewrite(口语 query 的最低成本解)

什么时候用:

  • 用户 query 很短
  • 口语偏好很强
  • 但你不希望引入太多不可控生成

怎么用:

让 LLM 输出一个"更适合检索"的 query,并要求:

  • 不新增事实
  • 不新增硬条件
  • 只做同义改写 + 补全上下文
# Query Rewrite (伪代码)

def rewrite_query(original_query):
    rewrite_prompt = f"""
    把用户问题改写成"更适合检索"的表达。
    
    原问题:{original_query}
    
    要求:
    1. 不新增事实
    2. 不新增硬条件
    3. 只做同义改写 + 补全上下文
    
    改写后的问题:
    """
    
    rewritten = llm.generate(rewrite_prompt)
    return rewritten

def retrieve_with_rewrite(query):
    # 原 query 召回
    results_original = hybrid_retrieval(query, top_k=50)
    
    # 改写后 query 召回
    rewritten = rewrite_query(query)
    results_rewritten = hybrid_retrieval(rewritten, top_k=50)
    
    # 合并
    merged = merge_and_deduplicate(results_original, results_rewritten)
    
    return merged

增强模块:HyDE(软偏好 query 的召回增强器)

什么时候用:

  • 软偏好 query 多(安静/通勤/采光)
  • Query 和文档语言差异大
  • 你希望提升语义召回的稳定性

怎么用:

不要用 HyDE 替代原 query,而是双通道融合

# HyDE (伪代码)

def hyde_retrieval(query):
    # Step 1: 生成假设文档
    hyde_prompt = f"""
    假设用户问题的答案是一篇文档,这篇文档会是什么样的?
    
    用户问题:{query}
    
    假设文档:
    """
    
    hypothetical_doc = llm.generate(hyde_prompt)
    
    # Step 2: 用假设文档去检索
    hyde_results = vector_search(hypothetical_doc, top_k=20)
    
    return hyde_results

def retrieve_with_hyde(query):
    # 原 query 召回
    results_original = hybrid_retrieval(query, top_k=20)
    
    # HyDE 召回
    results_hyde = hyde_retrieval(query)
    
    # 合并去重
    merged = merge_and_deduplicate(results_original, results_hyde)
    
    # Rerank
    reranked = rerank_model.rank(query, merged, top_k=5)
    
    return reranked

** HyDE 最容易翻车的地方:**

生成会乱补条件。比如用户说"预算 600 万",HyDE 可能生成"高端豪宅 900 万"。

工程原则:

硬条件问题:少用 HyDE
软偏好问题:HyDE 提升巨大
永远保留原 query 通道做兜底

进阶模块:GraphRAG(关系型问题才值得用)

什么时候用:

  • 多跳推理:A 影响 B,B 依赖 C
  • 企业内部系统关系网
  • 法规条款互相引用

什么时候别用:

  • Chunk 已经能直接回答的问题
  • 只要 topK 就能解决的简单问答
  • 构建成本远超收益

最小落地(行动起点):

GraphRAG 最小实现:
  1. 实体抽取:从文档中抽取关键实体
  2. 共现关系:建立实体间的关系
  3. BFS 扩展召回:从查询实体出发,扩展 N 跳

工程建议:

GraphRAG 很强,但构建成本高,别一上来就用它当默认方案。

什么时候从 Rerank 升级到 GraphRAG?

  • 你的问题本质是"关系型"
  • 单个文档无法回答,需要跨文档推理
  • 比如:“这个政策对哪些人有影响?” → 需要跨多个文档

进阶模块:Agentic RAG(复杂任务能力,但成本极高)

什么时候用:

  • 复杂问题且容错成本高(合规/医疗/金融)
  • 需要跨系统工具调用(DB + 文档 + API)

什么时候别用:

  • 高 QPS 问题
  • 问题很简单但量很大(客服 FAQ)

最小落地(行动起点):

Agentic RAG 最小实现:
  1. Planner:拆问题 → 生成子问题列表
  2. Retriever:多轮查证据 → 逐个回答子问题
  3. Answer:带引用输出 → 综合所有证据生成最终答案

工程建议:

要上 Agentic RAG,先把你的 Eval 和降级策略做好,否则成本会爆炸。

# Agentic RAG 降级策略 (伪代码)

def agentic_rag_with_fallback(query):
    # 高峰期:关闭 Agent,用简单 RAG
    if is_peak_hour():
        return simple_rag(query)
    
    # 低峰期:启用 Agent
    if is_low_traffic():
        return agentic_rag(query)
    
    # 成本爆了:降级
    if cost_exceeded():
        return simple_rag(query)

第三部分:落地交付

完整架构图(文字版)

用户 Query
    ↓
[Query 理解] → 判断硬条件/软偏好
    ↓
[多路召回]
  ├─ 向量召回 Top-50
  ├─ BM25 召回 Top-50
  └─ HyDE 召回 Top-20(仅软偏好)
    ↓
[Fusion] → 合并去重 → Top-80~100
    ↓
[Rerank] → Top-5
    ↓
[Context Engineering] → Evidence Table
    ↓
[Answer Generation] → 带引用回答
    ↓
[Verification] → 自检:每条结论是否可被证据支持
    ↓
[Eval Loop] → 每周回归测试集 + 线上监控
    ↓
用户回答

选型表:哪个技术解决哪个问题?

痛点 推荐方案 典型收益 典型代价
硬条件召回错 Hybrid 召回稳定 +30% 工程复杂
Top-1 不稳 Rerank 准确率提升最大 延迟增加 100ms
口语 query 崩 Rewrite / HyDE 软偏好提升明显 不可控
多跳关系问题 GraphRAG 跨文档推理强 构建成本高
复杂任务 Agentic RAG 复杂问题更强 成本爆炸

第四部分:生产经验 + 降级策略

升级路线图

第 1 周:Hybrid(稳定召回)
  ↓
第 2 周:Rerank(稳定 Top-1)
  ↓
第 3 周:Context Engineering(稳定输出)
  ↓
第 4 周:Verification + Eval(稳定上线)
  ↓
第 5+ 周:增强技术(按需加)

降级策略(生产系统必备)

上线必问:高峰期怎么办?成本爆了怎么办?

# 降级策略 (伪代码)

def rag_with_fallback(query):
    # 高峰期:关闭 HyDE + Rerank
    if is_peak_hour():
        return simple_hybrid_retrieval(query)
    
    # 成本爆了:只回答"有证据的内容"
    if cost_exceeded():
        results = retrieve_and_rerank(query)
        return filter_high_confidence_only(results)
    
    # 正常情况:完整流程
    return full_rag_pipeline(query)

硬条件解析的重要性

结构化约束不是 RAG 的敌人,是 RAG 的护城河。

在房产/电商/招聘场景,硬条件(价格/户型/范围/时间)非常多。

你应该做的是:

Hybrid + Filter + Rerank 才能稳

不是:

纯向量 + 祈祷

结语:前沿 RAG 的重点不是"更复杂",而是"更可控"

如果你读到这里,你会发现一个很重要的事实:

大多数所谓的"RAG 前沿技术",本质都在解决同一个目标:

  • 让检索更稳定
  • 让答案更可信
  • 让系统可评估、可迭代

你不需要一开始就上 GraphRAG、Agentic RAG。

真正的工程路线通常是:

  1. Hybrid(稳定召回)
  2. Rerank(稳定 Top-1)
  3. Context Engineering(稳定输出)
  4. Verification + Eval(稳定上线)

做到这四步,你的 RAG 就已经超过 90% 的"只会拼 chunk"的系统了。

你可以没有 Agent,但你不能没有 Eval:没有评估体系的 RAG,本质是随机系统。上线前,先把评估体系搭好。这不是"可选项",是"必选项"。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐