上一篇速通 AI(六):LLM 应用开发 — 提示词工程、LangChain、OpenAI API

目标:深入掌握 RAG 检索增强生成的完整体系——向量数据库、高级检索策略、GraphRAG、评估体系。

前置要求:上一篇(LangChain 基础、Embedding 概念、RAG 链入门)


本阶段知识依赖图

flowchart TD
    A["LangChain + RAG入门(上一篇)"]
    A --> E["RAG系统深入(核心)"]
    E -->|PDF/Markdown解析| E2[文档加载与切片]
    E -->|BGE-Large/BM25| E4[Embedding]
    E -->|Milvus/FAISS/Chroma| E1[向量数据库]
    E -->|高级检索/自适应RAG| E5[检索策略]
    E -->|Corrective RAG| E6[自我纠正]
    E -->|Adaptive RAG| E7[自适应检索]
    A --> F["向量数据库深入"]
    F -->|HNSW/IVF| F1[底层原理]
    F -->|选型对比| F2[数据库选型]
    A --> G["GraphRAG"]
    G -->|知识图谱增强| G1[核心思想]
    G -->|传统RAG对比| G2[优势分析]
    A --> H["Advanced RAG"]
    H -->|检索优化| H1[策略]
    H -->|生成优化| H2[策略]
    H -->|评估体系| H3[RAG评估]

1. RAG 系统深入——检索增强生成

为什么需要 RAG ?——大模型的三大硬伤

  • 硬伤 1 :知识截止日期
    • GPT-4 的知识截止到 2024 年 4 月
    • 问它“今天的新闻” → 完全不知道
  • 硬伤 2 :幻觉(Hallucination)
    • 大模型会“一本正经地胡说八道”
    • 问它一个它不知道的事实 → 可能编造看起来合理但错误的答案
  • 硬伤 3 :企业私有数据
    • 大模型从未见过你公司的内部文档、产品手册、客户数据
    • 问它“我们公司的退货政策是什么” → 完全不知道

RAG 的解决方案:不让大模型“凭记忆回答”,而是先帮它“查资料”,再让它“基于资料回答”。

  • 知识可以实时更新(查最新的资料)
  • 减少幻觉(有据可依)
  • 可以访问私有数据(先检索企业文档)

RAG 的完整流程——每一步详解

flowchart LR
    subgraph Offline["离线索引(一次性)"]
        D[文档] --> S[文本切分]
        S --> E[Embedding]
        E --> V[(向量数据库)]
    end
    subgraph Online["在线查询(每次)"]
        Q[用户问题] --> QE[Query Embedding]
        QE --> Search[相似度搜索]
        V --> Search
        Search --> R[Top-K 文档块]
        R --> P[Prompt 组装]
        Q --> P
        P --> LLM[LLM]
        LLM --> A[回答]
    end

Step 1 :文档处理(离线,一次性完成)

  • PDF/Word/Markdown → 文本提取 → 文本切分 → Embedding → 存入向量数据库

Step 2 :检索(在线,每次查询时执行)

  • 用户问题 → 问题 Embedding → 向量数据库中搜索最相似的文档块

Step 3 :生成(在线,每次查询时执行)

  • 检索到的文档块 + 用户问题 → 组装提示词 → 发送给 LLM → 生成回答

类比:

  • Step 1 = 把图书馆的书整理好,建立索引
  • Step 2 = 根据读者的问题,从图书馆找出相关的书
  • Step 3 = 让 AI 助手阅读这些书,然后回答读者的问题

数据加载与切片——决定 RAG 质量的关键

# PDF解析
from langchain_community.document_loaders import PyPDFLoader
loader = PyPDFLoader("enterprise_doc.pdf")
docs = loader.load()

# Markdown解析
from langchain_community.document_loaders import UnstructuredMarkdownLoader
loader = UnstructuredMarkdownLoader("readme.md")

# 语义切分(推荐)
from langchain_experimental.text_splitter import SemanticChunker
splitter = SemanticChunker(OpenAIEmbeddings())
chunks = splitter.split_documents(docs)

切分方式对比

  • 固定长度切分:每 500 个字符切一刀
    • 优点:简单
    • 缺点:可能在句子中间切断,语义不完整
  • 递归切分(RecursiveCharacterTextSplitter):按段落 → 句子 → 词的优先级切
    • 优点:尽量在自然边界处切分
    • 缺点:块大小不均匀
  • 语义切分(SemanticChunker):根据语义相似度自动找到切分点
    • 优点:每个块语义完整
    • 缺点:计算量较大(需要调用 Embedding 模型)

实际推荐:

  • 快速原型:用递归切分
  • 生产环境:用语义切分
  • 特定格式:用专门的解析器(如 Markdown 用 MarkdownHeaderTextSplitter)

向量数据库——存储和检索的"仓库"

数据库类型适用场景特点
FAISS内存型快速原型/小数据速度快,需手动调用 faiss.write_index() 持久化
Chroma嵌入型本地开发/小项目简单易用,自动持久化到磁盘
Milvus服务型生产环境/大数据分布式、高性能、企业级
Pinecone云服务无需运维托管服务,按量付费

类比:

  • FAISS = 纸质便签——快速方便,但容易丢
  • Chroma = 笔记本——持久保存,但容量有限
  • Milvus = 数据中心——高性能、高可靠,但需要运维
  • Pinecone = 云存储——不用操心基础设施,但要付费

高级检索策略——提升 RAG 效果的关键

# 1. 混合检索(Hybrid Search):语义 + 关键词
# 类比:搜索时同时考虑"意思相近"和"关键词匹配"
from langchain.retrievers import EnsembleRetriever
from langchain_community.retrievers import BM25Retriever

bm25_retriever = BM25Retriever.from_documents(chunks)  # 关键词检索
vector_retriever = vectorstore.as_retriever()            # 语义检索

# 70%语义 + 30%关键词
ensemble_retriever = EnsembleRetriever(
    retrievers=[vector_retriever, bm25_retriever],
    weights=[0.7, 0.3]
)

# 为什么需要混合检索?
# 纯语义检索的问题:可能检索到语义相似但关键词不匹配的文档
# 纯关键词检索的问题:可能漏掉语义相关但用词不同的文档
# 混合检索取长补短
# 2. 多查询检索(Multi-Query):一个问题,多种表述
# 类比:搜索时同时用多个关键词
from langchain.retrievers import MultiQueryRetriever
retriever = MultiQueryRetriever.from_llm(
    retriever=vectorstore.as_retriever(),
    llm=llm
)
# 原始问题:"什么是RAG?"
# 自动生成多个变体:
#   "解释检索增强生成技术"
#   "RAG的定义和原理"
#   "描述RAG的工作流程"
# 合并所有查询的检索结果 → 召回率大幅提升
# 3. 上下文压缩(Contextual Compression):只保留相关内容
# 类比:从一本书中只摘抄和问题相关的段落
from langchain.retrievers import ContextualCompressionRetriever
from langchain_cohere import CohereRerank
compressor = CohereRerank()
compression_retriever = ContextualCompressionRetriever(
    base_compressor=compressor,
    base_retriever=vectorstore.as_retriever()
)
# 检索到的文档块可能包含大量无关信息
# 压缩后只保留与问题最相关的部分 → 减少噪音,提高回答质量

Corrective RAG——自我纠正

标准 RAG 的问题:检索到的文档可能不相关,但模型仍会基于这些文档生成回答(“垃圾进,垃圾出”)。

Corrective RAG 的改进流程:

  1. 检索文档
  2. 评估文档与问题的相关性(用 LLM 判断)
  3. 如果相关性低 → 用网络搜索补充更相关的信息
  4. 如果相关性高 → 直接使用
  5. 生成回答后,再评估回答的质量
  6. 如果质量不达标 → 重新检索或重新生成

类比:一个负责任的研究员

  • 普通 RAG = 随便找几本书就回答
  • Corrective RAG = 先检查找的书是否相关,不相关就换一批,回答后还要检查质量

Adaptive RAG——自适应检索

核心思想:不同类型的问题需要不同的处理方式。

  • 简单事实问题:“法国的首都是哪?”
    • 大模型自己就知道,不需要检索
    • 直接回答,省时省力
  • 复杂知识问题:“比较 RAG 和微调的优劣”
    • 需要检索相关文档
    • 基于检索结果回答
  • 推理问题:“如果 A > B , B > C ,那么 A 和 C 的关系?”
    • 不需要检索(这不是知识问题,是推理问题)
    • 让模型用思维链推理

Adaptive RAG = 先判断问题类型 → 再选择最合适的处理方式 → 效率最高、效果最好。

RAG vs 微调 vs 提示词工程决策表

考量维度提示词工程RAG微调
开发成本最低(几小时)中等(几天)最高(几周)
数据需求无需数据需要文档库需要标注数据
计算成本极低低(检索+生成)高(训练+推理)
知识更新不支持实时更新需重新训练
适用场景简单任务、快速原型知识问答、文档查询专业领域、格式要求
推理延迟无额外延迟有检索延迟无额外延迟
推荐优先级先试这个其次考虑最后考虑

模块小结: RAG 系统

你学到了什么为什么重要
RAG 的三大硬伤知识截止、幻觉、私有数据
RAG 完整流程文档处理→检索→生成
数据切分策略固定长度 vs 递归 vs 语义
高级检索策略混合检索、多查询、压缩
Corrective/Adaptive RAG自我纠正、自适应检索

2. 向量数据库深入

向量搜索的底层原理

类比:在图书馆找"最相似的书"

  • 传统数据库(MySQL):精确匹配
    • SELECT * FROM books WHERE title = '深度学习'
    • 只能找到标题完全匹配的书
  • 向量数据库:语义相似度搜索
    • “找到和‘深度学习’含义最接近的书”
    • 能找到“神经网络”“机器学习入门”“TensorFlow 实战”等相关书籍

向量搜索的核心算法

  • 暴力搜索(Brute Force)
    • 计算查询向量和所有向量的距离 → 取最近的 k 个
    • 精度: 100% (不会漏掉任何结果)
    • 速度:$O(n\times d)$,$n$=向量数量,$d$=维度
    • 问题:数据量大时极慢(100 万个 1536 维向量需要计算 15 亿次)
  • 近似最近邻(ANN)
    • 用一些“聪明的策略”加速搜索,牺牲少量精度换取大量速度

HNSW——最常用的 ANN 算法

HNSW (Hierarchical Navigable Small World)= 分层可导航小世界图。

类比:找人的社交网络

  • 第 1 层(稀疏层):只有“超级节点”(明星、大 V)→ 快速定位大致区域
  • 第 2 层(中等层):普通节点 → 缩小范围
  • 第 3 层(密集层):所有节点 → 精确定位

搜索过程:

  1. 从最顶层的某个节点开始
  2. 在当前层找到最近的邻居
  3. 跳到下一层,继续找最近的邻居
  4. 重复直到最底层 → 找到最近的向量

精度: 95-99% (偶尔会漏掉,但几乎不影响结果)。 速度:$O(\log n)$,比暴力搜索快几个数量级。

动手计算:HNSW 搜索过程示例

假设 6 个向量(A-F),构建 3 层索引:

Layer 0(稀疏层):A ———————— D
Layer 1(中间层):A —— C —— D —— F
Layer 2(密集层):A — B — C — D — E — F(所有节点互连)

搜索 query 最近邻:

  1. 从 Layer 0 的 A 开始 → A 到 D 的距离更近 → 跳到 D
  2. 在 Layer 1 从 D 出发 → 检查 C、F → C 最近 → 跳到 C
  3. 在 Layer 2 从 C 出发 → 检查 B、D → B 最近 → 返回 B

只需检查 5 个节点(而非暴力搜索的全部 6 个)。当 $n=100$ 万时,HNSW 只需检查 $\log(100万) \approx 20$ 个节点。

IVF——另一种常用算法

IVF (Inverted File Index)= 倒排文件索引。

类比:图书馆的分区

  • 把所有书按主题分成 100 个区域
  • 找书时先确定在哪个区域,再在区域内搜索
  • 不需要翻遍整个图书馆

实现:

  1. 训练时:用 K-Means 把向量分成若干个聚类(Voronoi cells)
  2. 搜索时:先找到查询向量最近的几个聚类,只在这些聚类中搜索
  3. 参数 nprobe :搜索多少个聚类(越大越精确,越慢)

动手计算:IVF 检索示例

假设 12 个向量,K-Means 分成 3 个聚类:

聚类包含的向量
聚类 1(中心 [0.2, 0.3])A, B, C, D
聚类 2(中心 [0.8, 0.7])E, F, G, H
聚类 3(中心 [0.5, 0.9])I, J, K, L

查询向量 $q = [0.7, 0.8]$,距离各聚类中心:

  • 到聚类 1:$\sqrt{(0.7-0.2)^2+(0.8-0.3)^2} = 0.71$
  • 到聚类 2:$\sqrt{(0.7-0.8)^2+(0.8-0.7)^2} = 0.14$ ← 最近
  • 到聚类 3:$\sqrt{(0.7-0.5)^2+(0.8-0.9)^2} = 0.22$

nprobe=1:只搜索聚类 2(4 个向量),暴力搜索的 1/3

nprobe=2:搜索聚类 2 + 聚类 3(8 个向量),更精确但更慢

与暴力搜索对比:12 个向量暴力搜索需比较 12 次,IVF(nprobe=1) 只需比较 4 次 + 3 次聚类中心 = 7 次。当 $n=100$ 万、聚类数=1000 时,IVF 只需搜索 1000 个向量(0.1%),速度提升 1000 倍。

量化压缩

PQ (Product Quantization)= 乘积量化。

类比:用“代表色”代替所有颜色

  • 一张图片有 1600 万种颜色
  • 用 256 种“代表色”来近似 → 存储空间大幅减少

实现:

  1. 把 1536 维向量切成多段(如 8 段,每段 192 维)
  2. 每段用一个“码本”(codebook)中的最近码字代替
  3. 原始向量: 1536 × 4 bytes = 6 KB
  4. 量化后: 8 × 1 byte = 8 bytes → 压缩 768 倍

向量数据库选型深入

数据库索引算法持久化分布式适用场景
FAISSHNSW/IVF/PQ❌ 内存❌ 单机快速原型、小数据
ChromaHNSW✅ 磁盘❌ 单机本地开发、小项目
MilvusHNSW/IVF/DiskANN✅ 分布式生产环境、大数据
QdrantHNSW✅ 磁盘✅ 分布式新兴选择, API 友好
WeaviateHNSW✅ 磁盘✅ 分布式GraphQL 接口
Pinecone托管✅ 云✅ 云无需运维,按量付费

选型建议:

  • 学习和原型: FAISS (最快上手)
  • 小型生产: Chroma 或 Qdrant
  • 大型生产: Milvus (最成熟)或 Qdrant
  • 不想运维: Pinecone

模块小结:向量数据库

你学到了什么为什么重要
向量搜索原理语义相似度检索的基础
HNSW 算法最常用的 ANN 算法
IVF 倒排索引聚类加速搜索
PQ 乘积量化压缩向量,节省存储
数据库选型不同场景的最佳选择

3. GraphRAG

什么是 GraphRAG ?

类比:从"图书馆"到"知识图谱"

  • 传统 RAG = 图书馆找书
    • 把文档切成片段,用向量搜索找最相关的片段
    • 问题:片段之间没有“关系”——不知道 A 片段和 B 片段有什么联系
  • GraphRAG = 知识图谱 + 向量搜索
    • 不仅找到相关片段,还找到片段之间的“关系”
    • 能回答需要“综合多个信息源”的复杂问题

GraphRAG 的核心思想

  1. 从文档中提取实体和关系
    • 文档:“张三是百度的 CTO ,百度是李彦宏创办的公司”
    • 实体:张三、百度、李彦宏
    • 关系:(张三, 是 CTO, 百度), (百度, 创办者, 李彦宏)
  2. 构建知识图谱
  3. 社区检测
    • 把紧密相关的实体聚成“社区”
    • {张三, 百度, 李彦宏} 是一个社区
  4. 为每个社区生成摘要
    • “百度是一家由李彦宏创办的公司,张三担任 CTO”
  5. 检索时同时搜索向量和图谱
    • 问题:“张三在哪家公司工作?”
    • 向量搜索找到相关文档片段
    • 图谱搜索找到张三 → 百度的关系
    • 综合回答:“张三在百度担任 CTO”
flowchart TD
    A[提取实体与关系] --> B[构建知识图谱]
    B --> C[社区检测]
    C --> D[社区摘要]
    D --> E["检索:向量 + 图谱"]
    E --> F[综合回答]

GraphRAG vs 传统 RAG

特性传统 RAGGraphRAG
数据结构文档片段(扁平)知识图谱(结构化)
检索方式向量相似度向量 + 图遍历
多跳推理困难自然支持
全局摘要不支持支持(社区摘要)
适用场景单文档问答多文档、复杂关系推理
复杂度高(需要构建图谱)

GraphRAG 的实现

Microsoft 的 GraphRAG 实现:

示例:8 个实体、8 条关系的知识图谱

张三 --CTO--> 百度 <--创办-- 李彦宏
张三 --同事--> 李四        百度 --竞品--> 谷歌
谷歌 --CEO--> 桑达尔        谷歌 --总部--> 山景城
百度 --总部--> 北京         李四 --工程师--> 百度

社区检测后聚为 2 个社区:

  • 社区 1:{张三, 百度, 李彦宏, 李四, 北京} → “百度由李彦宏创办,总部在北京,张三任 CTO”
  • 社区 2:{谷歌, 桑达尔, 山景城} → “谷歌由桑达尔领导,总部在山景城”

传统 RAG 找不到"百度和谷歌的关系"(没有文档片段同时提到两家公司)。GraphRAG 通过图谱中的"百度—竞品—谷歌"直接回答。

  1. 使用 LLM 从文档中提取实体和关系
  2. 构建知识图谱
  3. 使用 Leiden 算法进行社区检测
  4. 为每个社区生成 LLM 摘要
  5. 检索时:局部搜索(向量 + 图谱)+ 全局搜索(社区摘要)

适用场景:

  • “这个公司的组织架构是什么?” → 需要从多份文档中综合信息
  • “这些产品的共同竞争对手是谁?” → 需要跨文档推理
  • “总结一下这个领域的最新进展” → 需要全局视角

模块小结: GraphRAG

你学到了什么为什么重要
GraphRAG 核心思想知识图谱 + 向量搜索
实体关系提取从文档构建图谱
社区检测与摘要全局视角的信息聚合
GraphRAG vs 传统 RAG结构化 vs 扁平化

4. Advanced RAG 工程实践

为什么需要"高级"RAG ?

基础 RAG 的问题:

  1. 检索质量不稳定——有时找到的文档不相关
  2. 生成质量参差——有时回答不准确或“幻觉”
  3. 系统鲁棒性差——输入格式变化就可能出错
  4. 评估困难——不知道效果好不好,怎么改进

Advanced RAG = 在每个环节都做优化。

检索优化策略

  1. 查询改写(Query Rewriting)
    • 原始问题:“这个东西怎么用?”
    • 改写后:“XX 产品的使用方法和操作步骤”
    • 让问题更明确,检索更精准
  2. 查询扩展(Query Expansion)
    • 原始问题:“RAG”
    • 扩展为:[“RAG”, “检索增强生成”, “Retrieval Augmented Generation”]
    • 多角度检索,提高召回率
  3. 假设文档嵌入(HyDE)
    • 先让 LLM 生成一个“假设的回答”
    • 用这个假设回答去检索(而不是用问题检索)
    • 假设回答和真实文档的语义更接近
  4. 上下文压缩(Contextual Compression)
    • 检索到的文档块可能很长,只有部分与问题相关
    • 用 LLM 提取出与问题最相关的部分
    • 减少噪音,提高回答质量

生成优化策略

  1. 提示词优化
    • 明确告诉模型“只基于提供的资料回答”
    • 要求模型“如果不确定就说不知道”
    • 指定输出格式(如“先总结再详细说明”)
  2. 引用追溯
    • 要求模型在回答中标注信息来源
    • “根据文档 A 第 3 段…”、“根据文档 B…”
    • 用户可以验证回答的准确性
  3. 多轮验证
    • 生成回答后,用另一个 LLM 调用检查回答是否与原文一致
    • 类似于“编辑审查”流程

RAG/Agent 评估体系

面试必问:“你怎么衡量 RAG 的效果?”

RAG 评估的三个维度:

  1. 检索质量(Retrieval Quality)

动手计算:检索评估指标数值示例

假设用户问"什么是 RAG?",数据库中有 5 个相关文档,检索系统返回 Top-3 结果:

排名文档是否相关
1文档 A(介绍 RAG 原理)✅ 相关
2文档 B(介绍 Transformer)❌ 不相关
3文档 C(RAG 实现代码)✅ 相关

Recall@3 = 检索到的相关文档数 / 全部相关文档数 = $2/5 = 0.4$(5 个相关文档只找到了 2 个)

$$\text{Recall@k} = \frac{|\{\text{相关文档}\} \cap \{\text{Top-k 结果}\}|}{|\{\text{全部相关文档}\}|}$$

Precision@3 = 检索结果中相关的数 / k = $2/3 = 0.67$(Top-3 中有 2 个相关)

$$\text{Precision@k} = \frac{|\{\text{相关文档}\} \cap \{\text{Top-k 结果}\}|}{k}$$

MRR(Mean Reciprocal Rank)= 第一个相关文档的排名的倒数。第一个相关文档排第 1,所以 $MRR = 1/1 = 1.0$。如果第一个相关文档排第 2,则 $MRR = 1/2 = 0.5$。

$$\text{MRR} = \frac{1}{|Q|}\sum_{i=1}^{|Q|}\frac{1}{\text{rank}_i}$$

NDCG(Normalized Discounted Cumulative Gain):考虑排名位置——排第 1 的相关文档比排第 10 的更有价值。

$$\text{DCG} = \sum_{i=1}^{k}\frac{2^{\text{rel}_i}-1}{\log_2(i+1)}, \quad \text{NDCG} = \frac{\text{DCG}}{\text{IDCG}}$$

以上例计算:$DCG = \frac{2^1-1}{\log_2(2)} + \frac{2^0-1}{\log_2(3)} + \frac{2^1-1}{\log_2(4)} = 1 + 0 + 0.5 = 1.5$。理想排序(相关文档排前 2)的 $IDCG = 1 + 0.63 = 1.63$。$NDCG = 1.5/1.63 = 0.92$。 2. 生成质量(Generation Quality)

  • Faithfulness (忠实度):回答是否基于检索到的文档(没有编造)
  • Relevance (相关性):回答是否和问题相关
  • Correctness (正确性):回答是否正确
  • Completeness (完整性):回答是否完整
  1. 端到端质量(End-to-End)
    • Answer Correctness :最终回答是否正确
    • Answer Relevance :最终回答是否和问题相关

评估工具

  • RAGAS:最流行的 RAG 评估框架
    • 自动生成评估数据集
    • 计算 Faithfulness 、 Relevance 、 Context Precision 等指标
    • 代码示例:
from ragas import evaluate
result = evaluate(dataset, metrics=[faithfulness, answer_relevancy])

Agent 评估

Agent 评估比 RAG 更复杂,因为 Agent 涉及多步决策:

  1. 任务完成率: Agent 是否完成了用户交给它的任务?
  2. 工具调用准确率: Agent 是否选择了正确的工具?
  3. 参数正确率: Agent 传给工具的参数是否正确?
  4. 步骤效率: Agent 用了多少步完成任务?(越少越好)
  5. 错误恢复: Agent 遇到错误时能否自动修正?

评估方法:

  • 人工评估:找人来判断 Agent 的表现(金标准,但成本高)
  • 自动评估:用另一个 LLM 来评判 Agent 的表现(成本低,但可能不准)
  • 基准测试:用标准化的测试集来评估(可比较,但覆盖有限)

RAG 的三代演进与完整 Pipeline

一个生产级 RAG 系统经历了三代演进:

代际名称核心思路问题
第一代Naive RAG文档切分→向量检索→生成检索精度低、chunk 切分丢失上下文
第二代Advanced RAG在 Naive 基础上增加查询改写、混合检索、重排、自纠错流程固定,无法动态决策
第三代Agentic RAG用 Agent 动态决策:是否需要检索、检索什么、是否需要重试复杂度高、成本高

第二代 Advanced RAG 的完整 Pipeline:

flowchart TD
    subgraph "索引阶段(离线)"
        A["原始文档"] --> B["文档解析<br/>PDF/表格/扫描件"]
        B --> C["Chunk 切分"]
        C --> D["Embedding 编码"]
        D --> E["存入向量数据库 + BM25 索引"]
    end
    subgraph "查询阶段(在线)"
        F["用户查询"] --> G["查询改写<br/>Multi-Query / HyDE / Step-back"]
        G --> H["混合检索<br/>稠密 + 稀疏 → RRF 融合"]
        H --> I["Reranker 重排"]
        I --> J["LLM 生成"]
    end

第三代 Agentic RAG 将在第八篇补充章节中详细介绍。

Chunk 策略进阶

Chunk 是 RAG 效果的第一大决定因素。切得不好,即使检索"召回"了正确的文档,chunk 边界破坏了信息完整性,LLM 拿到残缺的上下文,自然回答不好。

Chunk 大小的影响

问题原因后果
Chunk 太大噪声多,向量表示被稀释LLM 被不相关信息误导,消耗更多 token
Chunk 太小缺乏上下文,信息不完整“张三在阿里"和"巴巴工作了10年"被切断
切得不好在语义中间切断即使检索命中,信息也是残缺的

方法 1:语义切分(Semantic Chunking)

在"语义发生变化"的地方切分,而非固定位置。步骤:将文档按句子切分→对每个句子做 Embedding→计算相邻句子的余弦相似度→相似度骤降的位置 = 切分点。

from langchain_experimental.text_splitter import SemanticChunker
from langchain_openai import OpenAIEmbeddings

chunker = SemanticChunker(
    OpenAIEmbeddings(),
    breakpoint_threshold_type="percentile",
    breakpoint_threshold_amount=95  # 相似度降到 5% 分位数以下就切
)
# document 为待切分的原始文本字符串
chunks = chunker.split_text(document)

方法 2:Parent-Child Chunking(生产环境最推荐)

解决了核心矛盾:检索需要小 chunk(向量表示精准),生成需要大 chunk(上下文完整)。

flowchart TD
    P["Parent Chunk(大块,如 2000 字)"]
    P --> C1["Child Chunk 1(小块,如 300 字)← 用于检索"]
    P --> C2["Child Chunk 2(小块,如 300 字)← 用于检索"]
    P --> C3["Child Chunk 3(小块,如 300 字)← 用于检索"]
    C1 --> R["检索命中 Child 1"]
    R --> Q["返回其 Parent Chunk"]
    Q --> L["Parent 送入 LLM"]

检索流程:用 Child Chunk 的向量做检索(小块→精准)→命中后返回其 Parent Chunk(大块→完整上下文)→Parent Chunk 送入 LLM。

方法 3:基于文档结构的切分

对于有明确结构的文档(Markdown、HTML、代码),按标题层级切分(######),保留元数据(标题路径、来源、页码)。

Chunk 大小选择经验

场景推荐 chunk 大小推荐 overlap
精确问答(FAQ)200-500 字50-100 字
知识库检索500-1000 字100-200 字
长文档分析1000-2000 字200-400 字
代码检索按函数/类切分不重叠

核心原则:先看数据→先做评估→用数据说话。

Embedding 模型选型

Embedding = 把文本映射到高维空间中的一个向量。核心性质:语义相似的文本→空间中距离近的向量。

Embedding 算法演进

代际代表方法核心思路局限
第一代Word2Vec / GloVe静态词向量,每个词只有一个固定向量无法处理多义词(“苹果”=水果还是公司?)
第二代Sentence-BERT用 BERT 编码句子,对比学习训练主要面向英文,中文效果一般
第三代BGE-M3 / E5 / GTE多语言、多任务、对比学习训练模型较大,推理成本高

Word2Vec 的两种训练方式

  • CBOW(Continuous Bag of Words):用上下文预测中心词。输入"我 _ 大模型”,预测空格是"爱"
  • Skip-gram:用中心词预测上下文。输入"爱",预测周围可能出现"我"、“大模型”

从词向量到句向量的演进:早期方法简单平均词向量(信息稀释)→BERT 用 [CLS] token 的输出作为句向量→现代方法用对比学习训练(正样本对拉近,负样本对推远),直接优化句向量的语义区分度。

Bi-Encoder 架构(几乎所有 Embedding 模型都是):查询和文档分别独立编码,查询时只需编码查询 + 向量检索。优点是文档向量可以预计算存储,缺点是查询和文档独立编码,缺乏交互信息(Reranker 补这个短板)。

主流 Embedding 模型对比(2026):

模型维度中文英文适用场景
BGE-M3(BAAI)1024优秀良好中文首选,支持混合检索
GTE-Qwen2(阿里)1024优秀良好中文优秀,可微调
E5-Mistral(微软)4096一般优秀英文最佳之一
Voyage-3(Voyage)1024一般优秀代码检索特别好
text-embedding-3(OpenAI)3072良好优秀快速原型,支持维度缩减

Matryoshka Embedding(俄罗斯套娃 Embedding):训练时让前 $d$ 个维度也能独立工作,同一模型支持 256/512/1024/3072 等多种维度。数值示例:存储 1 亿向量×3072 维×float32 = 1.2 TB;存储 1 亿向量×256 维×float32 = 100 GB——12 倍的存储差异。

何时需要微调 Embedding:用户用行业术语查询(如"PD"在医学中是帕金森,在金融中是产品设计)、检索召回率始终低于预期、领域词汇的语义和通用含义差异大。

查询改写进阶

HyDE(Hypothetical Document Embeddings):先让 LLM"幻想"一个回答,用这个回答去检索。

flowchart LR
    Q["用户问:什么是 LoRA?"] --> LLM["LLM 生成假设回答<br/>(可能不完全准确)"]
    LLM --> V["用假设回答做向量检索"]
    V --> D["检索到的真实文档片段"]
    D --> G["LLM 基于真实文档生成最终回答"]

为什么有效?假设回答的向量表示更接近知识库中的文档向量,比短问题的向量表示更丰富。

Step-back Prompting:从具体问题退后到通用问题。例如原始查询"LLaMA 3.1 70B 用 LoRA 微调时 rank 设多少?"→退后为"LoRA 微调中 rank 参数的选择策略是什么?"→通用查询能检索到更全面的文档。

Reranker 重排模型

向量检索是"双编码器"架构(查询和文档分别编码,只做点积),快但不够精确。Reranker 是"交叉编码器"架构(将查询和文档拼接在一起送入模型),更精确但更慢。

维度Bi-Encoder(Embedding 检索)Cross-Encoder(Reranker)
架构查询和文档独立编码查询和文档拼接编码
速度快(可预计算)慢(每次都要重新计算)
精度较低较高
适用全库检索(百万级)精排(top-50→top-5)

工作流程:向量检索 top-50→Reranker 重排→取 top-5→送入 LLM。

RRF(Reciprocal Rank Fusion)融合公式:

$$ \text{RRF\_score}(d) = \sum_{i=1}^{n} \frac{1}{k + \text{rank}_i(d)} $$

其中 $k$ 是常数(通常 = 60),$\text{rank}_i(d)$ 是文档 $d$ 在第 $i$ 个检索器中的排名。

手算示例:假设 3 个检索器对 5 个文档的排名如下:

文档稠密检索排名BM25 排名Reranker 排名
文档 A132
文档 B211
文档 C324
文档 D453
文档 E545

取 $k=60$,RRF 计算:

  • 文档 A:$\frac{1}{61} + \frac{1}{63} + \frac{1}{62} = 0.01639 + 0.01587 + 0.01613 = 0.04839$
  • 文档 B:$\frac{1}{62} + \frac{1}{61} + \frac{1}{61} = 0.01613 + 0.01639 + 0.01639 = 0.04891$

文档 B 的 RRF 分数更高(在多个检索器中排名都靠前),最终排序 B>A。

代码示例

from FlagEmbedding import FlagReranker

reranker = FlagReranker('BAAI/bge-reranker-v2-m3', use_fp16=True)
pairs = [
    ["什么是 LoRA 微调?", "LoRA 是一种参数高效微调方法..."],
    ["什么是 LoRA 微调?", "今天天气很好适合出去玩..."],
]
scores = reranker.compute_score(pairs)
# scores: [0.95, 0.02]  → 第一个文档相关性远高于第二个

Self-RAG 与 Corrective RAG

传统 RAG 不管检索到的文档是否相关,都盲目地塞进 prompt。Self-RAG 让模型自己决定什么时候检索、检索结果是否有用。

Self-RAG 的反思 token 机制

  1. 模型生成一段文字
  2. 判断:需要检索吗?→ [Retrieve] / [No Retrieve]
  3. 如果需要检索→执行检索
  4. 判断:检索结果是否相关?→ [Relevant] / [Irrelevant]
  5. 判断:生成的回答是否被检索结果支持?→ [Supported] / [Not Supported]
  6. 如果不支持→重新生成

Corrective RAG 的思路:检索后加一层"纠错"。相关性高→直接用;相关性低→用 LLM 对文档做知识提炼,去掉不相关部分,或回退到网络搜索获取更相关的信息。

文档解析

实际项目中,RAG 最痛的不是检索不准,而是文档解析不好。

难点说明
扫描版 PDF图片,没有文字层
包含表格的 PDF行列对应关系容易乱
包含公式的学术论文公式无法直接提取
多列排版的文档顺序容易错乱

解析方案分级

级别方案适用场景
基础PyPDF / pdfplumber简单纯文字 PDF
中级Unstructured.io企业文档、混合格式
高级多模态大模型(GPT-4V、Qwen-VL)复杂布局、扫描件
表格Camelot / Tabula / 多模态 LLMPDF 表格提取

模块小结: Advanced RAG 工程实践

你学到了什么为什么重要
查询改写与扩展提升检索精准度
生成优化策略提升回答质量
RAG 评估体系衡量系统效果
Agent 评估评估智能体表现
RAG 三代演进理解从 Naive 到 Agentic 的演进路径
Chunk 策略进阶RAG 效果的第一大决定因素
Embedding 选型选择合适的向量化模型
Reranker 重排两阶段检索提升精度
Self-RAG让模型自判断检索质量
文档解析生产环境最痛的环节

RAG 实际落地最难的地方

  1. 文档解析:扫描件 PDF、复杂表格、多列排版、公式等,解析质量直接决定 RAG 效果(详见上文)
  2. 评估标准:没有统一的"好"标准——Faithfulness 高不代表用户满意,需要结合人工评估
  3. 长尾 case:80% 的查询效果很好,但 20% 的长尾查询(如跨文档推理、否定查询、多条件筛选)效果很差
  4. 知识时效性:文档更新后,旧的向量还在数据库中,新旧信息冲突
  5. 成本控制:Embedding 编码 + 向量检索 + Reranker + LLM 生成,每一步都有成本,大规模系统需要精细优化

Lost in the Middle

当上下文很长时,LLM 倾向于关注开头和结尾的信息,忽略中间的内容。这就是"Lost in the Middle"现象。

影响:如果相关的文档 chunk 恰好被放在上下文的中间位置,LLM 可能"看不到"它,导致回答质量下降。

缓解策略

  1. 重排(Rerank):将最相关的 chunk 放在上下文的最前面
  2. 减少上下文长度:只放最相关的 Top-K 个 chunk,减少中间噪声
  3. 分段处理:将长上下文分成多段,分别处理后合并结果
  4. 选择对 Lost in the Middle 鲁棒的模型:部分模型(如 Claude)对此问题的抵抗力更强

推荐补充资源

知识点推荐资源说明
LLaMAMeta LLaMA 论文原始论文
提示词工程OpenAI Prompt Engineering Guide官方指南
LangChainLangChain 官方文档最权威的参考
RAGLangChain RAG 教程实战教程
向量数据库Milvus 官方文档生产级向量数据库
GraphRAGMicrosoft GraphRAG 仓库官方实现
RAG 优化Lilian Weng《Prompt Engineering》Prompt 工程综述
Self-RAGSelf-RAG 论文(ICLR 2024)反思 token 机制
Corrective RAGCorrective RAG 论文检索后纠错
HyDEHyDE 论文假设文档嵌入
RerankerBGE Reranker开源重排模型
文档解析Unstructured.io多格式文档解析
RAG 综述RAG 综述论文全面了解 RAG 发展

下一篇预告:本文深入掌握了 RAG 检索增强生成。在速通 AI(八):Agent 开发与生产部署中,你将学习如何定制模型(PEFT 微调、量化)并构建能自主决策的智能体(Function Calling、MCP、LangGraph)。