为什么 RAG 的问题通常先出在检索层
很多团队第一次做 RAG,会把注意力放在向量库、模型选择和 Prompt 上。Demo 阶段这通常够用:上传文档、切块、向量化、检索 top-k、拼进上下文、让模型回答。
但进入生产环境后,问题会很快出现:用户问的是具体条款,检索出来的是相邻但无关的段落;文档里有表格,chunk 却把表头和数据拆散;检索 top-k 很多,但真正能回答问题的证据在第 8 位;生成模型看似回答得很完整,但引用并不支持结论。
这说明 RAG 的核心不是「把文档塞给模型」,而是把正确证据以正确顺序、正确粒度、正确压缩形式交给模型。
如果检索层错了,生成层通常只是在错误证据上做语言包装。因此,生产级 RAG 优化应该先建立 Retrieval Quality Engineering,而不是无止境地调 Prompt。
一句话理解检索质量工程
RAG 检索质量工程可以简化成下面这条链路:
Document Parsing -> Chunking -> Metadata Enrichment -> Sparse + Dense Retrieval -> Fusion -> Reranking -> Evidence Packing -> Generation -> Evaluation
每一层都会影响最终答案质量。一个稳定的系统不是依赖某个「最强 embedding 模型」,而是让每一层都可观测、可调参、可评估。
核心知识结构
可以把 RAG 检索质量拆成 6 个模块。
1. 文档解析
PDF、Word、HTML、Markdown、表格、扫描件的结构完全不同。解析阶段要尽量保留标题、层级、表格、页码、章节、来源和权限信息。
如果解析阶段丢掉结构,后续 chunking 和 retrieval 很难补救。
2. Chunking
Chunk 不是简单按 token 数切割。法律条款、技术文档、财务报表、API 文档、FAQ 的最佳切分方式可能完全不同。
生产系统应至少比较 fixed-size、recursive、semantic、structure-aware、table-aware 等策略,并按文档类型选择。
3. Sparse Retrieval
BM25 这类稀疏检索擅长处理精确词、编号、产品代码、金额、日期、表字段和专有名词。很多企业文档并不适合只用语义向量检索。
4. Dense Retrieval
向量检索擅长语义相似、同义表达和模糊问题。它适合用户表达不稳定、问题需要语义泛化的场景。
5. Reranking
第一阶段召回通常追求 recall,宁愿多拿一些候选。第二阶段 reranker 再判断 query 与 document 的精细相关性,把最有用证据排到前面。
6. Evaluation
RAG 评估必须拆开看:retriever 是否找到证据,reranker 是否排对顺序,generator 是否忠实使用证据,最终答案是否满足业务目标。
为什么不要迷信「大上下文直接塞进去」
长上下文模型降低了 RAG 门槛,但没有消灭检索质量问题。
如果把大量低相关 chunk 全塞进上下文,会带来 4 个问题:
- 噪声增加,模型更容易抓错证据。
- 关键证据可能出现在上下文中间,利用率下降。
- 成本和延迟上升。
- 引用和可追溯性变差。
更可靠的做法是:少给上下文,但提高上下文密度。
| 做法 | 说明 |
|---|---|
| Bad | retrieve 20 noisy chunks and hope the model finds the answer |
| Good | retrieve 50 candidates, rerank to 5 high-quality evidence chunks, then pack with citations |
这也是 reranking 和 evidence packing 的价值。
推荐流程:从文档到答案的检索闭环
一个生产级 RAG 检索流程可以这样设计:
- 解析文档,保留标题、页码、表格、章节、权限和来源
- 按文档类型选择 chunking 策略
- 为 chunk 增加 metadata,例如文档类型、章节、时间、产品、地域
- 同时执行 BM25 和 dense vector retrieval
- 用 RRF 或其他 fusion 方法合并候选结果
- 用 reranker 对 top-N 候选重新排序
- 按 token budget 打包证据,保留引用和来源
- 让模型基于证据生成答案
- 用 Context Precision、Context Recall、Faithfulness 等指标评估
- 将失败样本回流到 chunking、retrieval、reranking 和 prompt 策略
这条链路的重点是:检索不是一次性配置,而是一个持续评估和迭代的系统。
Chunking:决定证据粒度的第一道门
差的 chunking 会导致两种典型问题。
问题一:切得太碎
如果 chunk 太小,单个 chunk 缺少足够上下文。模型可能拿到一句结论,但看不到适用条件、例外条款或表格表头。
风险:高 precision,低 completeness
问题二:切得太大
如果 chunk 太大,embedding 会把多个主题压进一个向量,检索结果看似相关,但真正答案只占很小一部分。
风险:高 recall,低 precision,高噪声
更稳的策略是按内容结构切分:
| 文档类型 | 推荐 chunking 策略 |
|---|---|
| Markdown / HTML | 按标题层级切 |
| 合同 / 条款 | 按章节、条款、适用条件切 |
| 表格 | 保留表头、行列关系和单位 |
| API 文档 | 按 endpoint、参数、示例切 |
| FAQ | 按问答对切 |
| 扫描件 | 先做 OCR 质量检测,再分块 |
对企业文档来说,structure-aware chunking 通常比固定 token 切分更值得优先测试。
Hybrid Retrieval:BM25 和向量检索不是替代关系
很多团队早期会直接上 dense retrieval,然后发现一些看似简单的问题反而搜不到:
- 订单号、合同号、保单号。
- 精确金额或日期。
- 表格字段名。
- 产品型号。
- 法条编号。
- 代码函数名。
这些场景下,BM25 或其他 keyword retrieval 往往更稳。向量检索更适合语义泛化,例如「退保需要什么材料」和「取消保单要交哪些文件」。
因此,更实用的架构通常是:
BM25 Retriever -> candidate set A
Dense Retriever -> candidate set B
Fusion -> candidate set C
Reranker -> final evidence set
Fusion 可以使用 Reciprocal Rank Fusion,也可以按业务字段做加权。例如金融、保险、合同、代码文档中,精确命中的编号、标题、表字段可以给更高权重。
Reranking:把「召回很多」变成「排对证据」
第一阶段检索的目标是不要漏掉候选证据,所以 top-k 往往会取大一些。但大 top-k 不能直接塞给模型,否则会把噪声也带进上下文。
Reranker 的作用是对 query-document pair 做更精细判断:这个 chunk 是否真的能回答这个问题?它是否比其他 chunk 更直接?它是否只是主题相似但没有答案?
一个常见配置:
retrieval:
bm25_top_k: 30
dense_top_k: 30
fusion_top_k: 40
reranking:
model: cross_encoder_or_llm_reranker
final_top_k: 5
evidence_packing:
max_context_tokens: 4000
keep_citations: true
deduplicate_near_duplicates: true
这类配置的目标是让模型看到更少但更准的证据。
Evidence Packing:不是 top-k 拼接
即使 reranker 排好了顺序,证据打包仍然需要策略。
常见错误是直接把 top-k chunk 按顺序拼接。这样会产生 3 个问题:
- 重复 chunk 浪费上下文。
- 同一来源证据过多,覆盖面不足。
- 引用信息丢失,无法追溯。
更好的 evidence packing 应该考虑:
| 维度 | 策略 |
|---|---|
| 去重 | 删除近重复 chunk |
| 覆盖 | 不同章节或来源适度分散 |
| 顺序 | 把最关键证据放在更容易被使用的位置 |
| 压缩 | 对长 chunk 做上下文保留型摘要 |
| 引用 | 保留 source_id、page、section、url、timestamp |
| 权限 | 确保用户有权访问该证据 |
对严肃业务来说,答案中每个关键结论都应该能映射回至少一个证据片段。
评估指标:把 Retriever 和 Generator 分开看
RAG 失败时,不能只看最终答案。必须判断失败发生在哪一层。
Retriever 指标
| 指标 | 含义 |
|---|---|
| Recall@k | 相关证据是否被召回 |
| MRR | 第一个相关证据排在多前 |
| nDCG | 排序质量是否合理 |
| Context Precision | 前排 chunk 是否真的相关 |
| Context Recall | 相关证据是否覆盖完整 |
Generator 指标
| 指标 | 含义 |
|---|---|
| Faithfulness | 回答是否被检索上下文支持 |
| Answer Relevancy | 回答是否回应用户问题 |
| Citation Coverage | 关键结论是否有引用 |
| Completeness | 是否覆盖所有子问题 |
| Refusal Accuracy | 无证据时是否拒答或说明不确定 |
系统指标
retrieval_latency_ms
rerank_latency_ms
context_tokens
cost_per_query
cache_hit_rate
eval_pass_rate
regression_delta
只有拆开指标,才能知道应该调 chunking、top-k、fusion、reranker、prompt,还是生成模型。
一个可落地的评测样例
case_id: policy_claim_038
query: "胃肠炎门诊花费 720 元,医保统筹后还能报销吗?"
expected_evidence:
- source_id: policy_medical_2026
section: 门急诊责任
- source_id: policy_medical_2026
section: 免赔额与报销比例
retrieval_metrics:
recall_at_5_required: true
context_precision_min: 0.75
generation_requirements:
must_cite_policy: true
must_explain_deductible: true
must_not_invent_coverage: true
should_state_uncertainty_if_missing_evidence: true
这类样例比「看回答顺不顺眼」更适合进入 CI 回归测试。
常见失败模式
- 只用一种 chunking 策略处理所有文档 — 技术文档、合同条款、表格和 FAQ 的结构不同,不应被同一种固定 token splitter 处理。
- 只用向量检索 — 向量检索擅长语义相似,但对编号、金额、日期、字段名等精确匹配不一定稳定。
- top-k 越大越放心 — top-k 过大会增加噪声、成本和位置干扰。更好的策略是扩大候选召回,再用 reranker 收敛证据。
- 评估只看最终答案 — 如果不单独评估 retriever,很容易把检索错误误判为模型幻觉或 Prompt 问题。
- 不保留引用和来源 — 没有 source_id、page、section、timestamp,RAG 就无法审计,也很难用于高风险业务。
生产落地 Checklist
上线前建议检查:
- 是否保留文档结构、页码、章节、表头和权限信息。
- 是否按文档类型选择 chunking 策略。
- 是否同时评估 BM25、dense retrieval 和 hybrid retrieval。
- 是否对 top-N 候选使用 reranker。
- 是否记录 Context Precision、Context Recall、MRR 和 nDCG。
- 是否评估 Faithfulness 和 Citation Coverage。
- 是否有无证据拒答策略。
- 是否对表格、编号、金额、日期类问题单独建测试集。
- 是否把失败样本回流到 chunking 和 retrieval 参数调整。
- 是否监控 retrieval latency、rerank latency 和 context token 成本。
- 是否在模型、embedding、chunking、reranker 变更时跑回归测试。
- 是否保留证据引用,支持人工审计。
结论
RAG 的本质不是「让大模型读更多资料」,而是建立一条可追踪的证据供应链。
- 文档解析决定信息是否完整
- Chunking 决定证据粒度
- Hybrid retrieval 决定候选覆盖
- Reranking 决定证据顺序
- Evidence packing 决定上下文密度
- Evaluation 决定系统能否持续变好
对工程团队来说,最实用的原则是:不要先问 Prompt 怎么写得更聪明,而要先问证据是否真的被找对、排对、压缩对、引用对。
当检索质量成为可观测、可评估、可回归的工程流程,RAG 才能从 Demo 变成稳定的生产系统。