RAG 检索完整流程解析:从 Query 预处理到 LLM 生成答案
RAG 检索整体流程
RAG(Retrieval-Augmented Generation,检索增强生成)的核心思想是:
在大语言模型生成答案之前,先从外部知识库中检索相关信息,再让 LLM 基于这些资料生成答案。
一个完整的 RAG 在线检索流程如下:
整个过程可以分为:
- 理解用户问题
- 将问题转换为可搜索向量
- 从知识库快速召回候选内容
- 对候选内容重新排序
- 构建 LLM 上下文
- 生成最终答案
第一阶段:Query 预处理(Query Processing)
1. 为什么需要 Query 预处理?
用户输入的问题通常不是一个适合检索的 Query。
例如:
用户:
那个登录问题怎么解决?这个问题存在:
- 缺少上下文
- 口语化严重
- 关键词不足
直接搜索:
那个登录问题怎么解决很难找到准确资料。
因此,在进入检索前,需要先对 Query 进行处理。
2. Query 预处理主要方法
Query 预处理主要包含:
- Query Rewrite(查询改写)
- HyDE(假设文档嵌入)
- Query Expansion(查询扩展)
- 指代消解
(1) Query Rewrite(查询改写)
Query Rewrite 的目标:
将用户的问题转换成更适合搜索的表达。
例如:
用户:
Go里面P是什么?改写:
Go GMP调度模型中的P(Processer)有什么作用?改写后的 Query:
- 包含专业术语
- 语义更加明确
- 更容易匹配知识库
流程:
用户问题 ↓ LLM分析 ↓ 生成优化Query ↓ 进入检索(2) 指代消解
在多轮对话中,用户经常使用:
- 它
- 这个
- 那个
- 上面的
- 刚才那个
例如:
对话:
用户: Go中的channel是什么? AI: channel用于goroutine之间通信。 用户: 它为什么会阻塞?其中:
它 = channel需要转换:
Go channel为什么会阻塞?否则:
它为什么会阻塞无法进行有效检索。
实现方式:
结合:
Conversation History + LLM Rewrite生成完整 Query。
(3) HyDE(Hypothetical Document Embeddings)
HyDE 的核心思想:
不直接搜索用户问题,而是让 LLM 先生成一个假设答案,再使用这个答案进行检索。
普通方式:
用户问题 ↓ Embedding ↓ 向量搜索HyDE:
例如:
用户:
什么是GMP中的P?LLM生成:
GMP中的P表示Processor, 负责管理goroutine执行和调度资源。然后:
使用这个答案生成向量。
优势:
因为假设答案包含更多专业词:
GMP Processor goroutine scheduler所以更容易匹配知识库。
缺点:
如果生成答案错误,会影响检索方向。
(4) Query Expansion(查询扩展)
一个问题可能有多种表达方式。
例如:
用户:
Go如何实现任务队列?扩展:
Go worker pool实现 goroutine任务调度 channel任务队列 生产者消费者模型然后多个 Query 一起检索。
目的:
提高召回率。
第二阶段:Query Embedding(向量化)
经过 Query 处理后,需要将文本转换成向量。
因为计算机无法直接理解:
Go GMP中的P是什么?需要通过 Embedding 模型:
文本 ↓ Embedding模型 ↓ 向量例如:
Go GMP中的P ↓ [0.124, 0.532, 0.821, ...]这个向量代表文本的语义信息。
之后:
使用这个向量和知识库中的向量计算相似度。
第三阶段:向量检索 + BM25 多路召回(Retrieval)
这一阶段目标:
快速找到可能相关的候选文档。
通常采用:
1. Dense Retrieval(向量检索)
基于 Embedding。
例如:
用户:
Go调度里面P有什么作用?数据库:
GMP模型中的Processor负责调度goroutine虽然关键词不同:
作用 = 负责但是语义相似。
2. Sparse Retrieval(BM25)
BM25 是关键词检索算法。
例如:
搜索:
0x80072f78BM25 可以精准匹配错误码。
优势:
适合:
- 专业名词
- API名称
- 错误码
- 产品编号
为什么需要 Hybrid Retrieval?
单独使用一种方式都有缺点。
向量检索:
优点:
- 理解语义
缺点:
- 专有名词可能不准
BM25:
优点:
- 精确匹配关键词
缺点:
- 不理解语义
所以生产环境通常:
例如:
用户:
docker错误0x80072f78BM25:
找到:
错误码0x80072f78向量:
找到:
Docker网络连接失败原因两者结合效果更好。
第四阶段:Rerank 精排
为什么需要 Rerank?
理解了第三步的粗排召回,你会发现一个自然的问题:Top-20 的结果里不可能条条都相关,肯定混了一些干扰项进去。Rerank 就是为了解决这个问题的。
向量检索是「粗排」,召回的 Top-K(比如 20 条)里可能混入相关度不高的干扰片段。Rerank 模型(Cross-Encoder 结构)会把用户问题和每个候选片段拼在一起输入,深度理解它们之间的语义匹配程度,重新打分排序。最终只保留 Top-3 到 Top-5 的高质量片段,把噪音过滤掉。
你可能会问,为什么不直接用 Rerank 模型来检索,还要先粗排再精排?因为 Rerank 是 Cross-Encoder结构,需要把查询和每个候选拼在一起过模型,计算量比向量检索大得多。如果拿它对百万条数据逐一算分,延迟完全不可接受。所以工程上采用「粗排筛到几十条,精排再从几十条里挑最好的几条」这种两阶段策略,兼顾速度和质量。Rerank 整体耗时通常在几百毫秒以内,对用户体感影响不大,但检索质量的提升非常明显。
第五阶段:Prompt 拼接(Prompt Assembly)
经过 Rerank 后:
得到:
最相关的几个chunk然后构建 Prompt。
例如:
prompt=f""" 你是一个专业助手,请根据以下参考资料回答用户的问题。 如果参考资料中没有相关信息,请回答「根据现有资料无法回答」,不要自行猜测。 参考资料: [1]{chunk_1}[2]{chunk_2}[3]{chunk_3}用户问题:{user_query}"""这个过程:
就是 Context Building。
第六阶段:LLM生成答案 + 溯源
最后:
LLM 根据:
用户问题 + 检索资料 + 系统提示词生成答案。
流程:
Prompt ↓ LLM ↓ 回答 + 引用来源例如:
回答:
Go GMP模型中的P表示Processor, 负责连接M和G,并管理goroutine运行。 来源:Go scheduler文档十、完整耗时分析
根据图片中的数据:
| 阶段 | 耗时 |
|---|---|
| Query预处理 | 100~300ms |
| Query Embedding | 20~50ms |
| 检索召回 | 50~150ms |
| Rerank | 100~200ms |
| Prompt拼接 | 10~30ms |
| LLM生成 | 2~10s |
可以看到:
真正耗时最大的通常不是检索,而是:
LLM生成阶段十二、总结
RAG 检索并不是简单的:
用户问题 ↓ Embedding ↓ 向量数据库一个完整的 RAG 检索系统:
Query预处理 ↓ Embedding向量化 ↓ Hybrid Retrieval召回 ↓ Rerank精排 ↓ Prompt构建 ↓ LLM生成答案其中:
| 模块 | 作用 |
|---|---|
| Query Rewrite | 让问题更适合搜索 |
| HyDE | 利用假设答案增强语义 |
| Query Expansion | 提高召回范围 |
| Embedding | 文本向量化 |
| BM25 | 关键词匹配 |
| Vector Search | 语义匹配 |
| Rerank | 提高准确率 |
| Prompt Assembly | 提供上下文 |
| LLM | 生成最终答案 |
这就是现代 RAG 系统中一次完整的在线检索流程。