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)

企业知识库的来源五花八门:

格式 解析重点
PDF 保留页码、处理扫描版 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. "新产品价格表"

改写目标

  1. 补全多轮对话中省略的信息
  2. 消除口语化、指代、歧义
  3. 适配向量检索的语义匹配
  4. 生成多条候选问句提高召回率

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 系统成败的三大关键。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐