💻📚🚀
fly living
记录技术、学习与生活

RAG 全流程(切分/向量检索/召回/生成)

自我总结

RAG 全流程(切分/向量检索/召回/生成)

RAG 整体分成知识库构建阶段和在线检索生成阶段

离线知识入库:文档解析 → 清洗 → 切分 Chunk → Embedding 向量化 → 向量库建索引

在线问答:用户 Query → Query 向量化 → 召回 TopK → 重排 Rerank → 上下文组装 → Prompt → LLM 生成

知识库构建时,

首先对 PDF、Word、Markdown 等文件做解析和文本清洗,然后按照固定长度、递归分段或者语义边界把文档切成多个 Chunk,并保留一定 overlap,避免上下文在切分边界处丢失。

每一个 Chunk 会通过 Embedding 模型转成高维向量,同时保存 chunkId、documentId、原文、标题、页码等 Metadata,然后写入向量数据库,通过 HNSW、IVF 等 ANN 索引加速相似度检索。

用户提问时,
同样使用相同的 Embedding 模型把 Query 转成向量,然后通过 cosine similarity、dot product 等方式从向量库召回 TopK 个候选 Chunk。

实际生产环境一般不直接把 TopK 全部交给大模型,而是结合关键词检索、Metadata Filter,甚至 Hybrid Search,再通过 Reranker 对候选结果重新排序。

最后选择相关度最高的几个 Chunk,在控制上下文窗口和 Token 数量的情况下组装 Prompt,把“用户问题 + 检索上下文”一起交给 LLM,让模型基于检索内容生成答案。

同时我们还会保留引用来源,并通过召回率、MRR、NDCG、答案正确率等指标评估整个 RAG 链路。

1.文档为什么一定要切分?

比如一份 100 页的《支付系统设计》很多个语义主题,如果整个文档只生成一个向量,这个向量实际上是所有语义的“平均表示”
用户Query 和整份文档的向量相似度可能并不高

2.Chunk 应该切多大?

Chunk 太小:
优势:检索精准
问题:语义不完整 上下文缺失

Chunk 太大:
优势:上下文完整
问题:噪声多,Embedding 语义被稀释,Token 成本增加

3.为什么 Chunk 之间需要 overlap?

比如原文:

支付宝支付成功以后,
系统首先校验签名,然后判断订单状态,
如果订单已经支付,则直接返回 success。

如果切成:
Chunk1:
支付宝支付成功以后,
系统首先校验签名,然后判断订单状态

Chunk2:
如果订单已经支付,则直接返回 success

两个 Chunk 语义被割裂。
加入 overlap:

Chunk1:
支付宝支付成功以后,
系统首先校验签名,然后判断订单状态

Chunk2:
判断订单状态,
如果订单已经支付,则直接返回 success
语义连续性更好。

提醒

代价是:
数据量增加、Embedding 成本增加
可能召回大量重复 Chunk
所以 overlap 不能无限加。

4.文档到底怎么切?

可以分成四种。

① 固定长度切分

例如:

text
每 500 token 一段
overlap 100 token

优点:
简单、快。

缺点:
可能把一句话、一个代码块、一张表切断。


② Recursive Chunking(递归切分)

实际项目很常见。
本质上不是按某一个固定“维度”拆,而是按一组从粗到细的文本结构层级递归拆分,直到每个 Chunk 满足目标大小。

text
标题
↓
段落
↓
换行
↓
句号
↓
固定字符数

递归切。
比如 LangChain 的:

text
RecursiveCharacterTextSplitter

核心思想:

尽可能保留自然语义边界。


③ 结构化切分

Markdown:

text
# 一级标题
## 二级标题
### 三级标题

Word:

text
Heading 标题
Paragraph 段落
Table 表格

代码:

text
Class
Method
Function

这种通常比单纯固定字符切分效果好。


④ Semantic Chunking

通过 Embedding 判断相邻句子的语义变化。
例如:

text
A A A A B B B C C

语义发生明显变化时再切:

text
[A A A A]

[B B B]

[C C]

效果可能更好,但:

预处理成本也明显更高。


5. Chunk 切完之后发生什么?

每个 Chunk 一般会形成:

text
{
  "chunkId": "chunk-001",
  "documentId": "doc-001",
  "content": "支付宝回调必须保证幂等...",
  "title": "支付回调",
  "page": 21,
  "embedding": [...]
}

实际上可以进一步写成:

text
{
  "chunkId": "chunk-001",
  "content": "支付宝回调必须保证幂等...",
  "embedding": [0.12, -0.31, 0.78, ...],
  "metadata": {
    "documentId": "doc-001",
    "projectId": "10086",
    "userId": "u001",
    "title": "支付回调",
    "page": 21,
    "chunkIndex": 15,
    "fileName": "支付宝支付接入.pdf",
    "fileType": "pdf",
    "source": "knowledge-base",
    "createdAt": "2026-09-09"
  }
}

这里有一个非常重要的东西:

Metadata。
metadata = 这个 Chunk 是谁、从哪来、属于谁、在哪一页、能不能被你搜到

因为实际 RAG 不只是:

text
Vector Search

还经常:

text
Vector Search
+
Metadata Filter

例如:

查询 projectId=10086 的知识库。

不是全公司文档里检索,而是:

text
WHERE project_id = 10086
AND user_id = xxx

之后再做向量搜索。
在满足这些条件的 Chunk 中,寻找向量最相似的 TopK


6. Embedding 到底是什么?

Embedding 干了什么?

一句话:

Embedding 是把文本映射到一个高维稠密向量空间,使语义相近的文本在向量空间中的距离也比较接近。

例如:

text
"Java线程池"
→
[0.12, -0.42, 0.73, ...]

假设是:

text
1536维

那么就是:

text
x1
x2
x3
...
x1536

不是:

每一个维度对应一个具体单词。

而是神经网络学习出来的高维语义特征。


7. 为什么 Query 和文档必须使用同一个 Embedding 模型?

比如知识库:

text
Document
↓
Embedding Model A
↓
vector A

查询:

text
Query
↓
Embedding Model B
↓
vector B

即使维度碰巧一样,也不能可靠比较。

因为两个模型学习出来的:

向量空间坐标系不同。

就像:

text
一个使用经纬度
一个使用笛卡尔坐标

直接计算距离没有意义。

所以一般必须保证:

text
Document Embedding Model
=
Query Embedding Model

更换 Embedding 模型后通常需要:

全量重新向量化。

8. 什么叫向量检索?

用户问:

text
RabbitMQ 如何保证消息不丢失?

先做:

text
Query
 ↓
Embedding
 ↓
Query Vector

例如:

text
Q = [0.1, 0.8, -0.3 ...]

数据库里面:

text
Chunk A → Vector A
Chunk B → Vector B
Chunk C → Vector C

然后计算:

text
Similarity(Q, A)
Similarity(Q, B)
Similarity(Q, C)

假设:

text
A = 0.86
B = 0.32
C = 0.91

取 TopK:

text
C
A
...

这就是最基础的向量召回。

9. Cosine Similarity(余弦相似度) 是什么?

公式:

cos⁡(A,B)=A⋅B∥A∥∥B∥\cos(A,B)=\frac{A \cdot B}{\|A\|\|B\|}

本质:

比较两个向量方向是否相似。

例如:

text
A → ↗
B → ↗

方向非常接近:

text
Cosine Similarity ≈ 1 相似度

Embedding 经常使用:

  • Cosine Similarity 余弦相似度
  • Dot Product 点积
  • Euclidean Distance 欧几里得距离

具体要看 Embedding 模型和向量数据库设计。

提醒

在 RAG 中,用户 Query 和知识库 Chunk 都会通过 Embedding 模型转成高维向量,然后使用 Cosine Similarity 计算 Query Vector 与 Chunk Vector 的相似度,按照得分排序并获取 TopK Chunk,作为上下文交给 LLM。相比关键词匹配,它能够捕获文字不同但语义相近的内容。

10. 几百万条向量难道每一条都算一次?

1000 万 Chunk,每次 Query 都和 1000 万向量计算 cosine 吗?不会
HNSW 是什么?

HNSW 是一种基于多层邻接图的近似最近邻搜索算法。它会把向量构建成多层图结构,查询时先从高层快速定位大致区域,然后逐层下降,在底层进行更精细的邻居搜索,从而避免全量遍历所有向量。

理解成:

text
Level 3       A ────── Z
               ↓

Level 2       A ── H ── Z
                  ↓

Level 1       A-B-C-D-E-F...
                    ↓

找到最接近 Query 的节点

核心:

不是遍历所有向量,而是沿着邻居图快速逼近最近向量。

想象你人在中国,要找:

距离你最近的一家星巴克。

正常会:

text
中国
 ↓
广东
 ↓
广州
 ↓
天河区
 ↓
附近门店

只不过:

text
地理空间

换成了:

text
向量空间
先快速缩小搜索范围,再在附近精细搜索。

11.为什么只做向量检索不够?

Embedding 关注:

语义。

但对:

  • ID、产品型号、错误码、人名、精确版本号、API 名称、专有名词
提醒

可能不够精准。
所以:精确关键词匹配+向量检索

12.什么叫倒排索引?

为什么 LIKE 不等于关键词检索?
1,性能低,大数据量需要扫描大量文本。
2,搜索能力弱(相关度排序,同义词。。。

正向:

text
Doc1 → Java Redis MQ
Doc2 → Java MySQL

倒排:

text
Java  → Doc1, Doc2
Redis → Doc1
MQ    → Doc1
MySQL → Doc2

用户搜索:

text
Redis

直接:

text
Redis → Doc1

不需要扫描所有文档。所以全文检索效率高。

13. 什么是召回?

召回 Retrieval / Recall:

从整个知识库:

text
100 万 Chunk

里面快速找:

text
Top 20 / Top 50

候选文档。例如:

text
1000000
  ↓ Vector / BM25
Top 50

这一步最重要的目标不是:

把第一名排得绝对准确。

而是:

尽量不要漏掉真正相关的文档。

所以召回阶段通常:

text
高 Recall

优先。

14.什么叫 Rerank?重排序

流程:

text
100000 个 Chunk

       ↓ Recall

Top 50

       ↓ Reranker

Top 5

       ↓

LLM

Recall:

快,但精度相对低。

Reranker:

慢,但是精度高。

所以不能对:

text
100 万个 Chunk

全部 rerank。
一般:

text
召回 Top20~100
↓
Rerank
↓
Top3~10

实际企业 RAG一般是

text
用户 Query
    ↓
Metadata Filter

projectId = 10086
tenantId = xxx
permission = xxx

    ↓
Recall / Retrieval

Vector Search
BM25
Hybrid Search

    ↓
Top 50

    ↓
Reranker

    ↓
Top 5

    ↓
LLM

15. Embedding 和 Reranker 有什么区别?

Embedding 负责“从海量文档里快速找出可能相关的候选”,Reranker 负责“把这些候选再仔细比较,重新排出最相关的顺序”。

16. TopK 越大越好吗?不是。

TopK 太小:

text
相关文档可能没召回来

Recall 低。

TopK 太大:

text
大量无关 Chunk
↓
Prompt 噪声增加
↓
Token Cost 增加
↓
LLM 甚至可能被错误上下文干扰

所以:

TopK 本质上是 Recall、Precision、Latency、Token Cost 的权衡。

常见:

text
Recall TopK = 20~100

Rerank TopK = 3~10

实际通过评测集确定。

17. Context 是怎么组装的?

例如最终 Top3:

text
Chunk A
Chunk B
Chunk C

Prompt:

text
System:
你是一名技术助手。
只能根据下面提供的知识回答。
如果知识库没有答案,请回答不知道。

Context:
[文档1]
...

[文档2]
...

[文档3]
...

Question:
RabbitMQ 如何保证消息不丢?

然后:

text
Prompt
↓
LLM
↓
Answer

这就是:

Retrieval-Augmented Generation

Retrieval:找到知识
Augmented:把知识补进 Prompt
Generation:LLM 生成答案

18. RAG 为什么能够降低幻觉?

RAG 可以降低幻觉,但不能完全消除幻觉。

text
外部知识
↓
作为上下文提供给 LLM

减少模型单纯依赖参数记忆。

但仍然可能发生:

召回错

text
Retrieval Failure

上下文本身错误

text
Knowledge Error

模型没按照 Context 回答

text
Generation Hallucination
提醒

因此完整方案还可以加:

text
引用来源
Groundedness 检查
Answer Verification
拒答策略

如何排查?

先拆链路:

text
Question
   ↓
Query理解有没有问题?
   ↓
Retrieval有没有召回来?
   ↓
Rerank有没有排错?
   ↓
Context有没有丢失?
   ↓
Prompt有没有问题?
   ↓
LLM有没有生成错误?

19. Query Rewrite 是什么?

Query Rewrite 是在 RAG 检索前,将当前 Query 与多轮对话历史交给 LLM,把代词、省略信息和上下文补全为一个 Standalone Question,再使用改写后的 Query 进行向量检索和关键词检索,从而解决多轮对话中 Query 语义不完整导致的召回下降问题;改写只补全用户意图,不应该引入新的事实。

多轮 RAG 经常需要:

Standalone Question Generation / Query Rewrite。

20. RAG 最常见的完整生产架构

这已经不是“Demo RAG”,而是比较标准的:

Production RAG Pipeline。

21.你的知识库更新怎么办?

新增

text
Document
↓
Chunk
↓
Embedding
↓
INSERT Vector

修改

一般:

text
根据 documentId
↓
删除旧 chunks
↓
重新 Parse / Chunk / Embedding
↓
写入

删除

text
documentId
↓
删除全部 chunk/vector/index

不能只删除:

text
MySQL 文档记录

却把向量留在向量库里。

否则:

脏向量 / Ghost Retrieval。

22.文档重复上传怎么办?

可以做:

text
SHA256(file)
或者:
contentHash

例如:

text
fileHash = SHA256(fileContent)

数据库判断:

text
fileHash 是否已存在

避免重复:

  • Parse
  • Chunk
  • Embedding
  • Storage
    Chunk 也可以做 hash:
text
chunkHash

进行增量向量化。

23.Embedding 是不是很贵?

Embedding 通常比 LLM Generation 便宜很多,但是海量数据依然需要优化。

例如:

text
100万篇文档
×
大量 Chunk

不能每次启动服务重新向量化。

所以:

text
文档 Embedding

属于:

Offline Precomputation。离线预计算

只有:

text
Query Embedding

在请求时实时计算。
这是 RAG 能做到低延迟的重要原因。

24.pgvector、Milvus、Elasticsearch 怎么选?

pgvector 可以理解为:给 PostgreSQL 增加“向量存储 + 向量相似度检索”能力的扩展。

适合:

text
现有系统已经使用 PostgreSQL
数据规模中小
希望业务数据 + 向量数据事务管理简单

优势:系统复杂度低。

Milvus / Qdrant / Weaviate

专门向量数据库。

适合:

text
千万 / 亿级 Vector
高并发
复杂 ANN

优势:专业向量搜索能力更强。

Elasticsearch / OpenSearch

优势: 既能做“关键词搜索”,又能做“语义搜索”,还能按 Metadata 过滤,所以特别适合 RAG 的 Hybrid Search。

text
BM25
+
Vector Search
+
Filter

适合: Hybrid Search。

如果你的项目本身要求:

text
中文关键词全文检索 + 向量检索

ES/OpenSearch 会非常自然。

25.RAG 怎么评估?

可以把 RAG 评估简单理解成检查两件事:

① 有没有把正确资料搜出来?
② 搜出来以后,LLM 有没有根据资料正确回答?

  1. Retrieval Evaluation:评估“搜得好不好”

HikariCP 为什么连接超时?

正确答案所在 Chunk 应该被 Retriever 搜出来。

  • Recall@K:有没有搜到
  • Precision@K:搜出来的结果有多少是有用的
  • MRR:正确答案排得靠不靠前
  • NDCG:整体排序质量怎么样

2. Generation Evaluation:评估“答得好不好”

假设 Retriever 已经把正确资料给 LLM:

text
Context:
HikariCP connection timeout
通常表示等待数据库连接超过 connectionTimeout。

然后检查:

  • Faithfulness / Groundedness:回答是不是基于 Context,有没有瞎编。
  • Answer Relevance:有没有真正回答用户的问题。
  • Correctness:最终结论是否正确。
  • Citation Correctness:引用的 Chunk / 文档是不是真的支持这个答案。

26.RAG 性能怎么优化?

文档侧

text
异步解析
批量 Embedding
Embedding Cache
增量更新

Retrieval

text
ANN
HNSW 参数优化
Metadata Filter
合理 TopK

Rerank

不要:

text
Top1000 → Rerank

而是:

text
Top30 / Top50

Generation

控制:

text
Context Token
Chunk 数量
模型尺寸
Prompt 长度

完整延迟:

T=Trewrite+Tembedding+Tretrieval+Trerank+TLLMT = T_{rewrite} + T_{embedding} + T_{retrieval} + T_{rerank} + T_{LLM}

通常真正的大头往往是:

LLM Generation。

text
用户 Query
   ↓
Retriever
   ↓
正确 Chunk 有没有搜出来?
   │
   ├─ 没搜出来 → Retrieval 问题
   │
   └─ 搜出来了
          ↓
        LLM
          ↓
       仍然答错 → Generation 问题

可以这样理解:

RAG 评估必须把 Retrieval 和 Generation 分开。Retrieval 用 Recall@K、Precision@K、MRR、NDCG 等指标评估召回和排序;Generation 用 Faithfulness、Answer Relevance、Correctness、Citation Correctness 等指标评估答案质量。

一句话记忆:

Retrieval 看“资料找对没有”,Generation 看“拿到资料后回答对没有”。

27.为什么不直接使用大模型超长上下文?

大模型上下文再长,也只是“这一次最多能读多少内容”;RAG 解决的是“先从海量知识里挑出当前最需要的内容再给模型”。

如果只靠超长上下文

相当于:

text
100GB 公司文档
      ↓
全部塞给 LLM
      ↓
让它自己找答案

问题很明显:

  • 贵:输入 Token 越多,成本越高
  • 慢:模型要先处理大量 Context
  • 噪声多:真正有用的可能只有 5 个 Chunk
  • 放不下:128K、1M 也装不下几十 GB / TB 知识库
  • 权限难控制:不能把用户无权看到的资料先塞给模型

28.简短

你最好把下面这套练熟。

Q:什么是 RAG?

Retrieval-Augmented Generation,先从外部知识库检索与 Query 相关的信息,再把检索结果作为上下文输入 LLM,让模型基于外部知识生成答案。

Q:为什么切 Chunk?

提升检索粒度,避免整篇文档 Embedding 后多个主题的语义被平均掉。

Q:Chunk 越小越好吗?

不是。太小会丢上下文,太大语义容易被稀释,而且增加 Token 和噪声,需要在 Recall、Precision 和 Context Completeness 之间平衡。

Q:Overlap 为什么存在?

避免关键信息刚好跨越 Chunk 边界导致语义断裂。

Q:Embedding 是什么?

把文本编码成高维稠密向量,使语义相近文本在向量空间距离也更接近。

Q:为什么 Query 和文档必须一个 Embedding 模型?

因为必须处于同一个向量空间,否则两个向量的距离没有可靠语义。

Q:怎么找最相似向量?

可以使用 Cosine、Dot Product 等相似度指标,大规模场景一般通过 HNSW 等 ANN 索引近似搜索,而不是全量扫描。

Q:什么是 TopK?

Retriever 返回相似度最高的 K 个候选 Chunk。

Q:TopK 越大越好吗?

不是,会增加噪声、Rerank 成本和 LLM Token 消耗。

Q:召回和向量检索区别?

召回是一个阶段,向量检索只是召回手段之一,还可以通过 BM25、Graph、SQL 等召回。

Q:为什么还要 BM25?

Vector 擅长语义,BM25 擅长错误码、编号、专有名词等精确关键词,二者互补。

Q:怎么融合?

可以使用 RRF 根据多个 Retriever 中的排名进行融合,而不是直接比较不同体系的原始 Score。

Q:Rerank 是什么?

对召回阶段得到的少量候选文档用更精确的模型重新计算 Query-Document 相关度,然后选 TopN。

Q:为什么不直接全部 Rerank?

Cross-Encoder 计算成本高,只适合候选集,Retriever 负责大范围快速筛选。

Q:RAG 可以消灭幻觉吗?

不能,只能降低。检索错误、知识错误、上下文利用错误都仍然会产生幻觉。

Q:回答错误怎么排查?

先看正确 Chunk 有没有召回,再看 Rerank 有没有排掉,最后看正确 Context 已经进入 Prompt 后 LLM 是否仍然生成错误。

2026-09-14日记简记
AI中转站科普与揭秘-如何赚钱?

评论区

正在加载评论区

正在连接评论服务,请稍候…