← Resources
TUTORIAL · 2026-02-12
Construire un pipeline RAG en production sans LangChain (2026)
Vous pouvez livrer un pipeline RAG de production en quelques centaines de lignes en composant directement les SDK fournisseurs, pgvector et un reranker. Évitez les abstractions de LangChain tant que vous n'avez pas un besoin concret qu'elles résolvent réellement.
Pourquoi les équipes déballent LangChain en 2026
En 2026, retirer LangChain de la production est devenu un pattern d'ingénierie identifiable, avec des post-mortems publics d'équipes qui en faisaient l'évangélisation. Le procès est constant : abstractions empilées qui masquent ce qui est réellement envoyé au modèle, breaking changes fréquents entre versions mineures, et sessions de debug qui tournent à la spéléologie dans les wrapper classes.
Le basculement de fond, c'est que les SDK fournisseurs sont devenus bons. Les SDK OpenAI, Anthropic et Google embarquent désormais en first-class le streaming, les structured outputs, les tool calls et le batching. Voyage, Cohere et Jina exposent des endpoints REST propres pour les embeddings et le reranking. Postgres avec pgvector tient la recherche ANN jusqu'à environ 10 M de vecteurs sans base vectorielle dédiée.
Pour la plupart des charges RAG, le framework dont vous rêviez en 2023 tient désormais en quatre appels de fonction et une requête SQL. Le défaut raisonnable en 2026 est de partir des SDK bruts, d'ajouter une fine abstraction de pipeline quand la douleur est réelle, et de traiter les frameworks lourds comme opt-in.
Les cinq étapes que tout pipeline RAG doit avoir
Tout système RAG en production, quel que soit le framework, se décompose en cinq étapes identiques. Les nommer explicitement rend le code plus simple à tester et à remplacer par morceaux.
- Ingest : charger les documents sources, normaliser l'encodage, retirer le boilerplate.
- Chunk : découper en unités de retrieval avec IDs stables et metadata source.
- Embed et indexer : encoder les chunks dans un store vectoriel, en parallèle d'un index lexical pour la recherche hybride.
- Retrieve et rerank : tirer un large jeu de candidats puis affiner avec un reranker cross-encoder.
- Generate et citer : assembler un prompt avec le contexte récupéré et renvoyer des réponses attribuées à leurs sources.
Gardez chaque étape comme fonction pure aux entrées/sorties typées. L'étape de retrieve ne doit pas connaître le LLM qui générera ; l'étape de génération ne doit pas connaître le modèle d'embedding utilisé. Cette séparation est ce que les frameworks promettent et livrent rarement, parce qu'ils couplent les étapes par des objets de chain opaques. L'écrire vous-même prend un après-midi et supprime une catégorie de risque de mise à niveau.
Stratégies de chunking : sémantique, récursive et agentique
Le chunking est l'endroit où se gagne ou se perd la qualité RAG. Trois patterns dominent en 2026.
Le découpage récursif sur une hiérarchie de séparateurs (paragraphes, phrases, puis caractères) est la baseline. Rapide, déterministe, et suffisant pour la prose. Le chunking sémantique embed les coupures candidates et fusionne les chunks adjacents dont les embeddings sont proches, produisant des unités topiquement cohérentes au prix d'un coût d'ingestion plus élevé. Le chunking agentique demande à un petit LLM de proposer les points de coupure sur des documents structurés comme contrats ou transcripts, où les titres et frontières de tours comptent plus que le nombre de caractères.
def recursive_chunk(text, max_chars=1200, overlap=150):
seps = ["\n\n", "\n", ". ", " "]
def split(s, depth=0):
if len(s) <= max_chars or depth == len(seps):
return [s]
parts, sep = [], seps[depth]
for p in s.split(sep):
parts.extend(split(p, depth + 1))
return parts
raw = split(text)
return [raw[i] + raw[i+1][:overlap] for i in range(len(raw)-1)] + [raw[-1]]
Partez en récursif, mesurez, puis passez au sémantique uniquement sur les classes de documents où l'évaluation montre que cela paie.
Embeddings et rerankers : Voyage, BGE et Cohere
Le paysage des retrievers en 2026 est plus clair qu'il y a un an. Voyage AI, désormais filiale de MongoDB, propose voyage-3-large comme modèle dense polyvalent solide et a publié la famille voyage-4 début 2026, avec une variante mixture-of-experts visant le haut du classement RTEB. embed-v4 de Cohere reste l'autre tête d'affiche en production. Pour l'auto-hébergement en open-weights, bge-m3 de BAAI reste la valeur par défaut : un seul modèle supportant retrieval dense, sparse et multi-vecteurs sur plus de 100 langues, avec un contexte de 8 192 tokens.
Côté reranking, Cohere rerank-v3.5 est la valeur sûre : un modèle multilingue, des chunks de 4 096 tokens et environ 80-150 ms de latence p50 sur les payloads typiques. Voyage rerank-2 est compétitif et s'intègre proprement si vous utilisez déjà les embeddings Voyage.
Règle pratique : choisissez un seul embedder dense, un seul reranker, et figez la paire derrière une interface. Le swap ultérieur coûte une réindexation, pas une réécriture.
Câblage du retrieval, de la génération et des citations
Avec pgvector, vous obtenez recherche hybride et citations en SQL direct. Stockez les chunks avec leur document_id, leur embedding et un tsvector pour le rappel lexical. Récupérez un large jeu de candidats, rerankez, puis passez le top N au LLM avec des IDs de source explicites que le modèle est instruit de citer.
import psycopg, voyageai, cohere
vo, co = voyageai.Client(), cohere.Client()
def retrieve(query, k=40, top_n=8):
qvec = vo.embed([query], model="voyage-3-large").embeddings[0]
with psycopg.connect(DSN) as conn:
rows = conn.execute(
"SELECT id, doc_id, text FROM chunks ORDER BY embedding <=> %s LIMIT %s",
(qvec, k)).fetchall()
docs = [r[2] for r in rows]
ranked = co.rerank(model="rerank-v3.5", query=query, documents=docs, top_n=top_n)
return [rows[r.index] for r in ranked.results]
```
Pour pgvector, partez par défaut sur un index HNSW avec m=16 et ef_construction=64, ajoutez un préfiltre par tenant ou par récence pour que le scan ANN démarre étroit, et associez toujours `ORDER BY embedding <=> $1` à un `LIMIT`. Passez les chunks récupérés au LLM avec leurs IDs et demandez-lui d'émettre des marqueurs de citation ; résolvez ces marqueurs vers les URLs sources en post-traitement.
Évaluation : hit rate, MRR et faithfulness
Un pipeline RAG sans harnais d'évaluation est une supposition. Construisez le harnais avant tout réglage. Le kit minimal est un jeu de 100 à 500 requêtes labellisées couvrant les types de questions réellement attendus, plus trois métriques.
Le hit rate à K dit si le bon chunk a fait partie du jeu de candidats, ce qui isole la qualité du retrieval. Le mean reciprocal rank capture à quelle hauteur le bon chunk a été classé, ce que le reranker est censé améliorer. La faithfulness, notée par un juge LLM chargé de comparer chaque affirmation générée aux chunks cités, capture si le modèle a halluciné au-delà de son contexte.
Lancez le harnais à chaque changement : nouvelle taille de chunk, embedder différent, édition de prompt. Tracez les trois métriques dans le même tableau de bord au fil du temps. Quand un changement améliore le MRR mais effondre la faithfulness, le reranker fait remonter des distracteurs et c'est le prompt de génération qui a besoin de garde-fous, pas le retrieval.
Quand passer à un orchestrateur managé
Les pipelines faits main restent maintenables tant qu'une seule équipe les possède et que le nombre d'étapes reste réduit. Le moment où un orchestrateur managé devient rentable est quand des non-ingénieurs doivent régler le retrieval, quand vous gérez plusieurs pipelines en parallèle pour différentes classes de documents, ou quand vous voulez du config versionné et du routage A/B sans redéploiement.
À ce stade, le choix se fait entre frameworks lourds comme LlamaIndex ou Haystack et plateformes config-driven qui exposent les étapes de retrieval comme unités déclaratives. osStudio, l'éditeur d'orchestration no-code d'osFoundry, suit la seconde approche : les cinq étapes ci-dessus sont des objets de configuration first-class avec embeddings et reranking Voyage managés derrière un proxy unique, vous gardez donc le BYOK côté LLM tout en évitant le lock-in framework côté retrieval.
La bonne question n'est pas framework contre no-framework. C'est de savoir si la configuration de votre pipeline mérite d'être du code, de la config ou une UI, et cette réponse change avec la croissance de l'équipe.
Frequently asked questions
- Ai-je vraiment besoin d'une base vectorielle pour le RAG ?
- Probablement pas tant que vous ne dépassez pas plusieurs millions de vecteurs. Postgres avec pgvector tient confortablement jusqu'à environ 10 millions de vecteurs avec un index HNSW, la recherche hybride via tsvector et les filtres SQL standards pour le tenant et la récence. Vous héritez des sauvegardes, de la réplication et du contrôle d'accès de la base que vous opérez déjà. Les bases vectorielles dédiées comme Qdrant, Milvus ou Weaviate valent leur coût d'exploitation quand vous avez besoin d'index shardés à l'échelle du milliard, de filtrage spécialisé à très haut QPS, ou de capacités comme le retrieval multi-vecteurs que pgvector n'égale pas encore. Commencez avec pgvector et migrez seulement quand un goulet d'étranglement mesuré l'impose.
- Un reranker vaut-il vraiment la latence ?
- Pour la plupart des charges retrieval-heavy, oui. Un reranker cross-encoder comme Cohere rerank-v3.5 ou Voyage rerank-2 ajoute typiquement 80 à 200 millisecondes en p50 sur un jeu de 40 à 100 chunks candidats, et il améliore de 10 à 30 % le mean reciprocal rank par rapport au retrieval dense seul. La latence est masquée derrière l'appel LLM qui suit, lequel domine en général le budget visible utilisateur. N'évitez le reranker que pour les flux critiques en latence type autocomplete sous 200 millisecondes de bout en bout, ou quand votre jeu de candidats est déjà assez petit pour que le classement dense soit fiable.
- Comment gérer le chevauchement des chunks sans gonfler le stockage ?
- Utilisez de petits chevauchements de 10 à 15 % de la taille de chunk, stockés en offsets de caractères dans le document source plutôt qu'en texte dupliqué. À l'extraction, vous pouvez optionnellement récupérer le chunk voisin pour l'expansion de contexte. L'index reste léger et vous évitez de payer deux fois les mêmes tokens à l'embedding. Si la génération a besoin d'un contexte plus riche, le pattern parent-document fonctionne bien : indexez de petits chunks pour la précision du retrieval, puis résolvez les hits vers leur section parent avant de passer au LLM. La résolution parent est une requête indexée unique, à latence négligeable.
- Quel est le moyen le plus simple d'évaluer la qualité RAG ?
- Construisez un jeu labellisé de 100 à 200 requêtes représentatives avec les IDs de chunks qui doivent être récupérés. Calculez hit rate à K et mean reciprocal rank à partir de la seule étape de retrieval, ce qui isole la qualité du retriever du bruit de génération. Pour la faithfulness, utilisez un juge LLM qui compare chaque affirmation générée aux chunks cités et note grounded vs unsupported. Faites tourner les trois nombres à chaque changement significatif et traitez les régressions comme bloquantes. Ce setup à trois métriques attrape la majorité des régressions RAG en pratique et évite le piège d'optimiser un nombre en dégradant silencieusement un autre.
Sources