Skip to content

RAG架构与实现

一、RAG基础

Q1: 什么是RAG?为什么需要RAG?

RAG(Retrieval-Augmented Generation,检索增强生成) = 信息检索 + 大语言模型生成。让LLM在生成回答前先检索相关文档,基于文档内容生成答案。

为什么需要RAG?

LLM的三大痛点                     RAG的解决方案

1. 知识陈旧(训练数据有时效) → 接入实时知识库,动态更新
2. 幻觉问题(编造不存在事实) → 答案基于真实文档,可溯源
3. 私有知识(企业内部文档) → 连接企业文档,无需微调模型

Q2: RAG vs 微调(Fine-tuning)对比

维度RAG微调
核心思想外接知识库 → 让模型"查资料"注入知识 → 让模型"记住"
知识更新新增文档即可,无需重新训练需要重新训练/微调
事实准确性高(有文档来源支持)中(易产生幻觉)
可解释性强(可以展示引用来源)弱(无法解释知识来源)
部署成本低(仅需向量数据库)中高(需要训练GPU资源)
推理延迟中(多了检索步骤)低(标准推理)
风格/语气适配

结论: 对于基于文档的问答、知识检索等场景,RAG是首选;对于需要特定风格/语气的生成任务(如客服话术),微调更合适。实际项目中常两者结合使用。

Q3: RAG系统的核心流程

┌──────────────────────────────────────────────────────────────┐
│                       RAG 完整流程                             │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│  ═══════════ 离线数据处理 ═══════════                       │
│                                                              │
│  原始文档(PDF/Word/网页)                                     │
│       ↓ ① 文档解析                                           │
│  文本+元数据                                                 │
│       ↓ ② 文本切分(Chunking)                               │
│  Chunk 1 / Chunk 2 / Chunk 3 ...                            │
│       ↓ ③ 向量化(Embedding)                               │
│  向量1 / 向量2 / 向量3 ...                                   │
│       ↓ ④ 存储                                               │
│  向量数据库(Milvus / Chroma / Pinecone)                   │
│                                                              │
│  ═══════════ 在线推理阶段 ═══════════                       │
│                                                              │
│  用户问题                                                     │
│       ↓ ⑤ 问题向量化                                         │
│  查询向量                                                    │
│       ↓ ⑥ 相似度搜索(ANN索引)                              │
│  Top-K 相似文档                                              │
│       ↓ ⑦ 构建增强Prompt                                     │
│  [上下文] + [用户问题]                                        │
│       ↓ ⑧ LLM生成                                             │
│  答案 + 引用来源                                             │
│                                                              │
└──────────────────────────────────────────────────────────────┘

二、文档处理与切分

Q4: 文档切分(Chunking)的常用策略

策略说明优点缺点
固定长度切分按字符数/token数切分简单高效可能切断语义完整的句子
按段落切分以换行符/段落分隔切分语义完整段落长短差异大
递归切分先按大分隔符切分,不够再按小分隔符兼顾结构与长度需要调参
语义切分基于Embedding相似度,在语义转折处切分语义最完整计算开销大
Agent切分用LLM理解文档结构智能切分最智能成本高、速度慢

推荐实践: LangChain的 RecursiveCharacterTextSplitter

python
from langchain.text_splitter import RecursiveCharacterTextSplitter

text_splitter = RecursiveCharacterTextSplitter(
    separators=["\n\n", "\n", "。", "!", "?", ";", ",", " "],
    chunk_size=500,        # 目标chunk大小(字符/token)
    chunk_overlap=50,      # 重叠部分,保证上下文连续
    length_function=len,
)

chunks = text_splitter.split_text(long_text)

Q5: Chunk Size大小的选择

Chunk Size适用场景优缺点
小(100-200 tokens)关键词检索、事实问答检索精准但上下文不足
中(300-500 tokens)通用问答平衡精度与上下文
大(800-1000 tokens)需要完整上下文理解的任务上下文完整但噪声多

经验建议:

  • 先从500 token起步(约300-400中文字符)
  • 同时设置 50-100 token 的重叠
  • 根据实际效果微调:召回不够就增大chunk,噪声太多就减小chunk

Q6: 如何处理PDF/Word/HTML等格式文档?

文档格式处理策略:

1. PDF文档
   ├── PyPDF2 / pdfplumber: 提取文本
   ├── pdf2image + OCR: 扫描版PDF
   └── 保留表格: Camelot / Tabula-py

2. Word文档 (.docx)
   ├── python-docx: 提取段落、表格
   └── 保留格式信息(标题层级、加粗等)

3. HTML/网页
   ├── BeautifulSoup: 解析HTML
   ├── newspaper3k / Goose: 提取文章主体
   └── 去噪: 删除导航栏、广告、页脚

4. Markdown
   ├── 原生支持(已是结构化文本)
   └── 按标题层级切分效果最好

三、向量数据库与相似度搜索

Q7: 主流向量数据库对比

数据库类型特点适用场景
Milvus自建服务功能全面、性能强、支持分布式生产环境、大规模
Chroma本地/服务轻量级、LangChain友好、易部署原型开发、中小规模
PineconeSaaS云服务零运维、托管服务、弹性扩展快速上线、不想运维
Weaviate自建服务向量+传统字段混合查询需要丰富元数据
FAISS库(非DB)Facebook开源,仅向量索引本地研究、集成到自建系统

Q8: 相似度计算方法

1. 余弦相似度(Cosine Similarity) ⭐ 最常用
   cos(θ) = A · B / (|A| × |B|)
   范围: [-1, 1],越大越相似
   优点: 不随向量长度变化,对文本任务效果好

2. 欧式距离(L2 Distance)
   d = √(Σ(Ai - Bi)²)
   范围: [0, ∞),越小越相似
   适用: 图像等需要空间距离的场景

3. 点积(Inner Product / Dot Product)
   A · B = Σ(Ai × Bi)
   范围: 取决于向量长度
   优点: 计算快(如向量已归一化,等效于余弦)

实际选择:

  • 文本Embedding → 余弦相似度(或归一化后的点积)
  • 图像/特征向量 → L2距离
  • Milvus等支持自定义metric_type

Q9: 为什么需要ANN(近似最近邻)索引?

暴力搜索(Flat Index)计算量 = N × d(样本数 × 维度) 当N=1亿时,每次搜索要做1亿次向量乘法,太慢!

ANN索引方案对比:

索引原理召回率内存构建时间
HNSW多层小世界图
IVF倒排聚类+残差
IVF-PQIVF+乘积量化极低
DiskANN磁盘友好索引中高极低

生产推荐:HNSW(召回率高、搜索速度快,Milvus/FAISS都支持)


四、检索优化(RAG的关键瓶颈)

Q10: 基础检索为什么不够好?

核心问题:

  1. 语义漂移: "苹果"(公司) vs "苹果"(水果)
  2. 长尾词: 专业术语、缩写、代号
  3. 长文档: 信息分散在多个chunk
  4. 查询与文档不一致: 查询是"为什么",文档是"是什么"

Q11: 常用检索优化技术

技术1: 混合检索(Hybrid Search)——关键词+向量

      语义检索(向量)             关键词检索(BM25)
           ↓                           ↓
   "如何配置Nginx负载均衡"         "Nginx 负载均衡 配置"
           ↓                           ↓
   返回语义相关的Top-K             返回关键词匹配的Top-K
           ↓                           ↓
   ┌───────────融合(RRF/加权)───────────┐
   │ 最终排序 = α × 向量分数 + (1-α) × BM25分数 │
   └─────────────────────────────────────────┘

技术2: HyDE(Hypothetical Document Embedding)

先用LLM生成一个"假设性答案",再用这个假设答案去检索,而不是直接用用户问题。

用户问题: "公司年假制度是怎样的?"

LLM生成假设答案(不需要真实准确,只要风格对):
   "公司年假一般根据入职年限计算,新员工有5天,满1年后...
    公司制度规定,年假需要提前申请..."

用这个"假设答案"去检索(比问题更接近文档风格)

返回真实的年假制度文档

技术3: 重排序(Re-ranking / Cross-Encoder)

第一阶段(粗召回): 向量搜索 → 返回Top-100候选(快但不精)

第二阶段(精排): Cross-Encoder模型 → 对每个[查询, 文档]对打分

最终返回: Top-5相关文档(慢但精准)

常用模型:
- BGE-Reranker (中文效果好)
- Cross-Encoder/MS-Marco

技术4: 查询改写(Query Rewriting)

用户原始问题: "XX产品的退货流程?"

LLM改写(加入同义词、补充领域术语):
   "XX产品退货政策 退款流程 售后服务 7天无理由..."

用改写后的查询做检索(召回率更高)

Q12: RAG优化技术栈一览

┌────────────────────────────────────────────────────────────┐
│                    RAG 优化技术层级                          │
├────────────────────────────────────────────────────────────┤
│                                                            │
│  Level 1 - 基础RAG                                         │
│    纯向量搜索 + Top-K                                     │
│                                                            │
│  Level 2 - 高级检索                                        │
│    混合检索(向量+关键词)                                 │
│    查询改写 + HyDE                                        │
│    元数据过滤                                             │
│                                                            │
│  Level 3 - 精排                                            │
│    Cross-Encoder重排序                                    │
│    RRF/加权融合                                           │
│    LLM-as-a-Judge 打分                                     │
│                                                            │
│  Level 4 - 高级上下文管理                                  │
│    上下文压缩(Contextual Compression)                    │
│    句子级精确定位                                          │
│    多跳检索(先查文档A,再根据A查文档B)                    │
│                                                            │
│  Level 5 - 集成Agent                                      │
│    检索-推理-再检索的循环                                  │
│    文档理解与推理结合                                       │
│                                                            │
└────────────────────────────────────────────────────────────┘

五、Prompt与上下文管理

Q13: RAG中的Prompt设计要点

┌────────────────────────────────────────────────────────┐
│            RAG 增强 Prompt 模板                          │
├────────────────────────────────────────────────────────┤
│                                                        │
│  # 角色                                                │
│  你是基于知识库的问答助手                               │
│                                                        │
│  # 核心规则(⚠️ 最重要)                                │
│  - 仅基于参考资料回答,不要使用自身知识                 │
│  - 如果参考资料中没有答案,请明确说明"参考资料未包含该信息"│
│  - 回答中的关键信息必须引用来源编号                     │
│  - 如果多个来源有冲突,指出差异                         │
│                                                        │
│  # 参考资料                                            │
│  [1] [文档标题A] ...[文档内容]...                      │
│  [2] [文档标题B] ...[文档内容]...                      │
│  [3] [文档标题C] ...[文档内容]...                      │
│                                                        │
│  # 用户问题                                            │
│  {question}                                            │
│                                                        │
│  # 输出要求                                            │
│  - 答案控制在200字以内                                 │
│  - 关键信息标注来源编号,如"根据[1][2]..."              │
│  - 用自己的话复述,不要直接复制粘贴                     │
│                                                        │
└────────────────────────────────────────────────────────┘

Q14: 上下文过长怎么办?(Context Window问题)

策略1: 上下文压缩(Contextual Compression)

Top-K文档(可能很长)

LLM/Extractor → 提取每个文档中与问题最相关的句子

压缩后的上下文(只保留最相关片段,大幅减少token)

策略2: Map-Reduce模式

Step 1 (Map): 每个文档单独问LLM "这份文档是否回答了问题?如果有,请提取答案"

Step 2 (Reduce): 收集所有文档的答案,让LLM合并为最终答案

策略3: 分块总结(Refine)

第一个文档 → 生成初始答案

第二个文档 → 让LLM "根据新文档,是否需要更新答案?"

第三个文档 → 继续更新

...最终答案

Q15: 如何处理"检索到的文档都不相关"的情况?

防御性设计:

python
# 1. 设置相似度阈值
results = vector_store.similarity_search_with_score(query, k=5)
mean_score = sum(score for _, score in results) / len(results)

if mean_score < THRESHOLD:  # 例如:相似度 < 0.7
    return "抱歉,知识库中暂无相关信息,请换个说法或联系客服"

# 2. LLM判断
prompt = """
以下是检索到的文档,请问这些文档是否能回答用户的问题?
如果能,请输出答案;如果不能,请输出"无相关信息"

问题:{query}

参考文档:
{context}
"""

六、评估方法

Q16: 如何评估RAG系统的质量?

┌────────────────────────────────────────────────────────────┐
│                  RAG 评估指标体系                           │
├────────────────────────────────────────────────────────────┤
│                                                            │
│  🔍 检索质量(Retrieval Quality)                          │
│    · Precision@K: Top-K中有多少是真的相关的               │
│    · Recall@K: 相关文档有多少被检索到了                    │
│    · NDCG@K: 考虑排序位置的加权指标                        │
│                                                            │
│  ✍️ 回答质量(Generation Quality)                         │
│    · Faithfulness(忠实度): 回答是否都在上下文里          │
│    · Answer Relevance: 回答是否针对问题                   │
│    · 人工评测(Human Evaluation)                         │
│    · LLM-as-a-Judge: 用更强的LLM评测答案质量              │
│                                                            │
│  ⚡ 性能指标                                               │
│    · 端到端延迟(检索+生成)                               │
│    · Token消耗/成本                                       │
│    · 吞吐量(QPS)                                         │
│                                                            │
└────────────────────────────────────────────────────────────┘

Q17: 构建RAG评测数据集

三步构建法:

Step 1: 从文档中人工设计问题
   文档A第3段 → 问题:"XX产品的保修期是多久?"
   答案:"1年"
   (保证答案确实在文档中)

Step 2: 补充边缘情况
   · 多文档交叉引用的问题
   · 文档中没有答案的问题(测试"不知道"能力)
   · 需要综合多篇文档的问题

Step 3: 标注黄金答案
   由人工/专家写出高质量参考答案

七、生产环境部署要点

Q18: RAG系统的常见问题与解决方案

问题原因解决方案
答案不准确/幻觉检索到的文档不相关,或模型忽视上下文增加检索条数、提高Prompt约束、加入忠实度检查
检索太慢向量库数据量大,索引不当合理设置索引参数、设置分区、增加缓存层
上下文太长检索到的内容太多上下文压缩、Chunk大小调整
元数据缺失切分时信息丢失每个Chunk保留标题、来源、页码等元数据
中英文混合Embedding对中文效果差使用BGE/Zhina-Embedding等中文优化模型
表格数据检索差表格内容切分后结构丢失单独处理表格:转成结构化文本/JSON

Q19: RAG系统监控要点

┌────────────────────────────────────────────────────────┐
│              RAG 生产环境监控项                          │
├────────────────────────────────────────────────────────┤
│                                                        │
│  🔌 基础设施                                           │
│    · 向量数据库QPS / 延迟 / 内存                       │
│    · Embedding服务可用性                               │
│    · LLM API调用成功率                                 │
│                                                        │
│  📈 业务指标                                           │
│    · 用户满意度评分                                    │
│    · "无相关信息"的比例(监控检索质量)                 │
│    · 用户追问率(是否需要追问才能得到答案)             │
│                                                        │
│  📝 日志与可观测                                       │
│    · Query → 检索到的文档 → 最终答案 完整链路日志      │
│    · 负面反馈收集(用户点击"不准确"时记录)             │
│    · A/B测试框架(测试不同检索/Prompt策略)             │
│                                                        │
│  💾 成本监控                                           │
│    · 每次查询的Embedding+LLM token总成本               │
│    · 向量数据库存储成本                                │
│                                                        │
└────────────────────────────────────────────────────────┘

RAG高频问题速查

问题一句话解决方案
检索不准换更强的Embedding模型、增加混合检索、重排序
答案不来自文档加强Prompt约束、加入"不知道"出口、用LLM审查答案
无法回答多跳问题引入Agent模式,让LLM自主检索-推理-再检索
上下文太长上下文压缩、Map-Reduce模式、Refine模式
PDF表格处理差用专门的表格解析工具、转成结构化格式
代码检索效果差代码用AST-based切分、保留完整函数结构
成本高用本地部署的小模型做Embedding、设置缓存

Released under the MIT License.