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

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 retrieval

Options de configuration :

OptionTypeValeur par défautFinalité
llm_providerLLMProviderObligatoireLLM à 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

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 combined

Options de configuration :

OptionTypeValeur par défautFinalité
llm_providerLLMProviderObligatoireLLM à utiliser pour l'extension (MistralChat, etc.)
num_queriesint3Nombre 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 recall

Quand 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

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

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

Voir aussi