Prétraitement des requêtes
Le prétraitement des requêtes améliore les requêtes utilisateur avant la récupération. Des techniques comme la reformulation et l'expansion peuvent améliorer significativement la qualité de la récupération, même si elles augmentent la latence et le coût.
Réécriture de requête par LLM
Utilise un LLM pour reformuler les requêtes sous une forme plus susceptible de correspondre au contenu indexé. Convertit le langage informel en requêtes structurées, développe les abréviations et clarifie l'intention.
Installation : Bibliothèque principale (aucun module supplémentaire requis)
Exemple :
from mistralai.search.toolkit.retrieval.pre_processors import LLMQueryRewriter
from mistralai.search.toolkit.llm import MistralChat, LLMConfig
from mistralai.client import Mistral
llm = MistralChat(
client=Mistral(api_key="your-api-key"),
config=LLMConfig(model="mistral-small-latest"),
)
rewriter = LLMQueryRewriter(llm_provider=llm)
# Original: "rag mistral"
rewritten = await rewriter.rewrite("rag mistral")
# Result: "What is Retrieval-Augmented Generation with Mistral AI?"
# Use in QueryEngine
query_engine = QueryEngine(
retriever=vector_retriever,
query_rewriter=rewriter,
)
result = await query_engine.search(query="rag mistral")
# Query is rewritten before retrievalOptions de configuration :
| Option | Type | Valeur par défaut | Finalité |
|---|---|---|---|
llm_provider | LLMProvider | Obligatoire | LLM à utiliser pour la reformulation (MistralChat, etc.) |
Prompt de reformulation personnalisé :
from mistralai.search.toolkit.retrieval.pre_processors import LLMQueryRewriter
from mistralai.search.toolkit.llm import MistralChat, LLMConfig
llm = MistralChat(
client=Mistral(api_key="your-api-key"),
config=LLMConfig(model="mistral-small-latest"),
)
# With custom prompt
rewriter = LLMQueryRewriter(
llm_provider=llm,
prompt="Reformulate this query for a technical documentation search engine: ",
)
rewritten = await rewriter.rewrite("how to set up django")Quand l'utiliser :
- Requêtes courtes ou informelles nécessitant une expansion
- Requêtes contenant des acronymes ou des abréviations spécifiques à un domaine
- Amélioration du rappel pour les entrées utilisateur vagues
- Conversion des questions en combinaisons de mots-clés
Considérations de coût :
- 1 appel LLM par requête
- Ajoute 100 à 500 ms de latence
- À utiliser de manière stratégique, pas pour chaque requête
Extension de requête par LLM
Divise une requête en plusieurs sous-requêtes explorant différents aspects. Chaque sous-requête exécute une passe de récupération indépendante ; les résultats sont combinés pour un rappel plus large.
Installation : Bibliothèque principale (aucun module supplémentaire requis)
Exemple :
from mistralai.search.toolkit.retrieval.pre_processors import LLMQueryExtension
from mistralai.search.toolkit.llm import MistralChat, LLMConfig
from mistralai.client import Mistral
llm = MistralChat(
client=Mistral(api_key="your-api-key"),
config=LLMConfig(model="mistral-small-latest"),
)
extender = LLMQueryExtension(
llm_provider=llm,
num_queries=3, # Generate 3 sub-queries
)
# Original: "How does RAG work?"
extended = await extender.extend("How does RAG work?")
# Results in:
# - "What is RAG?"
# - "How does retrieval work in RAG?"
# - "How does generation work in RAG?"
# Use in QueryEngine
query_engine = QueryEngine(
retriever=vector_retriever,
query_rewriter=extender,
)
result = await query_engine.search(query="How does RAG work?")
# All 3 sub-queries are retrieved and results combinedOptions de configuration :
| Option | Type | Valeur par défaut | Finalité |
|---|---|---|---|
llm_provider | LLMProvider | Obligatoire | LLM à utiliser pour l'extension (MistralChat, etc.) |
num_queries | int | 3 | Nombre de sous-requêtes à générer |
Coût et performances :
# num_queries=3 means:
# - 1 LLM call to generate sub-queries
# - 3 retrieval passes (3x slower)
# - 3x embedding calls (for each sub-query)
# - Results combined/deduplicated
# Choose based on tolerance:
extender = LLMQueryExtension(llm_provider=llm, num_queries=2) # Faster, lower recall
extender = LLMQueryExtension(llm_provider=llm, num_queries=5) # Slower, higher recallQuand l'utiliser :
- Requêtes complexes présentant plusieurs aspects
- Amélioration du rappel sur différents aspects
- Questions multifacettes nécessitant une couverture large
- Quand la tolérance de latence permet plusieurs récupérations
Bonnes pratiques – combiner avec le réordonnancement :
query_engine = QueryEngine(
retriever=vector_retriever,
query_rewriter=LLMQueryExtension(llm_provider=llm, num_queries=3),
rerankers=[LLMReRanker(llm_provider=llm, top_k=10)],
)
# Flow:
# 1. 1 query → 3 sub-queries (LLM call)
# 2. 3 retrieval passes (3x embedding + vector search)
# 3. ~30 results combined
# 4. LLM reranking narrows to top 10 (1 more LLM call)
# Total: 2 LLM calls + 3 vector searches + deduplication + reranking
result = await query_engine.search(query="...", top_k=10)Prétraitements de requête personnalisés
Les préprocesseurs de requête sont des classes classiques — aucune classe de base n'est requise. QueryEngine accepte tout objet proposant une méthode rewrite(query, context=RetrievalContext()) pour son paramètre query_rewriter (ou extend(...) pour query_extension) :
from mistralai.search.toolkit.context import RetrievalContext
class DomainSpecificRewriter:
"""Rewrite queries for a specific domain."""
async def rewrite(self, query: str, context: RetrievalContext = RetrievalContext()) -> str:
"""Rewrite the query."""
# 1. Normalize
normalized = query.lower().strip()
# 2. Expand domain-specific abbreviations
expansions = {
"ml": "machine learning",
"nlp": "natural language processing",
"ai": "artificial intelligence",
}
for abbr, expansion in expansions.items():
normalized = normalized.replace(f" {abbr} ", f" {expansion} ")
# 3. Add domain context if needed
if "algorithm" in normalized:
normalized += " implementation approach"
return normalized
rewriter = DomainSpecificRewriter()
query_engine = QueryEngine(
retriever=vector_retriever,
query_rewriter=rewriter,
)Quand utiliser le prétraitement des requêtes
Utilisez le prétraitement si :
- Les requêtes utilisateur sont courtes/vagues (par ex. « RAG » au lieu de questions complètes)
- Votre index contient une terminologie très spécifique
- Vous avez besoin d'un meilleur rappel pour les questions multifacettes
- La tolérance de latence permet des appels LLM supplémentaires
Évitez le prétraitement si :
- Les requêtes utilisateur sont déjà bien formulées
- La latence est critique (chat en temps réel)
- Le coût est une préoccupation (chaque appel LLM s'ajoute)
- La récupération vectorielle seule donne de bons résultats
Approche hybride :
# Optional preprocessing based on query length
class OptionalRewriter:
async def rewrite(self, query: str, context: RetrievalContext = RetrievalContext()) -> str:
# Only rewrite short queries
if len(query.split()) < 3:
# Expand short query
return await llm.rewrite(query)
return query
query_engine = QueryEngine(
retriever=vector_retriever,
query_rewriter=OptionalRewriter(),
)Voir aussi
- Vue d'ensemble de la récupération — Architecture du pipeline de récupération
- Récupérateurs — Recherche vectorielle et par mots-clés
- Réordonnateurs — Affiner les résultats après la récupération
- Cache sémantique — Mettre en cache les requêtes prétraitées