
FAISS et Chroma tournent dans votre processus Python : parfait pour prototyper, insuffisant dès qu'un RAG doit être partagé entre applications, monter en charge ou filtrer finement. Qdrant est la réponse : une base vectorielle serveur, écrite en Rust, qui s'exécute comme un service auquel le code se connecte en réseau. Ce guide montre comment lancer Qdrant, créer une collection, y indexer des points avec leur payload, faire une recherche sémantique filtrée, et préparer le passage en production. C'est la base vectorielle de référence du parcours RAG. Public visé : développeur dont le RAG dépasse le stade du prototype.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Pourquoi une base vectorielle serveur plutôt qu'embarquée.
- Lancer Qdrant avec Docker.
- Créer une collection typée et y indexer des points.
- Attacher un payload à chaque vecteur.
- Rechercher et filtrer par payload — la base du multi-tenant.
Prérequis
Section intitulée « Prérequis »- Python 3.10+ et Docker.
- Une instance Ollama avec le modèle d'embedding
nomic-embed-text. - Comprendre les embeddings et avoir vu Chroma.
Pourquoi une base vectorielle serveur
Section intitulée « Pourquoi une base vectorielle serveur »FAISS et Chroma ont un point commun : elles vivent dans le processus Python qui les utilise. C'est leur force pour prototyper — rien à déployer — et leur limite dès qu'on industrialise.
Un RAG en production a d'autres besoins. Plusieurs applications — une API, un chatbot, un travail d'indexation — doivent interroger le même index en même temps. L'index doit survivre au redémarrage de n'importe lequel de ces clients. Et il doit tenir la charge de requêtes concurrentes. Une base embarquée ne fait rien de tout cela.
Qdrant est une base vectorielle serveur. Elle s'exécute comme un service indépendant ; les applications s'y connectent par le réseau. L'index est centralisé, partagé, persistant. Et Qdrant ajoute un filtrage par payload de premier ordre — la capacité qui rend possible le multi-tenant. C'est pourquoi le parcours RAG l'utilise comme base de référence pour tout ce qui dépasse le prototype.
Installer et lancer Qdrant
Section intitulée « Installer et lancer Qdrant »Qdrant se lance en une commande Docker. L'image officielle expose son API sur le port 6333.
docker run -d --name qdrant -p 6333:6333 qdrant/qdrantOn vérifie qu'il répond :
curl http://localhost:6333/# Doit renvoyer un JSON avec "title": "qdrant - vector search engine".Côté Python, on installe le client officiel :
pip install qdrant-client==1.18.0Créer une collection
Section intitulée « Créer une collection »Une collection est l'unité de stockage de Qdrant — l'équivalent d'une table. Elle est typée à sa création par deux paramètres : la dimension des vecteurs et la distance de comparaison.
from qdrant_client import QdrantClientfrom qdrant_client.models import Distance, VectorParams
DIMENSION = 768 # taille des vecteurs de nomic-embed-textCOLLECTION = "documentation"
client = QdrantClient(host="localhost", port=6333)if client.collection_exists(COLLECTION): client.delete_collection(COLLECTION)client.create_collection( COLLECTION, vectors_config=VectorParams(size=DIMENSION, distance=Distance.COSINE),)Les deux paramètres de VectorParams sont structurants. La size doit correspondre exactement à la dimension du modèle d'embedding — 768 pour nomic-embed-text ; un vecteur d'une autre taille sera rejeté. La distance fixe la mesure de proximité — COSINE est le choix standard pour des vecteurs de texte, le même que la similarité cosinus du guide sur les embeddings.
Indexer des points avec payload
Section intitulée « Indexer des points avec payload »Dans Qdrant, l'unité indexée est le point. Un point réunit trois choses : un identifiant, un vecteur, et un payload.
from qdrant_client.models import PointStruct
CORPUS = [ {"texte": "Un volume Docker conserve les données du conteneur.", "sujet": "docker", "annee": 2026}, {"texte": "Terraform décrit une infrastructure en code déclaratif.", "sujet": "terraform", "annee": 2024},]
vecteurs = vectoriser([d["texte"] for d in CORPUS])points = [ PointStruct(id=i, vector=vecteurs[i], payload=CORPUS[i]) for i in range(len(CORPUS))]client.upsert(COLLECTION, points=points)Le payload est l'atout de Qdrant. C'est un dictionnaire libre attaché au point : le texte d'origine, mais aussi toute métadonnée utile — un sujet, une année, une équipe propriétaire. Ce payload voyage avec le vecteur, et surtout il devient filtrable. La méthode upsert insère les points — ou les met à jour s'ils existent déjà, d'où son nom.
Rechercher dans la collection
Section intitulée « Rechercher dans la collection »La recherche se fait avec query_points : on fournit le vecteur de la question et le nombre limit de résultats voulus.
def rechercher(client, question, k=3, filtre=None): """Recherche les k documents les plus proches, avec filtre optionnel.""" resultat = client.query_points( COLLECTION, query=vectoriser([question])[0], limit=k, query_filter=filtre, with_payload=True, ) return [ {"texte": p.payload["texte"], "sujet": p.payload["sujet"], "score": p.score} for p in resultat.points ]query_points renvoie les points classés par similarité décroissante, chacun avec son score et son payload. L'option with_payload=True est ce qui ramène le texte et les métadonnées : sans elle, on n'obtiendrait que des identifiants et des scores, sans contenu.
Filtrer par payload
Section intitulée « Filtrer par payload »C'est la capacité qui distingue vraiment Qdrant. Le filtre restreint la recherche aux points dont le payload satisfait une condition — la recherche sémantique ne s'applique qu'à ce sous-ensemble.
from qdrant_client.models import FieldCondition, Filter, MatchValue
def filtre_sujet_annee(sujet, annee): """Construit un filtre Qdrant : payload sujet ET année.""" return Filter( must=[ FieldCondition(key="sujet", match=MatchValue(value=sujet)), FieldCondition(key="annee", match=MatchValue(value=annee)), ] )
# Chercher uniquement dans les documents Docker de 2026.resultats = rechercher(client, "conteneur", k=5, filtre=filtre_sujet_annee("docker", 2026))Un Filter se compose de FieldCondition — une condition sur une clé du payload. La clause must exige que toutes les conditions soient vraies ; il existe aussi should (au moins une) et must_not (aucune). Le filtre s'applique avant la recherche sémantique : un point hors filtre n'est jamais examiné, donc jamais renvoyé.
C'est le mécanisme du multi-tenant : plusieurs équipes ou clients partagent une seule collection, mais chaque recherche est cloisonnée à un périmètre par son filtre. Le guide sur le RAG en production en fait la pierre angulaire de la sécurité.
Qdrant en production
Section intitulée « Qdrant en production »Qdrant tient sa place du prototype à la production, mais l'usage réel demande quelques précautions.
La persistance d'abord : un volume monté, comme rappelé plus haut, pour que l'index survive aux conteneurs. Le déploiement ensuite : un docker compose pour un service simple, un déploiement Kubernetes pour de la haute disponibilité — Qdrant fournit les manifestes. La sécurité enfin : l'API se protège par une clé, et le trafic se chiffre en TLS — on n'expose jamais un Qdrant nu sur un réseau ouvert.
| Étape du projet | Base vectorielle |
|---|---|
| Prototype jetable | FAISS |
| Développement, métadonnées | Chroma |
| Production, service partagé, filtrage | Qdrant |
Le passage de l'une à l'autre ne remet jamais en cause le principe — vectoriser, indexer, rechercher. Seule la robustesse du stockage évolue. Apprendre Qdrant, c'est se donner la base qui tiendra du premier index au service en production.
Dépannage
Section intitulée « Dépannage »| Symptôme | Cause probable | Solution |
|---|---|---|
Connection refused sur le port 6333 | Qdrant non démarré | Lancer le conteneur qdrant/qdrant |
Erreur de dimension à l'upsert | size de la collection ≠ modèle d'embedding | Recréer la collection à la bonne dimension |
| Résultats sans texte | Payload non demandé | Passer with_payload=True à query_points |
| Le filtre ne restreint rien | Clé de payload ou valeur incorrecte | Vérifier les noms et types dans FieldCondition |
| Index perdu au redémarrage | Données dans le conteneur | Monter un volume sur /qdrant/storage |
À retenir
Section intitulée « À retenir »- Une base vectorielle serveur se partage entre applications, persiste et tient la charge — pas une base embarquée.
- Qdrant se lance en un conteneur Docker et s'interroge via son client Python.
- Une collection est typée par la dimension des vecteurs et la distance.
- Un point réunit un identifiant, un vecteur et un payload de métadonnées libres.
- Le filtre restreint la recherche par payload avant la similarité — la base du multi-tenant.
- Qdrant accompagne le projet du développement à la production, sans changer le principe.
Prochaines étapes
Section intitulée « Prochaines étapes »Pour aller plus loin
Section intitulée « Pour aller plus loin »- Documentation Qdrant — la référence de la base et de son client.