Imagine le setup classique en 2026 : une app Symfony ou Laravel, un worker de queue qui vectorise chaque document uploadé, et un nœud Qdrant posé à côté de la base de données pour faire de la recherche sémantique sur tout ça. L'app en elle-même ne coûte pas cher à faire tourner. Le vector store, si, parce que les vecteurs réclament de la RAM, et la RAM est la ressource la plus chère que tu puisses louer. Qdrant 1.19 apporte deux réponses à ça, et je veux défendre l'idée que la moins glamour des deux, l'API unifiée de tiers mémoire, est la fonctionnalité pour laquelle la plupart d'entre nous devraient migrer, tandis que turbo4, le datatype qui fait les gros titres, mérite à la fois de l'admiration et un autocollant d'avertissement. Il jette définitivement tes vecteurs pleine précision, et cette décision ne devrait pas se prendre uniquement dans un fichier de config infra.
{
"vectors": {
"size": 1536,
"distance": "Cosine",
"datatype": "turbo4"
}
}Commençons par la victoire ennuyeuse. Avant la 1.19, contrôler où Qdrant gardait les données voulait dire jongler entre on_disk sur les paramètres de vecteurs, always_ram sur la config de quantization et on_disk_payload au niveau de la collection, trois flags avec trois noms à trois endroits. Le graphe HNSW lui-même, impossible de le placer : il vivait toujours en mémoire heap. La version 1.19 réduit tout ça à un seul paramètre memory avec trois valeurs : pinned (verrouillé en RAM), cached (sur disque, page cache préchauffé, évictable) et cold (sur disque, chargé paresseusement). Ça marche aussi bien sur les vecteurs, les liens HNSW, les copies quantizées, les payloads et les index de payload, et tu peux le changer sur une collection en production avec update_collection, sans rebuild. Pour ceux d'entre nous qui exploitent Qdrant comme un sidecar d'une app PHP, en lui parlant en HTTP, ça transforme la planification mémoire de folklore en vrai bouton de réglage.
Le bouton compte parce que l'arithmétique est moche. La RAM cloud tourne autour de $3 à $8 par Go et par mois ; le disque NVMe coûte environ $0.10 à $0.30. L'exemple des notes de version : un milliard de vecteurs float32 en 768 dimensions demandent environ 2.9 TB de stockage, et un déploiement tout en pinned réclame à peu près 3.7 TB de RAM. Déplace les originaux en stockage cold et n'épingle qu'une copie quantizée int8 pour la traversée du graphe, et tu tombes à environ 768 GB. À $5 par Go et par mois, ça fait $18,500 contre $3,840. Toi et moi ne sommes probablement pas à un milliard de vecteurs, mais le ratio survit très bien à la descente vers dix millions, et dix millions de chunks, c'est un chiffre parfaitement atteignable pour n'importe quel produit qui vectorise les documents de ses clients.
Maintenant, le couteau bien aiguisé. TurboQuant est arrivé en 1.18 comme méthode de quantization construite sur une idée de Google Research : faire pivoter le vecteur aléatoirement avant de le compresser, pour que l'information se répartisse uniformément entre les dimensions et que l'encodage 4 bits perde un peu partout au lieu de beaucoup à un seul endroit. En 1.18, cette copie 4 bits s'ajoutait à tes originaux float32, soit 36 bits par dimension au total. En 1.19, turbo4 devient un datatype. Fixe-le à la création de la collection et Qdrant ne stocke que la forme 4 bits. Pas de float32 sur disque, pas en RAM, nulle part. Dix millions de vecteurs text-embedding-3-small en 1536 dimensions passent d'environ 64 GB avec l'ancien schéma à quelque 7 GB. Pour les collections multi-vecteurs façon ColBERT, où chaque document transporte des dizaines d'embeddings de tokens, les économies se multiplient par vecteur.
Le prix à payer, c'est le rescoring, ou plutôt son absence permanente. Sans copie pleine précision, la traversée du graphe et le classement final tournent tous les deux sur des distances 4 bits, et le recall typique atterrit autour de 0.90 à 0.95, contre 0.97 à 0.99 quand tu rescores contre du float32. Voilà mon vrai point : cet écart est une décision produit déguisée en ops. La personne qui écrit datatype turbo4 dans une config de collection décide qu'environ un résultat pertinent sur vingt peut discrètement ne jamais revenir. Pour de la récupération de premier étage qui alimente un reranker cross-encoder, ou un widget de recommandations, ce compromis est souvent le bon. Pour tout cas où un match raté a des conséquences, une archive juridique, une recherche de conformité, celui qui déploie la config ne devrait pas être le seul à avoir validé.
Le contre-argument honnête, c'est que cette porte n'est pas vraiment verrouillée. Si tu as gardé le texte source, et tu aurais dû, tu peux tout re-vectoriser et reconstruire une collection float32 quand tu veux. C'est vrai, et ça enlève le côté dramatique de la décision. Mais re-vectoriser dix millions de chunks coûte de vrais dollars d'API et de vraies journées, et le mode de défaillance est vicieux précisément parce qu'il est silencieux : les régressions de recall remontent sous la forme d'un ticket de support qui dit que la recherche semble moins bonne, et personne ne soupçonne en premier un datatype de stockage choisi huit mois plus tôt. Donc avant de basculer, mesure le recall sur tes propres requêtes contre tes propres données, pas sur des vecteurs synthétiques. Fais aussi attention aux petites lignes : turbo4 est réservé aux vecteurs denses, et la distance Manhattan force la reconstruction complète du vecteur, donc reste sur Cosine, Dot ou Euclidean. Et il existe une voie médiane que j'aime sincèrement : empiler du TurboQuant 1 bit par-dessus turbo4 et rescorer contre les valeurs 4 bits, un meilleur recall que rien du tout, avec toujours l'empreinte disque du 4 bits.
Il faut dire que personne d'autre n'offre exactement ce compromis aujourd'hui. Weaviate a son propre schéma de quantization à base de rotation mais conserve toujours les vecteurs non compressés, Milvus ne descend pas sous les 8 bits, et le tier serverless de Pinecone n'expose aucun contrôle de compression ou de placement. Depuis le monde PHP, où le vector store est en général un service qu'on appelle depuis un worker plutôt qu'un système qu'on patche, je prendrai un bouton explicite plutôt qu'une décision managée opaque, à chaque fois, parce que la facture arrive à notre adresse dans les deux cas.
Voilà donc où j'atterris : migre pour les tiers mémoire, traite turbo4 comme une migration de schéma que tu ne peux pas annuler à bas coût, et mets le chiffre de recall dans la description de la pull request, là où un humain doit le lire. Maintenant dis-moi où se situe ta limite. Est-ce que tu ferais tourner turbo4 pour de la recherche utilisateur en production, et si oui, quel chiffre de recall, mesuré sur ton propre journal de requêtes, te mettrait assez à l'aise pour supprimer les originaux ? Je soupçonne que les réponses sous cette chronique iront de 0.99 à un haussement d'épaules, et je veux voir les deux.
Commentaires
Pas encore de commentaire — écris le premier.
Lance la discussion
Pas de compte ni de mot de passe — saisis simplement ton adresse e-mail et nous t’envoyons un lien de connexion à usage unique. Première visite ? Tout se met en place automatiquement.
Ton évaluation sera appliquée automatiquement après ta connexion.
Vérifie ta boîte mail
Nous avons envoyé un lien de connexion à …. Ouvre-le sur cet appareil — cet onglet te connectera automatiquement.
Rien reçu ? Vérifiez le dossier spam — et marquez le message « Non spam » pour qu'il arrive directement la prochaine fois.