Skip to content

Embeddings & Vector Databases

Companion notes for HuggingFace NLP Course (chap 3) + Pinecone Learning (Phase 1). Objectif de ce fichier : passer de "je sais appeler une API d'embedding" à "je sais dimensionner, indexer, évaluer et exploiter un système de retrieval en prod, et défendre chaque chiffre en entretien".


🧠 Le modèle mental (à ancrer d'abord)

Un embedding est une fonction f: texte → ℝᵈ qui projette du sens dans un espace vectoriel, telle que la proximité géométrique ≈ la proximité sémantique. Tout le reste découle de ça :

  • Le modèle d'embedding définit la géométrie (ce qui est "proche").
  • La métrique de distance définit comment on mesure cette proximité.
  • L'index (HNSW, IVF, flat) définit le compromis vitesse/exactitude de la recherche du plus proche voisin.
  • L'éval (recall@k, nDCG) définit si tout ça marche réellement sur tes données.

Erreur de junior n°1 : croire que "choisir un bon modèle MTEB" suffit. Erreur de senior évitée : comprendre que le retrieval est une chaîne, et que le maillon faible est presque toujours le chunking et l'éval sur ton domaine, pas le modèle.

💡 Raisonnement staff : un embedding n'a de sens que relatif aux autres dans le même espace. Tu ne compares jamais deux vecteurs venant de deux modèles différents (ou deux versions du même modèle). Changer de modèle d'embedding ⇒ réindexation complète. C'est une décision d'architecture, pas un paramètre.


Concepts à maîtriser

1. Qu'est-ce qu'un embedding

Représentation vectorielle dense en haute dimension. Apprise telle que des textes sémantiquement proches ont des vecteurs proches. Contraste clé :

TypeExempleCe que ça captureFaiblesse
Lexical / sparseBM25, TF-IDF, SPLADEPrésence de mots exactsPas de synonymes, pas de paraphrase
Dense / sémantiqueOpenAI, Cohere, BGE, E5Sens, paraphrase, multilingueRate les termes rares exacts (codes, IDs, noms propres)

C'est précisément pourquoi la recherche hybride (lexical + dense) gagne en prod : les deux familles échouent sur des cas opposés.

2. Cosine vs Euclidean vs dot product

Le piège classique en entretien. La règle :

MétriqueFormuleQuand l'utiliserPiège
Cosine(a·b)/(‖a‖‖b‖)Défaut pour le texte ; insensible à la magnitude
Dot producta·bSi les vecteurs sont normalisés, dot = cosine (moins cher) ; sinon la magnitude pollueVecteurs non normalisés → biais vers les vecteurs longs
Euclidean (L2)‖a−b‖Quand la magnitude porte du sensSur du texte normalisé, monotone à cosine — souvent équivalent

Fait crucial : si ‖a‖ = ‖b‖ = 1 (vecteurs normalisés), alors cosine, dot et L2 produisent le même classement. La plupart des modèles modernes sortent des vecteurs normalisés ⇒ choisis dot product pour la perf et configure l'index en conséquence. Beaucoup d'embeddings (ex. la famille OpenAI text-embedding-3) sont déjà L2-normalisés.

⚠️ Le bug silencieux le plus courant : indexer en cosine des vecteurs déjà normalisés tout en re-normalisant côté requête, ou mélanger métrique d'index et métrique de requête. Vérifie que la métrique de l'index == celle attendue par le modèle.

3. Modèles d'embedding — comparaison

Toujours valider sur ton corpus via MTEB, mais les piliers (juin 2026) :

ModèleDimsForceCoût / hébergement
OpenAI text-embedding-3-large256–3072 (Matryoshka)EN très fort, API simplePayant à l'appel, pas de souveraineté
OpenAI text-embedding-3-small512–1536Bon rapport qualité/prixPayant à l'appel
Cohere embed-multilingual-v31024Multilingue / FR excellentAPI payante
Voyage voyage-3 / voyage-3-large1024–2048Top retrieval (souvent SOTA MTEB)API payante
BAAI/bge-m31024Open source, multilingue + dense/sparse/ColBERT en unSelf-host, gratuit
intfloat/multilingual-e5-large1024Open source, solide FRSelf-host, gratuit

💡 Pour un contexte FR/PME souverain : bge-m3 ou e5-large self-hosted couvrent 90 % des besoins sans envoyer de données à un tiers. Réserve les API payantes (Cohere/Voyage) quand le gain de recall justifie le coût récurrent et la fuite de données.

4. Embeddings multilingues

Un modèle multilingue projette FR et EN dans le même espace : une requête FR peut retrouver un doc EN (cross-lingual retrieval). Cohere embed-multilingual-v3 et bge-m3 sont les références. Piège : un modèle EN-only sur du FR ne plante pas — il dégrade silencieusement le recall. Mesure-le.

5. Dimensionnalité — le compromis

Plus de dimensions = plus d'expressivité, mais coût linéaire en stockage et en latence de scan.

DimsStockage / 1M vecteurs (float32)Usage typique
384~1.5 GBModèles compacts (MiniLM), prototypage
768~3 GBSweet spot open source (BGE base)
1024~4 GBMultilingue (Cohere, e5, bge-m3)
1536~6 GBOpenAI small / large tronqué
3072~12 GBOpenAI large pleine dim

Matryoshka Representation Learning (MRL) change la donne : les modèles text-embedding-3 et bge-m3 permettent de tronquer le vecteur (ex. 3072 → 512) en gardant l'essentiel du signal. Tu peux donc baisser la dimension après coup sans réentraîner — lève qualité/coût comme un curseur.

Calcul de coin de table à savoir refaire en entretien : N vecteurs × D dims × 4 octets (float32) = stockage brut. 10M × 1024 × 4 = ~41 GB de vecteurs bruts (avant index HNSW qui ajoute ~1.5–2× pour les graphes).

6. Quantization — le levier coût/scale que les juniors oublient

Réduire la précision des composantes :

TechniqueOctets/dimRéductionPerte de recall typique
float32 (baseline)40
float16 / bfloat162négligeable
scalar quant (int8)1~1–3 %
binary quant0.12532×5–15 % (rattrapable par re-ranking exact)

Pattern prod : binary/int8 pour le premier passage (rapide, mémoire-friendly) puis re-scoring float32 des top-k candidats (rescoring / oversampling). pgvector (halfvec, bit), Qdrant et Milvus supportent tous ça nativement. C'est le levier pour passer de 10M à 1B vecteurs sans exploser la RAM.

7. Indexation vectorielle — flat vs HNSW vs IVF

La recherche exacte du plus proche voisin (kNN) est O(N·D) — inacceptable au-delà de quelques 100k vecteurs en ligne. D'où les index ANN (Approximate Nearest Neighbor).

IndexTypeIdéeForceFaiblesse
FlatExactScan brut, distance à toutRecall = 1.0, simpleO(N), ne scale pas
HNSWGrapheGraphe navigable multi-couches (small-world)Latence ~log(N), excellent recall, ajouts incrémentauxRAM élevée (graphe en mémoire), build coûteux
IVFClusterk-means partitionne en cellules, on ne scanne que les nprobe plus prochesMémoire raisonnable, rapideRecall sensible au tuning, recherche sur frontières de cellules
IVF + PQCluster + compressIVF + Product QuantizationÉnorme scale (Milvus/FAISS)Build complexe, perte de précision

HNSW — les 3 paramètres à connaître par cœur :

  • M : nombre de voisins par nœud (connectivité du graphe). ↑ M ⇒ ↑ recall, ↑ RAM, ↑ build time. Typique : 16–64.
  • ef_construction : taille de la liste candidate pendant le build. ↑ ⇒ meilleur graphe, build plus lent. Typique : 100–400.
  • ef_search (runtime) : taille de la liste candidate à la requête. Le curseur recall/latence en prod — ajustable sans rebuild. ↑ ef_search ⇒ ↑ recall, ↑ latence.

💡 Raisonnement staff : ef_search est ton bouton de runtime. Tu builds le graphe une fois (M, ef_construction figés), puis tu tunes ef_search par requête selon le SLA. Un dashboard recall@10 vs p99 latency en fonction de ef_search est l'artefact d'éval que tout senior produit.

8. Recall@k vs precision — métriques de retrieval

  • Recall@k : fraction des documents pertinents qui apparaissent dans le top-k. La métrique du retrieval (on veut que la bonne réponse soit dans les k candidats envoyés au LLM).
  • Precision@k : fraction du top-k qui est pertinente.
  • nDCG@k : recall pondéré par le rang (un bon doc en position 1 vaut plus qu'en position 10). La métrique de référence pour le ranking.
  • MRR (Mean Reciprocal Rank) : 1/rang du premier bon doc. Pour le QA où une seule bonne réponse compte.

Deux notions de "recall" à ne pas confondre :

  1. Recall ANN : l'index approximatif retrouve-t-il les vrais plus proches voisins (vs flat) ? Mesure la qualité de l'index.
  2. Recall de retrieval : les docs pertinents pour la tâche sont-ils dans le top-k ? Mesure la qualité du système.

Un index avec recall ANN = 0.99 mais un mauvais modèle d'embedding aura un recall de retrieval pourri. Les deux se mesurent séparément.

9. Recherche hybride — BM25 + dense via RRF

Combiner lexical et sémantique. Le problème : leurs scores ne sont pas sur la même échelle (BM25 ∈ [0, ∞), cosine ∈ [−1, 1]). Solution robuste : Reciprocal Rank Fusion (RRF), qui ignore les scores et ne fusionne que les rangs :

RRF_score(d) = Σ_systèmes  1 / (k + rang_système(d))      # k ≈ 60 par convention

RRF est paramétriquement stable (le k=60 marche presque partout), ne demande aucune normalisation de score, et bat souvent une fusion pondérée mal calibrée. C'est le défaut sensé. L'alternative — normaliser puis pondérer (α·dense + (1−α)·lexical) — demande de tuner α par domaine.

⚠️ Piège RRF : le k du dénominateur aplatit les scores. Avec k=60, la différence entre le rang 1 et le rang 2 est minime (1/61 vs 1/62). Si ton domaine a un signal de rang très fort (le top-1 est presque toujours le bon), un k plus petit (10–20) accentue l'avantage des premiers rangs. Ne traite pas k=60 comme sacré — c'est un défaut, pas une loi.

10. Re-ranking — l'étage que les juniors confondent avec le retrieval

Le retrieval (bi-encoder : on embed requête et docs séparément, puis on compare des vecteurs) est rapide mais grossier : il ne voit jamais la requête et le doc ensemble. Un cross-encoder (re-ranker) prend la paire (requête, doc) en entrée unique et sort un score de pertinence — beaucoup plus précis, mais O(k) appels modèle par requête, donc inutilisable pour scanner des millions de docs.

D'où l'architecture en deux temps, universelle en prod :

ÉtageModèleRôleLatence
Retrieval (rappel)bi-encoder + ANNramène top-k candidats (k ≈ 50–200)~10–50 ms
Re-ranking (précision)cross-encoder (ex. BAAI/bge-reranker, Cohere Rerank, Voyage rerank)re-score ces k candidats, garde top-n (n ≈ 5–10)~50–300 ms
FamilleVu par le modèleCoûtQuand
Bi-encoder (embedding)requête et doc séparémentembed une fois, compare cheapretrieval de masse (millions de docs)
Cross-encoder (re-ranker)requête + doc ensemble1 forward pass / pairere-ranking d'un petit top-k
Late interaction (ColBERT, bge-m3 ColBERT)tokens vs tokens (MaxSim)entre les deux, index plus lourdcompromis qualité/coût intermédiaire

💡 Raisonnement staff : le re-ranking est le levier de précision le plus rentable du système. Tu gagnes souvent +5 à +15 points de nDCG@10 en re-rankant un top-50 dense, pour un surcoût de latence borné (tu re-scores 50 paires, pas 10M). La règle : élargis le top-k du retrieval (oversampling) puis re-ranke. Un retrieval qui ramène top-10 directement au LLM sans re-ranking laisse de la précision sur la table. Mais attention au budget latence : le cross-encoder est sur le chemin critique de chaque requête.


Vector DB comparison (juin 2026)

DBTypeWhen to use
pgvectorPostgres extAlready on Postgres, <50M vectors, default FR/PME
QdrantStandaloneSelf-hosted, sovereignty, fast Rust, EU
PineconeManaged"Just works", AWS-heavy clients
WeaviateHybridBuilt-in hybrid search, GraphQL queries
ChromaEmbeddedPrototyping, notebooks only
MilvusStandaloneMassive scale (>100M vectors), GPU
ElasticSearch engineExisting Elastic stack, hybrid out of the box

Comment un staff engineer choisit

La question n'est pas "quelle est la meilleure DB" mais "quelle contrainte domine ?" :

  • Tu es déjà sur Postgres et < 50M vecteurspgvector, sans hésiter. Une seule source de vérité, transactions ACID, joins SQL entre métadonnées et vecteurs, ops que ton équipe maîtrise déjà. La complexité opérationnelle d'une DB dédiée n'est pas justifiée. Active HNSW (pgvector ≥ 0.5) et halfvec pour la quantization.
  • Souveraineté / RGPD / on-prem EUQdrant (Rust, rapide, filtrage par payload de premier ordre) ou Milvus si très gros volume.
  • Tu veux zéro ops et un budget cloudPinecone ou Qdrant Cloud.
  • > 100M vecteurs, besoin GPUMilvus.
  • Filtrage par métadonnées massif (ex. multi-tenant, ACL par utilisateur) → vérifie le pre-filtering vs post-filtering : post-filtering peut vider ton top-k si le filtre est sélectif. Qdrant et Milvus font du pre-filtering natif ; pgvector dépend de la stratégie de l'index.

⚠️ Piège multi-tenant : si chaque requête filtre tenant_id = X, un post-filtering naïf récupère top-k global puis filtre — et peut renvoyer 2 résultats sur 10 demandés. Toujours valider que ta DB fait du filtered ANN (pre-filtering) sous charge.


⚙️ Considérations de production (le niveau senior)

Latence

Budget typique d'une requête RAG : embed query (20–80ms API / 5ms local GPU) + ANN search (5–50ms) + re-rank (50–200ms si cross-encoder) + LLM (1–10s). Le retrieval est rarement le goulot — mais l'embedding de la requête via API ajoute un aller-retour réseau. Cache les embeddings de requêtes fréquentes.

Coût

  • Indexation one-shot : N docs × coût d'embedding. 1M chunks × $0.13/1M tokens (OpenAI small) × ~500 tokens/chunk ≈ $65 pour tout indexer. Trivial.
  • Coût récurrent : embedding de chaque requête (volume × prix) + stockage + compute de l'index. C'est le coût récurrent qui décide self-host vs API à l'échelle.
  • Re-indexation : changer de modèle = ré-embedder tout le corpus. Budgète-le comme une migration.

Observabilité

Logge par requête : latence ANN, ef_search effectif, recall@k sur un golden set échantillonné, score du top-1 (un top-1 bas = requête hors distribution). Un retrieval qui dérive est invisible sans golden set versionné.

Sécurité & souveraineté

  • Fuite de données : envoyer chunks/requêtes à une API d'embedding tierce = data egress. Pour de la donnée sensible FR, self-host (bge-m3 / e5).
  • Inversion d'embedding : on peut partiellement reconstruire le texte source depuis un vecteur (attaques de type embedding inversion). Traite les vecteurs comme de la donnée sensible, pas comme des hashes anonymes.
  • Poisoning : un attaquant qui peut insérer des docs dans l'index peut détourner le retrieval (prompt injection indirect). Filtre/authentifie l'ingestion.

Le chunking — là où 80 % des systèmes RAG échouent

Le meilleur modèle d'embedding ne sauvera pas un mauvais chunking. Règles :

  • Chunk par unité sémantique (paragraphe, section), pas par nombre de tokens fixe aveugle.
  • Overlap de 10–20 % pour ne pas couper une idée en deux.
  • Garde le contexte : préfixe chaque chunk de son titre/section (contextual retrieval). Embedder « Le taux est de 3 % » sans contexte est inutile — 3 % de quoi ?
  • Teste plusieurs stratégies de chunking avec ton éval recall@k. C'est le levier #1, avant le choix du modèle.

💡 Contextual Retrieval (technique Anthropic) : avant d'embedder un chunk, on demande à un LLM de générer 1–2 phrases situant ce chunk dans le document entier (« Ce passage provient du rapport Q3 2025 de la société X et décrit la politique de remboursement… »), puis on préfixe le chunk de ce contexte avant l'embedding et le BM25. Coût : un appel LLM par chunk à l'indexation (one-shot, amorti par le prompt caching du document parent). Gain rapporté : −35 % de taux d'échec du retrieval, −49 % combiné avec un re-ranker. Le pattern complet que défend un staff engineer aujourd'hui : contextual chunks → hybride (dense + BM25 contextualisés) → re-ranking.


🏋️ Exercices

Progression du concret vers le production-grade. Chaque exercice a un Objectif et un Indice/Solution.

Exercice 1 — Bench multi-modèles honnête

Objectif : encoder 1000 docs avec 3 modèles (1 OpenAI, 1 Cohere/Voyage, 1 open source type bge-m3) et comparer recall@5 et nDCG@10 sur 50 requêtes avec ground truth. Indice/Solution : construis un golden set de 50 paires (requête, doc_pertinent_id). Pour chaque modèle : embed corpus → index flat (recall ANN = 1.0 pour isoler la qualité du modèle) → embed requêtes → top-5 → compte les hits. Tableau final : modèle × (recall@5, nDCG@10, dims, latence d'embed, coût). Le piège : un modèle peut gagner en EN et perdre en FR — sépare les métriques par langue.

Objectif : sur 100k vecteurs réels, tracer la courbe recall@10 (vs flat) en fonction de ef_search et de la latence p99. Trouver le point qui donne recall ≥ 0.95 au p99 minimal. Indice/Solution : flat search = ground truth des vrais voisins. Pour ef_search ∈ {10, 25, 50, 100, 200, 400} : mesure recall@10 et p50/p99 latence sur 1000 requêtes. Tu obtiens une courbe en plateau — le bon ef_search est juste avant le plateau. Note que M et ef_construction figent la borne max de recall : si tu plafonnes à 0.92, rebuild avec un M plus grand.

Exercice 3 — Hybride RRF qui bat le dense pur

Objectif : implémenter BM25 + dense fusionnés par RRF, et démontrer sur un set de requêtes où il bat chaque système isolé. Indice/Solution : prends des requêtes "piège" qui contiennent des termes exacts rares (codes produits, noms propres, numéros de version). Le dense seul va les rater, BM25 seul ratera les paraphrases. RRF(d) = Σ 1/(60 + rang). Compare recall@10 : dense_seul / bm25_seul / hybride. Si l'hybride ne gagne pas, c'est que ton set de test ne contient pas de cas lexicaux — c'est un résultat aussi (ton domaine n'a peut-être pas besoin d'hybride).

Exercice 4 — Re-ranking : prouve le gain de précision et défends son coût

Objectif : ajouter un cross-encoder au-dessus d'un retrieval dense et mesurer le delta nDCG@10, puis décider du top-k d'oversampling optimal sous budget latence p99. Indice/Solution : pipeline = dense top-k → re-ranker (bge-reranker ou Cohere Rerank) → top-10. Trace nDCG@10 et p99 latence en fonction de k pour k ∈ {10, 25, 50, 100, 200}. Tu verras le nDCG monter puis plafonner (re-ranker un top-200 n'aide plus si le bon doc était déjà dans le top-50) pendant que la latence croît linéairement (chaque candidat = 1 forward pass). Le bon k est au coude de la courbe nDCG, sous ton SLA p99. Piège à éviter : si le re-ranker n'améliore pas le nDCG, ton retrieval ramène peut-être déjà un top-10 parfait — le re-ranking ne crée pas de pertinence, il réordonne ce que le retrieval a ramené. Défends le chiffre : « re-ranker un top-50 nous donne nDCG 0.81 vs 0.68 sans, pour +120 ms p99 — acceptable car le LLM derrière coûte 3 s. »

Exercice 5 — Quantization sous contrainte mémoire

Objectif : prendre 1M vecteurs 1024-dim, les passer en int8 scalar quant puis binary quant + rescoring float32, et défendre le compromis recall/RAM/latence. Indice/Solution : mesure RAM (float32 ≈ 4GB → int8 ≈ 1GB → binary ≈ 128MB), recall@10 et latence à chaque niveau. Pour binary : récupère top-100 en binaire (rapide) puis re-score ces 100 en float32 (oversampling factor 10×) et garde top-10. Tu dois montrer un recall quasi-float32 à 1/32 de la RAM. Défends le chiffre : « binary + rescoring × 10 nous donne recall 0.94 vs 0.96 float32, pour 30× moins de RAM — viable jusqu'à ~500M vecteurs sur un seul nœud. »

Exercice 6 — Casse-le puis répare-le : le filtrage multi-tenant

Objectif : monter un index avec tenant_id en métadonnée, provoquer un top-k vidé par du post-filtering, puis le réparer avec du pre-filtering (filtered ANN). Indice/Solution : indexe 1M vecteurs répartis sur 1000 tenants (1000 vecteurs chacun). Requête avec tenant_id = X en post-filtering : récupère top-50 global puis filtre → tu obtiens souvent < 10 résultats car la majorité du top-50 appartient à d'autres tenants. Reproduis le bug, mesure le recall effondré. Répare : active le pre-filtering (Qdrant payload index / pgvector partial index / Milvus). Re-mesure. La leçon à verbaliser : « post-filtering casse le contrat top-k dès que le filtre est sélectif. »

Exercice 7 — Défends le système de bout en bout (capstone)

Objectif : assembler corpus FR/EN mixte → chunking contextuel (Contextual Retrieval) → bge-m3 self-hosted → pgvector HNSW + quantization → hybride RRF → re-ranking → éval recall@k / nDCG@10 versionnée. Puis répondre, chiffres en main, à : « pourquoi ce modèle, cette dim, cet index, cette métrique, ce re-ranker ? » Indice/Solution : le livrable n'est pas le code, c'est la note d'architecture avec un chiffre derrière chaque décision : recall@10 mesuré, p99 latence, $/mois à volume cible, GB de RAM, et la raison du self-host (souveraineté FR). Inclus le golden set versionné et le dashboard ef_search vs latence. C'est exactement le dossier qu'un staff engineer présente en design review.


🎤 En entretien

  • « Cosine ou dot product pour du texte ? » → Si les vecteurs sont normalisés (cas de la plupart des modèles modernes), les deux donnent le même classement : prends dot product, c'est moins cher. Sinon cosine, pour neutraliser la magnitude.
  • « HNSW vs IVF, tu choisis quoi et pourquoi ? » → HNSW : meilleur recall et ajouts incrémentaux, mais gourmand en RAM (graphe en mémoire). IVF(+PQ) : moins de RAM, scale énorme, mais recall sensible au tuning de nprobe. Sous ~50M vecteurs et avec de la RAM : HNSW. Au-delà ou sous contrainte mémoire : IVF+PQ (Milvus/FAISS).
  • « Comment tu mesures que ton retrieval marche ? » → Deux recalls distincts : recall ANN (l'index retrouve-t-il les vrais voisins vs flat) et recall de retrieval (les docs pertinents sont-ils dans le top-k) sur un golden set versionné. Plus nDCG@10 pour le ranking. Sans golden set, on ne mesure rien — on espère.
  • « Pourquoi la recherche hybride bat souvent le dense seul ? » → Lexical et dense échouent sur des cas opposés : le dense rate les termes exacts rares (codes, IDs, noms propres), le lexical rate les paraphrases et le multilingue. RRF les fusionne sur les rangs (pas les scores), donc sans calibration fragile.
  • « Bi-encoder vs cross-encoder, et où mets-tu chacun ? » → Bi-encoder (embedding) : on encode requête et docs séparément, comparaison de vecteurs O(1) par paire → retrieval de masse. Cross-encoder (re-ranker) : voit la paire (requête, doc) ensemble, 1 forward pass par paire → bien plus précis mais O(k). Architecture : bi-encoder ramène un top-k large (oversampling), cross-encoder re-ranke ce petit ensemble. On ne re-ranke jamais des millions de docs.
  • « Ton retrieval ramène le bon doc dans le top-50 mais le LLM répond mal. Que fais-tu ? » → C'est un problème de ranking, pas de recall : le bon doc est là mais noyé. Ajoute un re-ranking (cross-encoder) pour le remonter dans le top-3–5 effectivement envoyé au LLM, et mesure le gain en nDCG@10, pas en recall@k (qui était déjà bon).
  • « Je passe de 1024 à 3072 dims, qu'est-ce qui change en prod ? » → Stockage et latence de scan ↑ linéairement, RAM de l'index HNSW ↑, et réindexation complète obligatoire (espaces incompatibles). Avant de monter en dim, vérifie via MRL si tronquer un gros modèle ne suffit pas — souvent oui.

Embedding model leaderboard

→ Always check MTEB Leaderboard before choosing — et valide sur ton propre corpus, le classement global ne prédit pas ta tâche.

Current top picks (juin 2026) :

  • General EN : OpenAI text-embedding-3-large (256–3072 dims, Matryoshka) ou Voyage voyage-3-large
  • Multilingual / FR : Cohere embed-multilingual-v3 (API) ou BAAI/bge-m3 (open source, self-host)
  • Open source polyvalent : BAAI/bge-m3 (dense + sparse + ColBERT en un modèle) ou intfloat/multilingual-e5-large
  • Souveraineté FR self-hosted : bge-m3 / e5-large
  • Re-rankers (cross-encoders) : BAAI/bge-reranker-v2-m3 (open source, multilingue), Cohere Rerank ou Voyage rerank (API)

Resources

  • Course : HuggingFace NLP Course chap 3
  • Course : Pinecone Learning Center
  • Paper : Dense Passage Retrieval (Karpukhin 2020) — les fondations du dense retrieval
  • Paper : HNSW (Malkov & Yashunin 2018) — l'algo d'index de référence
  • Paper : Matryoshka Representation Learning (Kusupati 2022) — la troncature de dims
  • Paper : ColBERT (Khattab & Zaharia 2020) — late interaction, le compromis entre bi- et cross-encoder
  • Article : Anthropic — Contextual Retrieval (préfixer les chunks de leur contexte avant embedding ; −35 % d'échec retrieval, −49 % avec re-ranker)
  • Tool : MTEB Leaderboard
  • Article : "How HNSW works" — Pinecone blog
  • Doc : pgvector README (HNSW, halfvec, quantization binaire)

My notes

Bibliothèque tech perso — Achref