La génération augmentée par récupération (RAG) est devenue l'architecture standard pour la création d'applications de modèles de langage de grande taille (LLM) prêtes pour la production. En ancrant les modèles génératifs dans des bases de connaissances externes, les organisations peuvent atténuer les hallucinations et fournir des citations. Cependant, un goulot d'étranglement critique subsiste : la qualité de l'étape de récupération. Si la requête initiale ne parvient pas à correspondre au sens sémantique des documents stockés, même le LLM le plus puissant produira de mauvais résultats.
Voici l'expansion de requête. Cette technique consiste à transformer l'entrée clairsemée et souvent ambiguë d'un utilisateur en une représentation plus riche et plus complète avant de l'envoyer à la base de données vectorielle. En élargissant la requête, nous augmentons la probabilité de trouver un contexte pertinent, améliorant ainsi la qualité globale de la phase de génération.
Pourquoi la recherche vectorielle simple échoue
Prenons l'exemple d'un utilisateur demandant : "Mon ordinateur portable ne s'allume pas." Une recherche sémantique naïve pourrait chercher des documents contenant ces mots exacts ou des voisins vectoriels proches. Cependant, le guide de dépannage pertinent dans votre base de connaissances pourrait être intitulé : "Dépannage des problèmes d'alimentation lors d'un échec de démarrage de l'appareil".
Dans ce scénario, l'écart lexical et sémantique entre la requête informelle de l'utilisateur et le titre formel du document entraîne un échec de la récupération. L'expansion de requête comble cet écart en générant plusieurs versions de la requête, chacune se concentrant sur des aspects ou des synonymes différents.
Stratégies courantes d'expansion de requête
Il existe trois méthodes principales pour mettre en œuvre l'expansion de requête dans un pipeline RAG :
1. Expansion multi-vecteurs (RQ-RAG)
Cette approche utilise un modèle dédié pour décomposer une seule requête en plusieurs vecteurs sémantiques. Chaque vecteur capture une perspective différente de l'intention de l'utilisateur. Lors de la recherche, le système effectue une recherche de similarité pour tous les vecteurs étendus et fusionne les résultats.
2. Expansion synthétique basée sur les LLM
Ici, un LLM est invité à réécrire la requête originale. Il peut générer des synonymes, des questions connexes ou une affirmation plus large. Cette méthode est très flexible, mais introduit une latence et un coût supplémentaires.
3. Expansion par mots-clés et traits d'union
Combinaison de la recherche vectorielle dense avec la recherche lexicale clairsemée (comme BM25). En extrayant les mots-clés de la requête et en les recherchant aux côtés de la représentation vectorielle, vous capturez les correspondances exactes que la recherche sémantique pourrait manquer.
Mise en œuvre de l'expansion de requête basée sur les LLM
Voici un exemple pratique en Python utilisant LangChain et un LLM pour générer plusieurs variations de requête. Cette technique est souvent appelée "HyDE" (Hypothetical Document Embeddings) ou simplement récupération multi-requêtes.
from langchain.llms import OpenAI
from langchain.prompts import PromptTemplate
from langchain.chains import LLMChain
# Définir le prompt pour générer des requêtes connexes
prompt_template = """Vous êtes un assistant IA chargé d'améliorer les résultats de recherche.
Étant donné la requête utilisateur suivante, générez 3 variations distinctes qui pourraient récupérer des documents plus pertinents.
Concentrez-vous sur les synonymes, les termes techniques connexes et différentes formulations.
Requête utilisateur : "{query}"
Variations générées :
1.
2.
3.
"""
llm_chain = LLMChain(
llm=OpenAI(temperature=0),
prompt=PromptTemplate(
input_variables=["query"],
template=prompt_template
)
)
# Exemple d'utilisation
original_query = "Comment corriger un délai d'attente de connexion à la base de données en Python ?"
response = llm_chain.run(original_query)
# Dans un pipeline réel, vous analyseriez la réponse en une liste de chaînes
# et passeriez ces chaînes au récupérateur de votre magasin vectoriel.
print(response)
Meilleures pratiques et compromis
Bien que l'expansion de requête améliore considérablement le rappel (recall), elle comporte des compromis. La latence augmente car vous effectuez des appels API supplémentaires au LLM et plusieurs recherches dans la base de données. Le coût augmente également en raison d'une consommation plus élevée de jetons.
Pour atténuer ces problèmes, envisagez les meilleures pratiques suivantes :
- Mise en cache : Mettez en cache les requêtes étendues pour éviter un calcul redondant pour les termes de recherche courants.
- Réorganisation des résultats : Utilisez un réorganiseur à encodeur croisé sur les résultats top-K de toutes les requêtes étendues pour garantir que le contexte final est hautement pertinent.
- Recherche hybride : Combinez l'expansion de requête avec la correspondance de mots-clés BM25 pour capturer à la fois l'intention sémantique et la terminologie exacte.
Conclusion
L'expansion de requête n'est pas seulement une fonctionnalité optionnelle ; c'est un composant fondamental des systèmes RAG robustes. En reconnaissant que les requêtes des utilisateurs sont souvent clairsemées et ambiguës, les développeurs peuvent mettre en œuvre des stratégies d'expansion qui comblent l'écart entre l'intention humaine et la récupération machine. Que vous choisissiez la décomposition multi-vecteurs ou des requêtes synthétiques pilotées par des LLM, l'objectif reste le même : fournir au LLM le contexte précis dont il a besoin pour générer des réponses exactes, utiles et ancrées.
À mesure que les architectures RAG évoluent, l'intégration de l'expansion de requête dynamique distinguera les applications de niveau production des prototypes expérimentaux. Commencez simplement, mesurez vos métriques de récupération et itérez.