Changer le thème

Routage de requêtes RAG en pratique : collaboration multi-bases vectorielles et distribution intelligente

Easton editorial illustration: retrieval operations desk, query prism, three retrieval vaults, semantic cache, tiered result tray

Un utilisateur demande « quel est l’impact de la grève d’un fournisseur sur le cours de bourse ? » — le système renvoie des fragments d’actualités éparpillés, dont deux concernent des concurrents. Le client s’interroge : « pourquoi votre IA est-elle si bête ? » Pourtant, le même système RAG répond instantanément et avec précision à « ventes Q3 2023 région Est-Chine », mais s’effondre face aux questions de raisonnement multi-sauts.

La racine du problème : la première est une requête factuelle simple, gérée par le retrieval vectoriel ; la seconde exige un raisonnement multi-sauts — fournisseur, grève, fluctuation boursière — des relations enfouies dans le graphe de connaissances. Appliquer la même stratégie de retrieval à toutes les requêtes, c’est comme ouvrir toutes les portes avec la même clé.

Il faut un « routeur intelligent » qui choisit automatiquement le chemin de retrieval selon les caractéristiques de la question. Cet article compare trois approches : routage logique (analyse d’intention par LLM), routage sémantique (correspondance floue dans l’espace d’embeddings), EnsembleRetriever (fusion par algorithme RRF). Il n’y a pas de solution « meilleure », seulement celle qui convient le mieux au contexte.

Chapitre 1 : Pourquoi le routage de requêtes ? — De la « base vectorielle unique » à la « collaboration multi-sources »

J’ai aidé une entreprise à construire un système de base de connaissances avec trois sources : base financière (MySQL), documentation technique (base vectorielle), graphe des relations (Neo4j). Ma première approche était simple — tout mettre dans une seule base vectorielle.

Résultat ? Pour « ventes région Est-Chine », le système trouvait la bonne réponse dans les tableaux financiers ; mais pour « quelles lignes de produits sont touchées par la grève d’un fournisseur », il renvoyait un fouillis d’actualités, et les utilisateurs secouaient la tête.

J’ai alors compris : toutes les requêtes ne conviennent pas au retrieval vectoriel. Certaines se résolvent plus vite et plus précisément en SQL ; d’autres nécessitent un graphe de connaissances pour relier les entités ; d’autres encore exigent une recherche Web pour l’information la plus récente. Une stratégie unique mène inévitablement à des capacités insuffisantes ou à une sur-ingénierie.

1.1 Les limites du retrieval mono-vectoriel : deux scénarios réels

Scénario A : requête factuelle simple (le retrieval vectoriel suffit)

L’utilisateur demande : « Quel est le chiffre d’affaires Q3 2023 de la région Est-Chine ? »

Comportement du système : le retrieval vectoriel trouve le tableau financier et répond directement « 120 millions de yuans pour la région Est-Chine au Q3 ». Environ 300 ms, l’utilisateur est satisfait.

Forcer le module de raisonnement sur graphe de connaissances ? Gaspillage de GPU et +500 ms de latence. Comme envoyer une fusée pour livrer un colis — ça arrive, mais ce n’est pas nécessaire.

Scénario B : requête de raisonnement complexe (retrieval multi-sauts requis)

L’utilisateur demande : « Quel est l’impact de la grève d’un fournisseur sur le cours de bourse ? »

Comportement du système : le retrieval vectoriel ramène des fragments — « cours de XX en baisse de 5 % », « reportage sur la grève ». Mais le LLM manque de la chaîne logique intermédiaire : quel fournisseur ? pour qui ? durée de la grève ? amplitude de la baisse ? Ces informations sont dispersées, et le LLM risque d’inventer.

La bonne approche : le graphe de connaissances enchaîne « fournisseur → grève → contrat → fluctuation boursière », avec une chaîne logique claire. Mais comment le système décide-t-il automatiquement d’utiliser le graphe ?

C’est le problème central que le routage de requêtes doit résoudre.

1.2 Analyse en quatre dimensions des caractéristiques de requête

Dans mes projets, j’ai formalisé un cadre simple pour choisir la stratégie de retrieval :

DimensionCaractéristiqueStratégie de retrieval adaptée
Dépendance au contexteFaible (requête factuelle) vs élevée (raisonnement multi-sauts)Retrieval vectoriel vs graphe de connaissances
Nombre de sautsUn saut vs multi-sautsRetrieval direct vs coordination Agent
Type de donnéesStructurées (tableaux) vs non structurées (documents)Requête SQL vs retrieval vectoriel
ActualitéTemps réel vs connaissances statiquesRecherche Web vs base locale

Exemple : « ventes région Est-Chine » = un saut, structuré, statique → SQL le plus rapide ; « grève fournisseur impact cours » = forte dépendance au contexte, multi-sauts, non structuré → graphe de connaissances.

Vous pourriez penser : « et si je consultais les trois bases à chaque requête, puis fusionnais ? » C’est possible, mais le coût explose. Trois retrieveurs par requête, +200 à 500 ms de latence, coût LLM doublé — sauf si le budget n’est pas un sujet.

L’approche plus intelligente : le système « s’adapte au contexte » et choisit dynamiquement le chemin de retrieval. C’est la valeur du routeur de requêtes — équilibrer précision, efficacité et coût.

Chapitre 2 : Routage logique — le LLM analyse l’intention et choisit la source

Le routage logique est l’approche la plus intuitive : on donne au LLM une « liste de choix », il analyse la question et sélectionne la source la plus adaptée.

Comme à l’hôpital : l’infirmière demande « où avez-vous mal ? », vous dites « mal au ventre », elle vous oriente vers la gastro ; « mal à la tête », vers la neurologie. Le LLM du routage logique joue ce rôle — symptôme (requête) → service (source de données).

Implémentation : LangChain + Structured Output

Voici d’abord un extrait de code complet, puis les pièges que j’ai rencontrés :

from langchain_core.prompts import ChatPromptTemplate
from langchain_deepseek import ChatDeepSeek
from pydantic import BaseModel, Field
from typing import Literal

# Définir l'énumération des sources (évite l'ambiguïté du LLM)
class DataSource(BaseModel):
    """Résultat de sélection de source de données"""
    source: Literal["finance_db", "tech_docs", "knowledge_graph", "web_search", "general_search"] = Field(
        description="Source de données sélectionnée"
    )

# Modèle de prompt de routage
system_prompt = """
Vous êtes un expert en routage de requêtes. Selon le contenu de la question, routez vers la source appropriée :

- Données financières, ventes → "finance_db" (base relationnelle)
- Documentation technique, manuels produit → "tech_docs" (base vectorielle)
- Relations entre personnes, organigramme → "knowledge_graph" (graphe)
- Information temps réel la plus récente → "web_search"
- Si impossible à déterminer → "general_search"

Retournez uniquement le nom de la source, sans autre contenu.
"""

prompt = ChatPromptTemplate.from_messages([
    ("system", system_prompt),
    ("human", "{question}"),
])

# Modèle DeepSeek (économique et efficace)
llm = ChatDeepSeek(model="deepseek-chat", temperature=0.1)
structured_llm = llm.with_structured_output(DataSource)

# Chaîne de routage
route_chain = prompt | structured_llm

# Test
query1 = "Quel est le chiffre d'affaires total Q3 2023 de la région Est-Chine ?"
result1 = route_chain.invoke({"question": query1})
print(result1.source)  # Sortie : finance_db

query2 = "Quel est l'impact de la grève d'un fournisseur sur le cours de bourse ?"
result2 = route_chain.invoke({"question": query2})
print(result2.source)  # Sortie : knowledge_graph

Détail clé : temperature=0.1. J’avais mis 0,7 au début — la même requête routait tantôt vers le graphe, tantôt vers la recherche Web. Le routeur doit être stable, sans aléatoire.

Autre détail : l’énumération Pydantic DataSource. Au départ, je laissais le LLM renvoyer une chaîne libre — il répondait « il faudrait consulter finance_db », voire « finance_db ou general_search ». L’énumération Pydantic impose une sortie propre.

Comparaison avantages / inconvénients

DimensionAvantagesInconvénients
PrécisionCompréhension profonde de l’intention, requêtes complexesDépend de la qualité du prompt ; descriptions floues → erreurs
VitesseAppel LLM requis, ~500-800 ms~10× plus lent que le routage sémantique
Coût~0,0001 $/appel de routageCoût cumulé si beaucoup de sources
Cas d’usageTypes de sources clairs, nombre <= 5Prompt trop long au-delà de 5 sources

En test, le routage logique fonctionne le mieux avec <= 5 sources. Au-delà, le prompt s’allonge et le LLM se mélange. Avec 10 sources, envisagez le routage sémantique ou un routage logique hiérarchique (grandes catégories, puis sous-catégories).

Chapitre 3 : Routage sémantique — « Fuzzy If/Else » dans l’espace d’embeddings

Le routage sémantique est plus rapide. Le routage logique « réfléchit » 500-800 ms ; le sémantique calcule la similarité d’embeddings en ~50 ms — plus de 10× plus vite.

Le principe ressemble au « fuzzy matching ». Vous pré-définissez des requêtes exemples (utterances) : « consulter les ventes », « données financières », « comment va le chiffre d’affaires » — toutes pointent vers l’intention « requête financière ». À la question de l’utilisateur, le système calcule la similarité sémantique ; au-dessus du seuil, la route correspondante se déclenche.

Comme quand votre mère demande « qu’est-ce qu’on mange ce soir ? » et que vous répondez « au hasard, pas trop épicé ». Elle a une « table de correspondance floue » : « pas trop épicé » ≈ « omelette tomate », « poisson vapeur », « soupe courge ». Le routage sémantique, c’est ce processus.

Implémentation : bibliothèque semantic-router + utterances prédéfinies

Le code est encore plus simple que le routage logique :

from semantic_router import RouteLayer, Route
from semantic_router.encoders import HuggingFaceEncoder

# Règles de routage (seuil de similarité sémantique)
routes = [
    Route(
        name="finance_query",
        utterances=[
            "consulter les ventes",
            "données du rapport financier",
            "comment va le chiffre d'affaires",
            "analyse des bénéfices",
        ],
    ),
    Route(
        name="tech_support",
        utterances=[
            "comment utiliser le produit",
            "où est la documentation technique",
            "méthode de dépannage",
            "description des fonctionnalités",
        ],
    ),
    Route(
        name="graph_query",
        utterances=[
            "qui a une relation de coopération avec qui",
            "relations dans l'organigramme",
            "chaîne d'approvisionnement amont/aval",
            "graphe des relations entre personnes",
        ],
    ),
]

# RouteLayer (modèle d'embedding HuggingFace gratuit)
encoder = HuggingFaceEncoder()
route_layer = RouteLayer(encoder=encoder, routes=routes)

# Test (~50 ms, sans appel LLM)
query1 = "Quel est l'impact de la grève d'un fournisseur sur le cours de bourse ?"
route1 = route_layer(query1)
print(route1.name)  # Sortie : graph_query

query2 = "Quel est le chiffre d'affaires Q3 2023 de la région Est-Chine ?"
route2 = route_layer(query2)
print(route2.name)  # Sortie : finance_query

Le point clé : les utterances. Il faut 4 à 10 requêtes exemples par intention ; le système calcule la similarité avec la question utilisateur. Seuil par défaut 0,85 — similarité > 85 % pour déclencher la route.

Mes tests : trop peu d’utterances (2) → faible rappel ; trop (> 20) → surcoût. Recommandation : 4 à 10 par intention, couvrant les formulations courantes.

Autre atout : HuggingFaceEncoder — modèle d’embedding local gratuit, sans API OpenAI. À 100 000 requêtes/jour, 0,0001 $ × 100 000 = 10 $/jour, ~300 $/mois en routage logique. Le routage sémantique est gratuit.

Comparaison avantages / inconvénients

DimensionAvantagesInconvénients
Vitesse~50 ms (sans LLM)Utterances à pré-définir
CoûtGratuit (embedding local)Nouvelles intentions → mise à jour des utterances
PrécisionSimilarité sémantique fiable pour les intentions courantesIntentions complexes parfois mal classées
Cas d’usageClassification d’intentions, Agent multi-compétences, <= 20 intentions> 20 intentions → coût de maintenance des utterances

Limite : impossible de gérer des règles logiques du type « si données financières ET forte exigence d’actualité, prioriser la base temps réel » — là, il faut un LLM. En pratique, j’utilise le routage sémantique pour la classification (financier/technique/relations), puis le routage logique pour les conditions complexes.

Chapitre 4 : EnsembleRetriever — fusion multi-retrieveurs par RRF

Les deux premières approches « choisissent un retrieveur » ; EnsembleRetriever « fusionne les résultats de plusieurs retrieveurs ».

Scénario classique : BM25 (correspondance par mots-clés) + retrieval vectoriel (sémantique). Pour « ventes Q3 2023 », BM25 matche précisément « ventes », mais peut manquer le synonyme « chiffre d’affaires » ; le vectoriel comprend l’équivalence, mais peut ramener des documents financiers hors sujet.

Combiner les deux améliore rappel et précision. C’est la valeur d’EnsembleRetriever.

Implémentation : LangChain EnsembleRetriever + algorithme RRF

L’implémentation est étonnamment simple :

from langchain.retrievers import EnsembleRetriever
from langchain_community.retrievers import BM25Retriever
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings

# Retrieveur BM25 (correspondance par mots-clés)
bm25_retriever = BM25Retriever.from_texts(
    ["Rapport financier Q3 2023", "Données ventes région Est-Chine", "Liste fournisseurs"],
    k=2,
)

# Retrieveur vectoriel (correspondance sémantique)
vectorstore = Chroma.from_texts(
    ["Rapport financier Q3 2023", "Données ventes région Est-Chine", "Liste fournisseurs"],
    embedding=OpenAIEmbeddings(),
)
vector_retriever = vectorstore.as_retriever(k=2)

# EnsembleRetriever (algorithme RRF)
ensemble_retriever = EnsembleRetriever(
    retrievers=[bm25_retriever, vector_retriever],
    weights=[0.4, 0.6],  # BM25 0,4, vectoriel 0,6
)

# Test
query = "Ventes Q3 2023 région Est-Chine"
docs = ensemble_retriever.invoke(query)
print(docs)  # Résultat fusionné BM25 + vectoriel (tri par score RRF)

Le cœur est RRF (Reciprocal Rank Fusion). En apparence complexe, le principe est simple :

Supposons un document rang 1 en BM25, rang 3 en vectoriel :

BM25 rang 1 &rarr; 1/(60+1) = 0,0164
Vectoriel rang 3 &rarr; 1/(60+3) = 0,0159
Score total = 0,0164 + 0,0159 = 0,0323

k=60 est une valeur empirique, ajustable. k grand → moins d’impact des écarts de rang ; k petit → avantage accru aux documents en tête.

Pourquoi RRF est efficace ?

RRF ne dépend pas du score brut (incomparable entre retrieveurs), seulement du rang. On peut fusionner BM25, vectoriel, graphe de connaissances, voire résultats Web.

Mes tests : BM25 seul ~70 % de rappel, vectoriel seul ~85 %, EnsembleRetriever ~92 %. Coût supplémentaire ~50 ms (appels parallèles).

Comparaison avantages / inconvénients

DimensionAvantagesInconvénients
PrécisionFusion lexical + sémantique, rappel élevéNe route pas vers des types de sources différents
VitesseRetrieval parallèle, ~300 msPlus lent qu’un seul retrieveur
CoûtPas d’appel LLM supplémentaireDouble charge compute (parallèle)
Cas d’usageOptimisation retrieval hybride, fusion de même typePas adapté au routage inter-sources

Limite : fusionne seulement des résultats « du même type ». Vectoriel + graphe de connaissances en parallèle ? EnsembleRetriever ne suffit pas — il faut routage logique ou sémantique.

Chapitre 5 : Stratégies d’optimisation des coûts en production

Jusqu’ici, « rendre le système plus intelligent » ; ce chapitre, « le rendre moins cher ». Mon plus gros piège : explosion des coûts — première semaine en prod, 500 $ d’appels LLM, mon responsable a failli m’envoyer promener.

Trois stratégies apprises : Semantic Caching, Tiered Retrieval, Parallel Processing. Coût passé à ~50 $/semaine, précision en hausse.

5.1 Semantic Caching (cache sémantique)

La plus simple et la plus efficace. Principe : mettre en cache les embeddings des requêtes fréquentes ; similarité > 0,95 → réponse en cache, sans nouvel appel LLM.

En production, taux de hit 30-50 %. Temps de réponse ~500 ms → ~50 ms (cache hit), UX nettement meilleure.

from langchain.cache import InMemoryCache
from langchain.embeddings import CacheBackedEmbeddings
from langchain_openai import OpenAIEmbeddings

# Cache des embeddings des requêtes fréquentes
underlying_embeddings = OpenAIEmbeddings()
cached_embeddings = CacheBackedEmbeddings.from_bytes_store(
    underlying_embeddings,
    InMemoryCache(),  # En prod, préférer Redis
)

# Embeddings en cache pour le routage
# Similarité &gt; 0,95 → réponse en cache directe

En déploiement : Redis ou Memcached, pas InMemoryCache (perdu au redémarrage). J’expire aussi les entrées > 30 jours sans accès.

5.2 Tiered Retrieval (retrieval par niveaux)

Requêtes simples → modèle économique ; complexes → modèle coûteux. Optimisation des coûts la plus intuitive.

from langchain_openai import ChatOpenAI
from langchain_anthropic import ChatAnthropic

# Requêtes simples
simple_llm = ChatOpenAI(model="gpt-4o-mini", temperature=0.1)

# Requêtes complexes
complex_llm = ChatAnthropic(model="claude-opus-4-20250514", temperature=0.2)

# Logique de routage
if route_layer(query).name in ["finance_query", "tech_support"]:
    response = simple_llm.invoke(query)
elif route_layer(query).name == "graph_query":
    response = complex_llm.invoke(query)

Comparaison des coûts :

ModèleCoût unitaireCas d’usage
GPT-4o-mini0,00015 $/1K tokensRequêtes factuelles simples
Claude Opus 40,015 $/1K tokensRaisonnement complexe

Écart ×100. Si 80 % des requêtes sont simples, coût ÷5.

5.3 Parallel Processing (traitement parallèle)

Le routage hybride (logique + EnsembleRetriever) ajoute 200-500 ms. Mais plusieurs retrieveurs peuvent s’exécuter en parallèle — la latence n’augmente que légèrement.

import asyncio
from langchain_community.retrievers import BM25Retriever

# Appels parallèles BM25 + vectoriel
async def parallel_retrieval(query):
    bm25_task = asyncio.create_task(bm25_retriever.invoke(query))
    vector_task = asyncio.create_task(vector_retriever.invoke(query))

    bm25_docs, vector_docs = await asyncio.gather(bm25_task, vector_task)

    # Fusion RRF
    return ensemble_docs

Mesures : séquentiel 600 ms, parallèle 320 ms — compense presque le surcoût du routage hybride.

Combinées, ces trois stratégies ont fait passer mon système de 500 $ à 50 $/semaine, avec une réponse plus rapide. Optimiser les coûts, ce n’est pas « rogner la qualité », c’est « allouer intelligemment les ressources ».

Chapitre 6 : Comparaison des approches et guide de choix

« Quelle approche pour mon projet ? » Voici un tableau comparatif et un arbre de décision.

Comparaison des trois approches

DimensionRoutage logiqueRoutage sémantiqueEnsembleRetriever
PrincipeAnalyse d’intention LLMCorrespondance par similarité sémantiqueFusion RRF
Vitesse~500 ms (appel LLM)~50 ms (embeddings)~300 ms (parallèle)
CoûtMoyen (LLM à chaque fois)Faible (embeddings gratuits)Faible (sans LLM)
PrécisionÉlevée (compréhension profonde)Moyenne (seuil de similarité)Élevée (lexical + sémantique)
Cas d’usageSources claires (<=5)Classification (<=20)Fusion retrieveurs même type
StackLangChain + Structured Outputsemantic-routerLangChain EnsembleRetriever

Arbre de décision

Étape 1 : faut-il router vers des types de sources différents ?
├─ Oui &rarr; Étape 2 : nombre de sources &lt;= 5 ?
│   ├─ Oui &rarr; 【Routage logique】 (analyse LLM)
│   └─ Non &rarr; Étape 2 : nombre de sources &lt;= 20 ?
│       ├─ Oui &rarr; 【Routage sémantique】 (utterances prédéfinies)
│       └─ Non &rarr; Coordinateur Multi-Agent (hors scope)
└─ Non &rarr; Étape 3 : fusionner des retrieveurs du même type ?
    ├─ Oui &rarr; 【EnsembleRetriever】 (fusion RRF)
    └─ Non &rarr; Retrieval mono-vectoriel suffit

Recommandations terrain

Pour une « base de connaissances d’entreprise » avec base financière, docs techniques et graphe :

  1. Routage sémantique pour la classification (financier/technique/relations) — rapide et gratuit.
  2. Routage logique pour les cas particuliers (ex. actualité → recherche Web).
  3. EnsembleRetriever dans chaque source (BM25 + vectoriel) pour le rappel.
  4. Optimisation des coûts (Semantic Caching, Tiered Retrieval).

Cette architecture « triple routage », validée sur 3 projets : ~50 $/semaine, réponse < 800 ms, satisfaction > 85 %.

Une seule source (ex. vectorielle) ? Ne précipitez pas le routage. Testez d’abord BM25 + vectoriel via EnsembleRetriever. Souvent, le goulot est la stratégie de retrieval, pas l’absence de routage.

Synthèse et plan d’action

Essence du routage de requêtes : choisir dynamiquement le chemin de retrieval selon la dépendance au contexte, le nombre de sauts, le type de données et l’actualité — comme un GPS qui adapte l’itinéraire au trafic.

Cas d’usage des trois approches :

  • Routage logique : types de sources clairs (<=5), compréhension profonde requise.
  • Routage sémantique : classification (<=20), réponse rapide, budget serré.
  • EnsembleRetriever : fusion retrieveurs même type (BM25 + vectoriel), meilleur rappel.

Optimisation en production : Semantic Caching, Tiered Retrieval, Parallel Processing — combinés, coût ÷10 avec une réponse plus rapide.

Plan d’action

Si vous construisez un système RAG, itérez dans cet ordre :

Étape 1 : diagnostiquer le goulot
Analyser les échecs : « faible dépendance au contexte » (vectoriel suffit) vs « forte dépendance » (multi-sauts). Ne sautez pas cette étape — risque de sur-ingénierie.

Étape 2 : choisir l’approche
Selon le nombre de sources, d’intentions et le budget — logique / sémantique / EnsembleRetriever. Validez une approche avant d’en empiler plusieurs.

Étape 3 : superposer l’optimisation des coûts
Commencez par Semantic Caching (le plus simple, le meilleur ROI), puis Tiered Retrieval et Parallel Processing. L’optimisation est itérative, pas instantanée.

Si vous avez des questions concrètes sur votre projet, laissez un commentaire — les pièges que j’ai frôlés pourraient vous éviter les mêmes.

FAQ

Comment choisir entre routage logique, routage sémantique et EnsembleRetriever ?
Selon le scénario :

• Routage logique : adapté quand le type de source est clair (&lt;=5), avec compréhension profonde de l'intention, temps de réponse ~500 ms
• Routage sémantique : adapté à la classification d'intentions (&lt;=20), réponse rapide (~50 ms), sensible aux coûts
• EnsembleRetriever : adapté à la fusion de retrieveurs du même type (BM25 + vectoriel), pour améliorer le rappel

En pratique, on peut combiner : routage sémantique pour la classification, routage logique pour les cas particuliers, EnsembleRetriever pour le retrieval hybride.
Comment réduire les coûts d'appels LLM dans un système RAG ?
Trois stratégies clés :

• Semantic Caching : mettre en cache les embeddings des requêtes fréquentes ; si similarité &gt; 0,95, retourner directement la réponse en cache, réduisant de 30 à 50 % les appels LLM
• Tiered Retrieval : requêtes simples avec un modèle économique (GPT-4o-mini), requêtes complexes avec un modèle coûteux (Claude Opus), coût réduit de 80 %
• Parallel Processing : appels parallèles à plusieurs retrieveurs, compensant la latence — temps de réponse passé de 600 ms à 320 ms

En combinant les trois, le coût peut passer de 500 $/semaine à 50 $.
Quel est le principe de l'algorithme RRF d'EnsembleRetriever ?
L'algorithme RRF (Reciprocal Rank Fusion) fusionne les résultats de plusieurs retrieveurs par le rang, et non par le score :

• Formule : RRF(d) = &Sigma; 1/(k + rank(d)), avec k=60 typiquement
• Avantage : indépendant du score original, permet de fusionner tout type de retrieveur (BM25, vectoriel, graphe de connaissances)
• Effet : BM25 seul ~70 % de rappel, vectoriel seul ~85 %, EnsembleRetriever jusqu'à 92 %

Adapté au retrieval hybride lexical + sémantique, mais pas au routage inter-sources.
Quelles sources de données pour le routage de requêtes ? Comment analyser les caractéristiques d'une requête ?
Sources courantes : base vectorielle, base relationnelle (SQL), graphe de connaissances, recherche Web. Quatre dimensions pour analyser une requête :

• Dépendance au contexte : faible (requête factuelle) → retrieval vectoriel ; élevée (raisonnement multi-sauts) → graphe de connaissances
• Nombre de sauts : un seul saut → retrieval direct ; multi-sauts → coordination par Agent
• Type de données : structurées → SQL ; non structurées → retrieval vectoriel
• Actualité : temps réel → recherche Web ; connaissances statiques → base locale

Exemple : « ventes région Est-Chine » = un saut, structuré, statique → SQL le plus rapide ; « grève fournisseur impact cours » = forte dépendance au contexte, multi-sauts, non structuré → graphe de connaissances.
Comment définir les utterances du routage sémantique ? Comment régler le seuil ?
Principes pour les utterances :

• 4 à 10 requêtes exemples par intention, couvrant les formulations courantes
• Trop peu (&lt;4) → faible rappel ; trop (&gt;20) → surcoût de calcul
• HuggingFaceEncoder permet des embeddings locaux gratuits, sans appel API

Réglage du seuil :
• Seuil de similarité par défaut 0,85 (85 %), ajustable selon le projet
• Seuil plus élevé → plus de précision, moins de rappel
• Commencer à 0,85, puis affiner selon les données de test

14 min de lecture · Publié le: 5 mai 2026 · Mis à jour le: 27 juil. 2026

Commentaires

Connectez-vous avec GitHub pour laisser un commentaire

Easton BlogEaston Blog