🔍 Elasticsearch + Milvus 构建高效知识库问答系统(RAG 技术实战)
📌 目录
- 背景介绍
- [Elasticsearch 在知识库检索中的作用](#Elasticsearch 在知识库检索中的作用)
- [Milvus 在知识库检索中的作用](#Milvus 在知识库检索中的作用)
- [混合检索:Elasticsearch + Milvus](#混合检索:Elasticsearch + Milvus)
- 完整代码实现
- 部署建议与优化方向
- 总结
背景介绍
在构建基于大语言模型(LLM)的知识增强型生成系统(RAG)中,知识库检索是整个流程的核心环节。它决定了模型是否能从庞大的文档中快速定位到相关上下文信息。
传统的 RAG 系统通常采用以下两阶段流程:
[Query] → [Retriever] → [Top-k Docs] → [LLM] → [Answer]
其中 Retriever 可以是稀疏检索(如 BM25)、稠密检索(如 Milvus),也可以是两者的混合。
本文将详细介绍如何使用 Elasticsearch 和 Milvus 来构建一个高效的多模态检索系统,并提供可运行的 Python 示例代码。
Elasticsearch 在知识库检索中的作用
功能概述:
- 基于关键词匹配的稀疏检索
- 支持倒排索引和 TF-IDF/BM25 模型
- 快速召回高相关性文档
- 支持中文分词、拼音搜索、近义词扩展等功能
适用场景:
- 中文医疗问答系统
- 法律条文检索
- 小规模 FAQ 库
- 对语义理解要求不高的冷启动阶段
示例代码(Python)
python
from elasticsearch import Elasticsearch
from sentence_transformers.util import cos_sim
# 初始化 ES 客户端
es = Elasticsearch(hosts=["http://localhost:9200"])
# 插入文档
doc1 = {"content": "大模型训练需要大量高质量数据"}
doc2 = {"content": "RAG 系统通过外部知识提升回答能力"}
es.index(index="medical_kb", document=doc1)
es.index(index="medical_kb", document=doc2)
# 查询
query_body = {
"match": {
"content": "如何提升问答系统的准确性?"
}
}
response = es.search(index="medical_kb", body=query_body)
# 输出结果
print("Elasticsearch 回答结果:")
for hit in response['hits']['hits']:
print(f" - {hit['_source']['content']}")
Milvus 在知识库检索中的作用
功能概述:
- 支持高维向量存储与相似度检索(ANN)
- 可与 BERT、Sentence-BERT、BGE 等句向量模型结合
- 实现语义级别的相似度计算
- 支持大规模数据检索(亿级向量)
适用场景:
- 大规模知识库
- 高精度语义匹配
- 图像/文本混合检索
- LLM + 向量数据库联合部署
示例代码(Python + Milvus)
bash
pip install pymilvus sentence-transformers
python
from sentence_transformers import SentenceTransformer
from pymilvus import connections, Collection
# 加载语义编码器
model = SentenceTransformer('paraphrase-MiniLM-L6-v2')
# 连接 Milvus
connections.connect(host='localhost', port='19530')
collection = Collection("faq_collection")
# 插入向量(假设你已建立好 collection 并导入了知识库向量化内容)
# 查询
query_text = "如何提升问答系统的准确性?"
query_vec = model.encode([query_text])
collection.load()
results = collection.search(data=query_vec, anns_field="embedding", param={"metric_type": "IP", "offset": 0}, limit=3)
# 输出结果
print("Milvus 语义检索结果:")
for result in results:
for hit in result:
print(f" - ID: {hit.id} Distance: {hit.distance}")
混合检索:Elasticsearch + Milvus
你可以采用如下流程来构建一个高效的 RAG 问答系统:
[用户问题]
↓
Elasticsearch → [Top-50 粗召回文档]
↓
Milvus → [Top-10 语义相似文档]
↓
Reranker → [Top-3 最佳匹配段落]
✅ 混合优势:
优点 | 描述 |
---|---|
冷启动友好 | 利用 ES 快速上线 |
语义准确 | Milvus 提升召回质量 |
高效排序 | 结合 reranker 进一步优化输出 |
支持中文 | 可选择支持中文的 embedding 模型 |
完整代码实现(Python 示例)
以下是一个完整的混合检索流程示例:
python
from elasticsearch import Elasticsearch
from sentence_transformers import SentenceTransformer
from pymilvus import connections, Collection
# 初始化组件
es = Elasticsearch(hosts=["http://localhost:9200"])
model = SentenceTransformer('paraphrase-MiniLM-L6-v2')
connections.connect(host='localhost', port='19530')
milvus_col = Collection("faq_collection")
def hybrid_retrieval(query, k=3):
# Step 1: Elasticsearch 粗召回
es_result = es.search(index="medical_kb", body={"match": {"content": query}})
es_docs = [hit["_source"]["content"] for hit in es_result["hits"]["hits"]]
# Step 2: Milvus 语义精排
query_vec = model.encode([query])
milvus_results = milvus_col.search(data=query_vec, anns_field="embedding", param={"metric_type": "IP"}, limit=k)
# Step 3: 返回 top-k 文档
final_docs = []
for result in milvus_results:
for hit in result:
final_docs.append(es_docs[hit.id])
return final_docs[:k]
部署建议与优化方向
1. 数据预处理建议:
- 使用
jieba
或HanLP
对中文进行分词 - 清洗无意义符号、HTML、乱码
- 构建统一的数据格式(如 JSON)
2. 索引构建建议:
- Elasticsearch :
- 使用
ik-analyzer
中文分词插件 - 设置字段类型为
text
或keyword
- 使用
- Milvus :
- 使用 HNSW 或 IVF-PQ 索引加速查询
- 设置合适的维度(如 768 / 1024)
- 开启 GPU 加速(如支持)
3. 性能调优建议:
组件 | 调优方式 |
---|---|
Elasticsearch | 分片策略、索引合并、关闭不必要的日志 |
Milvus | 使用 ANN 索引、调整 nprobe、批量插入 |
Embedding 模型 | 使用轻量模型(如 bge-small , gte-base ) |
缓存机制 | Redis 缓存高频问题与答案 |
异步检索 | 使用 Celery 或 FastAPI 异步接口 |
4. 可选高级功能:
- Reranking :使用
BAAI/bge-reranker-base
等交叉编码器进一步打分排序 - 向量更新机制:定期更新 Milvus 中的知识库向量
- 混合评分融合:对 ES 和 Milvus 的结果做加权得分排序
总结
方法 | 是否理解语义 | 是否需训练 | 是否支持中文 | 是否适合大规模 | 是否适合冷启动 |
---|---|---|---|---|---|
Elasticsearch | ❌ 否 | ❌ 否 | ✅ 是 | ✅ 是 | ✅ 是 |
Milvus | ✅ 是 | ✅ 是 | ✅(模型决定) | ✅ 是 | ❌ 否 |
FAISS | ✅ 是 | ✅ 是 | ✅(模型决定) | ⭐ 有限 | ❌ 否 |
混合检索(ES+Milvus) | ✅ 是 | ✅ 是 | ✅ 是 | ✅ 是 | ✅ 是 |
✅ 推荐组合方案
方案一:纯稀疏检索(仅使用 ES)
适合冷启动或无语义模型的场景,无需 GPU 资源。
markdown
Query → Elasticsearch → Top-k Docs
方案二:纯稠密检索(仅使用 Milvus)
适合有预训练语义模型(如 BGE、Jina、OpenAI embeddings)的场景。
markdown
Query → Dense Encoder → Milvus → Top-k Docs
方案三:混合检索(ES + Milvus)
适合企业级 RAG 系统,兼顾效率与精度。
markdown
Query → Elasticsearch → Top-50 Docs
↓
Milvus → Top-10 Docs
↓
Reranker → Top-3 最终输出
📌 欢迎点赞、收藏,并关注我,我会持续更新更多关于 AI、LLM、视觉-语言模型等内容!