一篇帮助你理解向量数据库、RAG技术及两者关系的入门教程


📖 目录

  1. 引言:AI时代的新型数据存储
  2. 什么是向量数据库
  3. 什么是RAG技术
  4. 向量数据库与RAG的关系
  5. 实战示例
  6. 最佳实践
  7. 总结

1. 引言:AI时代的新型数据存储

在人工智能快速发展的今天,我们面临着两个核心挑战:

挑战1:如何让机器"理解"数据的语义?

传统数据库使用精确匹配来查询数据。例如,搜索"苹果"只能找到包含"苹果"这个词的记录,而无法找到"iPhone"或"水果"等语义相关的内容。

挑战2:如何让大语言模型获得最新、最准确的知识?

大语言模型(LLM)虽然强大,但存在两个问题:

  • 知识截止日期:模型的训练数据有时间限制,无法了解最新信息
  • 幻觉问题:模型可能生成看似合理但实际错误的内容

向量数据库RAG技术正是为解决这些问题而生的。它们让机器能够理解语义、检索相关信息,并基于真实数据生成准确的回答。


2. 什么是向量数据库

2.1 核心概念

向量数据库(Vector Database)是一种专门存储和检索高维向量数据的数据库系统。

什么是"向量"?

在计算机中,向量是一组数字的序列。例如:

文本 "机器学习" → 向量 [0.23, -0.45, 0.78, ..., 0.12]  (假设384维)
图片 "猫"     → 向量 [0.89, 0.34, -0.12, ..., 0.56]  (假设512维)

这个转换过程叫做向量化嵌入(Embedding)。神奇之处在于:语义相近的内容,其向量在空间中的距离也更近

示例:文本向量化
# 伪代码示例
embedding_model = load_model("sentence-transformer")

text1 = "我喜欢吃苹果"
text2 = "我爱吃水果"
text3 = "今天天气很好"

vector1 = embedding_model.encode(text1)  # → [0.2, 0.8, -0.3, ...]
vector2 = embedding_model.encode(text2)  # → [0.3, 0.7, -0.2, ...]  (与vector1接近)
vector3 = embedding_model.encode(text3)  # → [-0.5, 0.1, 0.9, ...]  (与vector1/2距离远)

# 计算相似度
similarity(vector1, vector2)  # → 0.85 (高相似度)
similarity(vector1, vector3)  # → 0.23 (低相似度)

2.2 向量数据库的工作原理

graph LR
    A[原始数据<br/>文本/图片/音频] --> B[向量化模型<br/>Embedding Model]
    B --> C[高维向量<br/>[0.2, 0.8, -0.3, ...]]
    C --> D[向量数据库<br/>Vector Database]
    
    E[查询请求] --> F[向量化]
    F --> G[相似度搜索]
    D --> G
    G --> H[返回最相似的<br/>Top-K结果]
    
    style D fill:#e1f5ff
    style G fill:#fff4e1

核心步骤

  1. 索引构建:将数据转换为向量并存储
  2. 相似度检索:查询时计算向量间的距离或相似度
  3. 返回结果:返回最接近的Top-K个结果

2.3 向量相似度计算方法

向量数据库使用多种方法计算相似度:

1️⃣ 余弦相似度(Cosine Similarity)

衡量两个向量方向的接近程度,值域在-1到1之间。

公式:cos(θ) = (A · B) / (||A|| × ||B||)

示例:
向量A = [1, 2, 3]
向量B = [2, 4, 6]
余弦相似度 = 1.0  (方向完全相同)

向量C = [-1, -2, -3]
余弦相似度 = -1.0 (方向完全相反)
2️⃣ 欧氏距离(Euclidean Distance)

计算向量在空间中的直线距离。

公式:d = √[(A₁-B₁)² + (A₂-B₂)² + ... + (Aₙ-Bₙ)²]

示例:
向量A = [1, 2]
向量B = [4, 6]
欧氏距离 = √[(1-4)² + (2-6)²] = √(9 + 16) = 5
3️⃣ 点积(Dot Product)

简单快速,适合已归一化的向量。

公式:A · B = A₁×B₁ + A₂×B₂ + ... + Aₙ×Bₙ

2.4 向量数据库 vs 传统数据库

特性 传统关系型数据库 向量数据库
数据类型 结构化数据(表格) 高维向量(数组)
查询方式 精确匹配(WHERE id=123) 相似度搜索(找最接近的)
索引结构 B树、哈希 ANN索引(如HNSW、IVF)
应用场景 事务处理、数据管理 语义搜索、推荐系统
查询示例 "找出价格=100的商品" "找出与'手机'语义最接近的商品"
性能优化 索引、分区 量化、近似搜索

2.5 常见的向量数据库

mindmap
  root((向量数据库))
    开源方案
      FAISS
        Facebook开发
        高性能
        多种索引类型
      Milvus
        专为AI设计
        分布式架构
        云原生
      ChromaDB
        轻量级
        易于集成
        适合小规模
    商业方案
      Pinecone
        全托管
        自动扩展
      Weaviate
        GraphQL接口
        混合搜索
    数据库插件
      PostgreSQL + pgvector
        扩展向量能力
      Elasticsearch + Dense Vector
        结合全文检索
特点对比
数据库 特点 适用场景
FAISS 性能极高,仅支持内存 科研、原型开发
Milvus 企业级、分布式、持久化 生产环境、大规模应用
ChromaDB 简单易用、嵌入式 小项目、快速开发
Pinecone 全托管、免运维 快速上线、SaaS应用
pgvector 基于PostgreSQL、成熟稳定 已有PG基础设施的团队

2.6 向量数据库的应用场景

  1. 语义搜索:搜索引擎、文档检索、问答系统
  2. 推荐系统:内容推荐、商品推荐、音乐推荐
  3. 图像搜索:以图搜图、人脸识别、相似图片查找
  4. 异常检测:欺诈检测、网络安全、质量监控
  5. 知识图谱:实体关系、知识推理
  6. RAG系统:为大语言模型提供外部知识

3. 什么是RAG技术

3.1 RAG的定义

RAG(Retrieval-Augmented Generation,检索增强生成)是一种结合信息检索文本生成的AI技术。

graph TB
    A[用户提问] --> B[检索阶段<br/>Retrieval]
    B --> C[知识库/文档库]
    C --> D[检索相关文档]
    D --> E[增强阶段<br/>Augmentation]
    E --> F[构建Prompt:<br/>问题 + 检索内容]
    F --> G[生成阶段<br/>Generation]
    G --> H[大语言模型<br/>LLM]
    H --> I[生成答案]
    
    style B fill:#e1f5ff
    style E fill:#fff4e1
    style G fill:#ffe1e1

3.2 为什么需要RAG?

大语言模型的局限性

尽管GPT-4、Claude等大模型能力惊人,但它们有明显的短板:

问题 具体表现 示例
知识截止 训练数据有时间限制 无法回答2024年最新发生的事件
领域知识缺失 通用模型缺少专业深度 企业内部文档、私有知识
幻觉问题 编造不存在的信息 虚构论文引用、错误的数据
无法溯源 不知道答案来自哪里 无法验证信息的准确性
成本高昂 重新训练模型代价大 每次更新知识都要重新训练
RAG的解决方案

RAG通过检索真实文档来增强模型的生成能力:

❌ 传统LLM方式:
用户:"2024年公司Q3销售额是多少?"
模型:[凭记忆回答,可能编造数据]

✅ RAG方式:
用户:"2024年公司Q3销售额是多少?"
系统:[检索公司财报文档]
      → 找到:Q3销售额为2.3亿元
      → 将文档内容提供给模型
模型:"根据2024年Q3财报,公司销售额为2.3亿元。"

3.3 RAG的工作流程

RAG包含两个阶段:离线索引构建 和 在线查询应答

阶段1:离线索引构建
graph TD
    A[原始文档集合] --> B[文档加载]
    B --> C[文本分块<br/>Chunking]
    C --> D[向量化<br/>Embedding]
    D --> E[存入向量数据库]
    
    C --> C1[文档1: 第1块<br/>文档1: 第2块<br/>...]
    D --> D1[向量1: [0.2, 0.8, ...]<br/>向量2: [0.3, 0.7, ...]<br/>...]
    
    style E fill:#e1f5ff

详细步骤

  1. 文档加载:读取PDF、Word、Markdown等格式文档
  2. 文本分块:将长文档切分成小块(如500字/块)
    • 为什么要分块?因为模型有输入长度限制,且小块检索更精确
  3. 向量化:将每个文本块转换为向量
  4. 存储:向量+原文本一起存入向量数据库

示例代码片段

from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.embeddings import HuggingFaceEmbeddings
from langchain.vectorstores import FAISS

# 1. 加载文档
documents = [
    "向量数据库是一种专门存储高维向量的数据库...",
    "RAG技术结合了信息检索和文本生成...",
    # 更多文档...
]

# 2. 文本分块
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=500,      # 每块500字符
    chunk_overlap=50     # 相邻块重叠50字符
)
chunks = text_splitter.create_documents(documents)

# 3. 向量化并存储
embeddings = HuggingFaceEmbeddings(
    model_name="sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2"
)
vectorstore = FAISS.from_documents(chunks, embeddings)

# 4. 保存索引
vectorstore.save_local("./faiss_index")
阶段2:在线查询应答
sequenceDiagram
    participant User as 用户
    participant RAG as RAG系统
    participant VDB as 向量数据库
    participant LLM as 大语言模型
    
    User->>RAG: 提出问题
    RAG->>RAG: 问题向量化
    RAG->>VDB: 检索相似文档
    VDB-->>RAG: 返回Top-K相关文档
    RAG->>RAG: 构建增强Prompt
    RAG->>LLM: 发送Prompt
    LLM-->>RAG: 生成答案
    RAG-->>User: 返回答案+来源

详细步骤

  1. 问题向量化:将用户问题转换为向量
  2. 相似度检索:在向量数据库中找到最相关的Top-K个文档块
  3. Prompt构建:将问题和检索到的文档组合成提示词
  4. LLM生成:大语言模型基于检索内容生成答案
  5. 返回结果:回答+引用来源

示例代码片段

from langchain.chains import RetrievalQA
from langchain.llms import OpenAI

# 1. 加载向量数据库
vectorstore = FAISS.load_local("./faiss_index", embeddings)

# 2. 创建检索器
retriever = vectorstore.as_retriever(
    search_type="similarity",
    search_kwargs={"k": 3}  # 返回最相关的3个文档
)

# 3. 创建RAG链
qa_chain = RetrievalQA.from_chain_type(
    llm=OpenAI(temperature=0),
    chain_type="stuff",  # 将所有检索文档一次性传给LLM
    retriever=retriever,
    return_source_documents=True  # 返回来源文档
)

# 4. 提问
question = "什么是向量数据库?"
result = qa_chain({"query": question})

print(f"答案:{result['result']}")
print(f"来源:{result['source_documents']}")

3.4 RAG的核心组件

graph TB
    subgraph "RAG系统架构"
        A[文档加载器<br/>Document Loaders] --> B[文本分割器<br/>Text Splitters]
        B --> C[向量化模型<br/>Embedding Models]
        C --> D[向量存储<br/>Vector Stores]
        
        E[用户查询] --> F[检索器<br/>Retriever]
        D --> F
        F --> G[Prompt模板<br/>Prompt Templates]
        G --> H[语言模型<br/>LLMs]
        H --> I[输出解析器<br/>Output Parsers]
        I --> J[最终答案]
    end
    
    style D fill:#e1f5ff
    style H fill:#ffe1e1

3.5 RAG的类型

1️⃣ Naive RAG(朴素RAG)

最基础的RAG实现:

检索 → 增强 → 生成

优点:简单直接,易于实现
缺点:检索质量可能不佳,上下文可能不完整

2️⃣ Advanced RAG(高级RAG)

加入预处理和后处理:

查询重写 → 检索 → 文档重排序 → 生成 → 答案验证

改进点

  • 查询扩展:将简单问题扩展为多个相关查询
  • 重排序:对检索结果进行二次排序
  • 答案验证:检查生成内容是否与检索文档一致
3️⃣ Modular RAG(模块化RAG)

灵活组合各种组件:

graph LR
    A[查询] --> B{路由器}
    B -->|文档查询| C[向量检索]
    B -->|结构化查询| D[SQL查询]
    B -->|简单问答| E[直接生成]
    
    C --> F[融合结果]
    D --> F
    E --> F
    F --> G[生成答案]

特点

  • 支持多种数据源
  • 可插拔的组件
  • 根据查询类型选择策略

3.6 RAG vs 其他方法

方法 优点 缺点 适用场景
直接使用LLM 简单快速 知识过时、易产生幻觉 通用对话
微调(Fine-tuning) 深度定制、性能好 成本高、更新困难 专业领域模型
RAG 知识实时更新、可溯源 系统复杂、依赖检索质量 问答系统、知识库
混合方法 结合各方法优势 开发维护成本最高 企业级应用

4. 向量数据库与RAG的关系

4.1 向量数据库是RAG的"大脑记忆"

如果把RAG系统比作一个人:

🧠 向量数据库 = 长期记忆(知识库)
🔍 检索系统   = 回忆能力(从记忆中找相关信息)
💬 大语言模型 = 表达能力(组织语言回答问题)

没有向量数据库的RAG

  • 无法存储大量知识
  • 无法快速找到相关信息
  • 检索效率低下

有向量数据库的RAG

  • 高效存储百万级文档向量
  • 毫秒级检索相关内容
  • 支持实时更新知识

4.2 完整的技术栈关系

graph TB
    subgraph "数据层"
        A1[原始文档<br/>PDF/Word/网页]
        A2[结构化数据<br/>数据库/API]
    end
    
    subgraph "向量化层"
        B[Embedding模型<br/>Sentence-BERT<br/>OpenAI Embeddings]
    end
    
    subgraph "存储层"
        C[向量数据库<br/>FAISS/Milvus<br/>Pinecone]
    end
    
    subgraph "检索层"
        D[检索器<br/>Similarity Search<br/>Hybrid Search]
    end
    
    subgraph "生成层"
        E[大语言模型<br/>GPT-4/Claude<br/>LLaMA]
    end
    
    subgraph "应用层"
        F[RAG应用<br/>问答系统<br/>智能助手]
    end
    
    A1 --> B
    A2 --> B
    B --> C
    C --> D
    D --> E
    E --> F
    
    style C fill:#e1f5ff
    style E fill:#ffe1e1

4.3 向量数据库在RAG中的关键作用

1️⃣ 高效的语义检索
# 示例:对比传统检索 vs 向量检索

# ❌ 传统关键词检索
query = "如何提升模型性能?"
# 只能匹配到包含"模型"、"性能"的文档
# 错过了"优化算法"、"调参技巧"等相关内容

# ✅ 向量语义检索
query_vector = embedding_model.encode(query)
results = vector_db.search(query_vector, top_k=5)
# 能找到:
# - "神经网络调优方法"
# - "超参数调整指南"
# - "模型压缩与加速"
# 即使没有相同关键词,但语义相关
2️⃣ 可扩展的知识存储
传统方式:将所有文档拼接到Prompt中
- 问题:GPT-4最多支持128K tokens,约10万字
- 限制:无法处理大规模知识库

向量数据库方式:
- 存储容量:支持百万、千万级文档
- 检索效率:O(log n) 时间复杂度
- 成本优化:只检索相关内容,减少LLM调用成本
3️⃣ 动态知识更新
sequenceDiagram
    participant Admin as 管理员
    participant VDB as 向量数据库
    participant RAG as RAG系统
    participant User as 用户
    
    Admin->>VDB: 添加新文档
    VDB->>VDB: 向量化并索引
    Note over VDB: 知识库实时更新
    
    User->>RAG: 提问(涉及新知识)
    RAG->>VDB: 检索
    VDB-->>RAG: 返回最新文档
    RAG-->>User: 基于最新知识回答

优势

  • 无需重新训练模型
  • 知识更新成本低
  • 实时生效
4️⃣ 多模态支持

向量数据库不仅支持文本,还能处理图像、音频等:

文本向量 + 图像向量 + 音频向量
     ↓          ↓          ↓
    统一的向量空间
     ↓
  跨模态检索

应用示例

  • 用文字描述搜索图片
  • 用图片搜索相关文档
  • 构建多模态RAG系统

4.4 实际应用案例

案例1:企业知识库问答
场景:员工需要快速查找公司规章制度

传统方案:
1. 人工翻阅文档 → 耗时费力
2. 关键词搜索 → 结果不准确
3. 咨询HR同事 → 增加沟通成本

RAG方案:
1. 将所有规章制度文档存入向量数据库
2. 员工提问:"年假如何申请?"
3. RAG系统:
   - 在向量数据库中检索相关政策
   - 找到"员工假期管理办法"第3章
   - LLM基于检索内容生成清晰答案
4. 返回答案并标注来源文档页码
案例2:代码助手
场景:开发者需要了解项目代码库的使用方法

技术实现:
1. 索引构建:
   - 将代码文件、API文档、注释向量化
   - 存入向量数据库
   
2. 开发者提问:"如何使用用户认证模块?"

3. RAG系统工作流程:
   ┌─────────────────────────────────┐
   │ 检索相关代码片段:              │
   │ - auth.py 的 authenticate() 函数 │
   │ - README中的认证说明            │
   │ - 相关单元测试示例              │
   └─────────────────────────────────┘
             ↓
   ┌─────────────────────────────────┐
   │ LLM生成答案:                    │
   │ "用户认证步骤如下:              │
   │  1. 导入 auth 模块               │
   │  2. 调用 authenticate(user, pwd) │
   │  3. 处理返回的 token..."         │
   └─────────────────────────────────┘
案例3:客服机器人
场景:电商网站的智能客服

数据来源:
- 商品信息数据库
- 历史客服对话记录
- 退换货政策文档
- 物流信息

工作流程:
用户:"我买的耳机可以退货吗?"
  ↓
检索向量数据库:
  → 找到"7天无理由退货政策"
  → 找到"电子产品退货须知"
  → 用户的订单信息
  ↓
生成个性化回答:
  "您购买的蓝牙耳机符合7天无理由退货政策。
   由于商品尚未发货,您可以直接取消订单。
   如已收货,请确保包装完好并填写退货申请..."

4.5 为什么RAG必须使用向量数据库?

理论对比
检索方式 原理 优点 缺点 适合RAG?
关键词匹配 BM25、TF-IDF 速度快、实现简单 无法理解语义 ❌ 不适合
全文搜索 Elasticsearch 功能丰富 语义理解弱 🔶 部分场景
向量检索 语义相似度 理解语义、跨语言 需要向量化 ✅ 最适合
混合检索 关键词+向量 综合优势 复杂度高 ✅ 更佳方案
实验数据

某问答系统的检索准确率对比:

测试集:1000个问题

关键词检索(BM25):
  Top-1准确率:45%
  Top-5准确率:68%

向量检索(Sentence-BERT + FAISS):
  Top-1准确率:72%
  Top-5准确率:89%

混合检索(0.7×向量 + 0.3×BM25):
  Top-1准确率:78%
  Top-5准确率:93%

5. 实战示例

5.1 简化的RAG系统架构

让我们通过代码来理解向量数据库和RAG的配 合:

示例1:构建向量数据库
"""
示例:将文档存入向量数据库
"""
from sentence_transformers import SentenceTransformer
import faiss
import numpy as np

# 1. 准备文档
documents = [
    "向量数据库专门用于存储和检索高维向量数据",
    "RAG技术结合了信息检索和文本生成",
    "Python是一种简洁易学的编程语言",
    "机器学习让计算机能够从数据中学习",
    "深度学习是机器学习的一个分支"
]

# 2. 加载向量化模型
model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2')

# 3. 将文档转换为向量
document_vectors = model.encode(documents)
print(f"向量维度: {document_vectors.shape}")
# 输出: 向量维度: (5, 384)  → 5个文档,每个384维

# 4. 创建FAISS索引
dimension = document_vectors.shape[1]  # 384
index = faiss.IndexFlatL2(dimension)   # 使用L2距离
index.add(document_vectors)            # 添加向量到索引

print(f"索引中的向量数量: {index.ntotal}")
# 输出: 索引中的向量数量: 5

# 5. 保存索引和文档映射
faiss.write_index(index, "document_index.faiss")
np.save("documents.npy", documents)

print("✅ 向量数据库构建完成!")
示例2:语义检索
"""
示例:在向量数据库中进行语义检索
"""
import faiss
import numpy as np
from sentence_transformers import SentenceTransformer

# 1. 加载向量数据库
index = faiss.read_index("document_index.faiss")
documents = np.load("documents.npy", allow_pickle=True)
model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2')

# 2. 用户查询
query = "什么是检索增强生成技术?"

# 3. 将查询向量化
query_vector = model.encode([query])

# 4. 在向量数据库中检索最相似的文档
k = 3  # 返回Top-3结果
distances, indices = index.search(query_vector, k)

# 5. 显示检索结果
print(f"查询: {query}\n")
print("检索结果:")
for i, (idx, distance) in enumerate(zip(indices[0], distances[0])):
    print(f"{i+1}. [{distance:.2f}] {documents[idx]}")

"""
输出示例:
查询: 什么是检索增强生成技术?

检索结果:
1. [3.24] RAG技术结合了信息检索和文本生成
2. [5.67] 向量数据库专门用于存储和检索高维向量数据
3. [8.91] 机器学习让计算机能够从数据中学习
"""
示例3:完整的RAG流程
"""
示例:完整的RAG问答系统
"""
from sentence_transformers import SentenceTransformer
import faiss
import numpy as np

class SimpleRAG:
    def __init__(self, index_path, documents_path):
        """初始化RAG系统"""
        self.model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2')
        self.index = faiss.read_index(index_path)
        self.documents = np.load(documents_path, allow_pickle=True)
    
    def retrieve(self, query, top_k=3):
        """检索相关文档"""
        # 向量化查询
        query_vector = self.model.encode([query])
        
        # 在向量数据库中检索
        distances, indices = self.index.search(query_vector, top_k)
        
        # 返回检索到的文档
        retrieved_docs = [self.documents[idx] for idx in indices[0]]
        return retrieved_docs
    
    def generate_answer(self, query, retrieved_docs):
        """
        生成答案(简化版,实际应调用LLM)
        这里只是演示RAG的流程
        """
        # 构建增强的提示词
        context = "\n".join([f"- {doc}" for doc in retrieved_docs])
        
        prompt = f"""
基于以下参考信息回答问题:

参考信息:
{context}

问题:{query}

答案:"""
        
        # 实际应用中,这里会调用OpenAI API或其他LLM
        # response = openai.ChatCompletion.create(
        #     model="gpt-4",
        #     messages=[{"role": "user", "content": prompt}]
        # )
        
        # 这里用简化的方式模拟
        return {
            "answer": f"[模拟回答] 根据检索到的{len(retrieved_docs)}份文档...",
            "sources": retrieved_docs,
            "prompt": prompt
        }
    
    def query(self, question):
        """完整的RAG查询流程"""
        print(f"❓ 问题: {question}\n")
        
        # 步骤1: 检索
        print("🔍 正在检索相关文档...")
        retrieved_docs = self.retrieve(question, top_k=3)
        print(f"✅ 检索到{len(retrieved_docs)}份相关文档\n")
        
        for i, doc in enumerate(retrieved_docs, 1):
            print(f"  {i}. {doc}")
        
        # 步骤2: 生成
        print("\n💬 正在生成答案...")
        result = self.generate_answer(question, retrieved_docs)
        
        print(f"\n📝 答案: {result['answer']}")
        return result

# 使用示例
if __name__ == "__main__":
    # 初始化RAG系统
    rag = SimpleRAG(
        index_path="document_index.faiss",
        documents_path="documents.npy"
    )
    
    # 提问
    rag.query("RAG技术是什么?")
    print("\n" + "="*50 + "\n")
    rag.query("如何学习编程?")

5.2 高级示例:使用LangChain实现完整RAG

"""
使用LangChain框架实现生产级RAG系统
"""
from langchain.embeddings import HuggingFaceEmbeddings
from langchain.vectorstores import FAISS
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.chains import RetrievalQA
from langchain.llms import OpenAI
from langchain.document_loaders import TextLoader
import os

# 设置API密钥
os.environ["OPENAI_API_KEY"] = "your-api-key-here"

# 1. 加载文档
loader = TextLoader("knowledge_base.txt", encoding="utf-8")
documents = loader.load()

# 2. 文档分块
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=500,
    chunk_overlap=50,
    separators=["\n\n", "\n", "。", "!", "?", ";", ",", " "]
)
chunks = text_splitter.split_documents(documents)
print(f"文档被分割成 {len(chunks)} 个块")

# 3. 创建向量数据库
embeddings = HuggingFaceEmbeddings(
    model_name="sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2"
)
vectorstore = FAISS.from_documents(chunks, embeddings)

# 4. 创建检索器
retriever = vectorstore.as_retriever(
    search_type="similarity",
    search_kwargs={"k": 4}  # 返回最相关的4个块
)

# 5. 创建RAG链
qa_chain = RetrievalQA.from_chain_type(
    llm=OpenAI(temperature=0, model_name="gpt-3.5-turbo"),
    chain_type="stuff",
    retriever=retriever,
    return_source_documents=True,
    verbose=True
)

# 6. 提问
def ask_question(question):
    result = qa_chain({"query": question})
    
    print(f"\n{'='*60}")
    print(f"问题: {question}")
    print(f"{'='*60}")
    print(f"\n答案:\n{result['result']}\n")
    
    print("来源文档:")
    for i, doc in enumerate(result['source_documents'], 1):
        print(f"\n[{i}] {doc.page_content[:100]}...")
    print(f"{'='*60}\n")
    
    return result

# 使用示例
if __name__ == "__main__":
    # 询问多个问题
    ask_question("向量数据库的主要优势是什么?")
    ask_question("RAG如何解决大模型的幻觉问题?")
    ask_question("如何选择合适的文本分块大小?")

6. 最佳实践

6.1 文本分块策略

"""
不同场景的分块策略
"""

# 场景1:技术文档
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=800,          # 较大块,保持完整性
    chunk_overlap=100,       # 较大重叠,避免语境断裂
    separators=["\n## ", "\n### ", "\n\n", "\n", "。"]
)

# 场景2:对话记录
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=300,          # 较小块,每个对话回合独立
    chunk_overlap=30,
    separators=["\n\n", "\n"]
)

# 场景3:法律文档
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=1000,         # 大块,保持条款完整
    chunk_overlap=200,       # 大重叠,保持引用关系
    separators=["\n第", "\n(", "\n\n", "\n"]
)

经验法则

  • 块太小:语境不完整,检索准确率下降
  • 块太大:检索不精确,LLM输入成本增加
  • 推荐范围:300-800字符
  • 重叠比例:10-20%

6.2 向量模型选择

模型 维度 大小 速度 效果 适用场景
all-MiniLM-L6-v2 384 80MB ⚡⚡⚡ ⭐⭐⭐ 英文、快速原型
paraphrase-multilingual-MiniLM 384 420MB ⚡⚡ ⭐⭐⭐⭐ 中英文、平衡选择
text-embedding-ada-002 (OpenAI) 1536 API ⭐⭐⭐⭐⭐ 生产环境、高精度
m3e-base 768 400MB ⚡⚡ ⭐⭐⭐⭐ 中文优化

6.3 检索优化技巧

1️⃣ 混合检索
# 结合向量检索和关键词检索
from langchain.retrievers import BM25Retriever, EnsembleRetriever

# 向量检索器
vector_retriever = vectorstore.as_retriever(search_kwargs={"k": 5})

# 关键词检索器
bm25_retriever = BM25Retriever.from_documents(documents)
bm25_retriever.k = 5

# 混合检索器(70%向量 + 30%关键词)
ensemble_retriever = EnsembleRetriever(
    retrievers=[vector_retriever, bm25_retriever],
    weights=[0.7, 0.3]
)
2️⃣ 查询扩展
# 将简单查询扩展为多个相关查询
def expand_query(original_query):
    """
    查询扩展示例
    """
    expansions = [
        original_query,
        f"{original_query} 的定义",
        f"{original_query} 的应用场景",
        f"如何理解{original_query}"
    ]
    return expansions

# 使用扩展后的查询进行检索
query = "RAG"
expanded_queries = expand_query(query)
all_results = []
for q in expanded_queries:
    results = retriever.get_relevant_documents(q)
    all_results.extend(results)

# 去重和重排序
unique_results = list(set(all_results))
3️⃣ 重排序
from sentence_transformers import CrossEncoder

# 使用CrossEncoder进行精确重排序
cross_encoder = CrossEncoder('cross-encoder/ms-marco-MiniLM-L-6-v2')

def rerank_documents(query, documents, top_k=3):
    """
    对检索结果重新排序
    """
    # 计算每个文档与查询的相关性分数
    pairs = [[query, doc.page_content] for doc in documents]
    scores = cross_encoder.predict(pairs)
    
    # 按分数排序
    ranked_docs = sorted(
        zip(documents, scores),
        key=lambda x: x[1],
        reverse=True
    )
    
    return [doc for doc, score in ranked_docs[:top_k]]

6.4 Prompt工程

# 优化的RAG Prompt模板
from langchain.prompts import PromptTemplate

# 基础模板
basic_template = """
使用以下参考信息回答问题。

参考信息:
{context}

问题:{question}

答案:
"""

# 高级模板(带约束)
advanced_template = """
你是一个专业的助手。请基于以下参考信息回答用户的问题。

**重要规则**:
1. 只使用参考信息中的内容回答
2. 如果参考信息不足以回答问题,明确说明"根据现有信息无法回答"
3. 回答要准确、简洁
4. 如果合适,引用参考信息的具体部分

**参考信息**:
{context}

**用户问题**:{question}

**你的回答**:
"""

# 带思维链的模板
cot_template = """
请基于参考信息回答问题,并展示你的推理过程。

参考信息:
{context}

问题:{question}

请按照以下格式回答:

1. 分析:[分析问题和参考信息的关联]
2. 推理:[说明推理过程]
3. 答案:[给出最终答案]
4. 依据:[指出答案来自哪部分参考信息]
"""

# 使用模板
prompt = PromptTemplate(
    template=advanced_template,
    input_variables=["context", "question"]
)

6.5 常见问题排查

问题 可能原因 解决方案
检索结果不相关 向量模型不合适 换用多语言模型或领域专用模型
回答产生幻觉 检索内容不足 增加Top-K数量,优化分块策略
响应速度慢 向量维度过高 使用降维或更小的模型
内存占用大 索引类型不合适 FAISS使用量化索引(IVF+PQ)
更新不及时 索引未重建 实现增量索引更新机制

6.6 性能优化建议

"""
FAISS索引优化示例
"""
import faiss

# 1. 基础索引(小规模,<10万向量)
index = faiss.IndexFlatL2(dimension)

# 2. IVF索引(中等规模,10万-100万向量)
nlist = 100  # 聚类中心数量
quantizer = faiss.IndexFlatL2(dimension)
index = faiss.IndexIVFFlat(quantizer, dimension, nlist)
index.train(training_vectors)  # 需要训练

# 3. IVF+PQ索引(大规模,>100万向量)
m = 8  # 子向量数量
bits = 8  # 每个子向量的位数
quantizer = faiss.IndexFlatL2(dimension)
index = faiss.IndexIVFPQ(quantizer, dimension, nlist, m, bits)
index.train(training_vectors)

# 4. HNSW索引(高精度需求)
index = faiss.IndexHNSWFlat(dimension, 32)  # 32是连接数

7. 总结

7.1 核心要点回顾

mindmap
  root((RAG生态系统))
    向量数据库
      语义理解
        文本向量化
        相似度计算
      高效存储
        百万级向量
        毫秒级检索
      应用场景
        语义搜索
        推荐系统
        异常检测
    RAG技术
      工作流程
        文档索引
        语义检索
        增强生成
      核心价值
        知识更新
        减少幻觉
        可溯源性
      应用场景
        问答系统
        智能客服
        代码助手
    技术栈
      向量化模型
        Sentence-BERT
        OpenAI Embeddings
      向量数据库
        FAISS
        Milvus
        Pinecone
      RAG框架
        LangChain
        LlamaIndex
      大语言模型
        GPT-4
        Claude
        开源LLM

7.2 三者的关系总结

🎯 完整的关系链:

数据 → 向量化 → 向量数据库 → RAG系统 → 智能应用
         ↓           ↓            ↓
      Embedding   语义检索    检索+生成

核心结论

  1. 向量数据库是存储和检索的基础设施
  2. RAG是应用向量数据库的典型场景
  3. 两者结合实现了可靠、可更新、可溯源的智能问答系统

7.3 学习路径建议

graph LR
    A[入门阶段] --> B[实践阶段] --> C[进阶阶段] --> D[专家阶段]
    
    A --> A1[理解向量概念]
    A --> A2[了解RAG原理]
    
    B --> B1[使用FAISS]
    B --> B2[实现简单RAG]
    
    C --> C1[优化检索策略]
    C --> C2[Prompt工程]
    
    D --> D1[分布式部署]
    D --> D2[多模态RAG]

推荐学习资源

  1. 向量数据库

  2. RAG技术

  3. 实战项目

    • 构建个人知识库问答系统
    • 企业文档智能助手
    • 代码库搜索引擎

7.4 未来趋势

  1. 多模态RAG:支持文本、图像、视频的统一检索
  2. 实时RAG:支持流式数据的实时索引和查询
  3. 自适应RAG:根据查询类型自动选择检索策略
  4. 可解释RAG:提供更透明的检索和生成过程
  5. 边缘RAG:在移动设备上部署轻量级RAG系统

📚 延伸阅读

学术论文

  • RAG原始论文:Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks (Lewis et al., 2020)
  • 向量检索:Billion-scale similarity search with GPUs (Johnson et al., 2017)

开源项目

技术博客

  • OpenAI Embeddings指南
  • Pinecone Learning Center
  • Weaviate Blog

🙋 FAQ

Q1: 向量数据库可以替代传统数据库吗?

A: 不能。它们解决不同的问题:

  • 传统数据库:精确查询、事务处理
  • 向量数据库:语义搜索、相似度匹配
  • 实际应用中常常结合使用

Q2: RAG vs 微调,哪个更好?

A: 各有优劣:

  • RAG优势:知识更新快、成本低、易维护
  • 微调优势:性能更好、响应更快、更个性化
  • 推荐:通用知识用RAG,专业能力用微调

Q3: 如何评估RAG系统的效果?

A: 常用指标:

  • 检索质量:准确率@K、召回率@K、MRR
  • 生成质量:BLEU、ROUGE、人工评分
  • 端到端:答案准确率、用户满意度

Q4: 向量数据库的成本如何?

A: 成本构成:

  • 存储成本:每百万384维向量约需150MB
  • 计算成本:向量化和检索的GPU/CPU开销
  • 托管成本:云服务按请求和存储量计费
  • 优化建议:使用量化、选择合适的索引类型

如有疑问或建议,欢迎交流讨论! 🎉

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐