向量检索
🎯 学习目标
- 按规模与部署方式选择合适的向量库
- 理解 Hybrid(向量 + BM25)何时优于纯向量
- 知道 MultiQuery 与压缩检索解决的问题与成本
- 配置相似度阈值实现「查不到就拒答」
引言
InMemoryVectorStore 适合学习;上线后你要面对百万 chunk、过滤条件、P99 延迟。本节讲向量库选型与检索优化套路,让 recall 与 precision 可 trade-off。
章节正文
第 1 步:向量库选型维度
| 类型 | 代表 | 适用 |
|---|---|---|
| 内存 | FAISS、numpy | 原型、<100万向量 |
| 自托管 | Chroma、Qdrant、Milvus | 企业 VPC、要 metadata filter |
| 云托管 | Pinecone、Zilliz Cloud | 免运维、弹性 scale |
选型问:数据量、QPS、是否要 Hybrid 内置、多租户隔离、备份与合规地域。
第 2 步:Hybrid 检索(向量 + BM25)
纯向量对专有名词、型号、错误码弱;BM25 擅精确词匹配。
# 概念:分别召回后 RRF 融合
vector_hits = store.search(query_vec, top_k=20)
bm25_hits = bm25_index.search(query_text, top_k=20)
merged = reciprocal_rank_fusion(vector_hits, bm25_hits)[:10]代码、日志、SKU 类知识库建议默认 Hybrid。
第 3 步:MultiQueryRetriever
用户口语与文档用语不一致时,让 LLM 生成 3–5 个查询变体,分别检索后去重合并:
variants = llm.generate(f"为检索生成3个同义查询:{question}")
all_hits = []
for q in variants:
all_hits.extend(rag_retrieve(store, q, top_k=5))
hits = dedupe_by_chunk_id(all_hits)提升 recall,但增加 embedding 与检索成本,适合「问法多样、漏召回严重」场景。
第 4 步:压缩检索与阈值拒答
Top-K 片段仍可能很长。Contextual Compression:用小模型或 LLM 对每段 extract 相关句,再注入 Prompt。
if hits[0][0] < SIMILARITY_THRESHOLD:
return {"answer": "知识库中未找到足够相关资料,请咨询人工。", "sources": []}阈值需按 embedding 模型校准,勿直接抄他人默认值。
第 5 步:metadata 过滤与性能
检索前 filter:product=payments AND version>=2,缩小搜索空间。
索引侧:HNSW 参数、量化(PQ)权衡 recall vs 内存;热数据与冷数据分 collection。监控:P95 检索延迟、hit@K、空结果率。
动手练习
- 用 Chroma 或 Qdrant 复现 4.4 索引,对比 InMemory 与持久化差异。
- 对含 SKU「XJ-9001」的语料,对比纯向量 vs Hybrid 的 hit@1。
- 实现 MultiQuery 3 变体检索,统计 recall 提升与延迟增加。
- 画 SIMILARITY_THRESHOLD 曲线:拒答率 vs 人工 judged 准确率。
- 设计 metadata filter(product + lang),验证 filter 错误时「空结果」如何提示用户。
常见问题
Q:HNSW 是什么?
近似最近邻图索引,牺牲少量 recall 换大幅提速。向量库默认多为此类;参数 efConstruction、M 影响构建时间与查询质量。
Q:MultiQuery 会不会引入噪声?
会。合并后应 dedupe、可 rerank(4.6),并限制变体数量。对精确 FAQ 有时反而 hurt precision。
Q:云向量库贵怎么办?
热冷分层、减小 embedding 维度(在质量允许下)、批量离线检索、缓存热门 query 结果;中小规模自托管 Qdrant 常更省。
本节小结
向量库按规模与合规选型;Hybrid 补专有词;MultiQuery 补 recall;压缩与阈值平衡窗口与拒答。优化前先 baseline 指标,避免同时改多变量。