最终项目:生产就绪的文档搜索引擎
你的任务
是时候将你所学的一切整合到一个可放入作品集的应用中了。你将构建一个复杂的文档搜索引擎,它将展示混合检索、多向量重排序和生产质量评估。
你的搜索引擎将理解语义含义和精确关键词,然后使用细粒度重排序来浮现最相关的文档部分。当有人搜索“如何配置 HNSW 参数”时,你的系统应该返回带有实际示例的精确部分,而不仅仅是提到“HNSW”的某个页面。
这反映了真实世界的检索挑战,即用户需要从大量文档集中获取精确答案。你将实现完整的管道:智能分块的摄取、结合稠密和稀疏信号的混合搜索,以及用于提高精度的多向量重排序。
预计时间: 210 分钟
您将构建什么
- 一个存储稠密、稀疏和 ColBERT 多向量的单一集合
- 一个混合搜索管道(稠密 + 稀疏,带服务器端融合)
- ColBERT 重排序,用于细粒度匹配
- 一个包含 Recall@10、MRR 和 P50/P95 延迟的评估步骤
设置
先决条件
- Qdrant 云集群(URL + API 密钥)
- Python 3.9+(或 Google Colab)
- 包:
qdrant-client,numpy
模型
- 稠密:
BAAI/bge-small-en-v1.5(384-维) 或BAAI/bge-base-en-v1.5(768-维) - 稀疏:BM25/TF-IDF 或 SPLADE
- 多向量:
colbert-ir/colbertv2.0(128-维 token)
数据集
- 范围: 完整的文档集(例如,Qdrant 文档或你使用的库的文档)
- 字段: 按文档结构分块。保留:
page_title,section_title,page_url,section_url,breadcrumbs,chunk_text,prev_section_text,next_section_text,tags。 - 过滤器: 考虑使用
tags或breadcrumbs进行分面。 - 有效载荷示例
payload = {
"page_title": "Configuration Guide",
"section_title": "HNSW Parameters",
"page_url": "/docs/guides/configuration/",
"section_url": "/docs/guides/configuration/#hnsw-parameters",
"breadcrumbs": ["Guides", "Configuration", "HNSW Parameters"],
"chunk_text": "The main section content...",
"prev_section_text": "Previous section for context...",
"next_section_text": "Next section for context...",
"tags": ["configuration", "performance", "hnsw"]
}
构建步骤
步骤 1:初始化客户端
from qdrant_client import QdrantClient, models
import os
client = QdrantClient(url=os.getenv("QDRANT_URL"), api_key=os.getenv("QDRANT_API_KEY"))
# For Colab:
# from google.colab import userdata
# client = QdrantClient(url=userdata.get("QDRANT_URL"), api_key=userdata.get("QDRANT_API_KEY"))
步骤 2:集合设计
创建带有三个向量(稠密 384、稀疏、ColBERT 多向量,m=0)的 docs_search。如果你选择 768 维稠密模型,请将下面的 size 设置为 768。
collection_name = "docs_search"
client.create_collection(
collection_name=collection_name,
vectors_config={
"dense": models.VectorParams(size=384, distance=models.Distance.COSINE),
"colbert": models.VectorParams(
size=128,
distance=models.Distance.COSINE,
multivector_config=models.MultiVectorConfig(
comparator=models.MultiVectorComparator.MAX_SIM
),
hnsw_config=models.HnswConfigDiff(m=0) # Reranking only
)
},
sparse_vectors_config={"sparse": models.SparseVectorParams()}
)
步骤 3:解析和分块文档
选择一个文档集,并将其解析为结构化部分。保留用户期望的层次结构。
基于部分的块化
- 主要单元:每部分一个块
- 上下文:在
prev_section_text/next_section_text中存储相邻部分 - 元数据:保留标题、URL 和面包屑,用于归因和导航
步骤 4:嵌入和摄取
嵌入并上传所有三个向量以及你需要用于显示和过滤的有效载荷字段。
待测试的示例模型:
- 稠密(主要检索):使用
BAAI/bge-small-en-v1.5追求速度,或使用BAAI/bge-base-en-v1.5追求更高质量。对于多语言文档,考虑使用intfloat/multilingual-e5-base。 - 多向量(重排序):使用 ColBERTv2 实现延迟交互评分。这为区分相似部分提供了 token 级精度。
- 稀疏(词汇):从 BM25 风格的稀疏权重开始,用于精确关键词匹配。可选地尝试 SPLADE 编码器。
步骤 5:搜索管道
将用户查询转换为混合搜索所需的三种向量表示。使用 Qdrant 的通用查询 API 结合稠密和稀疏向量,实现服务器端融合。
多阶段管道
- 阶段 1 – 混合检索:稠密 + 稀疏,使用 RRF(或 DBSF)。检索 50-200 个候选结果以获得良好的召回率。
- 阶段 2 – 多向量重排序:对候选结果应用 token 级延迟交互(MAX_SIM)。
步骤 6:结果格式化
将原始结果转换为用户友好的输出:页面标题、部分标题、URL、分数以及一个解释匹配的简短上下文片段。
步骤 7:分析结果
构建一个小型的评估集,并测量质量和延迟。使用结果指导调优(融合策略、候选集大小、搜索时 hnsw_ef 等)。
真实标签:
- 创建 20-30 个包含预期部分 URL/锚点的真实查询。
- 目标是涵盖操作指南、概念、API 使用和故障排除等多样化的查询类型。
ground_truth_examples = [
{
"query": "how to configure HNSW parameters for better recall",
"expected_urls": ["/docs/guides/configuration/#hnsw-parameters"],
"query_type": "how-to"
},
{
"query": "quantization memory reduction",
"expected_urls": ["/docs/guides/quantization/", "/docs/concepts/optimization/"],
"query_type": "concept"
},
{
"query": "create collection with replication factor",
"expected_urls": ["/docs/guides/distributed-deployment/#replication-factor"],
"query_type": "api-usage"
}
]
要跟踪的指标:
- Recall@10 衡量你的系统是否在前 10 个结果中找到正确答案。通过检查你的前 10 个结果中是否有任何一个与预期的 URL 或部分锚点匹配来计算。0.8 的分数意味着你的系统在 80% 的时间里找到了正确答案。
- 平均倒数排名 (MRR) 衡量用户找到正确答案的速度。如果正确结果排名第 1,你得到 1.0 分。如果排名第 2,你得到 0.5 分。如果不在前 10 名中,你得到 0 分。这个指标非常重视将最佳答案放在最前面。
- 延迟 P50/P95 衡量实际性能。P50 是中位响应时间(一半的查询速度更快),而 P95 捕获尾部延迟(95% 的查询在此时间内完成)。两者都对用户体验很重要。
成功标准
当你的项目展示了具有可衡量性能的生产级搜索时,即为成功。
完整的端到端 Jupyter Notebook 或针对 Qdrant Cloud 运行的应用程序
包含稠密、稀疏和多向量组件的混合搜索实现
具有真实查询和黄金标准答案的评估框架
性能指标显示 Recall@10 ≥ 0.8 和合理的延迟
清晰的设计决策文档及其理由
具有文档化配置的可重现结果
分享你的发现
步骤 1:反思你的发现
当你测试搜索引擎时,请考虑
分块粒度: 部分是否足够大以回答问题,但又足够小以保持精确度?
有效载荷设计: 字段是否有助于归因、过滤和评估,而不会造成膨胀?
融合策略: RRF 或 DBSF,哪个更适合你?
重排序方法: 输入多向量阶段的正确候选限制(50/100/200)是多少,聚合 token 级分数的最佳方法是什么?
是否重排序: 多向量是否值得,还是仅融合就足够了?
性能调优: 哪些搜索和 HNSW 设置能达到你的准确性/延迟目标?
- 搜索时间:将
hnsw_ef从 64 → 128 → 256 提高,直到收益趋于平稳。 - 索引时间(如果重建):尝试更高的
m(16, 32) 和ef_construct(200, 400)。
- 搜索时间:将
步骤 2:发布你的结果
展示你的运行并向他人学习。在 中使用此复制粘贴模板发布你的结果:
**[Day 6] Final Project: Production-Ready Documentation Search Engine**
**High-Level Summary**
- **Domain:** "Documentation search for <product>"
- **Key Result:** "Hybrid + multivector reranking reached Recall@10=<value> with P95=<ms>."
**Reproducibility**
- **Notebook/App:** <link>
- **Repo (optional):** <link>
- **Models:** dense=<id>, sparse=<method>, colbert=<id>
- **Collection:** docs_search (Cosine), points=<count>
- **Dataset:** <N sections> from <source> (snapshot: YYYY-MM-DD)
- **Ground truth:** <M queries> (how-to / concept / api / troubleshooting)
**Settings (today)**
- **Chunking:** <one section per heading | other>
- **Payload fields:** <page_title, section_title, section_url, breadcrumbs, tags, prev/next>
- **Fusion:** <RRF/DBSF>, k_dense=<100>, k_sparse=<100>
- **Reranker:** ColBERT (MaxSim), top-k=<N>
- **Index/Search params:** hnsw_ef=<...>, m=<...>, ef_construct=<...> # if tuned
**Queries (examples)**
1) "<user query>"
Top 3:
1) <section title> → <url> → <score>
2) ...
3) ...
2) "<second query>"
Top 3:
1) ...
2) ...
3) ...
**Evaluation**
- Recall@10: <value> | MRR: <value> | P50: <ms> | P95: <ms>
**Why these matched**
- <one line>
**Surprise**
- "<…>"
**Next step**
- "<…>"
可选:更进一步
- 尝试不同的稠密模型(速度与质量)
- 如果你的数据集很大,使用更高的
m/ef_construct重建 - 添加过滤器(标签、部分类型)并测量影响