RAG原理讲解
RAG(检索增强生成)深度原理讲解
基于 FastAPI + Milvus + Ollama 的企业级私有化 RAG 系统实践
一、什么是 RAG
RAG(Retrieval-Augmented Generation,检索增强生成) 是一种将外部知识检索与大语言模型(LLM)生成能力相结合的技术架构。它的核心思想很简单:
在让 LLM 回答之前,先从知识库中检索出相关的参考资料,然后把问题和参考资料一起喂给 LLM,让它基于事实来回答。
为什么需要 RAG?
| LLM 原生局限 | RAG 解决方案 |
|---|---|
| 知识截止(无法知道训练后发生的事) | 实时检索企业私有文档 |
| 幻觉(一本正经地胡说八道) | 基于检索到的原文回答,可溯源 |
| 无法访问私有数据 | 企业自有知识库即插即用 |
| 长文本理解能力有限 | 精准检索最相关的文本片段 |
二、RAG 核心架构全景
┌─────────────────────────────────────────────────────────────┐
│ 用户提问 │
└──────────────────────┬──────────────────────────────────────┘
▼
┌─────────────────────────────────────────────────────────────┐
│ 1. 查询改写(Query Rewriting) │
│ - 补全省略信息、消除歧义、生成多角度候选查询 │
└──────────────────────┬──────────────────────────────────────┘
▼
┌─────────────────────────────────────────────────────────────┐
│ 2. 混合检索(Hybrid Retrieval) │
│ ├─ 向量检索:语义相似度匹配(Milvus + IVF_FLAT) │
│ └─ 关键词检索:BM25 精确匹配 │
└──────────────────────┬──────────────────────────────────────┘
▼
┌─────────────────────────────────────────────────────────────┐
│ 3. 重排序(Rerank) │
│ - 用 Cross-Encoder 对候选结果重新按相关性排序 │
└──────────────────────┬──────────────────────────────────────┘
▼
┌─────────────────────────────────────────────────────────────┐
│ 4. 上下文构建(Context Building) │
│ - 将 Top-K 结果拼接成结构化参考文档 │
└──────────────────────┬──────────────────────────────────────┘
▼
┌─────────────────────────────────────────────────────────────┐
│ 5. LLM 生成(Generation) │
│ - System Prompt + 参考资料 + 用户问题 → 结构化回答 │
└──────────────────────┬──────────────────────────────────────┘
▼
┌─────────────────────────────────────────────────────────────┐
│ 6. 返回结果(含引用溯源) │
│ - 答案 + 来源文档列表 + 置信度分数 │
└─────────────────────────────────────────────────────────────┘
三、文档处理流水线
3.1 文档解析(Parser)
企业知识库的来源五花八门:
| 格式 | 解析重点 |
|---|---|
| 保留页码、处理扫描版 OCR、提取表格 | |
| Word/Excel/PPT | 保留标题层级、表格结构、幻灯片大纲 |
| TXT/MD | 直接读取,注意编码统一 |
| HTML | 去除标签噪音,保留正文 |
关键挑战:
- 版面恢复:PDF 中的双栏、页眉页脚需要智能识别
- 表格保持:金融报表、产品参数表不能打散成纯文本
- OCR 准确性:扫描件的文字识别错误会直接污染知识库
3.2 文本分块(Chunking)
分块是 RAG 最关键的前置步骤,直接影响检索质量。
常见分块策略
| 策略 | 原理 | 适用场景 |
|---|---|---|
| 固定大小 | 按字符数均匀切分 | 结构化数据、表格、代码 |
| 递归分块 | 段落→句子→单词→字符,优先在语义边界切分 | 通用长文本 |
| 语义分块 | 按语义边界合并,保持完整意思 | 需要语义连贯性的文档 |
| 结构分块 | 按 Markdown 标题层级、Word 大纲切分 | 技术文档、论文 |
| 父子分块 | 父块存大段上下文,子块存精确检索片段 | 需要完整上下文的场景 |
| LLM 智能分块 | 让大模型分析文档结构后智能切分 | 高质量需求、成本不敏感 |
分块的核心矛盾
分块太小 → 丢失上下文 → LLM 无法理解完整语义
分块太大 → 检索噪声大 → 无关信息淹没关键内容
工程实践建议:
- 设置合理的 overlap(重叠区),确保跨块信息不丢失
- 对表格、代码块单独处理,避免被打散
- 父子分块是目前最平衡的方案:用子块做精准检索,用父块补全上下文
四、Embedding 向量化
4.1 什么是 Embedding
Embedding 是将文本映射到高维向量空间的技术。语义相近的文本在向量空间中距离更近。
"苹果是一种水果" → [0.12, -0.34, 0.89, ..., 0.05] (1024维)
"iPhone 是智能手机" → [0.45, 0.22, -0.11, ..., 0.78] (1024维)
"香蕉很好吃" → [0.15, -0.30, 0.85, ..., 0.02] (1024维)
4.2 Embedding 模型选型
| 模型 | 维度 | 优势 | 适用场景 |
|---|---|---|---|
| bge-m3 | 1024 | 中英双语、开源免费 | 国内企业私有化部署 |
| text-embedding-3-large | 3072 | 效果顶尖 | 云服务场景 |
| m3e | 768 | 中文优化、轻量 | 资源受限环境 |
| bge-large-zh | 1024 | 中文语义强 | 纯中文知识库 |
4.3 向量索引算法
Milvus 中常用的索引:
| 索引 | 原理 | 优点 | 缺点 |
|---|---|---|---|
| IVF_FLAT | 聚类后精确搜索最近簇 | 平衡效果好 | 数据量大时内存占用高 |
| HNSW | 图索引,近似最近邻 | 查询极快 | 构建慢、内存大 |
| FLAT | 暴力全量扫描 | 精确度100% | 数据量大时极慢 |
距离度量:余弦相似度(COSINE)是语义检索的最佳选择,因为 Embedding 模型通常将向量归一化到单位球面上。
五、检索策略
5.1 向量检索
基于语义相似度,能找到"意思相近但用词不同"的内容:
查询:"如何申请年假"
→ 匹配到:"员工休假流程说明"(关键词不同,语义相近)
局限:对专有名词、编号、代码的精确匹配能力弱。
5.2 BM25 关键词检索
基于词频和逆文档频率的经典算法:
查询:"QWEN-2024-001 产品规格"
→ 精确匹配到包含该编号的文档
局限:无法理解语义,"年假"和"带薪休假"被认为是完全不同的词。
5.3 混合检索 + RRF 融合
最佳实践:向量检索 + BM25 并行执行,然后用 RRF(Reciprocal Rank Fusion)融合结果。
# RRF 公式
score = Σ(1 / (k + rank_i))
# k 通常取 60
# rank_i 是该文档在某一检索方式中的排名
为什么融合?
- 向量检索补全 BM25 的语义盲区
- BM25 补全向量检索的精确匹配盲区
- RRF 不需要校准两种检索的分数尺度,直接用排名融合
5.4 查询改写(Query Rewriting)
用户的问题往往是口语化、有歧义的:
用户问:"那个新产品的价格"
→ 改写后:
1. "新产品定价策略"
2. "最新产品售价是多少"
3. "新产品价格表"
改写目标:
- 补全多轮对话中省略的信息
- 消除口语化、指代、歧义
- 适配向量检索的语义匹配
- 生成多条候选问句提高召回率
5.5 多查询检索(Multi-Query Retrieval)
对改写后的每个候选查询分别检索,然后合并去重:
all_results = {}
for q in rewritten_queries:
results = retriever.retrieve(q)
for r in results:
chunk_id = r["chunk_id"]
if chunk_id not in all_results:
all_results[chunk_id] = r
all_results[chunk_id]["_hit_count"] = 1
else:
# 被多个查询命中,提高权重
all_results[chunk_id]["_hit_count"] += 1
优势:多角度查询能覆盖用户问题的不同侧面,大幅提升召回率。
六、重排序(Rerank)
6.1 为什么需要重排序
向量检索和 BM25 返回的是"粗排"结果,它们只考虑了查询和文档的局部相似度。重排序用更精确的 Cross-Encoder 模型来做"精排"。
6.2 原理
向量检索(双塔模型):分别编码查询和文档,计算向量距离
→ 速度快,但交互信息少
重排序(Cross-Encoder):将查询和文档拼接后一起编码
→ 速度慢,但精确度高
6.3 工程实践
- 先用向量/BM25 召回 Top-50
- 再用 Reranker 精排,取 Top-5
- 本地模型(如 bge-reranker)效果足够,无需调用云端 API
七、LLM 生成与提示工程
7.1 系统提示词(System Prompt)设计
你是一个企业知识库助手,专门基于提供的参考文档回答用户问题。
## 回答规则:
1. 严格基于【参考文档】内容回答,不要编造信息
2. 如果参考文档不足以回答问题,请明确告知"根据现有资料无法回答"
3. 回答中需要引用来源时,使用 [^1], [^2] 等标记对应参考文档序号
4. 保持回答简洁、专业、结构化
## 参考文档:
[1] 文档A的内容...
[2] 文档B的内容...
请回答用户的问题。
7.2 关键约束
- 不要编造:明确告知 LLM “不知道就说不知道”
- 引用溯源:让用户可以追溯到原始文档
- 上下文窗口:注意 LLM 的上下文长度限制,避免参考资料过长
7.3 流式输出
使用 SSE(Server-Sent Events)实现打字机效果:
const resp = await fetch('/api/query/stream', {...})
const reader = resp.body.getReader()
// 逐字读取并渲染
八、RAG 的优势与局限
优势
- ✅ 消除 LLM 幻觉,回答可溯源
- ✅ 知识实时更新,无需重新训练模型
- ✅ 保护数据隐私(私有化部署)
- ✅ 降低 LLM API 调用成本(不需要长上下文)
局限
- ❌ 检索质量决定回答上限(Garbage In, Garbage Out)
- ❌ 复杂推理问题(需要多文档关联推理)仍有挑战
- ❌ 文档更新后需要重新 Embedding
- ❌ 对表格、图表等非文本内容的处理能力有限
九、性能优化要点
| 优化点 | 策略 |
|---|---|
| Embedding 加速 | GPU 推理、bge-m3 用 FP16、批量处理 |
| 检索加速 | Milvus HNSW 索引、缓存热门查询 |
| LLM 加速 | 本地 Ollama/vLLM、模型量化(INT8/INT4) |
| 降低延迟 | 查询改写和多查询可并行执行 |
| 减少幻觉 | 严格的 System Prompt + 引用溯源 |
十、总结
RAG 的本质是 “先检索,后生成”。它的价值不在于让 LLM 变得更聪明,而在于让 LLM 的回答有据可依、有源可溯。
在企业落地中,文档分块质量、检索策略选择、权限隔离 是决定 RAG 系统成败的三大关键。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐
所有评论(0)