Abbeal

IA

Embeddings : c'est quoi, et comment les utiliser dans un RAG d'entreprise.

Vecteurs, similarité sémantique, choix du modèle, chunking, pièges multilingues FR/JA. Le guide concret pour construire un retrieval qui tient en production.

10 min

Vous avez construit votre premier RAG, connecté un LLM à vos docs internes, et… les réponses sont à côté de la plaque. Le modèle hallucine sur des sujets pourtant présents dans la base. Le problème ? 9 fois sur 10, ce n'est pas le LLM qui déconne, c'est le retrieval. Et au cœur du retrieval, il y a les embeddings.

Les embeddings sont la colonne vertébrale invisible de tout RAG en production. Ils transforment vos documents en vecteurs, permettent la recherche sémantique, et conditionnent la qualité de ce que vous allez injecter dans le contexte du LLM. Mal configurés, et c'est toute la chaîne qui s'effondre.

Ce guide couvre ce qu'on aurait aimé savoir avant de mettre en prod nos premiers RAG : l'intuition derrière les embeddings, comment choisir son modèle, découper ses documents, gérer le multilingue (y compris le japonais qui casse tout), et surtout comment évaluer qu'on ne construit pas sur du sable.

C'est quoi un embedding, concrètement ?

Un embedding, c'est un vecteur de nombres (typiquement 768 à 3072 dimensions) qui représente le sens d'un bout de texte. Deux phrases sémantiquement proches se retrouvent proches dans l'espace vectoriel, même si elles ne partagent aucun mot.

Exemple : « Comment résilier mon contrat ? » et « Procédure d'annulation d'abonnement » n'ont quasiment aucun terme en commun, mais leurs embeddings seront voisins. C'est ce qui permet au RAG de retrouver le bon document même quand l'utilisateur formule sa question différemment.

Techniquement, un modèle d'embedding est un réseau de neurones (souvent un transformer) entraîné pour projeter du texte dans cet espace vectoriel. On le passe une fois sur tous les chunks de documents (indexation), puis on l'utilise à chaque requête utilisateur pour encoder la question et chercher les chunks les plus proches par similarité cosinus.

Choisir son modèle d'embedding : dimensions, domaine, coûts

Plus de dimensions ≠ automatiquement mieux

La tentation est forte de prendre le modèle avec le plus de dimensions sur le leaderboard MTEB. En pratique, on benchmarke toujours 2-3 modèles sur les vraies questions métier avant de trancher.

Un modèle 1024 dimensions bien adapté à votre domaine (droit, médical, technique) bat régulièrement un modèle générique 3072 dimensions. Et les coûts d'infra ne sont pas neutres :

  • Stockage : 3× plus de dimensions = 3× plus de stockage dans la vector DB
  • RAM : les index HNSW chargent tout en mémoire ; sur 10M de chunks, ça compte
  • Latence : le calcul de similarité sur 3072 dim est plus lent, surtout à grande échelle

Modèles à considérer (fin 2024)

Quelques options qu'on utilise en prod, par cas d'usage :

  • text-embedding-3-large / text-embedding-3-small (OpenAI) : solides, multilingues, API managed. Pas open-source, coût par token.
  • intfloat/e5-mistral-7b-instruct : open-source, 4096 dim, très bon sur tâches complexes. Lourd à self-host.
  • sentence-transformers/all-MiniLM-L6-v2 : léger (384 dim), rapide, suffisant pour beaucoup de cas anglophones simples.
  • multilingual-e5-large : 1024 dim, multilingue réel (y compris japonais), bon compromis perf/coût.

On privilégie les modèles avec un contexte window >= 512 tokens pour pouvoir embedder des chunks substantiels sans les tronquer.

Self-host vs API managée

OpenAI embeddings : simple, pas d'infra à gérer, pricing prévisible. Mais vos données sortent, et vous êtes exposé aux rate limits / downtimes.

Self-host (HuggingFace + vLLM / TEI) : contrôle total, coûts fixes une fois l'infra payée, pas de data leak. Mais vous gérez scaling, monitoring, versions. Sur gros volume (>100k queries/jour), le self-host devient rentable.

Chunking : découper sans casser le sens

Le chunking est le talon d'Achille de 90 % des RAG qu'on audite. Un embedding ne code que ce qui est dans le chunk. Si vous coupez une phrase en deux ou qu'un concept s'étale sur 3 chunks disjoints, le retrieval échoue.

Stratégies de chunking

  1. Fixed-size + overlap : chunks de 512 tokens avec overlap de 50 tokens. Simple, générique, souvent suffisant pour de la doc technique.
  2. Semantic chunking : on détecte les transitions de sujet (embeddings consécutifs qui divergent) pour couper. Plus propre, mais plus lent à indexer.
  3. Structure-aware : on respecte les frontières markdown (headers, listes), les sections de PDF, les paragraphes. Préserve le contexte hiérarchique.
  4. Hybrid : fixed-size avec fallback sur les frontières de phrase. Compromis vitesse/qualité.

En pratique, on commence fixed-size + overlap, on mesure le recall, et on itère si nécessaire. Sur des corpus structurés (wikis internes, docs techniques), le structure-aware apporte un gain net.

Overlap et contexte

L'overlap évite qu'une phrase coupée en deux ne soit jamais retrouvée. 10-20 % de la taille du chunk est un bon point de départ. Trop d'overlap = explosion du nombre de chunks = coûts storage/latence.

On ajoute aussi souvent du contexte parent dans le chunk (titre de section, nom du document) pour que l'embedding capte « ce chunk parle de facturation, pas de support ». Ça peut être un simple préfixe : [Facturation] <contenu du chunk>.

Vector databases : stockage et recherche

Une fois les embeddings calculés, il faut les stocker et pouvoir requêter par similarité cosinus en <50ms. C'est le job de la vector DB.

Quelle vector DB ?

Les options se multiplient, voici celles qu'on utilise selon le contexte :

  • pgvector (Postgres) : extension Postgres, parfait si vous avez déjà du Postgres, méta-données relationnelles + vecteurs dans la même base. Scale jusqu'à ~1M vecteurs sans souci.
  • Qdrant : open-source, rapide, self-host facile (Docker), filtres riches, bon monitoring. Notre choix par défaut pour du self-host.
  • Pinecone / Weaviate cloud : managed, scale automatique, bon DX. Coût par vecteur stocké + queries, peut vite grimper.
  • Milvus : très scalable (clusters), overkill pour <10M vecteurs, utile si vous visez des centaines de millions.

Pour 80 % des RAG d'entreprise (<5M chunks), pgvector ou Qdrant suffisent largement.

Index HNSW et filtres

L'algorithme de recherche dominant est HNSW (Hierarchical Navigable Small World). Il construit un graphe multi-couches pour des recherches approximatives en log(n). Trade-off précision/vitesse configurable via ef_construction et ef_search.

En prod, on combine souvent similarité vectorielle + filtres métadonnées : « retrieval dans les docs du département Finance, langue FR, datant de moins d'un an ». La vector DB doit supporter ces filtres sans tuer les perfs (pre-filtering ou post-filtering selon la DB).

Multilingue : FR, EN, JA… et les pièges du japonais

Un corpus multilingue casse beaucoup d'hypothèses implicites des pipelines RAG anglophones.

Modèle d'embedding multilingue

Il faut un modèle réellement multilingue, entraîné sur vos langues cibles. Les modèles anglophones projettent souvent le français dans un sous-espace dégradé, et le japonais… encore pire.

On valide toujours le retrieval cross-lingue : une question en français doit pouvoir remonter un document en anglais si c'est le bon contexte. Certains modèles alignent mal les espaces vectoriels entre langues.

Le japonais casse tout

Le japonais n'a pas d'espaces, les tokenizers byte-level (type GPT) sur-segmentent, et les stratégies de chunking par phrase nécessitent un segmenteur dédié (pas de point final fiable).

  • Tokenizer : utiliser un modèle avec tokenizer adapté (SentencePiece multilingue, ou tokenizer japonais intégré).
  • Chunking : on utilise un splitter comme fugashi ou sudachipy pour détecter les frontières de phrases.
  • Overlap : plus critique en japonais, car couper au milieu d'un mot composé détruit le sens.

Sur un projet récent avec corpus FR/EN/JA, on a dû passer de text-embedding-ada-002 (performances JP médiocres) à multilingual-e5-large + chunking custom par langue. Le recall@5 sur questions JP est passé de 45 % à 78 %.

Évaluer la qualité du retrieval

Un embedding n'est jamais bon ou mauvais dans l'absolu. On mesure la qualité du retrieval qu'il permet. Sans éval, impossible de comparer deux modèles, deux stratégies de chunking, ou de détecter une régression après un changement.

Métriques de retrieval

  • Recall@k : sur les k premiers chunks renvoyés, quelle proportion contient la bonne réponse ? Recall@5 est le standard.
  • MRR (Mean Reciprocal Rank) : en moyenne, à quel rang apparaît le premier bon chunk ? Plus c'est haut, mieux c'est.
  • NDCG : prend en compte l'ordre des résultats, utile si vous avez des relevances graduées (pertinent / très pertinent).

On préfère Recall@5 + MRR : simples à comprendre pour les POs, suffisamment discriminants pour trancher entre options techniques.

Construire le jeu d'éval

Le jeu d'éval, c'est 50-200 paires (question, chunks de référence attendus). On le construit avec les experts métier, en partant des vraies questions utilisateurs (logs support, FAQ, user research).

Format minimal : un CSV question | doc_id | chunk_id | langue. On passe chaque question dans le retrieval, on mesure si les chunks attendus sont dans le top-k.

py
# Exemple simplifié d'éval recall@k def evaluate_recall(questions, vector_db, k=5): hits = 0 for q in questions: results = vector_db.search(q['text'], top_k=k) retrieved_ids = [r['chunk_id'] for r in results] if q['expected_chunk_id'] in retrieved_ids: hits += 1 return hits / len(questions)

On exécute cette éval en CI à chaque changement de modèle d'embedding, de stratégie de chunking, ou de mise à jour du corpus. Une régression de >5 points de recall = alerte.

Pièges classiques et retours terrain

Embedding les métadonnées… ou pas ?

Certains ajoutent titre, auteur, date dans le texte embedé. Avantage : l'embedding capte « ce chunk parle de RH ». Inconvénient : pollution si les métadonnées sont répétitives ou non sémantiques (IDs techniques).

On préfère stocker les métadonnées séparément et utiliser les filtres de la vector DB. L'embedding reste purement sémantique, on filtre après par département/langue/date.

Reranking : la deuxième passe

Le retrieval vectoriel renvoie ~20-50 candidats rapidement. On peut ensuite appliquer un reranker (cross-encoder) qui score finement chaque (question, chunk) et garde les top-5.

Le reranker est plus lent mais plus précis. Ça améliore MRR de 10-20 % sur des questions complexes. Modèles : cross-encoder/ms-marco-MiniLM, jina-reranker-v1, ou via Cohere Rerank API.

Drift du corpus et refresh des embeddings

Le corpus évolue (nouveaux docs, mises à jour). Il faut ré-embedder les chunks modifiés. On track les doc_id + hash du contenu, et on ré-indexe en delta plutôt que full reindex.

Attention : changer de modèle d'embedding = ré-indexer tout le corpus. Les vecteurs de deux modèles ne vivent pas dans le même espace, on ne peut pas les mélanger.

Coûts et dimensionnement

Quelques ordres de grandeur sur un corpus de 1 million de chunks (512 tokens / chunk, embedding 1024 dim) :

  • Indexation one-shot : ~4-8h sur GPU V100 (self-host) ou ~50-100$ d'API calls (OpenAI embeddings).
  • Stockage vector DB : ~4-6 Go en RAM (HNSW index), ~2-3 Go sur disque (Qdrant).
  • Latency retrieval : <30ms @ p95 pour top-20, sur infra standard (16 vCPU, 32 Go RAM).

Scale à 10M chunks : on passe à un cluster Qdrant ou Milvus, avec sharding. Latency reste <50ms si l'index tient en RAM distribuée.

En vrai, un RAG c'est 80 % de retrieval

Le LLM final ne fait que reformuler ce que le retrieval lui donne. Si les chunks renvoyés sont hors-sujet, même GPT-4 hallucinera. Un retrieval solide (embeddings adaptés, chunking propre, éval continue) est la différence entre un POC qui impressionne en démo et un système qui tient en prod sous la charge et les cas limites.

Chez Abbeal, on construit des RAG pour des environnements exigeants : multilingue, gros corpus, latence serrée, compliance data. Si vous êtes en train de scaler votre RAG et que vous butez sur le retrieval, les pièges du chunking multilingue ou l'évaluation en continu, [parlons-en](https://abbeal.com/contact). On a déjà fait les erreurs pour vous.

Vous avez un projet qui ressemble à ça ?

Parler à un architecte