跳到主要内容

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-small1536高质量,需 API通用首选
OpenAI text-embedding-3-large3072最高质量高精度需求
BAAI/bge-large-zh1024中文优化,开源中文场景
Cohere embed-v31024多语言多语言
nomic-embed-text768开源,性能好本地部署

选择建议:

  1. SaaS 服务:OpenAI text-embedding-3-small(性价比最高)
  2. 中文优先:bge-large-zh
  3. 私有化部署:nomic-embed-text 或 bge 系列

四、混合搜索

纯向量搜索可能错过关键词精确匹配的结果。混合搜索(Hybrid Search) 结合向量搜索和关键词搜索,互补优劣。

RRF(Reciprocal Rank Fusion)融合算法

RRF(d)=rR1k+r(d)\text{RRF}(d) = \sum_{r \in R} \frac{1}{k + r(d)}

其中 r(d)r(d) 是文档 dd 在排序列表 rr 中的排名,kk 是常数(通常为 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
全托管 SaaSPinecone
全文 + 向量混合Elasticsearch 8.x

常见面试问题

Q1: RAG中向量检索的效果不好怎么优化?

答案

分阶段排查:

  1. 分块问题:块太大(噪声多)或太小(丢上下文)→ 调整 chunk_size
  2. Embedding 模型:模型与数据语言不匹配 → 换中文优化模型
  3. 检索方式:纯向量召回不足 → 引入混合搜索(BM25 + 向量)
  4. Query 质量:用户提问模糊 → Query 改写 / HyDE
  5. 排序精度:初始排序不准 → 加 Reranker 重排序
  6. 元数据:检索范围太大 → 加标量过滤缩小范围

Q2: 向量数据库中如何处理文档更新?

答案

文档更新时需要同步更新向量数据库:

  1. 删除旧向量:根据文档 ID 删除所有相关的 chunk 向量
  2. 重新分块:将更新后的文档重新分块
  3. 重新 Embedding:生成新的向量
  4. 写入新向量:插入向量数据库

建议为每条向量记录关联 doc_idchunk_id 元数据,方便按文档维度删除和更新。

Q3: 如何评估 RAG 检索效果?

答案

常用指标:

指标含义
Hit Rate@KTop-K 结果中是否包含正确答案
MRR正确答案的排名倒数的均值
NDCG考虑排名位置的相关度评分
Recall@KTop-K 中找到了多少个相关文档

评估方法:构建标注数据集(query → 相关文档),自动化计算指标,对比不同方案。

Q4: 混合搜索中向量搜索和关键词搜索的权重如何调?

答案

两种方式:

  1. RRF(推荐):无需手动调权重,根据排名自动融合
  2. 加权求和final_score = α × vector_score + (1-α) × keyword_score
    • α = 0.7 是常见起始值
    • 通过评估集 A/B 测试找最优 α

经验:对于知识问答场景,向量权重略高(0.6~0.7);对于精确术语搜索场景,关键词权重略高。

相关链接