RAG(Retrieval-Augmented Generation,检索增强生成)是当前企业落地大模型应用非常常见的一种技术方案。
它的核心思想很简单:大模型负责理解和生成,外部知识库负责提供实时、准确的知识。
RAG 工作流程的内容,对一个完整 RAG 系统从离线知识库构建 → 在线问题检索 → 重排序 → Prompt 增强 → LLM 生成 → 答案溯源进行完整拆解。
什么是 RAG?
RAG 的全称是:
Retrieval-Augmented Generation
中文叫:
检索增强生成
简单来说,RAG 并不是让大模型重新学习一批知识,而是在用户提问的时候:
用户问题↓从外部知识库检索相关知识↓把检索结果作为上下文↓连同用户问题一起交给 LLM↓LLM 根据这些资料生成答案
可以把 RAG 理解成:
给大模型准备了一本可以实时查询的“参考资料”。
大模型本身不需要把企业内部文档全部记到参数里,而是在回答问题之前,先从知识库中找到相关资料,再基于这些资料进行回答。
这也是 RAG 和传统搜索系统最大的区别:
传统搜索:用户问题↓搜索引擎↓返回文档
而 RAG 是:
用户问题↓检索知识↓筛选相关知识↓构造 Prompt↓LLM 理解↓生成自然语言答案
所以:
RAG = Retrieval(检索) + Augmented(增强) + Generation(生成)
为什么需要 RAG?
理解 RAG,首先要理解一个问题:
为什么不能直接让大模型回答?
因为 LLM 本身存在一个非常明显的问题:
1. 大模型存在“知识冻结”
一个大模型经过训练之后,它所掌握的知识主要存在于模型参数中。
例如:
模型训练数据↓模型训练↓模型参数↓LLM
如果公司内部有一份新的:
2026 年公司员工手册.pdf大模型并不会因为这份 PDF 出现,就自动知道里面的内容。
如果企业今天修改了:
请假制度报销制度薪资制度技术规范产品文档
也不可能每修改一次文档,就重新训练一次大模型。
这时候 RAG 就非常有价值。
RAG 和微调有什么区别?
这是面试中非常容易被问到的问题。
RAG
RAG 的思路是:
知识放在外部知识库里,需要的时候检索出来。
企业知识↓知识库↓用户提问↓检索知识↓Prompt↓LLM
RAG 不需要修改 LLM 的核心参数。
Fine-tuning
微调的思路则不同:
训练数据↓Fine-tuning↓修改模型参数↓得到新的模型
所以两者可以简单理解成:
一句话总结:
微调是让模型“学会”,RAG 是让模型“查资料”。
一个完整 RAG 系统分成哪两个阶段?
一个完整的 RAG 系统,可以拆成两个核心阶段:
RAG│┌─────────┴─────────┐│ │离线阶段 在线阶段Indexing Retrieval│ │构建知识库 用户提问│ │文档处理 检索知识│ │向量化 Rerank│ │数据入库 Prompt│LLM│最终答案
简单来说:
离线阶段负责“把知识整理好”。
在线阶段负责“找到知识并回答问题”。
RAG 离线阶段:知识库是怎么建立的?
离线阶段也可以叫:
Indexing / 索引阶段
它的核心目标是:
把原始文档转换成能够被快速检索的知识。
整体流程:
原始文档↓文档加载↓文本解析↓文档清洗↓Chunking↓Embedding↓向量数据库
下面逐个分析。
第一步:文档加载 Document Loading
企业中的知识来源非常复杂。
例如:
WordExcelPPTMarkdownHTML网页数据库接口数据企业 Wiki代码仓库FAQ
所以第一步需要做的事情就是:
把各种数据源统一读取出来。
例如:
员工手册.pdf产品说明.docx技术文档.md公司官网.html数据库中的 FAQ
经过文档加载之后,统一转换成系统可以处理的文本数据。
可以理解为:
PDF ──────┐Word ─────┤Markdown ─┤HTML ─────┤数据库 ───┤网页 ─────┤↓Document↓Text
在实际开发中,可以使用 LangChain、LlamaIndex 等框架提供的 Document Loader,也可以根据企业数据源自己开发解析器。
第二步:文档清洗
原始文档通常不能直接拿去做 Embedding。
例如 PDF 解析之后可能出现:
公司员工手册第 一 页员工福利 2026 年xxxxxxxxxxxxx页码:1
其中:
页码页眉页脚重复标题HTML 标签无意义符号
这些内容实际上没有太大的检索价值。
所以通常需要进行数据清洗:
原始文档↓去除页眉↓去除页脚↓去除重复内容↓清理特殊字符↓结构化文本
如果是企业级 RAG,这一步其实非常重要。
因为:
垃圾进,垃圾出。
知识库原始数据质量不好,后面的 Embedding、检索、Rerank 再强,也很难得到理想结果。
第三步:Chunking 文档切割
这是 RAG 中非常核心的一步。
为什么?
因为你不能把一份 100 页的 PDF 整体转换成一个向量。
例如:
员工手册.pdf│├── 公司介绍├── 入职流程├── 考勤制度├── 请假制度├── 加班制度├── 薪资制度├── 报销制度└── 离职流程
如果整个 PDF 只生成一个 Embedding:
员工手册.pdf↓Embedding↓一个向量
那么这个向量包含的信息太多,具体语义容易被“平均掉”。
所以需要进行切分:
完整文档↓Chunk 1Chunk 2Chunk 3Chunk 4Chunk 5...
例如:
Chunk1:公司员工入职需要提交身份证、学历证明……Chunk 2:员工每月考勤时间为……Chunk 3:员工请假需要提前提交申请……Chunk 4:员工报销需要提供发票……
这样每个 Chunk 都可以成为一个独立的知识单元。
Chunk 为什么不能太大,也不能太小?
这是 RAG 中非常经典的问题。
Chunk 太大
例如:
2000~5000 Token可能包含大量无关内容:
员工入职考勤请假报销离职薪资福利
用户问:
“公司请假需要什么手续?”
结果召回整个大文档。
这样会导致:
上下文变长↓Token 增加↓噪声增加↓LLM 理解难度增加
Chunk 太小
例如:
只有 30~50 Token又可能导致语义不完整。
例如原文:
员工请假超过三天,需要提交部门负责人审批。
如果切成:
Chunk1:员工请假超过三天
和:
Chunk2:需要提交部门负责人审批
那么两个 Chunk 单独看都缺少完整语义。
所以需要控制 Chunk 大小
实践中通常需要根据具体场景进行测试。
一个常见思路是:
Chunk Size500~1000 TokenOverlap50~200 Token
但这并不是固定标准。
真正合理的 Chunk 大小应该根据:
文档类型+Embedding 模型+查询类型+上下文长度+检索效果
综合确定。
什么是 Chunk Overlap?
Chunk Overlap 指的是:
相邻 Chunk 之间保留一部分重复内容。
例如:
Chunk 1AB C D E F G HChunk 2E F G H I J K L
其中:
E F G H就是 Overlap。
为什么需要这样做?
因为直接切割很容易把一个完整语义拆开。
有了 Overlap:
Chunk 1↓AB C D E F GE F G↓Chunk 2E F G H I J K
就能够降低语义被切断的概率。
第四步:Embedding 向量化
Chunk 完成之后,就进入 RAG 非常核心的一步:
Embedding
Embedding 的作用是:
把文本转换成一个高维向量。
例如:
“公司年假有多少天?”经过 Embedding 模型:
[0.123,-0.234,0.875,...]
最终形成一个高维向量。
可以简单理解成:
文本↓Embedding Model↓向量
Embedding 到底有什么用?
它解决的是一个非常关键的问题:
如何让计算机理解“两个文本的意思是否相近”?
例如:
苹果手机怎么截图?和:
iPhone 如何截屏?虽然关键词不完全一样:
苹果手机 ≠ iPhone截图 ≠ 截屏
但是它们表达的语义非常接近。
Embedding 模型会尽可能让:
向量 A ≈ 向量 B而对于:
苹果手机怎么截图?和:
今天北京天气怎么样?这样的文本,向量距离就会比较远。
因此可以把 Embedding 理解成:
把自然语言转换成一个可以进行数学计算的“语义坐标”。
第五步:向量入库
完成 Embedding 后,需要把数据存储起来。
通常会保存:
Chunk 文本+Embedding 向量+Metadata
例如:
{”text”: ”员工请假超过三天,需要提交部门负责人审批。”,”vector”: [0.12, -0.23, 0.87, ”...”],”metadata”: {”document”: ”员工手册.pdf”,”page”: 15,”department”: ”HR”}}
然后存入向量数据库。
常见的向量数据库包括:
MilvusQdrantWeaviateChroma
实际生产中也可以使用支持向量检索能力的传统数据库或搜索系统。
到这里,离线阶段完成
整个离线流程可以总结成:
PDF / Word / Markdown / HTML↓文档加载↓数据清洗↓Chunk 文档切割↓Embedding 向量化↓向量数据库
最终形成:
知识库│┌────────┼────────┐↓ ↓ ↓Chunk Vector Metadata│ │ │└────────┼────────┘↓等待用户查询
RAG 在线阶段:用户提问之后发生什么?
真正有意思的部分来了。
用户输入:
“公司年假最多可以累计多少天?”
RAG 并不会直接把这个问题交给 LLM。
它通常需要经过一套完整的检索链路:
用户问题↓Query 处理↓Query Rewrite↓Embedding↓向量检索↓Top-K 召回↓Rerank↓Top-N 精排结果↓构造 Prompt↓LLM↓生成答案↓返回用户
这就是 RAG 在线阶段的核心流程。
第一步:用户输入 Query
假设用户输入:
公司年假最多可以累计多少天?这个 Query 看起来已经比较明确。
但真实用户可能这样问:
我去年没休完的假怎么办?或者:
之前说的那个假期政策呢?甚至:
那个最多能留多少?这些问题脱离上下文后,很难直接检索。
所以需要进行 Query 处理。
第二步:Query Rewrite 查询改写
Query Rewrite 的作用就是:
把用户原始问题改写成更适合检索的问题。
例如用户:
之前说的那个假期最多能留多少?经过 LLM 改写:
公司未使用的年假最多可以累计多少天?这样检索系统就更容易找到相关内容。
Query Rewrite 可以解决什么问题?
主要包括:
1. 口语化
那个东西怎么申请?↓公司报销流程如何申请?
2. 指代问题
它什么时候生效?↓2026年员工新考勤制度什么时候生效?
3. 上下文补全
那最多是多少?↓公司年假最多可以累计多少天?
因此:
Query Rewrite 的核心目的,是把“用户语言”转换成“检索语言”。
第三步:Query Embedding
Query 处理完成之后,同样需要经过 Embedding。
例如:
公司年假最多可以累计多少天?↓Query Model
然后拿这个 Query Vector 去向量数据库中进行搜索。
第四步:向量检索——粗排
向量数据库中已经存在大量 Chunk:
Chunk1Chunk 2Chunk 3...Chunk 1000000
现在系统拿 Query Vector:
Q去寻找与它最相似的向量:
Q│├── Chunk 102├── Chunk 587├── Chunk 923├── Chunk 1204├── Chunk 3288└── ...
这一步叫:
向量检索 / Semantic Search
通常会返回 Top-K:
Top20Top50Top100
具体数量根据系统规模和实际效果进行调整。
为什么向量检索叫“粗排”?
因为它的主要任务不是最终判断:
“这个 Chunk 到底是不是最适合回答问题?”
而是:
从海量数据中快速找出一批候选结果。
例如:
100 万个 Chunk↓向量检索↓Top50
从 100 万个结果缩小到 50 个。
所以它更像:
第一轮筛选。
优点是:
速度快缺点是:
精度不一定最高因为单纯依赖向量距离,并不一定能完全理解 Query 和 Chunk 之间的复杂关系。
第五步:Rerank 精排
向量检索之后,一般还会增加:
Rerank(重排序)
例如粗排得到:
Top20然后:
Query+Chunk 1Chunk 2Chunk 3...Chunk 20
交给 Rerank 模型进行进一步判断。
Rerank 模型会更加深入地判断:
Query 和 Chunk 到底相关不相关?然后重新打分:
Chunk8 0.98Chunk 3 0.95Chunk 15 0.92Chunk 2 0.73Chunk 11 0.52...
最终只保留:
Top3Top5
作为真正交给 LLM 的上下文。
粗排和精排到底有什么区别?
可以用招聘来理解。
假设公司收到:
10000 份简历第一轮:
关键词 / 简历筛选↓500 人
这就是:
粗排
第二轮:
面试官深入评估↓10 人
这就是:
精排
所以:
向量检索↓快速找候选↓Rerank↓精准筛选
一句话:
粗排负责“找得多”,精排负责“找得准”。
第六步:构造增强 Prompt
经过 Rerank 之后,我们终于拿到了真正有价值的知识。
例如:
Chunk1:员工未使用的年假可以累计到下一年度,最多累计 5 天。Chunk 2:员工申请年假需要提前提交申请。
现在不能只把这些文本直接丢给 LLM。
还需要构造一个增强 Prompt。
例如:
你是一名企业 HR 助手。请根据下面提供的参考资料回答用户问题。要求:1. 优先依据参考资料回答。2. 不要编造资料中不存在的信息。3. 如果参考资料无法回答,请明确告诉用户无法确定。4. 可以对资料进行总结,但不要改变原始含义。参考资料:[资料 1]员工未使用的年假可以累计到下一年度,最多累计 5 天。[资料 2]员工申请年假需要提前提交申请。用户问题:公司年假最多可以累计多少天?
这一步就是:
Prompt Augmentation / 上下文增强
第七步:LLM 生成最终答案
接下来才真正进入大模型。
LLM 接收到:
System Prompt+参考资料+用户问题
然后进行:
理解问题↓理解参考资料↓提取相关信息↓组织语言↓生成答案
最终可能回答:
根据公司员工手册,未使用的年假可以累计到下一年度,但最多累计 5 天。
注意:
LLM 并不是直接从知识库里“复制答案”。
而是:
读取检索结果 → 理解上下文 → 根据上下文生成自然语言答案。
这就是 RAG 中的Generation。
RAG 为什么可以降低幻觉?
普通 LLM:
用户问题↓LLM↓根据参数中的知识回答
如果模型不知道,就可能:
猜测+推理+编造
最终产生:
幻觉(Hallucination)
RAG:
用户问题↓检索真实资料↓资料作为 Context↓LLM↓基于资料回答
Prompt 还可以明确要求:
只能根据参考资料回答。如果参考资料没有相关内容,请回答“根据现有资料无法确定”。
这样能够在一定程度上降低模型胡编乱造的概率。
不过需要注意:
RAG 并不能 100% 消除幻觉。
如果检索结果本身就是错误的,LLM 依然可能生成错误答案。
所以 RAG 的效果不仅取决于 LLM,也取决于:
数据质量+Chunk 策略+Embedding+召回+Rerank+Prompt+LLM
第八步:答案溯源
一个优秀的企业级 RAG 系统,通常不仅返回答案,还会返回:
答案+引用来源
例如:
公司未使用的年假最多可以累计 5 天。
来源:
《公司员工手册》第 15 页
甚至可以做到:
答案:公司年假最多可以累计 5 天。参考来源:📄 公司员工手册.pdf📌 第 15 页
这样用户就可以验证答案。
因此 RAG 相比单纯 LLM,一个非常重要的优势就是:
答案具备知识来源和一定的可追溯性。
把整个 RAG 流程串起来
现在把前面的内容全部连接起来。
离线阶段
原始知识│┌─────────┼─────────┐↓ ↓ ↓PDF Word Markdown│ │ │└─────────┼─────────┘↓文档加载↓文档清洗↓Chunking↓Embedding↓向量 + 文本 + Metadata↓向量数据库
在线阶段
用户问题│↓Query 处理│↓Query Rewrite│↓Query Embedding│↓向量数据库│↓Top-K 粗排│↓Rerank 精排│↓Top-N 相关 Chunk│↓构造增强 Prompt│↓LLM│↓生成答案│↓引用来源│↓返回用户
一个完整 RAG 请求到底经历了什么?
假设用户问:
“公司的年假最多可以累计多少天?”
系统实际经历的过程可以理解成:
① 用户提问“公司的年假最多可以累计多少天?”↓② Query Rewrite“公司未使用的年假最多可以累计多少天?”↓③ Query Embedding转换成向量:[0.123, -0.456, 0.789, ...]↓④ 向量检索从 100 万个 Chunk 中召回 Top20↓⑤ Rerank重新计算 Query 与 Chunk 的相关性↓⑥ Top-N最终保留 Top3↓⑦ Prompt用户问题+相关知识+系统指令↓⑧ LLM理解上下文并生成答案↓⑨ Citation返回答案和知识来源
这就是一个完整的 RAG 请求。
RAG 的核心其实可以浓缩成一句话
如果面试官问:
“你能不能用一句话解释 RAG?”
可以回答:
RAG 是一种让大模型在生成答案之前,从外部知识库检索相关信息,并将这些信息作为上下文提供给 LLM,从而让模型基于实时、私有、可追溯的知识生成答案的技术方案。
如果继续问:
“完整流程是什么?”
直接回答:
离线阶段:文档加载→ 文档清洗→ Chunking→ Embedding→ 向量数据库在线阶段:用户 Query→ Query Rewrite→ Query Embedding→ 向量检索→ Top-K 粗排→ Rerank 精排→ 构造 Prompt→ LLM→ 生成答案→ 返回引用来源
这个回答基本就把 RAG 的主干讲清楚了。
RAG 最核心的几个技术点
如果准备 RAG 面试,建议重点掌握下面这些知识:
1. Chunking
解决:
如何把长文档切成适合检索的知识片段?
2. Embedding
解决:
如何把文本转换成可以进行语义相似度计算的向量?
3. Vector Database
解决:
如何快速从大量向量中找到相似内容?
4. Query Rewrite
解决:
如何把用户口语化、模糊的问题转换成更适合检索的 Query?
5. Retrieval
解决:
如何从海量知识中召回可能相关的内容?
6. Rerank
解决:
如何从召回结果中进一步筛选真正相关的内容?
7. Prompt Augmentation
解决:
如何把检索到的知识正确地交给 LLM?
8. LLM Generation
解决:
如何根据用户问题和参考知识生成最终答案?
9. Citation
解决:
如何让用户知道答案来自哪里?
RAG 为什么适合企业应用?
企业内部有大量:
产品文档技术文档员工手册规章制度客户资料FAQ知识库项目文档API 文档
这些知识具有几个特点:
经常变化+数据量巨大+存在大量私有数据+不适合直接训练到模型里
RAG 恰好可以解决这些问题。
例如:
公司修改员工制度↓更新知识库↓重新 Chunk↓重新 Embedding↓更新向量数据库↓用户立即可以查询新知识
不需要重新训练大模型。
这就是 RAG 的一个非常重要的优势:
知识和模型解耦。
RAG 的核心优势
1. 知识可以快速更新
新增文档↓知识库更新↓立即可以检索
不需要重新训练模型。
2. 支持企业私有知识
例如:
公司内部技术文档内部制度内部 FAQ客户资料项目资料
都可以放入企业自己的知识库。
3. 降低模型幻觉
通过:
检索真实资料+Prompt 约束
让模型尽可能基于事实回答。
4. 支持答案溯源
可以返回:
答案+文档+章节+页码
提高答案可信度。
5. 成本相对可控
相比为了增加大量私有知识而频繁进行模型训练,RAG 通常更加灵活。
RAG 并不是简单的“向量搜索”
很多初学者会把 RAG 理解成:
用户问题↓向量数据库↓查数据↓LLM
实际上,生产级 RAG 往往复杂得多。
一个更完整的系统可能是:
用户 Query│↓Query Rewrite│┌──────────┴──────────┐↓ ↓向量检索 关键词检索│ │└──────────┬──────────┘↓多路召回↓粗排↓Rerank↓Context↓Prompt 构建↓LLM↓Answer + Citation
也就是说:
现代 RAG 已经从简单的“检索 + 生成”,逐渐发展成一套完整的知识检索与生成系统。
面试时如何完整回答“RAG 工作流程”?
如果面试官问:
“请详细讲一下 RAG 的完整工作流程。”
可以按照下面这个逻辑回答:
第一步:先解释 RAG
RAG 全称 Retrieval-Augmented Generation,即检索增强生成。
它主要解决 LLM 知识冻结、私有知识无法覆盖以及实时知识更新困难的问题。
第二步:介绍离线阶段
离线阶段主要负责构建知识库。
首先通过 Document Loader 加载 PDF、Word、Markdown、HTML 等数据,然后进行数据清洗和 Chunking,把长文档切成多个语义完整的 Chunk。
之后使用 Embedding 模型将每个 Chunk 转换成向量,并将:
文本+向量+Metadata
保存到向量数据库中。
第三步:介绍在线阶段
用户提问后,系统首先对 Query 进行预处理和 Query Rewrite,让问题更加适合检索。
然后对 Query 做 Embedding,去向量数据库进行相似度搜索,召回 Top-K 结果。
第四步:介绍 Rerank
召回结果只是粗排结果,因此可以使用 Rerank 模型对候选 Chunk 重新排序,筛选出真正相关的 Top-N 内容。
第五步:介绍 Prompt
将:
用户问题+检索到的相关知识+系统指令
组合成增强 Prompt。
第六步:介绍 LLM
最后把增强后的 Prompt 交给 LLM,让 LLM 基于检索到的上下文生成最终答案。
如果系统设计完善,还可以同时返回:
答案+引用文档+来源位置
实现答案溯源。
最终总结
RAG 最核心的思想其实非常简单:
不要要求大模型把所有知识都记在脑子里,而是在它回答问题的时候,先给它找资料。
整个 RAG 可以浓缩成下面这张流程图:
┌──────────────────────┐│ 离线阶段 |│ 构建企业知识库 |└──────────┬───────────┘│↓文档加载↓数据清洗↓Chunking↓Embedding↓向量 + 文本 + Metadata↓向量数据库│═══════════════════════════════╪══════════════════════════════│在线阶段│↓用户 Query↓Query Rewrite↓Query Embedding↓向量检索↓Top-K 粗排↓Rerank 精排↓Top-N 相关知识↓构造增强 Prompt↓LLM↓生成最终答案↓Citation / 溯源↓返回用户
所以,真正完整的 RAG 并不是简单的:
搜索 → LLM而是一条完整的数据处理与生成链路:
知识进入系统→ 文档解析→ 文档切割→ 向量化→ 建立索引→ 用户提问→ Query 改写→ 向量召回→ 粗排→ Rerank 精排→ Context 构建→ Prompt 增强→ LLM 生成→ 答案溯源
一句话记忆:
离线阶段负责“把知识整理好”,在线阶段负责“把正确的知识找出来,再让大模型基于这些知识回答问题”。
这也是理解 RAG 最重要的一条主线。
夜雨聆风