Aller au contenu principal
Retour au journal
IA26 avril 202610 min de lecture

RAG en 2026 : pourquoi 80% des projets échouent (et le pattern qui marche)

Trois erreurs d'architecture font échouer la majorité des RAG en production. Voici ce que nous voyons en audit, et la stack qui passe la barre des 85% de précision.

ParPatrice Huetz

Un client fintech nous appelle un mardi matin. Leur agent de support, branché sur leur base de connaissances avec un RAG « state-of-the-art », vient de coûter 4 200 € de transactions perdues. Un développeur junior a appliqué une suggestion de l'agent : un snippet d'intégration Stripe, sûr de lui, parfaitement formaté. Sauf qu'ils utilisent Adyen depuis trois ans. Le LLM n'a jamais vu leur code — il a juste halluciné ce qu'il avait vu le plus souvent sur GitHub. Le RAG était mal configuré : retrieval naïf, pas de reranking, embeddings génériques. Voici les trois erreurs qu'on retrouve dans 80% des audits RAG, et l'architecture qui marche.

Pourquoi un RAG « qui marche en démo » se casse en production

En démo, le RAG semble magique. Vous chargez 50 PDF, vous posez trois questions, vous obtenez trois réponses correctes, le client signe. Six semaines plus tard, le support vous remonte que l'agent répond à côté une fois sur quatre. Pourquoi ?

Parce qu'un RAG enchaîne quatre maillons fragiles : chunking, embedding, retrieval, augmentation. Si un seul lâche, l'agent hallucine ou rate la bonne source. Et un retrieval correct sur 100 documents ne garantit rien sur 100 000.

Les chiffres que nous mesurons en audit chez nos clients :

MétriqueDémo (50 docs)Production (50 000 docs)
Précision @580–90 %45–65 %
Hallucinations< 5 %18–32 %
Latence p95800 ms3 200 ms
Coût mensuel embeddings2 €480 €

Le projet ne « rate » pas brutalement. Il dérive lentement, jusqu'au jour où un utilisateur applique une suggestion fausse et que ça coûte de l'argent réel.

Un RAG qui répond « je ne trouve pas l'information dans le contexte fourni » est un RAG qui marche. Un RAG qui invente avec assurance est un RAG cassé. La différence se joue dans le system prompt et le prompt de retrieval.

La stack minimale qui passe en production

Voici le pipeline que nous déployons par défaut chez nos clients. Pas de framework lourd, pas de LangChain — quatre composants, 200 lignes de TypeScript ou Python.

// 1. Indexation (offline, à chaque déploiement)
const chunks = chunkByAST(file);          // Découpe par fonctions/classes
const embeddings = await localEmbedder.embedBatch(chunks); // MiniLM local
await vectorDb.upsert(chunks, embeddings); // Qdrant ou pgvector

// 2. Runtime (à chaque requête)
const queryEmb = await localEmbedder.embed(question);
const semantic = await vectorDb.search(queryEmb, 20);     // Sémantique
const keyword  = await vectorDb.bm25(question, 20);       // BM25
const fused    = reciprocalRankFusion([semantic, keyword]); // RRF
const reranked = await crossEncoderRerank(question, fused).slice(0, 5);

// 3. Augmentation
const answer = await llm.chat(buildPrompt(question, reranked));

Quatre composants, dans cet ordre — et chaque mot compte.

ComposantChoix par défautCoût mensuelQuand changer
ChunkingAST (tree-sitter)0 €Jamais sauf langage exotique
EmbeddingsXenova/all-MiniLM-L6-v2 local0 €Multilingue → BGE-M3
Vector DBpgvector si déjà Postgres, Qdrant sinon20–80 €> 1 M chunks → Qdrant cluster
Rerankerbge-reranker-v2-m30 € (CPU)Latence < 200 ms → API Cohere
Commencez toujours avec pgvector si vous avez déjà Postgres. Ajouter une dépendance Qdrant pour 30 000 chunks, c'est de l'over-engineering qui vous coûtera six mois de maintenance.

Choisir sa vector DB en 2026 : la décision en 3 questions

La question « quelle vector DB ? » occupe trop de réunions pour ce qu'elle apporte. Trois questions règlent 95 % des cas :

  1. Avez-vous déjà Postgres en production ? Oui → pgvector. Pas de débat. L'extension est mature depuis 2023, l'index HNSW est natif depuis 0.5, vous évitez une dépendance.
  2. Dépassez-vous 5 millions de chunks ? Oui → Qdrant ou Weaviate cluster. Postgres + pgvector tient jusqu'à 2–3 M chunks confortablement, au-delà la latence p95 se dégrade.
  3. Avez-vous des contraintes de souveraineté (santé, défense, banque) ? Oui → Qdrant self-hosted ou Milvus. Évitez Pinecone et les SaaS US par défaut.

Tout le reste — Pinecone, Vespa, Chroma, Marqo — est de l'optimisation prématurée pour un projet B2B classique.

Pourquoi 80% des projets échouent : les trois erreurs qu'on retrouve à chaque audit

Pipeline RAG en production

Erreur 1 — Chunking par caractères ou par lignes fixes

Le piège classique. Vous découpez vos documents tous les 500 caractères ou toutes les 100 lignes. C'est rapide, c'est trivial, c'est faux.

Une fonction de 80 lignes coupée en deux donne deux chunks dont aucun n'est utilisable seul. Le LLM voit la moitié haute (signature, début de logique) ou la moitié basse (return, gestion d'erreur) — jamais les deux. Il extrapole le reste, donc il hallucine.

Le bon découpage respecte les frontières sémantiques : fonctions, classes, sections de doc. Notre benchmark interne sur 12 codebases clients :

Méthode de chunkingPrécision @5Effort d'implémentation
Caractères fixes (500)60 %Trivial
Lignes fixes (100)65 %Trivial
Split sur regex function75 %Faible
AST (tree-sitter)85 %Moyen
AST + imports propagés92 %Élevé

Le saut de 65 % à 85 % de précision pour deux jours de travail est l'investissement RAG le plus rentable que vous puissiez faire.

L'outil qu'on utilise par défaut : tree-sitter. Il couvre 40+ langages, génère un AST en quelques millisecondes, et permet d'extraire les frontières sémantiques sans parser maison. Pour du Markdown ou de la documentation, on coupe sur les H2/H3 — un H3 == un chunk, avec le H2 parent injecté en préfixe pour préserver le contexte.

Erreur 2 — Recherche sémantique seule

C'est l'erreur la plus contre-intuitive. La recherche par embeddings est censée « comprendre le sens » — donc on l'utilise seule, et on rate systématiquement les noms exacts.

Demandez à un RAG sémantique de trouver la classe PaymentProcessor. Il va vous remonter TransactionHandler, BillingService, OrderManager — tous sémantiquement proches. Mais PaymentProcessor ? Probablement pas dans le top-5, parce que son embedding ressemble à 200 autres classes dans votre code.

La correction tient en trois lignes : ajoutez BM25 en parallèle, fusionnez avec Reciprocal Rank Fusion. C'est dans toutes les vector DB modernes (pgvector 0.7+, Qdrant, Weaviate). L'impact mesuré chez un client SaaS :

StratégiePrecision@5Recall@5
Sémantique seule72 %65 %
BM25 seul68 %58 %
Hybride + RRF85 %78 %

Erreur 3 — Pas de reranking, top-20 envoyé brut au LLM

L'argument économique a la peau dure : « le reranker coûte 50 ms supplémentaires, donc on le saute ». Sauf que sans reranker, vous envoyez 20 chunks au LLM dont 12 ne sont pas pertinents. Ces 12 chunks parasites :

  1. Diluent l'attention du modèle sur les bonnes sources.
  2. Coûtent en tokens : 20 chunks × 500 tokens = 10 000 tokens d'input à chaque requête.
  3. Augmentent le risque d'hallucination : le LLM mélange des fragments hors-sujet avec les bons.

Un cross-encoder local (bge-reranker-v2-m3) tourne en 80 ms sur CPU pour 20 candidats. L'économie de tokens compense largement la latence : nous mesurons -40 % de tokens consommés et -25 % d'hallucinations sur les déploiements clients.

Si vous utilisez Claude ou GPT-4 et que votre facture mensuelle dépasse 500 €, le reranker se rentabilise en moins de deux semaines. Calcul : 0,003 $ / 1k tokens × 4 000 tokens économisés × 1 000 requêtes/jour = 360 € / mois.

L'erreur bonus que personne n'évoque : pas de citation des sources

Même avec un pipeline parfait, un agent qui ne cite pas ses sources reste un agent qui hallucine de manière indétectable. Le pattern qu'on impose à chaque déploiement : forcer le LLM à inclure dans sa réponse les identifiants des chunks qu'il a utilisés, avec un format strict ([doc-42:fonction-submitTransaction]). En sortie, on parse ces tags et on les transforme en liens cliquables.

Bénéfice double : (1) l'utilisateur peut vérifier la source en un clic, (2) on détecte les hallucinations en regardant les réponses sans tags ou avec des tags inventés. Sur le projet fintech évoqué en intro, ce simple ajout a baissé de 40 % les remontées « l'agent dit n'importe quoi » — non pas parce que l'agent s'améliorait, mais parce que les utilisateurs validaient eux-mêmes en cliquant sur la source.

Edge cases : où le pattern « marche » casse

Cas 1 : codebases legacy sans structure exploitable

Un client avait 1,2 million de lignes de COBOL et de PL/SQL générées par des outils des années 90. Pas d'AST tree-sitter pour ça. Solution : chunking par procédure stockée pour PL/SQL (split sur CREATE OR REPLACE), chunking par paragraphe nommé pour COBOL. Précision tombée à 78 % — acceptable pour le cas d'usage (refactoring assisté), pas pour du Q&A client.

Cas 2 : documents très longs (> 10k tokens) à indexer entiers

Un éditeur juridique nous a confié 40 000 contrats de 30 à 200 pages. Découper par paragraphe perd le contexte (« comme stipulé à l'article 3.2 »). Solution : indexation hiérarchique — un embedding par section + un embedding par document complet. Le retrieval cherche d'abord le bon contrat, puis la bonne section. +15 points de précision vs flat indexing.

Cas 3 : multilingue avec langues rares

Embeddings MiniLM couvre l'anglais. Pour du français, c'est OK. Pour de l'arabe, du japonais ou du polonais en mélange, il faut BGE-M3 ou multilingual-e5-large. Coût : 2× plus de RAM (1,5 Go vs 90 Mo), mais c'est la seule option viable. Tester avant : générer 200 paires question-réponse, mesurer recall@5 sur chaque langue.

SituationStack standard ?Adaptation
Codebase TypeScript / Python / GoAucune
Codebase legacy (COBOL, PL/SQL)⚠️Chunking custom par procédure
Documents > 50 pages⚠️Indexation hiérarchique
Multilingue (>3 langues)Embeddings multilingues, RAM 2×
Codebase > 5 M lignesSharding par module + retrieval en cascade

Cas 4 : RAG sur des données qui se contredisent

Un éditeur médical avait dans son corpus deux versions d'un même protocole, l'ancienne et la nouvelle, sans marquage clair. Le RAG remontait les deux, le LLM choisissait au hasard. Solution : enrichir chaque chunk avec des métadonnées de fraîcheur (date de validation, version, statut « actif »/« déprécié ») et filtrer au retrieval par status = active AND date >= '2025-01-01'. Précision passée de 71 % à 93 % en deux jours, sans toucher aux embeddings.

Cette approche — chunks + métadonnées filtrables — est ce que la littérature appelle parfois le « RAG hybride » ou le « metadata-aware RAG ». C'est rarement abordé dans les tutos parce que ce n'est pas sexy, mais c'est ce qui distingue un RAG qui marche d'un RAG qui devine.

Ce qu'il faut retenir

Trois règles, dans cet ordre :

  1. Le chunking est plus important que le modèle d'embedding. Un AST chunking avec MiniLM bat un chunking naïf avec OpenAI text-embedding-3-large à tous les coups.
  2. La recherche hybride n'est pas optionnelle. Sémantique + BM25 + RRF ajoute 50 lignes de code et +13 points de précision.
  3. Le reranker se rentabilise en tokens économisés, pas seulement en qualité. Calculez l'économie avant de l'écarter pour cause de latence.

Pour aller plus loin :

  • Documentation pgvector : index HNSW vs IVFFlat selon la taille
  • Papier RRF original (Cormack et al., 2009) — la formule est triviale, l'effet ne l'est pas
  • Benchmark MTEB pour comparer les modèles d'embeddings sur votre langue

Conclusion

Un RAG en production qui dépasse 85 % de précision tient sur quatre composants choisis avec soin, pas sur un framework miracle. Le client fintech évoqué en intro est passé de 18 % d'hallucinations à 4 % en deux semaines, en changeant uniquement le chunking et en ajoutant un reranker. Aucun changement de modèle, aucune migration de vector DB.

Patrice Huetz
Auteur

Patrice Huetz

Co-fondateur — IA & Logiciel

Site auteur
XLinkedIn