Skip to content

RAG 是什么 ​

定义 ​

RAG 是 Retrieval-Augmented Generation 的缩写,中文通常翻译为 检索增强生成。

如果只用一句话总结:

RAG 是先从外部知识源中检索与当前问题相关的信息,再把这些信息提供给模型,让模型基于它们生成回答。

最简单的流程可以表示成:

text
用户问题
   ↓
检索相关资料
   ↓
把资料交给模型
   ↓
生成回答

这里最重要的一点是:

模型不是只依赖自己训练时学到的知识,而是在回答之前先获取一部分外部信息。

例如用户问:

公司出差住宿标准是多少?

大模型本身一般都不知道具体某家公司的内部制度。

RAG 系统会先去公司知识库里找到相关规定,再把这部分内容和用户问题一起交给模型。

于是模型回答时依据的不再只是自己的通用知识,而是刚刚检索到的公司资料。

这就是 RAG 最核心的思路。


为什么需要 RAG ​

大语言模型已经学习了大量知识,但它仍然不可能知道所有信息。

尤其是下面这些内容:

  • 企业内部文档
  • 私有项目资料
  • 最新更新的产品文档
  • 公司制度
  • 内部 FAQ
  • 大量专业或长尾资料

这些信息可能根本没有出现在模型训练数据里。

即使出现过,也可能已经发生变化。

例如一家公司今年刚修改了报销制度。

模型训练时不可能提前知道这次更新。

如果直接问:

现在差旅住宿标准是多少?

模型可能不知道,也可能根据通用经验生成一个看起来合理但实际错误的答案。

RAG 的思路不是要求模型重新训练,而是:

text
用户提问
   ↓
先去查最新制度
   ↓
找到相关内容
   ↓
再让模型回答

这样知识更新以后,只需要更新知识库。

模型本身不一定需要发生变化。


可能有同学问:

既然模型需要这些资料,为什么不直接把所有文档都放进 Prompt?

理论上,在资料很少时确实可以这么做。

但当文档越来越多以后,很快会遇到一些问题。

例如一个企业知识库可能包含:

text
产品文档
公司制度
技术手册
客服 FAQ
项目资料
培训资料
历史公告
……

用户只是问:

年假怎么申请?

模型真正需要的可能只是《员工休假管理制度》里的几个段落。

如果每次都把整个知识库全部交给模型,会带来很多没有必要的信息。

这些无关内容不仅增加上下文长度和成本,也可能干扰模型判断。

所以合理的方式应该是:

text
大量知识
   ↓
先检索
   ↓
找出最相关的一小部分
   ↓
交给模型

模型真正需要的通常不是:

所有知识。

而是:

当前问题最相关的知识。

这也是 RAG 存在的重要原因。


一个最小 RAG 长什么样 ​

假设现在要做一个公司内部知识库。

知识库里有一份文档:

text
《差旅费用管理办法》

其中写着公司的住宿、交通和报销规定。

现在员工提出一个问题:

北京出差的住宿标准是多少?

如果直接把问题交给模型:

text
用户问题
   ↓
LLM
   ↓
回答

模型可能根本不知道这家公司的具体规定。

加入 RAG 以后,流程会变成:

text
用户问题
   ↓
检索公司知识库
   ↓
找到《差旅费用管理办法》
   ↓
找到住宿标准相关段落
   ↓
问题 + 相关段落
   ↓
LLM
   ↓
生成回答

例如系统最后实际交给模型的内容可能类似:

text
用户问题:

北京出差的住宿标准是多少?

参考资料:

《差旅费用管理办法》
北京地区普通员工住宿标准不超过 500 元 / 晚,
部门负责人不超过 650 元 / 晚。

请根据参考资料回答用户问题。

模型这时候就可以生成:

北京地区普通员工住宿标准不超过 500 元 / 晚,部门负责人不超过 650 元 / 晚。

如果系统支持引用,还可以告诉用户:

来源:《差旅费用管理办法》

这里有一个非常重要的认识:

模型并没有因为 RAG 而突然“学会”这份公司制度。

它只是:

在回答当前问题时,临时拿到了相关资料。

下一次公司更新制度,只要知识库里的资料同步更新,后续检索到的内容也可以随之变化。


RAG 是怎么运行的 ​

一个完整的 RAG 系统一般可以分成两个阶段:

text
准备知识库
+
用户提问后的检索与生成

也可以简单理解成:

text
离线准备
+
在线回答

整体流程大致如下:

text
原始文档
   ↓
解析
   ↓
切片
   ↓
建立索引
   ↓
知识库


用户问题
   ↓
检索相关内容
   ↓
组织上下文
   ↓
LLM
   ↓
生成回答

准备知识库 ​

RAG 首先要有可以检索的知识来源。

例如:

  • PDF
  • Word 文档
  • Markdown
  • 网页
  • 产品文档
  • FAQ
  • 公司制度
  • 数据库中的文本资料

这些原始资料通常不能直接拿来检索,需要先经过处理。


文档解析 ​

第一步通常是把原始文件转换成可以处理的文本内容。

例如:

text
PDF
 ↓
提取文字
 ↓
得到正文

或者:

text
网页
 ↓
提取主要内容
 ↓
去掉导航、广告等无关信息

不同文件类型的解析方式可能不同,但目标基本一致:

把原始资料变成后续可以检索的内容。


文本切片 ​

文档解析以后,通常不会把整篇文档作为一个检索单位。

例如一份 100 页的产品手册,如果用户只是问:

怎么重置密码?

真正相关的可能只有其中两三个段落。

所以通常需要把长文档拆成更小的文本片段。

这些片段一般被称为:

Chunk。

例如原始文档:

text
《员工管理制度》

第一章 入职
第二章 考勤
第三章 请假
第四章 差旅
第五章 离职

系统可能进一步切成:

text
Chunk 1:入职流程
Chunk 2:试用期规定
Chunk 3:考勤规则
Chunk 4:年假申请
Chunk 5:病假规定
Chunk 6:差旅住宿标准
……

以后用户问年假时,就不需要把整份《员工管理制度》交给模型。

只需要找到:

text
Chunk 4:年假申请

即可。

所以切片的目的很简单:

让后面的检索更加精确。


建立索引 ​

文档切片以后,还需要让系统能够快速找到相关 Chunk。

因此通常要为这些内容建立索引。

最常见的做法之一是使用 Embedding。

Embedding 可以把文本转换成一组数字表示。

例如:

text
"如何申请年假"
        ↓
Embedding Model
        ↓
[0.12, -0.35, 0.81, ...]

文档 Chunk 也可以做同样的处理。

以后用户提出一个问题时,系统可以比较问题和不同 Chunk 之间的语义相关程度,找出最接近的内容。

这些向量经常会被保存到向量数据库中。

不过需要注意:

RAG 并不等于向量数据库。

检索知识时可以使用很多方法,例如:

  • 关键词检索
  • 全文检索
  • 向量检索
  • 语义检索
  • Hybrid Search

具体使用哪一种,要根据实际场景决定。

我们只需要先记住:

建立索引的目的,就是让系统以后能够快速找到和问题相关的资料。

整个知识库准备过程可以先理解成:

text
原始文档
   ↓
解析
   ↓
Chunk
   ↓
建立索引
   ↓
可检索知识库

检索并生成回答 ​

知识库准备完成以后,用户就可以开始提问。

例如:

员工一年有多少天年假?

系统首先不会直接调用 LLM。

而是先进入 Retrieval,也就是检索阶段。


Retrieval:检索 ​

系统会根据用户问题,在知识库中查找相关 Chunk。

例如:

text
用户问题:
员工一年有多少天年假?

系统可能找到:

text
Chunk A:
正式员工工作满一年后,每年享受 5 天带薪年假。

Chunk B:
工作满 10 年后,年假调整为 10 天。

Chunk C:
年假需要提前三个工作日提交申请。

这些内容就是当前问题的候选资料。


有时第一次检索出来的内容并不一定完全准确。

所以真实系统里还可能继续进行:

  • 过滤
  • 排序
  • 去重
  • 重排

目的都是一样的:

尽量把真正相关的信息留下来。

例如最终只保留:

text
正式员工工作满一年后,每年享受 5 天带薪年假。
工作满 10 年后,年假调整为 10 天。

Augmented:增强上下文 ​

检索到资料以后,系统会把这些内容加入模型的输入。

例如:

text
问题:

员工一年有多少天年假?

参考资料:

1. 正式员工工作满一年后,每年享受 5 天带薪年假。
2. 工作满 10 年后,年假调整为 10 天。

请基于参考资料回答问题。

这里的“增强”,就是:

用外部资料补充模型当前的上下文。

所以 Retrieval-Augmented Generation 里的 Augmented,并不是修改模型本身。

而是给模型增加新的上下文。


Generation:生成 ​

最后才进入真正的生成阶段。

模型根据:

text
用户问题
+
检索到的资料

生成最终回答。

例如:

正式员工工作满一年后,每年享受 5 天带薪年假;工作满 10 年后,年假调整为 10 天。

如果系统保留了文档来源,还可以继续返回引用:

text
来源:《员工休假管理制度》

所以整个在线流程可以压缩成:

text
用户问题
   ↓
Retrieval
检索相关资料
   ↓
Augmented
补充模型上下文
   ↓
Generation
生成回答

这也是 RAG 这个名字最直接的理解方式:

Retrieval → Augmented → Generation


RAG 适合什么任务 ​

RAG 最典型的使用场景,是:

模型回答问题时,需要依赖大量外部知识。


企业知识库 ​

例如员工询问:

text
报销制度
请假规则
产品资料
销售政策
内部流程

这些信息通常属于企业私有知识。

大模型本身并不知道。

通过 RAG,可以让模型先检索企业内部资料,再生成回答。


产品文档问答 ​

例如一个开发平台有几千页文档。

用户询问:

API Key 怎么创建?

系统可以:

text
用户问题
 ↓
检索 API 文档
 ↓
找到相关章节
 ↓
生成回答

这样就不需要每次把全部产品文档交给模型。


客服知识问答 ​

客服场景中通常有大量:

  • FAQ
  • 售后政策
  • 产品说明
  • 常见故障
  • 服务流程

用户提问以后,可以先检索这些资料,再生成回复。

例如:

text
怎么申请退款?
 ↓
检索退款政策
 ↓
找到对应规则
 ↓
生成回答

专业资料辅助 ​

RAG 也很适合处理大量专业文档。

例如:

  • 技术资料
  • 法律资料
  • 项目文档
  • 研究资料
  • 行业报告

这类场景通常都有一个共同特点:

知识很多,而且模型不一定天然知道。


综合来看,RAG 比较适合下面这些任务:

  • 回答依赖外部知识
  • 知识量比较大
  • 知识可能持续更新
  • 模型训练时不知道这些内容
  • 希望回答尽量基于明确资料
  • 希望能够保留引用来源

所以判断一个场景是否适合 RAG 时,可以先问一个非常简单的问题:

当前问题的主要瓶颈,是不是“模型缺少相关知识”?

如果答案是“是”,那么 RAG 通常就是一个值得优先考虑的方向。


总结 ​

RAG 的全称是:

Retrieval-Augmented Generation

也就是:

检索增强生成。

它最核心的思路非常简单:

模型回答之前,先去外部知识源中找到与当前问题相关的资料。

一个最小的 RAG 可以表示成:

text
用户问题
   ↓
检索资料
   ↓
补充上下文
   ↓
LLM
   ↓
生成回答

如果再把知识库准备过程加进来:

text
原始文档
   ↓
解析
   ↓
切片
   ↓
建立索引
   ↓
知识库


用户问题
   ↓
检索
   ↓
组织上下文
   ↓
LLM
   ↓
生成回答

其中:

  • 文档解析负责得到可处理的内容
  • Chunk 负责把长文档拆成更合适的检索单位
  • 索引负责帮助系统快速找到相关内容
  • Retrieval 负责找到资料
  • Augmented 负责把资料加入模型上下文
  • Generation 负责生成最终回答

所以理解 RAG 时,不需要一开始就被向量数据库、Embedding、Rerank 等术语绕进去。

先记住最基本的一句话:

RAG 的核心,就是让模型在回答之前先拿到当前问题真正需要的知识。

关键就在于,如何找到这些知识,这个就尤为重要,我们后续在RAG栏目再深入讲解。