RAG深度解析

为什么需要RAG

RAG = 检索(Retrieval)+ 增强(Augmented)+ 生成(Generation)。在 LLM 生成回答之前,先从外部知识库检索相关信息,拼接后一起送入模型。

方案知识来源准确性更新成本典型场景
纯 LLM 训练参数中的记忆 幻觉风险高 重新训练/微调 通用对话
微调 LLM 微调数据 + 原始参数 领域内较好 新数据需重新微调 垂直领域问答
RAG 外部知识库(实时) 可溯源、可验证 更新文档即可 企业知识库、客服、法律

RAG 解决的三个核心痛点:

① 幻觉——LLM 不知道的事会编造,RAG 提供事实依据;

② 知识时效——训练数据有截止日期,RAG 可接入最新文档;

③ 可解释性——每个回答都能溯源到具体文档,不是黑箱。

RAG完整流程

# ============ 离线阶段(Indexing)============

原始文档(PDF/Word/HTML)
    │
    ▼  ① 文档解析 & 分块
文本块 [chunk_1, chunk_2, ..., chunk_N]
    │
    ▼  ② Embedding 向量化
向量 [v_1, v_2, ..., v_N]
    │
    ▼  ③ 存入向量数据库
Milvus / Pinecone / Weaviate / Qdrant

# ============ 在线阶段(Retrieval & Generation)============

用户提问: "如何配置 Nginx 反向代理?"
    │
    ▼  ④ Query 向量化(同 Embedding 模型)
    │
    ▼  ⑤ 向量检索(ANN 近似最近邻)
Top-K 相关文档块
    │
    ▼  ⑥ 重排序(Rerank)
精排后的 Top-M 结果
    │
    ▼  ⑦ Prompt 组装
System: "根据以下文档回答问题:{docs}\n\n问题:{query}"
    │
    ▼  ⑧ LLM 生成
最终回答(带引用来源)

文档解析与分块

文档解析

文档类型工具常见问题
纯文本 / Markdown 直接读取 编码问题、特殊字符
PDF PyMuPDF, PDFPlumber, Unstructured 扫描版 PDF 无文字层;表格/多栏排版错乱
Word python-docx 嵌入图片/公式丢失
HTML BeautifulSoup, Trafilatura 导航栏/广告等噪声混入正文
PPT python-pptx SmartArt/图表文字丢失

⚠ 最大痛点:扫描件与复杂排版

扫描版 PDF 需要 OCR(Tesseract / PaddleOCR / LLM Vision),但识别准确率受限。表格和多栏排版容易被解析成乱序文本——这是 RAG 系统的第一道坎,文档解析的质量直接决定了后续所有环节的上限。

文本分块(Chunking)

分块是 RAG 中最容易被低估的环节。切太细→语义不完整;切太粗→检索精度下降。

策略做法优点缺点
固定长度 每 N 个 token 一刀切 简单、速度快 经常切断句子/段落
基于分隔符 按 \\n\\n、\\n、。!?等分隔 较自然 复杂文档分隔符不统一
语义分块 用 Embedding 算句子相似度,断在"语义突变"处 最自然 计算成本高
递归分块 先大后小逐层尝试:段落→句→词 兼顾精度与完整性 工程复杂度高
Small-to-Big 检索用小块(精确匹配),生成用大块(完整上下文) 检索与生成各取所需 需维护两种索引

⚠ 分块陷阱:Chunk Overlap 的权衡

overlap 太小→相邻 chunk 间的信息断裂;overlap 太大→冗余信息挤占上下文窗口。通常设置为 chunk_size 的 10%~20%。举个例子:chunk_size=512 tokens,overlap=50~100 tokens。没有普适最优值——取决于文档结构和下游任务。

前沿方案

LlamaIndex / LangChain 的智能解析

Hierarchical Chunking(层级分块):文档 → 章节 → 段落 → 句子,不同粒度同时建索引。检索时先用粗粒度定位,再精细召回。

Metadata 增强:每个 chunk 附带标题层级、页码、文档来源等元信息,生成时用于引用溯源。

LLM 辅助清洗:用 LLM 对原始文档做"结构化改写"——把杂乱格式统一成标准 Markdown,表格转文字描述——然后再分块入库。

Embedding嵌入模型

模型选型

模型维度最大长度中文效果适用场景
text-embedding-3-small 512/1536 8191 通用,英文为主
text-embedding-3-large 256~3072 8191 较好 高质量需求
bge-large-zh-v1.5 1024 512 中文场景首选
bge-m3 1024 8192 多语言、长文本、稀疏+稠密双表征
stella-base-zh-v3-1792d 1792 512 高维度,精度优先
GTE-Qwen2-7B-instruct 3584 32768 最优 LLM-based Embedding,需 GPU

核心问题

问题一:Embedding 模型的"语义盲区"

稠密向量擅长捕捉语义相似度,但对精确关键词匹配不敏感。查询"AK-47 参数"时,向量检索可能返回"步枪发展史"(语义相近)而不是具体的 AK-47 技术手册(关键词精确)。

解决:混合检索(Hybrid Search)= 稠密向量 + BM25 关键词检索,取长补短。

问题二:不对称语义(Query-Document Mismatch)

用户问"怎么修漏水的水龙头",文档写的是"水龙头维修指南"。Query 和 Document 的表达方式不一样——Embedding 模型必须理解它们是同一件事。使用专门做过对比学习训练的 Embedding 模型(如 BGE、E5 系列),它们在训练时就用 (query, positive_doc, negative_doc) 三元组优化过这种对齐能力。

问题三:长文本截断

大多数 Embedding 模型有最大输入长度限制(512/8192 tokens),超过部分直接截断→信息丢失。

解决:

① 用 bge-m3 (8192) 或 GTE-Qwen2 (32768);

② 对超长文档先摘要再 Embedding;

③ 分块时保证每块在限制内。

向量数据库与索引

主流选型

数据库定位索引算法特点
Milvus 分布式向量数据库 HNSW, IVF_FLAT, DiskANN 十亿级向量、混合检索、多租户
Pinecone 云原生向量数据库 自研 免运维、按量付费
Weaviate 开源向量数据库 HNSW 内置 GraphQL + 混合检索
Qdrant 高性能向量数据库 HNSW Rust 实现、过滤能力强
Chroma 轻量向量数据库 HNSW 适合原型、Python 原生
Elasticsearch 搜索引擎 + 向量 HNSW 已有 ES 集群的首选

ANN 索引算法

底层需求

你手里有几百万 / 上亿条高维向量(图片、文本、音频转出来的数字特征),现在输入一条新向量,要找出库里和它最像的 N 条。

如果逐条对比全部向量,速度慢到爆炸,ANN 近似最近邻就是「不用全部比对,牺牲一丢丢精准度,换极速查找」的算法,HNSW、IVF_PQ 是两种主流方案。

 

HNSW(Hierarchical Navigable Small World)

当前最主流的 ANN 算法。构建多层图结构,上层稀疏、下层密集。检索时从顶层快速"跳"到目标区域,再在下层精确搜索。内存占用高(需存全图),但查询速度最快。

关键参数:M(每层节点连接数,越大精度越高但内存越大)、ef_construction(构建时搜索宽度)、ef_search(查询时搜索宽度)。

 

IVF_FLAT + PQ(Product Quantization)

IVF:用 K-means 聚类将向量空间分成 N 个区域,检索时只搜最近的几个区域。PQ:将高维向量压缩为短码,大幅降低内存占用。适合内存受限场景,但精度略低于 HNSW。

 

⚠ 索引构建慢、内存爆炸、精度衰减

索引构建:HNSW 构建 O(N·logN·M),百万级向量可能耗时数小时。解决——增量索引、分布式构建。

内存爆炸:1024 维 × 1000 万向量 × 4 bytes ≈ 40GB。解决——PQ 量化压缩、DiskANN 磁盘索引。

精度衰减:ANN 是近似检索,召回率不是 100%。解决——适当增大 ef_search,或 ANN + 精确重排两阶段。

检索策略

稀疏检索(Sparse Retrieval)— BM25

基于词频-逆文档频率(TF-IDF)的经典算法。核心公式:

BM25(q, d) = Σ IDF(qi) · f(qi, d) · (k1+1) / (f + k1·(1−b+b·|d|/avgdl))

优势:精确关键词匹配(人名、专有名词、代码变量名),不会被"语义相似"带偏。

劣势:同义词、近义词完全不懂——搜"汽车"不会返回"轿车"。

稠密检索(Dense Retrieval)— 向量相似度

将 Query 和 Document 都用 Embedding 模型变成向量,算余弦相似度。

优势:语义理解——"怎么退钱"能匹配到"退款流程说明"。

劣势:精确匹配能力弱,边界 case 容易出错。

混合检索(Hybrid Search)

⭐ 生产环境标配:BM25 + 向量,双路召回 → 融合排序

两路各自返回 Top-K,然后通过 RRF(Reciprocal Rank Fusion)合并:

RRFscore(d) = Σ 1/(ranki(d) + k)   (k 通常取 60)

文档在多路中同时靠前→总分最高→最终排名最前。这是目前工业界最成熟的混合检索方案。

 

检索阶段的常见问题

问题一:检索到的文档和问题无关(Low Recall)

原因:Embedding 模型不够好、chunk 切得太碎或太粗、索引参数不合理。

解决:

① 换更强 Embedding 模型;

② Query 改写(Query Rewriting)——用 LLM 把口语化提问改写成检索友好的查询;

③ 多轮检索(Multi-hop Retrieval)——第一轮召回→提取关键实体→第二轮精确搜索。

问题二:检索到的文档太多太杂(Low Precision)

解决:

① Rerank 精排(见下一节);

② 元数据过滤(按日期/来源/类别预筛选);

③ Self-Query Retrieval——LLM 先解析 query 中的过滤条件("最近的"→date>2026-01-01),再检索。

问题三:信息重复——检索回来的 N 个 chunk 内容高度重叠

解决:

① 检索后去重(MinHash / 向量相似度阈值);

② 多样性重排(MMR——Maximal Marginal Relevance),在相关性和多样性之间平衡。

重排序

粗排(向量检索)追求"快",精排(Rerank)追求"准"——两阶段是工业界标准范式。

常见Rerank模型

模型类型速度精度
bge-reranker-v2-m3 Cross-Encoder
Cohere Rerank v3 API
Jina Reranker v2 Cross-Encoder
LLM-as-Reranker GPT/DeepSeek 打分 很慢 最高

Cross-Encoder vs Bi-Encoder

Bi-Encoder(向量检索)

Query 和 Document 分别独立编码成向量。检索时只需算向量距离——快,但 Query 和 Document 之间没有交互

Cross-Encoder(Rerank 精排)

把 [Query, Document] 拼接后一起送入模型,输出一个相关性分数。Query 和 Document 在 Transformer 内部充分交互——准,但每对都要过一遍模型,无法用于大规模检索

score = CrossEncoder([CLS] query [SEP] document [SEP])

常见问题

⚠ Rerank 会不会把正确的排下去?

会的。Cross-Encoder 通常比 Bi-Encoder 更准,但并非绝对。

解决:

① 保留多路结果,Reranker 只做加分不做减法(被翻下去的文档在生成阶段仍有概率被用到);

② 用 LLM 再验证一遍 Top-3 结果是否真的相关。

增强与生成

Prompt 组装策略

# 标准 RAG Prompt 模板
system_prompt = """
你是一个专业的技术文档助手。请根据以下参考资料回答用户问题。
如果参考资料不足以回答,请明确说"根据现有资料无法确定",
不要编造信息。

参考资料:
{retrieved_docs}

要求:
- 回答末尾列出引用的文档来源
- 如果参考资料中有矛盾,指出矛盾点
"""

user_prompt = f"问题:{query}"

常见问题与解决方案

⚠ 幻觉依然存在——模型可能无视检索结果

即使检索回来了正确答案,LLM 有时会"坚持己见",忽略给定文档。这通常发生在:模型对某领域有很强的先验信念、检索结果和模型训练记忆冲突。

解决:

① Prompt 中加"只能用参考资料中的信息回答"的硬约束;

② SELF-RAG——让模型在生成时主动判断是否需要检索,以及检索结果是否可信;

③ Citation-Enhanced(引用增强)——要求模型每句话标注来源 chunk_id,用约束解码强制引用格式。

⚠ 上下文窗口不够——检索到的文档塞不下

GPT-4 128K、Claude 200K 看起来很大,但 RAG 中如果有 5 个 chunk 各 2000 tokens + 对话历史 + system prompt,轻松突破 20K。况且 token 越多越贵,延迟越高。

解决:

① 对检索结果做摘要压缩再送入 LLM;

② Lost in the Middle——LLM 对中间位置的文本关注度最低,重要的文档放最前面或最后面;

③ Long-Context Reorder——按相关性降序排列文档,越相关越靠前。

⚠ 多文档冲突——检索回来的文档互相矛盾

解决:

① Prompt 中明确要求"指出矛盾";

② 分文档生成、再综合——每个文档独立生成回答,再用 LLM 合并、标注分歧点;

③ 可信度加权——每个文档有可信度分数,高可信度的优先采纳。

前沿方案

1、 GraphRAG(Microsoft, 2024)

从"块检索"到"图推理"

传统 RAG 检索的是孤立的文本块。GraphRAG 先对文档做实体抽取+关系构建,形成知识图谱,然后检索时在图上做多跳推理。

优势:能回答需要跨文档推理的复杂问题("A 公司和 B 公司有哪些共同供应商?"),普通 RAG 做不到。

代价:离线构建图成本高(需要 LLM 做实体/关系抽取),图更新不如向量库灵活。

2、 Agentic RAG(智能体 RAG)

从"固定流程"到"动态决策"

标准 RAG 的流程是死的:检索→生成。Agentic RAG 给 LLM 配工具(搜索、数据库查询、计算器),让模型自己决定:什么时候检索、检索什么、检索结果够不够、要不要再搜一轮。

关键能力:Query 分解(复杂问题拆成子问题逐个检索)、工具选择(向量库 vs SQL vs 搜索引擎)、自反思(检索结果不好→改写Query→重新检索)。

3、Self-RAG(自我反思 RAG)

生成时动态判断是否检索

训练模型输出特殊 token:<Retrieve>(需要检索)、<ISREL>(文档相关)、<ISSUP>(文档支持该结论)、<ISUSE>(回答有用)。模型在生成过程中自己决定每一步。

优势:不需要外部触发器,模型自己判断什么时候要查资料、查到的资料能不能用。

4、ColBERT — 延迟交互(Late Interaction)

介于 Bi-Encoder 和 Cross-Encoder 之间

Query 和 Document 分别编码成多个 token-level 向量,然后在检索时做 token-by-token 的 MaxSim 匹配。既保留了 Bi-Encoder 的离线索引能力(Document 向量可以预计算),又获得了 Cross-Encoder 的细粒度交互。

score = Σq maxd (vq · vd)

ColBERTv2 + PLAID 引擎可以在毫秒级完成大规模检索+交互式匹配。

5、HyDE(假设文档嵌入)

让 LLM 先"编"一个答案,再用这个答案去检索

Query → LLM 生成一个假设的答案文档(可能不准确)→ 将假设答案的 Embedding 作为检索向量。原理:LLM 生成的答案在语义空间中和真实文档更近——因为它是"文档风格"的,而不是"问题风格"的。

代价:多一次 LLM 调用,延迟翻倍。

关键问答

Q1:RAG 和微调的区别是什么?什么时候用哪个?
RAG 是"给模型一本书让它查"——知识在外部,随时更新;
微调是"让模型把书背下来"——知识内化到参数中,但更新需要重新训练。
RAG 适合:知识频繁更新、需要溯源引用、私有数据不想训练进模型。
微调适合:需要模型学会特定风格/格式、任务需要端到端优化、数据稳定不常变。
最佳实践往往是两者结合——微调做风格对齐,RAG 做知识注入。
 
Q2:为什么需要混合检索?只用向量检索不行吗?
向量检索在语义理解上强,但精确匹配弱。
典型翻车场景:搜"Error 503"期望返回该错误码的文档,向量检索可能返回"服务器常见故障"这种"语义相近但信息无用"的结果。
BM25 补的就是这个——关键词精确匹配。另外 BM25 不需要 Embedding 模型,对于新增文档立即可检索(向量需要先编码入库)。
 
Q3:RAG 系统中最容易被忽视的环节是什么?
文档解析和分块。大家往往把精力花在选 Embedding 模型和调检索参数上,但如果文档解析时表格变成了乱码、分块把一句话切成两半,后面的环节再好也没用。
另外分块策略没有定论——固定长度适合通用场景,语义分块适合结构化文档,Small-to-Big 适合需要精确匹配+完整上下文的场景。需要根据实际文档类型和数据特点做选择。
 
Q4:如何评估 RAG 系统的质量?
三层指标:
① 检索质量(Recall@K, MRR, NDCG)——检索回来的文档是不是真相关;
② 生成质量(Faithfulness——回答是否忠于检索文档、Answer Relevance——回答是否切题);
③ 端到端质量(人工评估通过率)。常用评估框架:RAGAS(自动评估 faithfulness + relevance)、TruLens。
关键原则:不能只看端到端——检索不好但 LLM 恰好"猜对"了答案,不等于系统好。
 
Q5:GraphRAG 相比传统 RAG 有什么本质不同?
传统 RAG 检索的是文档块(chunks),回答依赖"找到包含答案的那段文字"。
GraphRAG 在文档之上构建了知识图谱(实体+关系),检索时在图上游走,可以回答需要多跳推理的问题。
比如"这家医院过去 5 年引进了哪些新的影像设备?"——传统 RAG 需要某个文档明确写了这个结论;GraphRAG 可以从"设备采购记录"+"医生培训记录"+"设备维护记录"三个分散的文档中推理出答案。
代价:图构建依赖 LLM 做实体抽取,成本高、更新慢。

参考文献

#论文核心贡献
1 Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks
Lewis et al., Facebook AI, 2020
RAG 开山之作。提出 RAG-Sequence 和 RAG-Token 两种架构,用 DPR 做检索 + BART 做生成,验证了知识密集型任务上 RAG 优于纯参数化模型。
2 Dense Passage Retrieval for Open-Domain Question Answering
Karpukhin et al., Facebook AI, 2020
提出 DPR(Dense Passage Retriever):用对比学习训练双塔模型,Query 和 Passage 独立编码后做点积,大幅超越 BM25 在开放域 QA 上的表现。
3 Self-RAG: Learning to Retrieve, Generate, and Critique through Self-Reflection
Asai et al., 2023
训练模型输出反思 token(Retrieve/ISREL/ISSUP/ISUSE),在生成过程中自主决定何时检索、检索结果是否相关、回答是否有据可依。
4 GraphRAG: Unlocking the Power of Knowledge Graphs for Retrieval-Augmented Generation
Microsoft Research, 2024
从文档中构建知识图谱(实体+关系+社区),通过图上的社区摘要和遍历实现跨文档推理,解决传统 RAG 无法处理的多跳问题。
5 ColBERT: Efficient and Effective Passage Search via Contextualized Late Interaction over BERT
Khattab & Zaharia, Stanford, 2020
延迟交互范式:Query 和 Document 分别编码后在 token 级别做 MaxSim 匹配,兼顾 Bi-Encoder 的效率和 Cross-Encoder 的精度。
6 Precise Zero-Shot Dense Retrieval without Relevance Labels (HyDE)
Gao et al., 2022
用 LLM 生成假设文档,以其 Embedding 作为检索向量——利用 LLM 的"文档风格"生成能力桥接 Query-Document 语义鸿沟。
posted @ 2026-07-23 16:25  黄艺龙  阅读(0)  评论(0)    收藏  举报