Розробка RAG з векторною базою даних Qdrant
Qdrant — відкрита векторна база даних, написана на Rust. Вирізняється високою продуктивністю, багатою системою фільтрації через payload, вбудованим гібридним пошуком та зручним REST/gRPC API. Доступна як керована хмара (Qdrant Cloud) та self-hosted. Один з найпопулярніших рішень для production RAG-систем.
Встановлення через Docker та підключення
docker pull qdrant/qdrant
docker run -p 6333:6333 -v $(pwd)/qdrant_storage:/qdrant/storage qdrant/qdrant
from qdrant_client import QdrantClient
from qdrant_client.models import (
Distance, VectorParams, SparseVectorParams,
SparseIndexParams, HnswConfigDiff
)
client = QdrantClient(url="http://localhost:6333")
# Або хмара
client = QdrantClient(url="https://cluster.qdrant.tech", api_key="...")
Створення колекції з dense та sparse векторами
from qdrant_client.models import VectorsConfig, SparseVectorsConfig
client.create_collection(
collection_name="documents",
vectors_config={
"dense": VectorParams(
size=1536,
distance=Distance.COSINE,
hnsw_config=HnswConfigDiff(m=16, ef_construct=200)
)
},
sparse_vectors_config={
"sparse": SparseVectorParams(
index=SparseIndexParams(on_disk=False)
)
}
)
Індексація з payload-метаданими
from qdrant_client.models import PointStruct, SparseVector
from fastembed import SparseTextEmbedding, TextEmbedding
import uuid
dense_model = TextEmbedding("sentence-transformers/paraphrase-multilingual-mpnet-base-v2")
sparse_model = SparseTextEmbedding("prithivida/Splade_PP_en_v1")
def index_chunks(chunks: list) -> None:
points = []
for chunk in chunks:
# Dense embedding
dense_vec = list(dense_model.embed([chunk.text]))[0].tolist()
# Sparse embedding (SPLADE)
sparse_output = list(sparse_model.embed([chunk.text]))[0]
point = PointStruct(
id=str(uuid.uuid4()),
vector={
"dense": dense_vec,
"sparse": SparseVector(
indices=sparse_output.indices.tolist(),
values=sparse_output.values.tolist()
)
},
payload={
"text": chunk.text,
"source": chunk.source,
"doc_type": chunk.doc_type,
"page": chunk.page,
"date": chunk.date,
"department": chunk.department,
}
)
points.append(point)
client.upsert(collection_name="documents", points=points)
Гібридний пошук з RRF
from qdrant_client.models import Prefetch, FusionQuery, Fusion, Filter, FieldCondition, MatchValue
def hybrid_search(
query: str,
doc_type: str = None,
top_k: int = 5
) -> list:
# Векторы для запиту
dense_vec = list(dense_model.embed([query]))[0].tolist()
sparse_output = list(sparse_model.embed([query]))[0]
sparse_vec = SparseVector(
indices=sparse_output.indices.tolist(),
values=sparse_output.values.tolist()
)
# Фільтр за метаданими
query_filter = None
if doc_type:
query_filter = Filter(
must=[FieldCondition(key="doc_type", match=MatchValue(value=doc_type))]
)
# Гібридний пошук з RRF fusion
results = client.query_points(
collection_name="documents",
prefetch=[
Prefetch(query=dense_vec, using="dense", limit=30, filter=query_filter),
Prefetch(query=sparse_vec, using="sparse", limit=30, filter=query_filter),
],
query=FusionQuery(fusion=Fusion.RRF),
limit=top_k,
with_payload=True,
)
return [
{"text": r.payload["text"], "source": r.payload["source"], "score": r.score}
for r in results.points
]
Практичний кейс: RAG для e-commerce підтримки
Завдання: багатомовний помічник підтримки інтернет-магазину (рус/англ), 85 000 чанків (FAQ, політики, описи товарів).
Стек: Qdrant self-hosted (Docker), SPLADE для sparse, paraphrase-multilingual-mpnet-base-v2 для dense, GPT-4o-mini для генерації.
Результати гібридного vs лише dense:
| Метрика | Лише dense | Гібридний (RRF) |
|---|---|---|
| MRR@5 | 0.71 | 0.84 |
| NDCG@5 | 0.68 | 0.81 |
| Faithfulness | 0.82 | 0.91 |
| Latency P95 | 95мс | 140мс |
Гібридний пошук дає +13% до MRR за рахунок точного BM25-matching на номерах замовлень, артикулах товарів та конкретних термінах.
Фільтрація через payload-індекси
Для прискорення фільтрації створюємо payload-індекси:
from qdrant_client.models import PayloadSchemaType
client.create_payload_index(
collection_name="documents",
field_name="doc_type",
field_schema=PayloadSchemaType.KEYWORD,
)
client.create_payload_index(
collection_name="documents",
field_name="date",
field_schema=PayloadSchemaType.DATETIME,
)
Строки
- Налаштування Qdrant + схема колекції: 1–2 дні
- Ingestion pipeline (dense + sparse): 3–7 днів
- Гібридний пошук + фільтрація: 3–5 днів
- Оцінка та оптимізація: 1–2 тижні
- Всього: 2–4 тижні







