RAG 中的向量检索
问题
RAG 系统中如何使用向量数据库?向量检索有哪些实践技巧?
答案
一、RAG 架构中的向量检索
RAG(Retrieval-Augmented Generation)的核心流程是先检索 → 再生成:
向量数据库在 RAG 中的角色是知识库——存储所有文档的向量表示,在查询时快速找到与用户问题最相关的文档片段。
二、文档分块策略
文档分块(Chunking)直接影响检索质量,是 RAG 效果的关键因素。
常见分块方式
| 方式 | 说明 | 适用 |
|---|---|---|
| 固定大小 | 按字符数/Token 数切分 | 通用 |
| 按段落/句子 | 保持语义完整性 | 结构化文档 |
| 递归分割 | 先按大块分,再按小块分 | 长文档 |
| 语义分割 | 基于 Embedding 相似度判断断点 | 高质量需求 |
分块参数
from langchain.text_splitter import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(
chunk_size=500, # 每块 ~500 字符
chunk_overlap=50, # 块之间重叠 50 字符
separators=["\n\n", "\n", "。", ",", " "], # 分割优先级
)
chunks = splitter.split_documents(documents)
分块经验值
- chunk_size:300~1000 Token(过小丢失上下文,过大引入噪声)
- chunk_overlap:10%~20%(保持块间语义连贯)
- 嵌入模型通常有最大长度限制(如 8192 Token),chunk_size 不能超过此上限
三、Embedding 模型选择
| 模型 | 维度 | 特点 | 适用 |
|---|---|---|---|
| OpenAI text-embedding-3-small | 1536 | 高质量,需 API | 通用首选 |
| OpenAI text-embedding-3-large | 3072 | 最高质量 | 高精度需求 |
| BAAI/bge-large-zh | 1024 | 中文优化,开源 | 中文场景 |
| Cohere embed-v3 | 1024 | 多语言 | 多语言 |
| nomic-embed-text | 768 | 开源,性能好 | 本地部署 |
选择建议:
- SaaS 服务:OpenAI text-embedding-3-small(性价比最高)
- 中文优先:bge-large-zh
- 私有化部署:nomic-embed-text 或 bge 系列
四、混合搜索
纯向量搜索可能错过关键词精确匹配的结果。混合搜索(Hybrid Search) 结合向量搜索和关键词搜索,互补优劣。
RRF(Reciprocal Rank Fusion)融合算法
其中 是文档 在排序列表 中的排名, 是常数(通常为 60)。
def reciprocal_rank_fusion(results_list, k=60):
"""
融合多个排序列表
results_list: [向量搜索结果, 关键词搜索结果, ...]
"""
scores = {}
for results in results_list:
for rank, doc in enumerate(results):
doc_id = doc["id"]
scores[doc_id] = scores.get(doc_id, 0) + 1 / (k + rank + 1)
# 按融合分数降序排列
sorted_docs = sorted(scores.items(), key=lambda x: x[1], reverse=True)
return sorted_docs
pgvector 混合搜索示例
-- 结合全文搜索和向量搜索
WITH vector_results AS (
SELECT id, title, content,
RANK() OVER (ORDER BY embedding <=> $1) AS vector_rank
FROM documents
ORDER BY embedding <=> $1
LIMIT 20
),
text_results AS (
SELECT id, title, content,
RANK() OVER (ORDER BY ts_rank(to_tsvector('chinese', content),
plainto_tsquery('chinese', $2)) DESC) AS text_rank
FROM documents
WHERE to_tsvector('chinese', content) @@ plainto_tsquery('chinese', $2)
LIMIT 20
)
-- RRF 融合
SELECT COALESCE(v.id, t.id) AS id,
COALESCE(v.title, t.title) AS title,
COALESCE(1.0 / (60 + v.vector_rank), 0) +
COALESCE(1.0 / (60 + t.text_rank), 0) AS rrf_score
FROM vector_results v
FULL OUTER JOIN text_results t ON v.id = t.id
ORDER BY rrf_score DESC
LIMIT 10;
五、检索优化技巧
1. Query 改写
用户的提问通常不是最佳的检索 Query。通过 LLM 改写可以提高召回率。
# HyDE:Hypothetical Document Embeddings
# 先让 LLM 生成假设性答案,用答案的 Embedding 去检索
hypothetical_answer = llm.generate(f"请详细回答:{user_query}")
query_embedding = embed(hypothetical_answer) # 用假设答案做检索
results = vector_db.search(query_embedding, limit=10)
2. 重排序(Reranking)
向量搜索的初始结果可能不够精确,用 Cross-Encoder 模型做二次排序。
from sentence_transformers import CrossEncoder
reranker = CrossEncoder("BAAI/bge-reranker-v2-m3")
# 初始检索:粗召回
candidates = vector_db.search(query_embedding, limit=50)
# 重排序:精排
pairs = [(query, doc["content"]) for doc in candidates]
scores = reranker.predict(pairs)
# 按重排序分数排列
reranked = sorted(zip(candidates, scores), key=lambda x: x[1], reverse=True)
top_results = reranked[:10]
3. 元数据过滤
# 限制检索范围:只搜索特定来源/时间的文档
results = vector_db.search(
query_embedding,
limit=10,
filter={
"source": "official_docs",
"updated_at": {"$gte": "2024-01-01"}
}
)
六、向量数据库选型
| 场景 | 推荐方案 |
|---|---|
| 已有 PostgreSQL,数据量 < 100 万 | pgvector |
| 需要大规模向量搜索(RAG 核心) | Milvus |
| 轻量级 / 嵌入式 | Chroma, LanceDB |
| 全托管 SaaS | Pinecone |
| 全文 + 向量混合 | Elasticsearch 8.x |
常见面试问题
Q1: RAG中向量检索的效果不好怎么优化?
答案:
分阶段排查:
- 分块问题:块太大(噪声多)或太小(丢上下文)→ 调整 chunk_size
- Embedding 模型:模型与数据语言不匹配 → 换中文优化模型
- 检索方式:纯向量召回不足 → 引入混合搜索(BM25 + 向量)
- Query 质量:用户提问模糊 → Query 改写 / HyDE
- 排序精度:初始排序不准 → 加 Reranker 重排序
- 元数据:检索范围太大 → 加标量过滤缩小范围
Q2: 向量数据库中如何处理文档更新?
答案:
文档更新时需要同步更新向量数据库:
- 删除旧向量:根据文档 ID 删除所有相关的 chunk 向量
- 重新分块:将更新后的文档重新分块
- 重新 Embedding:生成新的向量
- 写入新向量:插入向量数据库
建议为每条向量记录关联 doc_id 和 chunk_id 元数据,方便按文档维度删除和更新。
Q3: 如何评估 RAG 检索效果?
答案:
常用指标:
| 指标 | 含义 |
|---|---|
| Hit Rate@K | Top-K 结果中是否包含正确答案 |
| MRR | 正确答案的排名倒数的均值 |
| NDCG | 考虑排名位置的相关度评分 |
| Recall@K | Top-K 中找到了多少个相关文档 |
评估方法:构建标注数据集(query → 相关文档),自动化计算指标,对比不同方案。
Q4: 混合搜索中向量搜索和关键词搜索的权重如何调?
答案:
两种方式:
- RRF(推荐):无需手动调权重,根据排名自动融合
- 加权求和:
final_score = α × vector_score + (1-α) × keyword_score- α = 0.7 是常见起始值
- 通过评估集 A/B 测试找最优 α
经验:对于知识问答场景,向量权重略高(0.6~0.7);对于精确术语搜索场景,关键词权重略高。
相关链接
- 向量索引原理
- Milvus 向量数据库
- pgvector 扩展
- RAG 基础
- 高级检索
- 重排序
- Embedding 基础