据统计,超过 60% 的 RAG 生产系统在上线后遇到过检索质量退化的问题——要么搜不到相关文档,要么搜到的东西模型不会用。
很多人以为 RAG 就是"把文档扔进向量库,让 LLM 去搜"。实际上,RAG 是一条从文档到答案的完整流水线,每个环节的决策都会影响最终质量。本文不讲概念,只讲工程——你在搭建 RAG 系统时真正会遇到的问题和对应的解法。
先澄清三个最常见的认知偏差:
Chunking 策略直接决定了检索的精度和召回率。没有一种策略适合所有场景,你需要根据文档类型和查询模式来选择。
// 伪代码:递归分块策略示意
function chunk(doc, maxTokens = 512, overlap = 64):
if len(doc) <= maxTokens:
return [doc]
// 优先按语义边界切分
splits = split_at_boundary(doc)
chunks = []
for split in splits:
if len(split) > maxTokens:
// 递归切分大块
chunks.extend(chunk(split, maxTokens, overlap))
else:
chunks.append(split)
// 添加重叠窗口
return add_overlap(chunks, overlap) Embedding 模型的选择不是"越强越好",而是"越匹配越好"。
常用 Embedding 模型对比(2026 年中):
┌──────────────────────┬────────┬──────────┬───────────┐
│ 模型 │ 维度 │ 语言 │ 适用场景 │
├──────────────────────┼────────┼──────────┼───────────┤
│ bge-m3 │ 1024 │ 多语言 │ 通用 │
│ multilingual-e5-large │ 1024 │ 多语言 │ 通用/高精度 │
│ text-embedding-3-small│ 512-1536│ 多语言 │ OpenAI 生态 │
│ jina-embeddings-v3 │ 1024 │ 多语言 │ 长文本 │
│ gte-Qwen2 │ 1024-4096│ 中文为主 │ 中文优化 │
└──────────────────────┴────────┴──────────┴───────────┘ 检索是整个 RAG 管线的瓶颈。优化检索能在不换模型的前提下显著提升质量。
不要指望一次向量搜索拿到答案。生产级 RAG 应该走多阶段管道:
用户查询
↓
Stage 1: 粗排(高效召回 Top-K)
├─ 向量检索(语义相似度)
└─ BM25 检索(关键词匹配)
↓
Stage 2: 融合(去除重复,按分融合)
├─ Reciprocal Rank Fusion (RRF)
└─ 加权合并
↓
Stage 3: 精排(高精度重排序)
└─ Cross-encoder Re-ranker
↓
Stage 4: 截断(保留 Top-N 送入 LLM)
└─ 按质量阈值 + 数量上限
↓
LLM 生成 这是被低估最多的一步。向量检索的 Embedding 是双向的(查询和文档各自编码),而 Cross-encoder 是双向的(查询和文档一起编码),精度远高于向量检索,但速度慢(每次只能比较一对)。
正确做法:先用向量检索粗排 Top-100,再用 Cross-encoder 精排 Top-10。这样兼顾精度和速度。
用户的原始查询往往不是最优的检索语句。一个简单的优化:让 LLM 先对用户的查询做一次重写,然后再去检索。
原始查询:"那个报错怎么解决"
→ 重写后:"Python ModuleNotFoundError 报错的常见原因和解决方案"
→ 检索质量显著提升 搜到了还不够,模型得会用。这是 LLM 层要解决的问题。
上下文注入不是把检索结果原样扔进去就行了。设计原则:
RAG Prompt 模板示例:
---
你是一个基于知识库的问答助手。
请严格遵循以下规则:
1. 你的回答只能基于以下提供的文档内容
2. 如果文档中没有相关信息,请回答"我没有找到相关信息"
3. 引用来源:在回答末尾用 [来源: 文档X/第Y段] 标注
文档内容:
--- BEGIN CONTEXT ---
|{检索结果}|--- END CONTEXT ---
|
|用户问题:{用户输入}|--- 即使有 RAG,LLM 仍然会幻觉。工程层面的防护措施:
RAG 系统需要从两个维度评估,缺一不可:
// 忠实度评估的自动化方法
function checkFaithfulness(answer, context):
// 从回答中提取所有声明性句子
claims = extractClaims(answer)
for claim in claims:
// 检查每个声明是否在上下文中被支持
if not isSupportedBy(claim, context):
return false // 发现幻觉
return true RAG 不是"把文档扔进去",而是一条完整工程流水线:
Chunking → 分块策略决定精度上限
Embedding → 模型选型匹配场景
检索 → 多阶段(粗排→融合→精排)
生成 → Prompt 设计 + 引用 + 幻觉控制
评估 → 检索 + 生成双维度闭环
核心原则:
1. 检索质量决定系统上限,LLM 只是执行者
2. 没有一种方案适合所有场景——测试、度量、迭代
3. 质量评估必须基于真实数据,而不是完美问题 RAG 不是什么新技术,但能在生产环境中持续稳定运行的系统少之又少。如果你正在搭建 RAG 系统,先从 Chunking 和检索质量入手——这两步做对了,后续的问题会少一大半。
💬 评论