我重新梳理了一遍 RAG,终于明白它不只是接个向量库

一、引言

这两天系统学习了一遍 RAG,原本以为它就是文档切片 + 向量检索 + 大模型回答这么一条标准流程,但真正从头到尾梳理下来之后,我发现事情没那么简单。

RAG 最有意思的地方,不是它用了什么新概念,而是它重新回答了一个很关键的问题:

当大模型面对企业知识、私有文档和最新资料时,怎么才能不靠猜,而是基于真实内容回答问题?

很多人第一次接触 RAG,都会先记住几个关键词:Embedding、向量数据库、检索、Rerank、Chunk

但如果这些概念没有被串成一条完整链路,就很容易变成每个词都认识,但整体还是有点模糊。

所以这篇文章,我想不只是罗列概念,而是尝试把 RAG 从头到尾重新讲清楚:

文档是怎么进入系统的?为什么一定要切片?检索为什么不只是向量搜索?为什么召回之后还要重排?RAG 真正难的地方到底在哪?

如果你也在学 Agent,希望这篇梳理能帮你把 RAG 真正串起来。

二、为什么大模型需要RAG?

先看一个最根本的问题:大模型已经这么强了,为什么还需要 RAG?

因为大模型再强,也不天然知道你的私有知识。

比如:

  • 企业内部制度
  • 产品说明书
  • 招投标材料 这些内容,大模型本身并不会自动掌握。即使好像知道一些,也很难保证准确,更难保证是最新的。

于是问题就出现了:

  • 它可能根本不知道
  • 它也可能不知道,但仍然生成一个看起来很对的答案 后者,就是我们熟悉的幻觉。

而 RAG 的核心思路,就是让模型在回答之前,先去外部知识库里查资料,再基于资料作答。

所以,RAG 的本质可以概括成一句话:不是让模型凭记忆回答,而是让模型基于证据回答。

这也是为什么 RAG 特别适合企业知识库场景。企业真正需要的,往往不是一个会聊天的模型,而是一个能基于内部资料准确回答问题的系统。

三、RAG 到底是怎么跑起来的?

从整体流程看,一个完整的 RAG,大致是这样一条链路:

  1. 加载文档
  2. 对文档做清洗和切片
  3. 把文本块做 Embedding
  4. 存入向量数据库
  5. 用户提问时先做检索
  6. 对检索结果做重排
  7. 把最相关的上下文交给大模型生成答案

看起来不复杂,但真正难的是:这条链路里,每一步都会影响最终回答质量。

比如:

  • 文档解析错了,后面全都不准
  • 切片太碎,语义不完整
  • 切片太大,检索不精准
  • 召回到了,但排序不对
  • 检索结果不错,但上下文组织得不好

所以,RAG 不是单点能力,而是一整套知识如何流向答案的系统设计。

四、第一步:先让知识进入系统

RAG 的起点不是模型,而是数据。

因为模型最终能回答什么,很大程度上取决于你给了它什么知识。现实里的知识源往往非常杂,常见的包括:PDF、Markdown、Word、网页等

其中最常见、也最麻烦的,通常是 PDF。

1. PDF 为什么麻烦?

因为 PDF 更接近排版结果,而不是天然结构化文本。

它抽取出来之后,经常会出现:标题层级丢失、段落断裂、页眉页脚混入正文等

所以,RAG 里的文档加载,绝不是把字读出来这么简单。更重要的是尽量保留结构。

常见做法比如:

  • pypdf 抽文本,适合相对规则的 PDF
  • unstructured 做更复杂的结构解析,适合版式复杂的文档 如果是 Markdown,会相对友好很多。因为它天然带有标题、段落、列表等结构信息,更适合进入后续流程。

2. 为什么预处理很关键?

因为原始文档通常不能直接进入知识库。

在正式切片前,往往还要做一层清洗,比如:去掉无效空行、去掉重复页眉页脚、清理乱码和特殊符号等

这些步骤看起来像基础工作,但其实非常重要。

后面做过滤检索、结果溯源、答案引用时,很多能力都依赖这些结构和元数据。

一句话来说就是:知识库效果好不好,第一步常常不是模型决定的,而是文档处理决定的。

五、为什么切片是 RAG 里最容易被低估的一步?

很多人学 RAG,第一反应会把重点放在 Embedding 或向量数据库上。

但真正做下来会发现,切片往往才是最影响效果的环节之一。

原因很简单:文档太长,不能整篇直接拿去检索,也不可能完整塞进模型上下文。

所以必须把它拆成一个个 chunk。

1. 固定长度切片

最基础的方式,就是按固定长度切。

比如每 300 字、500 字,或者每 1000 token 切一块。

这种方法实现简单,适合快速搭原型。但问题也明显:

  • 可能把一个完整语义硬切断
  • 也可能把两个不同主题拼到一起

2. 带 overlap 的切片

为了减少边界信息丢失,通常会在相邻 chunk 之间加入 overlap,也就是重叠区域。

这样做的好处是:即使关键信息刚好落在边界上,也不容易被切丢。

这是很常见、也很有效的一种工程优化。

3. 语义切片

更进一步的方式,是按语义边界切片,比如:

  • 按标题切
  • 按段落切
  • 按主题变化切
  • 按句子相似度切

所以切片本质上是在平衡三件事:

  • chunk 要足够小,便于精准召回
  • chunk 又要足够完整,不能把语义切碎
  • chunk 的组织方式要适配后面的生成

说得更直接一点:你怎么切,决定了后面模型能检索到什么。

3.1 句子相似度

其中,按句子相似度切可以单独展开一下。

它的思路不是按固定长度硬切,而是先判断一段文本内部,语义究竟是在哪里发生变化的。

如果某个位置前后已经不像在讲同一件事了,那么这个位置就很适合作为切分点。

比如一段文本被拆成 1、2、3、4、5、6 六个句子。

如果窗口大小设为 3,就可以得到 1-2-3、2-3-4、3-4-5、4-5-6 这些滑动窗口。

接着,把每个窗口送进 embedding 模型,得到对应的语义向量,再比较相邻窗口之间的差异。

如果某个位置前后的差异突然变大,就说明主题可能在这里发生了变化,这个变化最大的点就可以作为候选切分点。

本质上,它不是按长度切,而是沿着语义变化最明显的地方切。

这种方式更符合人类阅读习惯,也更容易保留完整语义。但它对文档质量要求更高,实现复杂度也更高。

六、Embedding 和向量数据库,到底在做什么?

切完片之后,下一步就是把文本变成可计算的语义表示,这就是 Embedding。

你可以把它理解成:把一句话映射成一个语义坐标。

这样,用户提问时,系统就可以根据语义距离,去找最接近的文本块。

1. 密集嵌入(Dense Embedding)

最常见的一类是密集嵌入,也就是 Dense Embedding。

它会把文本表示成一个稠密向量,比较擅长处理表达不同,但意思相近的情况。

比如怎么报销差旅费和出差费用报销流程是什么,虽然字面不一样,但语义其实很接近,Dense Embedding 通常能把它们映射到比较近的位置,所以特别适合做语义检索。

实际工程里,这一类模型常见的代表有 BGE 和 GTE 系列,比如 bge-large-zh、bge-m3,或者 gte-large 等。它们本质上做的都是同一件事:尽量让语义相近的文本,在向量空间里离得更近。

1.1 GTE算法

GTE 这类密集嵌入模型,本质上是在做一件事: 把文本映射成一个能够表示语义的向量。 你可以把它理解成,模型先读一句话,理解它大概在说什么,然后再给这句话分配一个语义坐标。以后系统做检索时,就不再只是比关键词,而是去比较这些语义坐标之间的距离。距离越近,通常说明语义越接近;距离越远,通常说明语义差别越大。

2. 稀疏嵌入(Sparse Embedding)

另一类是稀疏嵌入,也就是 Sparse Embedding。

它更偏向关键词和稀疏特征,对专业术语、编号、错误码、实体词会更敏感。

比如用户搜的是产品型号、法条编号、报错代码、专有名词,这时候单靠 Dense 不一定最稳,因为语义模型有时候能理解大意,但未必能稳稳抓住关键词。在这种场景下,Sparse 或全文检索往往更有效。

这里一个非常经典的代表就是 BM25。它虽然不是大模型时代才出现的方法,但在检索系统里一直非常实用,尤其适合做关键词召回。所以在很多实际系统里,Dense 和 BM25 并不是互相替代,而是一起使用,形成混合检索。

2.1 BM25算法

BM25 可以理解成一种基于关键词相关性的排序算法。它会根据查询词有没有出现、出现了多少次、这个词在整个语料里是否稀有,以及文本长度是否合适,来判断一段文本和问题的匹配程度。它不擅长理解深层语义,但对术语、编号、错误码、专有名词这类关键词非常敏感,所以在很多 RAG 系统里,BM25 依然是很重要的基础能力。

3. 向量数据库

做完 Embedding 之后,还需要把这些向量和原始文本一起存起来,这就是向量数据库的工作。

它解决的不是如何理解文本,而是如何高效地存和如何快速地找。

它通常负责几件事:存储向量、做相似度搜索、保存原文和元数据、支持过滤检索,以及配合混合检索和索引优化。在这一类系统里,Milvus 是一个很典型的代表,也是业界比较常用的向量数据库之一。

真正进入向量数据库的,通常不只是一个向量,还会包括对应的 chunk 原文、来源文档、页码、标签、时间、业务字段等信息。

因为最终系统返回给用户的,不是一个抽象向量,而是一段可读、可追踪、可用的知识。

七、RAG 的检索,不只是向量搜索

初学 RAG 时,很容易把它理解成一句话:把问题转成向量,然后去向量数据库里搜。

这当然没错,但只说对了一半。真实场景里的检索,通常是多种方式的组合。

1. 相似度检索

这是最基础的一种方式。

把用户问题也转成向量,再找最相似的 chunk。

它的优势是:即使用户的说法和文档原文不完全一致,也有机会召回到相关内容。

2. 过滤检索

有些时候,仅靠语义相似还不够。

比如你希望:

  • 只查某个部门的文档
  • 只查 2024 年之后的制度
  • 只查产品手册,不查会议纪要 这时候就需要元数据过滤。它能让检索结果更可控,也更贴近业务场景。

3. 全文检索

全文检索擅长精准命中关键词。

对于这些内容,它往往特别有用:版本号、错误码、专有名词、编号、条款名称

现实里,很多问题并不只是语义理解问题,而是我就要找这个词。

这种时候,纯向量检索并不一定最优。

4. 混合检索

所以在很多实际项目里,最稳定的做法往往是混合检索,也就是把:

  • 语义检索
  • 关键词检索
  • 元数据过滤 结合起来一起用。

因为真实用户的问题,往往既有语义理解需求,也有精确匹配需求。

单一路径,很难兼顾两边。

所以很多时候,RAG 效果不好,不是模型太弱,而是检索策略太单一。

八、为什么召回之后,还要做 Rerank?

因为召回到了,不代表排得最好。

系统可能一次召回了 10 条都相关的内容,但真正最适合回答当前问题的那条,未必排在最前面。

如果不再做一次排序优化,最终交给模型的上下文就可能不是最优的。

所以在 RAG 里,常见做法通常不是召回完就结束,而是再加一层 Rerank,也就是重排。

你可以把它理解成两阶段:

  • 先尽可能召回一批候选内容
  • 再从候选里选出最值得给模型看的内容

1. 融合排序

有些场景下,系统并不是只有一路召回,而是会同时结合向量检索、全文检索、关键词检索等多种方式。

这时候首先要解决的问题,不是文本理解得够不够深,而是多路结果怎么合并。

常见方法有两种:

  • Weighted Ranker: 给不同召回通道设置不同权重,再综合排序
  • RRF Ranker: 不过度依赖绝对分数,而更关注一条结果在多个列表中的相对排名 这类方法的优点是实现简单、工程上容易落地,而且对混合检索非常实用。

但它们本质上更像融合排序,还不是严格意义上的深度精排。

2. 模型精排

如果想进一步判断哪段内容最适合当前问题,通常还会引入专门的精排模型,比如 Cross-Encoder 类的 reranker

它和前面的向量检索有一个很大的区别。

向量检索通常属于双塔结构,也就是先把问题和文本分别编码成两个向量,再通过向量相似度判断它们是否接近;

而 Cross-Encoder 则是把问题和候选文本作为一对输入,一起送进模型,让模型直接输出一个匹配分数。

这样做的好处是,模型看到的不再是两个彼此独立的向量,而是问题和文本之间更细粒度的交互信息,所以通常更适合做最终排序。

也正因为如此,Cross-Encoder 类方法往往比普通向量相似度更准,尤其适合用来判断这段内容到底是不是最适合回答当前问题。

不过它的代价也更高。因为每一个候选文本,都要和当前问题单独配对,再跑一遍模型,所以计算成本会明显高于普通向量检索。

也因此,在实际工程里,它一般不会用来做大规模召回,而是放在召回之后,对前几十条候选结果再做一次精排。

所以从工程角度看,Cross-Encoder 类精排模型本质上是在用更高的计算成本,换取更高质量的排序结果。

2.1 Cross-Encoder 为什么能做精排

3. Rerank 的本质

Rerank 的意义可以概括成一句话:不是把相关内容再找一遍,而是把可能相关进一步筛成最适合当前问题的内容。

  • Weighted Ranker 和 RRF 解决的是多路结果怎么合并得更合理
  • Cross-Encoder 解决的是这些候选里,哪个和当前问题最匹配 召回解决的是先把东西找出来,而 Rerank 解决的是把最该给模型看的内容排到前面。

九、RAG 最后一公里:怎么把检索结果交给模型?

检索和重排做完之后,下一步才是真正把信息交给大模型,也就是生成阶段。

很多文章讲 RAG,讲到检索和重排就差不多结束了。

但真正决定回答质量的,往往还包括最后一步:检索到的内容,究竟怎么交给模型。

1. 上下文编排

生成阶段最常见的做法,是把检索到的若干 chunk 拼进 Prompt,再连同用户问题一起发给模型。

但这一步并不是简单拼接,而更像是在做上下文编排。

比如,取几个 chunk,按什么顺序放,要不要去重,要不要带来源,内容会不会超出上下文长度,这些都会直接影响最终回答质量。

因为上下文不是塞得越多越好。塞太多,模型可能抓不住重点;塞太少,信息又可能不足。

所以这一层真正要解决的问题,不是怎么把内容放进去,而是怎么把最合适的内容,用最适合模型理解的方式放进去。

2. 幻觉控制

生成阶段另一个核心目标,是尽量降低幻觉。

RAG 不能彻底消灭幻觉,但可以明显降低它出现的概率。前提通常有两个:一是检索结果本身足够相关,二是 Prompt 约束足够明确。

常见做法包括:

  • 要求模型仅基于提供材料回答
  • 如果材料不足,就直接说明无法确定
  • 要求在回答中标注来源或出处 这些约束的本质,都是尽量减少模型脱离材料自由发挥,让它更像是在根据材料作答,而不是凭印象补全答案。

3. 为什么检索差不多,答案却差很多

很多时候,同样是 RAG,前面的检索结果看起来差不多,但最终回答效果还是会有明显差异。

原因就在于,生成阶段并不是一个机械的拼接动作,而是整条链路里的最后一次质量放大,或者质量损失。

如果上下文组织得不好,模型即使拿到了相关材料,也未必能用好。

如果约束不清楚,模型即使看到了证据,也可能继续自由发挥。

所以从工程上看,生成阶段真正影响的是:模型能不能把检索到的信息稳定转化成可用的答案。

说得更直接一点,检索决定模型能不能看到,而生成决定模型能不能答好。

十、RAG 的进阶优化,优化的到底是什么?

如果说前面讲的,更多还是标准 RAG 的主链路,那么再往后走,很多优化已经不只是检索得更准一点这么简单了。

因为在真实系统里,问题往往不只是能不能检索到,还包括:

  • 这次检索结果靠不靠谱
  • 证据够不够支撑回答
  • 要不要补一次检索
  • 不同问题是不是应该走不同流程 也就是说,RAG 的优化重点,正在从单点能力优化,逐渐走向整条链路的判断与决策优化。

Corrective RAG(自我纠正的RAG)

Corrective RAG 可以理解成一种带纠偏能力的 RAG。

它不默认第一次检索结果一定靠谱,而是会进一步判断:当前证据是不是不足,检索结果之间有没有冲突,如果这次检索不理想,是否需要补检索、改写查询,或者调整后续流程。

所以它优化的,已经不只是检索,而是当检索结果不够好时,系统怎么自我修正。

Adaptive RAG(自适应RAG)

Adaptive RAG 更强调按问题类型动态调整策略。

因为不是所有问题,都值得走同样一套固定流程。

有些问题一句话就能召回,有些问题需要多跳检索,有些问题甚至根本不该走知识库,而应该直接回答,或者先做路由判断。

所以到了这一步,RAG 就不再只是固定流水线,而更像是一套带决策能力的工作流。

这也是为什么现在很多人会把 RAG 和 Agent、工作流编排放在一起讨论。

因为继续往后优化,优化的往往已经不只是检索效果,而是整套系统在不同场景下,能不能做出更合适的决策。

十一、结尾

回过头看,RAG 的价值并不在于引入了多少新概念,而在于它提供了一种更可控的知识接入方式。

它让大模型在生成答案之前,不是直接依赖参数记忆,而是先从外部知识中检索证据,再基于证据生成回答。

这件事对于企业知识库、私有数据问答、以及需要持续更新知识的系统来说,意义非常明确。

但与此同时,RAG 也不是加一个向量库就能自然成立的方案。

它最终效果,取决于整条链路的质量,包括文档解析、切片策略、召回方式、重排机制,以及上下文组织方式。

所以从工程视角看,RAG 更像一套系统设计问题,而不是单一模型能力问题。

这也是我这次梳理之后最明确的一个结论:RAG 的关键,不在于有没有搭起来,而在于每一个环节是否真正为最终回答质量服务。

如果你也在学习 RAG、Agent 架构,或者正在做 AI 应用落地相关的事情,欢迎来找我交流。

我是爱敲代码的小黄,阿里巴巴高级开发工程师,CSDN 博客专家,平时会持续分享后端架构、中间件源码,以及 AI 应用实践相关内容。

如果这篇文章对你有帮助,也欢迎加我微信:hls1793929520

备注RAG,我拉你进群一起交流学习。

我们下期再见。

相关推荐
久菜盒子工作室3 小时前
面试经验|产品经理|自我介绍
面试·职场和发展·产品经理
Ruihong3 小时前
Vue v-bind 转 React:VuReact 怎么处理?
vue.js·react.js·面试
亦暖筑序3 小时前
Spring AI Alibaba 报错合集:我踩过的那些坑
java·后端
石榴树下的七彩鱼3 小时前
OCR 识别不准确怎么办?模糊 / 倾斜 / 反光图片优化实战(附完整解决方案 + 代码示例)
图像处理·人工智能·后端·ocr·api·文字识别·图片识别
卜夋4 小时前
Rust 学习笔记 - Day 6: 引用与借用
后端·rust
优秀1354 小时前
计算机基础面试重点知识
网络·面试·职场和发展
木斯佳5 小时前
前端八股文面经大全:字节TikTok前端一面(2026-04-17)·面经深度解析
前端·面试·八股·面经
考虑考虑5 小时前
图片居中
java·后端·java ee
Wect5 小时前
深度解析浏览器本地存储:原理、方案与实战指南
前端·面试·浏览器