Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Vector search engine for production RAG systems.
.claude/skills/nousresearch-qdrant-vector-search/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 128% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 134% | 0% |
| case-04 | ✓→✓ | = Same ✓ | 246% | 0% |
| case-05 | ✓→✓ | = Same ✓ | 177% | 0% |
| case-06 | ✓→✓ | = Same ✓ | 183% | 0% |
High-performance vector database written in Rust for production RAG and semantic search.
Use Qdrant when:
Key features:
Use alternatives instead:
bash# Python client pip install qdrant-client # Docker (recommended for development) docker run -p 6333:6333 -p 6334:6334 qdrant/qdrant # Docker with persistent storage docker run -p 6333:6333 -p 6334:6334 \ -v $(pwd)/qdrant_storage:/qdrant/storage \ qdrant/qdrant
pythonfrom qdrant_client import QdrantClient from qdrant_client.models import Distance, VectorParams, PointStruct # Connect to Qdrant client = QdrantClient(host="localhost", port=6333) # Create collection client.create_collection( collection_name="documents", vectors_config=VectorParams(size=384, distance=Distance.COSINE) ) # Insert vectors with payload client.upsert( collection_name="documents", points=[ PointStruct( id=1, vector=[0.1, 0.2, ...], # 384-dim vector payload={"title": "Doc 1", "category": "tech"} ), PointStruct( id=2, vector=[0.3, 0.4, ...], payload={"title": "Doc 2", "category": "science"} ) ] ) # Search with filtering (query_points is the current API; client.search is removed in qdrant-client 1.14+) response = client.query_points( collection_name="documents", query=[0.15, 0.25, ...], query_filter={ "must": [{"key": "category", "match": {"value": "tech"}}] }, limit=10 ) for point in response.points: print(f"ID: {point.id}, Score: {point.score}, Payload: {point.payload}")
pythonfrom qdrant_client.models import PointStruct # Point = ID + Vector(s) + Payload point = PointStruct( id=123, # Integer or UUID string vector=[0.1, 0.2, 0.3, ...], # Dense vector payload={ # Arbitrary JSON metadata "title": "Document title", "category": "tech", "timestamp": 1699900000, "tags": ["python", "ml"] } ) # Batch upsert (recommended) client.upsert( collection_name="documents", points=[point1, point2, point3], wait=True # Wait for indexing )
pythonfrom qdrant_client.models import VectorParams, Distance, HnswConfigDiff # Create with HNSW configuration client.create_collection( collection_name="documents", vectors_config=VectorParams( size=384, # Vector dimensions distance=Distance.COSINE # COSINE, EUCLID, DOT, MANHATTAN ), hnsw_config=HnswConfigDiff( m=16, # Connections per node (default 16) ef_construct=100, # Build-time accuracy (default 100) full_scan_threshold=10000 # Switch to brute force below this ), on_disk_payload=True # Store payload on disk ) # Collection info info = client.get_collection("documents") print(f"Points: {info.points_count}, Vectors: {info.vectors_count}")
| Metric | Use Case | Range | |--------|----------|-------| | COSINE | Text embeddings, normalized vectors | 0 to 2 | | EUCLID | Spatial data, image features | 0 to ∞ | | DOT | Recommendations, unnormalized | -∞ to ∞ | | MANHATTAN | Sparse features, discrete data | 0 to ∞ |
python# Simple nearest neighbor search (returns a QueryResponse; use .points) response = client.query_points( collection_name="documents", query=[0.1, 0.2, ...], limit=10, with_payload=True, with_vectors=False # Don't return vectors (faster) ) results = response.points
pythonfrom qdrant_client.models import Filter, FieldCondition, MatchValue, Range # Complex filtering response = client.query_points( collection_name="documents", query=query_embedding, query_filter=Filter( must=[ FieldCondition(key="category", match=MatchValue(value="tech")), FieldCondition(key="timestamp", range=Range(gte=1699000000)) ], must_not=[ FieldCondition(key="status", match=MatchValue(value="archived")) ] ), limit=10 ).points # Shorthand filter syntax response = client.query_points( collection_name="documents", query=query_embedding, query_filter={ "must": [ {"key": "category", "match": {"value": "tech"}}, {"key": "price", "range": {"gte": 10, "lte": 100}} ] }, limit=10 ).points
pythonfrom qdrant_client.models import QueryRequest # Multiple queries in one request (search_batch is replaced by query_batch_points) responses = client.query_batch_points( collection_name="documents", requests=[ QueryRequest(query=[0.1, ...], limit=5), QueryRequest(query=[0.2, ...], limit=5, filter={"must": [...]}), QueryRequest(query=[0.3, ...], limit=10) ] ) # Each element is a QueryResponse; use .points for resp in responses: for point in resp.points: print(point.id, point.score)
pythonfrom sentence_transformers import SentenceTransformer from qdrant_client import QdrantClient from qdrant_client.models import VectorParams, Distance, PointStruct # Initialize encoder = SentenceTransformer("all-MiniLM-L6-v2") client = QdrantClient(host="localhost", port=6333) # Create collection client.create_collection( collection_name="knowledge_base", vectors_config=VectorParams(size=384, distance=Distance.COSINE) ) # Index documents documents = [ {"id": 1, "text": "Python is a programming language", "source": "wiki"}, {"id": 2, "text": "Machine learning uses algorithms", "source": "textbook"}, ] points = [ PointStruct( id=doc["id"], vector=encoder.encode(doc["text"]).tolist(), payload={"text": doc["text"], "source": doc["source"]} ) for doc in documents ] client.upsert(collection_name="knowledge_base", points=points) # RAG retrieval def retrieve(query: str, top_k: int = 5) -> list[dict]: query_vector = encoder.encode(query).tolist() response = client.query_points( collection_name="knowledge_base", query=query_vector, limit=top_k ) return [{"text": r.payload["text"], "score": r.score} for r in response.points] # Use in RAG pipeline context = retrieve("What is Python?") prompt = f"Context: {context}\n\nQuestion: What is Python?"
pythonfrom langchain_community.vectorstores import Qdrant from langchain_community.embeddings import HuggingFaceEmbeddings embeddings = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2") vectorstore = Qdrant.from_documents(documents, embeddings, url="http://localhost:6333", collection_name="docs") retriever = vectorstore.as_retriever(search_kwargs={"k": 5})
pythonfrom llama_index.vector_stores.qdrant import QdrantVectorStore from llama_index.core import VectorStoreIndex, StorageContext vector_store = QdrantVectorStore(client=client, collection_name="llama_docs") storage_context = StorageContext.from_defaults(vector_store=vector_store) index = VectorStoreIndex.from_documents(documents, storage_context=storage_context) query_engine = index.as_query_engine()
pythonfrom qdrant_client.models import VectorParams, Distance # Collection with multiple vector types client.create_collection( collection_name="hybrid_search", vectors_config={ "dense": VectorParams(size=384, distance=Distance.COSINE), "sparse": VectorParams(size=30000, distance=Distance.DOT) } ) # Insert with named vectors client.upsert( collection_name="hybrid_search", points=[ PointStruct( id=1, vector={ "dense": dense_embedding, "sparse": sparse_embedding }, payload={"text": "document text"} ) ] ) # Search specific named vector (pass the vector name via `using`) response = client.query_points( collection_name="hybrid_search", query=query_dense, using="dense", # Specify which named vector to search limit=10 ) results = response.points
pythonfrom qdrant_client.models import SparseVectorParams, SparseIndexParams, SparseVector # Collection with sparse vectors client.create_collection( collection_name="sparse_search", vectors_config={}, sparse_vectors_config={"text": SparseVectorParams(index=SparseIndexParams(on_disk=False))} ) # Insert sparse vector client.upsert( collection_name="sparse_search", points=[PointStruct(id=1, vector={"text": SparseVector(indices=[1, 5, 100], values=[0.5, 0.8, 0.2])}, payload={"text": "document"})] )
pythonfrom qdrant_client.models import ScalarQuantization, ScalarQuantizationConfig, ScalarType # Scalar quantization (4x memory reduction) client.create_collection( collection_name="quantized", vectors_config=VectorParams(size=384, distance=Distance.COSINE), quantization_config=ScalarQuantization( scalar=ScalarQuantizationConfig( type=ScalarType.INT8, quantile=0.99, # Clip outliers always_ram=True # Keep quantized in RAM ) ) ) # Search with rescoring response = client.query_points( collection_name="quantized", query=query, search_params={"quantization": {"rescore": True}}, # Rescore top results limit=10 ) results = response.points
pythonfrom qdrant_client.models import PayloadSchemaType # Create payload index for faster filtering client.create_payload_index( collection_name="documents", field_name="category", field_schema=PayloadSchemaType.KEYWORD ) client.create_payload_index( collection_name="documents", field_name="timestamp", field_schema=PayloadSchemaType.INTEGER ) # Index types: KEYWORD, INTEGER, FLOAT, GEO, TEXT (full-text), BOOL
pythonfrom qdrant_client import QdrantClient # Connect to Qdrant Cloud client = QdrantClient( url="https://your-cluster.cloud.qdrant.io", api_key="your-api-key" )
python# Optimize for search speed (higher recall) client.update_collection( collection_name="documents", hnsw_config=HnswConfigDiff(ef_construct=200, m=32) ) # Optimize for indexing speed (bulk loads) client.update_collection( collection_name="documents", optimizer_config={"indexing_threshold": 20000} )
on_disk_payload for large payloadsSlow search with filters:
python# Create payload index for filtered fields client.create_payload_index( collection_name="docs", field_name="category", field_schema=PayloadSchemaType.KEYWORD )
Out of memory:
python# Enable quantization and on-disk storage client.create_collection( collection_name="large_collection", vectors_config=VectorParams(size=384, distance=Distance.COSINE), quantization_config=ScalarQuantization(...), on_disk_payload=True )
Connection issues:
python# Use timeout and retry client = QdrantClient( host="localhost", port=6333, timeout=30, prefer_grpc=True # gRPC for better performance )
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 11,888 | 7,683 | -35% | 1 | 1 | 0% | 2,400 | 5,467 | +128% | 0 | 0 | — |
case-02 | fail→fail | 5,017 | 5,225 | +4% | 1 | 1 | 0% | 1,025 | 4,782 | +367% | 0 | 0 | — |
case-03 | fail→pass | 11,453 | 7,194 | -37% | 1 | 1 | 0% | 2,311 | 5,409 | +134% | 0 | 0 | — |
case-04 | pass→pass | 6,685 | 4,079 | -39% | 1 | 1 | 0% | 1,326 | 4,584 | +246% | 0 | 0 | — |
case-05 | pass→pass | 10,038 | 8,262 | -18% | 1 | 1 | 0% | 1,987 | 5,501 | +177% | 0 | 0 | — |
case-06 | pass→pass | 10,690 | 7,404 | -31% | 1 | 1 | 0% | 1,859 | 5,258 | +183% | 0 | 0 | — |
case-07 | pass→pass | 7,173 | 3,772 | -47% | 1 | 1 | 0% | 1,431 | 4,559 | +219% | 0 | 0 | — |
case-08 | pass→pass | 8,569 | 7,018 | -18% | 1 | 1 | 0% | 1,689 | 5,350 | +217% | 0 | 0 | — |
case-09 | pass→pass | 6,367 | 4,680 | -26% | 1 | 1 | 0% | 1,217 | 4,728 | +288% | 0 | 0 | — |
case-10 | pass→pass | 3,747 | 2,930 | -22% | 1 | 1 | 0% | 660 | 4,344 | +558% | 0 | 0 | — |
case-11 | pass→pass | 5,997 | 3,422 | -43% | 1 | 1 | 0% | 1,170 | 4,590 | +292% | 0 | 0 | — |
case-12 | pass→pass | 13,421 | 8,619 | -36% | 1 | 1 | 0% | 2,635 | 5,422 | +106% | 0 | 0 | — |
case-13 | pass→pass | 4,913 | 3,538 | -28% | 1 | 1 | 0% | 877 | 4,525 | +416% | 0 | 0 | — |
case-14 | pass→pass | 4,353 | 3,433 | -21% | 1 | 1 | 0% | 791 | 4,502 | +469% | 0 | 0 | — |
case-15 | pass→pass | 7,779 | 5,618 | -28% | 1 | 1 | 0% | 1,590 | 4,852 | +205% | 0 | 0 | — |
case-16 | fail→fail | 5,859 | 5,769 | -2% | 1 | 1 | 0% | 1,109 | 5,060 | +356% | 0 | 0 | — |
case-17 | pass→pass | 6,811 | 5,247 | -23% | 1 | 1 | 0% | 1,341 | 4,940 | +268% | 0 | 0 | — |
case-18 | pass→pass | 11,659 | 4,010 | -66% | 1 | 1 | 0% | 1,930 | 4,583 | +137% | 0 | 0 | — |
case-19 | pass→pass | 6,957 | 5,149 | -26% | 1 | 1 | 0% | 1,390 | 4,772 | +243% | 0 | 0 | — |
case-20 | pass→pass | 6,119 | 5,989 | -2% | 1 | 1 | 0% | 1,438 | 5,216 | +263% | 0 | 0 | — |
case-21 | fail→fail | 8,591 | 7,980 | -7% | 1 | 1 | 0% | 1,619 | 5,444 | +236% | 0 | 0 | — |
case-22 | pass→pass | 6,957 | 5,959 | -14% | 1 | 1 | 0% | 1,477 | 5,028 | +240% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +9 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.