RAG:用检索增强生成打破大模型的知识局限

如果你曾用 ChatGPT 问过一个它训练数据之外的问题,或者需要它根据你的专业文档生成答案,你可能就遇到了大模型的两大”绝症”:知识过时幻觉问题

RAG(Retrieval-Augmented Generation)就是为解决这些问题而生的技术方案。它不是重新训练模型,而是聪明地把 LLM 变成一个”可查阅资料的专家”。


为什么需要 RAG?

大模型的四大痛点

  1. 静态知识库 - 训练数据有截止日期
  2. 幻觉问题 - 编造看起来真实的回答
  3. 领域局限 - 专业知识覆盖不完整
  4. 数据泄露 - 可能泄露训练数据信息

RAG 的核心价值

  • 减少幻觉,提高答案准确性
  • 增加实时性,快速适配新数据
  • 扩展领域知识,支持专业应用
  • 降低数据泄露风险(配合私有部署)

RAG 的完整流程

graph LR
    A["文档输入<br/>PDF/Word/Excel<br/>txt等"]
    B["文本分块<br/>切分策略"]
    C["Embedding<br/>向量化"]
    D["向量数据库<br/>Milvus/Elasticsearch"]

    E["用户提问"]
    F["语义改写<br/>HyDE/分解问题"]
    G["多路召回<br/>向量+BM25混合"]
    H["重排序<br/>精排Top-K"]
    I["LLM生成<br/>基于检索结果"]
    J["最终答案"]

    A --> B --> C --> D
    E --> F --> G --> H --> I --> J
    D -.检索相关文档.-> H

    style A fill:#ffe6e6
    style D fill:#e6f3ff
    style E fill:#fff9e6
    style J fill:#e6ffe6

1. 数据预处理:文本分块

这是 RAG 系统的基础,直接影响检索精度。

五大经典分块策略

策略 原理 优点 缺点
固定分块 按 token/字符数等比例切分 简单快速 易割裂上下文
语义分块 计算句子相似度,在漂移点切分 语义连贯 计算成本高
结构感知 按标题/章节/段落边界切分 保留文档结构 依赖文档质量
大模型分块 用 tokenizer 按 token 边界切分 精准可控 需调用 LLM
递归字符分块 先粗后细,兼顾结构和灵活性 平衡性好 仍可能割裂语义

进阶方案:重叠和混合策略

为什么要用重叠?
固定分块容易割裂上下文关键信息。重叠是补偿手段:

  • 增加的信息噪声 < 重叠带来的语义连续性收益
  • 因此推荐使用重叠

混合分块
结合上述策略,例如:

  • 基础组合:固定分块 + 结构感知 + 递归字符分块
  • 高级组合:再加语义分块和大模型分块
# 伪代码:混合分块策略
chunks = []
# 先按结构分割
for section in document.sections:
# 再按固定大小分块
for chunk in fixed_split(section, size=512, overlap=50):
# 最后用语义相似度合并相邻段落
if similar(chunk, prev_chunk) > threshold:
merge(chunk, prev_chunk)
chunks.append(chunk)

2. 向量化:把文本变成 AI 理解的语言

选择合适的 Embedding 模型

graph TD
    A["Embedding 模型选择"]
    B["维度"]
    C["Token 数"]
    D["质量"]

    A --> B
    A --> C
    A --> D

    B --> B1["维度越多<br/>信息越精细"]
    C --> C1["Token 越少<br/>在相同维度下<br/>编码越精细"]
    D --> D1["优先选择<br/>领域相关的<br/>微调模型"]

关键指标

  • 维度(Dimension):更高 = 信息更丰富但成本更高
  • Token 数:相同维度下,token 少的模型编码更细致
  • 模型质量:通用模型 vs 领域微调模型

3. 检索:找到相关的文档

graph LR
    A["用户提问"]

    B["向量检索<br/>语义相似"]
    C["关键词检索<br/>BM25算法"]

    D["融合策略"]

    E["手动加权<br/>0.7*向量+0.3*BM25"]
    F["模型加权<br/>训练小模型<br/>学习最优权重"]

    G["重排序<br/>精排Top-K"]

    A --> B
    A --> C
    B --> D
    C --> D
    D --> E
    D --> F
    E --> G
    F --> G

    style B fill:#e6f3ff
    style C fill:#fff9e6
    style E fill:#e6ffe6
    style F fill:#ffe6e6

多路召回策略

不要只依赖单一检索方式。实际应用中推荐:

  1. 向量检索:捕捉语义相似性,效果好但可能漂移
  2. BM25 关键词检索:精准定位关键信息,但无法理解语义
  3. 混合融合:取两者之长,补两者之短

加权融合

相关性分数 = α × 向量相似度 + (1-α) × BM25分数

三种加权方法:
1. 手动调参:设置固定的 α 值(0.3-0.7)
2. 机器学习:训练小模型自动学习最优权重
3. 启发式规则:根据查询类型动态调整

4. 语义改写:消除歧义,靠近文档

用户的提问往往有歧义、缺少上下文,或表述不匹配文档术语。

三大改写技巧

graph TD
    A["语义改写的目标"]

    B["假设性问答 HyDE"]
    C["问题分解"]
    D["上下文补全"]

    A --> B
    A --> C
    A --> D

    B --> B1["原理:用LLM生成<br/>假的答案/文档<br/>用假文档向量检索"]
    B --> B2["效果:比原提问<br/>更接近真实文档"]

    C --> C1["分解复杂问题为<br/>多个简单问题<br/>提高语义准确性"]

    D --> D1["补全'它''我们之前说的'<br/>这类代词指代<br/>增加上下文信息"]

HyDE 工作流

用户提问:「如何优化搜索引擎性能?」
⬇️
LLM 生成假答案:「搜索引擎性能优化涉及...
1. 索引优化,使用倒排索引...
2. 查询优化,采用缓存...」
⬇️
对假答案做向量检索
⬇️
找到真实相关文档

5. 重排序:让最相关的文档排第一

检索出 Top-100 个候选后,用更精细的模型精排 Top-K。

常见重排序方案

  • 交叉编码器(Cross-Encoder):精度最高但速度慢
  • LLM 排序:直接用 LLM 判断相关性
  • 多维度评分:综合考虑相关性、权威性、新鲜度

结果评估:衡量 RAG 效果

检索评测维度

检索效果不等于最终答案效果。

错误认知:召回了相关文档 = 能给出好答案

正确理解:需要同时衡量

  • 召回量:有没有都召回出来?
  • 召回质:召回的都是相关的吗?
  • 命中率:能解决实际问题吗?

检索质量三问

维度 含义 评估方法
召回率 有多少相关文档被找到了? 标准答案中出现的词,在回答中出现了几次?
精确率 找到的有多少是真的相关? 回答中出现的词,在标准答案中的占比?
命中率 能实际解决问题吗? 人工验证:答案是否真的回答了问题?

生成评测:忠诚度和简洁度

graph LR
    A["生成结果评测"]

    B["忠诚度<br/>是否按文档内容生成?"]
    C["简洁度<br/>是否简洁回复了问题?"]

    A --> B
    A --> C

    B --> B1["方法1:LLM自动评估"]
    B --> B2["方法2:重叠词分析<br/>精确率/召回率"]

    C --> C1["方法1:LLM自动评估"]
    C --> C2["方法2:长度/关键词<br/>匹配度分析"]

精确度和召回率计算(使用重叠词):

召回率 = 标准答案中的词在回答中出现的个数 / 标准答案中的词总数
精确率 = 回答中的词在标准答案中出现的个数 / 回答中的词总数
F1分数 = 2 × (精确率 × 召回率) / (精确率 + 召回率)

向量检索的黑科技:相似度算法与索引

相似度计算三大算法

  1. 点积 (Dot Product)

    • 速度快,但对向量长度敏感
  2. 欧式距离 (Euclidean Distance)

    • 几何直观,计算成本中等
  3. 余弦相似度 (Cosine Similarity)

    • 最常用,归一化处理,范围[-1,1]

向量搜索加速:从暴力到 ANN

为了在大规模数据集(百万、亿级)上快速搜索,需要优化索引。

graph TD
    A["向量搜索算法"]

    B["暴力搜索<br/>时间复杂度O(n)"]
    C["近似最近邻 ANN<br/>牺牲精度换速度"]

    A --> B
    A --> C

    C --> C1["HNSW<br/>图索引<br/>层级导航"]
    C --> C2["LSH<br/>哈希桶<br/>快速定位"]
    C --> C3["Tree-base<br/>树形索引<br/>二分查找"]
    C --> C4["Cluster-base<br/>簇索引<br/>先找簇再检索"]

    C1 --> P["实际效果<br/>HNSW通常最好"]

压缩算法:节省内存

大向量模型(维度 1024+ )消耗大量内存。压缩算法很必要。

算法 原理 特点
SQ 标量量化,用哈希桶思想将向量分割 有损压缩,简单快速
PQ 乘积量化,将 float 映射为 int 有损压缩,压缩率高

实践建议:打造高质量 RAG 系统

数据清洗是基础

垃圾进,垃圾出

再好的 RAG 架构也救不了烂数据。数据清洗和规范化至少要包括:

  • 去除重复、错误的文本
  • 统一术语、格式规范
  • 验证数据准确性和完整性
  • 处理特殊字符和编码问题

四个优化方向

  1. 纯文本 → 多模态(加入视频、图片)
  2. 线性检索 → 多路并行(向量+关键词+图像)
  3. 简单索引 → 高性能索引(优化向量DB)
  4. 静态生成 → 循环自我修正(反馈优化)

总结:RAG 的核心心法

RAG = 检索 + 生成

核心:把信息检索当主业,生成只是锦上添花

  1. 分块很关键

    • 选对策略,保留语义连贯性
  2. 检索是核心

    • 多路召回,精排融合
  3. 改写要细致

    • 消除歧义,靠近文档
  4. 评估要全面

    • 不只看召回,看最终答案

最后的建议

RAG 不是一蹴而就的技术,而是一个持续优化的过程

  1. 从简到繁:先用固定分块 + 向量检索,再逐步加复杂度
  2. 从通用到专用:用通用模型验证方案,再用领域模型优化
  3. 闭环反馈:不断收集用户反馈,迭代评估体系和算法
  4. 成本优先:在保证效果的前提下,优先考虑成本和延迟

参考资源

  • 向量数据库:Milvus, Pinecone, Weaviate
  • Embedding 模型:OpenAI API, Sentence Transformers
  • 自动评估工具:RAGAS, TruLens
  • 框架:LangChain, LlamaIndex

希望这篇文章能帮你理解 RAG 的全貌。如果有问题,欢迎留言讨论!