Fondamentaux du Retrieval : Comment fonctionne la recherche RAG

Maîtrisez les bases du retrieval dans les systèmes RAG : embeddings, recherche vectorielle, chunking et indexation pour des résultats pertinents.

Auteur
Équipe Ailog
Date de publication
Temps de lecture
18 min de lecture
Niveau
intermediate
Étape du pipeline RAG
Retrieval

Fondamentaux du Retrieval : Comment fonctionne la recherche RAG

Le retrieval est le cœur battant de tout système RAG (Retrieval-Augmented Generation). Sans une recherche efficace, même le meilleur LLM du monde produira des réponses hors sujet ou incomplètes. Ce guide vous accompagne dans la compréhension approfondie des mécanismes de retrieval, de la théorie à l'implémentation pratique.

Pourquoi le retrieval est critique dans un système RAG

Un système RAG fonctionne en deux temps : d'abord récupérer les documents pertinents (retrieval), puis générer une réponse basée sur ces documents (generation). La qualité de la réponse finale dépend directement de la qualité des documents récupérés.

Imaginez un assistant qui doit répondre à "Quelle est votre politique de retour ?" Si le retrieval ramène des pages sur les conditions de livraison au lieu de la politique de retour, le LLM générera une réponse incorrecte ou inventera une politique fictive.

Les trois piliers du retrieval Représentation : Comment transformer le texte en vecteurs mathématiques Indexation : Comment organiser ces vecteurs pour une recherche rapide Recherche : Comment trouver les documents les plus pertinents

Comprendre les embeddings

Les embeddings sont des représentations vectorielles du texte. Chaque mot, phrase ou document est transformé en un vecteur de nombres (typiquement 384 à 1536 dimensions) qui capture son sens sémantique.

Comment fonctionnent les embeddings

``python from sentence_transformers import SentenceTransformer

Charger un modèle d'embedding model = SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2')

Créer des embeddings textes = [ "Comment retourner un produit ?", "Quelle est la politique de remboursement ?", "Horaires d'ouverture du magasin" ]

embeddings = model.encode(textes)

Calculer la similarité from sklearn.metrics.pairwise import cosine_similarity similarites = cosine_similarity(embeddings)

print("Similarité 'retour' vs 'remboursement':", similarites[0][1]) ~0.85 print("Similarité 'retour' vs 'horaires':", similarites[0][2]) ~0.25 `

Les deux premières phrases, bien que formulées différemment, ont une forte similarité car elles traitent du même sujet. La troisième est sémantiquement éloignée.

Choisir son modèle d'embedding

| Modèle | Dimensions | Performance | Vitesse | Usage recommandé | |--------|------------|-------------|---------|------------------| | all-MiniLM-L6-v2 | 384 | Bonne | Rapide | Prototypage, volumes importants | | all-mpnet-base-v2 | 768 | Très bonne | Moyenne | Production généraliste | | text-embedding-3-small | 1536 | Excellente | Rapide (API) | Production avec budget API | | text-embedding-3-large | 3072 | État de l'art | Moyenne (API) | Cas critiques haute précision | | multilingual-e5-large | 1024 | Excellente multilingue | Moyenne | Contenus FR/EN/multilingue |

Pour un projet en français, privilégiez les modèles multilingues ou entraînés sur des corpus francophones :

`python Excellent choix pour le français model = SentenceTransformer('intfloat/multilingual-e5-large')

Préfixe requis pour E5 query = "query: Comment fonctionne la garantie ?" documents = ["passage: La garantie couvre les défauts de fabrication pendant 2 ans..."] `

Le chunking : découper intelligemment les documents

Le chunking est l'art de découper les documents en morceaux de taille appropriée. Trop grand, le chunk contient du bruit. Trop petit, il perd le contexte.

Stratégies de chunking Chunking par taille fixe

La méthode la plus simple : découper tous les X caractères avec chevauchement.

`python from langchain.text_splitter import RecursiveCharacterTextSplitter

splitter = RecursiveCharacterTextSplitter( chunk_size=500, Taille cible chunk_overlap=50, Chevauchement pour conserver le contexte separators=["\n\n", "\n", ". ", " ", ""] )

document = """ Politique de retour

Vous avez 30 jours pour retourner un produit non utilisé dans son emballage d'origine.

Procédure de retour : Connectez-vous à votre espace client Sélectionnez la commande concernée Cliquez sur "Demander un retour" Imprimez l'étiquette de retour

Les frais de retour sont à votre charge sauf en cas de produit défectueux.

Remboursement

Une fois le retour réceptionné et validé, le remboursement est effectué sous 5 jours ouvrés sur le moyen de paiement utilisé lors de l'achat. """

chunks = splitter.split_text(document) for i, chunk in enumerate(chunks): print(f"Chunk {i+1}: {chunk[:100]}...") ` Chunking sémantique

Plus sophistiqué : découper aux frontières naturelles du texte (paragraphes, sections).

`python from langchain.text_splitter import MarkdownTextSplitter

md_splitter = MarkdownTextSplitter( chunk_size=500, chunk_overlap=0 )

Respecte la structure Markdown chunks = md_splitter.split_text(markdown_document) ` Chunking par phrase avec fenêtre glissante

Idéal pour les FAQ et contenus courts :

`python import nltk nltk.download('punkt')

def chunk_by_sentences(text, sentences_per_chunk=3, overlap=1): sentences = nltk.sent_tokenize(text, language='french') chunks = []

for i in range(0, len(sentences), sentences_per_chunk - overlap): chunk = " ".join(sentences[i:i + sentences_per_chunk]) chunks.append(chunk)

return chunks `

Tableau comparatif des stratégies

| Stratégie | Avantages | Inconvénients | Cas d'usage | |-----------|-----------|---------------|-------------| | Taille fixe | Simple, prévisible | Coupe au milieu des idées | Documents homogènes | | Sémantique | Respecte le sens | Plus complexe | Documentation structurée | | Par phrase | Précision fine | Chunks parfois trop courts | FAQ, support | | Hiérarchique | Contexte parent préservé | Complexité accrue | Documentation technique |

Indexation avec les bases vectorielles

Une fois les embeddings créés, il faut les stocker et les indexer pour permettre une recherche rapide. Les bases de données vectorielles sont optimisées pour cette tâche.

Qdrant : exemple d'implémentation

`python from qdrant_client import QdrantClient from qdrant_client.models import Distance, VectorParams, PointStruct

Connexion client = QdrantClient(host="localhost", port=6333)

Créer une collection client.create_collection( collection_name="knowledge_base", vectors_config=VectorParams( size=384, Dimension de vos embeddings distance=Distance.COSINE ) )

Indexer des documents points = [ PointStruct( id=i, vector=embedding.tolist(), payload={ "text": chunk, "source": "politique_retour.md", "category": "support" } ) for i, (embedding, chunk) in enumerate(zip(embeddings, chunks)) ]

client.upsert( collection_name="knowledge_base", points=points ) `

Recherche vectorielle

`python def search(query: str, top_k: int = 5): Encoder la requête query_embedding = model.encode(query)

Rechercher results = client.search( collection_name="knowledge_base", query_vector=query_embedding.tolist(), limit=top_k )

return [ { "text": hit.payload["text"], "score": hit.score, "source": hit.payload["source"] } for hit in results ]

Exemple resultats = search("Comment me faire rembourser ?") for r in resultats: print(f"Score: {r['score']:.3f} - {r['text'][:100]}...") `

Métriques de similarité

Le choix de la métrique impacte les résultats de recherche.

Cosine similarity

La plus utilisée. Mesure l'angle entre deux vecteurs, indépendamment de leur magnitude.

`python import numpy as np

def cosine_similarity(a, b): return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b)) `

Avantages : Insensible à la longueur du texte original Inconvénients : Peut manquer des nuances de magnitude

Dot product (produit scalaire)

Plus rapide, mais sensible à la magnitude des vecteurs.

`python def dot_product(a, b): return np.dot(a, b) `

Avantages : Plus rapide à calculer Inconvénients : Nécessite des vecteurs normalisés pour être comparable au cosine

Distance euclidienne

Mesure la distance "à vol d'oiseau" entre deux points.

`python def euclidean_distance(a, b): return np.linalg.norm(a - b) `

Avantages : Intuitive géométriquement Inconvénients : Sensible aux outliers et à la dimensionnalité

Optimiser le retrieval Query expansion

Enrichir la requête utilisateur pour améliorer le recall :

`python def expand_query(query: str, llm) -> list[str]: prompt = f""" Génère 3 reformulations de cette question pour améliorer la recherche : Question originale : {query}

Reformulations : """

expansions = llm.generate(prompt) return [query] + expansions

Rechercher avec toutes les variantes def search_expanded(query: str, top_k: int = 5): queries = expand_query(query, llm) all_results = []

for q in queries: results = search(q, top_k=top_k) all_results.extend(results)

Dédupliquer et re-scorer return deduplicate_and_rerank(all_results) ` Reranking

Utiliser un modèle de reranking pour affiner les résultats :

`python from sentence_transformers import CrossEncoder

reranker = CrossEncoder('cross-encoder/ms-marco-MiniLM-L-6-v2')

def rerank(query: str, documents: list[str], top_k: int = 3): pairs = [[query, doc] for doc in documents] scores = reranker.predict(pairs)

Trier par score décroissant ranked = sorted(zip(documents, scores), key=lambda x: x[1], reverse=True) return ranked[:top_k]

Pipeline complet def search_with_rerank(query: str): Recherche initiale (recall élevé) initial_results = search(query, top_k=20) Reranking (précision élevée) documents = [r["text"] for r in initial_results] reranked = rerank(query, documents, top_k=5)

return reranked ` Filtrage par métadonnées

Combiner recherche vectorielle et filtres classiques :

`python from qdrant_client.models import Filter, FieldCondition, MatchValue

def search_filtered(query: str, category: str = None, top_k: int = 5): query_embedding = model.encode(query)

Construire le filtre filter_conditions = None if category: filter_conditions = Filter( must=[ FieldCondition( key="category", match=MatchValue(value=category) ) ] )

results = client.search( collection_name="knowledge_base", query_vector=query_embedding.tolist(), query_filter=filter_conditions, limit=top_k )

return results

Rechercher uniquement dans la catégorie "support" resultats = search_filtered("politique retour", category="support") `

Évaluer la qualité du retrieval

Pour mesurer l'efficacité de votre système de retrieval, utilisez ces métriques :

Recall@k

Proportion de documents pertinents retrouvés parmi les k premiers résultats.

`python def recall_at_k(retrieved: list, relevant: list, k: int) -> float: retrieved_k = set(retrieved[:k]) relevant_set = set(relevant)

return len(retrieved_k & relevant_set) / len(relevant_set) `

MRR (Mean Reciprocal Rank)

Position moyenne du premier document pertinent.

`python def mrr(queries_results: list[tuple[list, list]]) -> float: reciprocal_ranks = []

for retrieved, relevant in queries_results: for i, doc in enumerate(retrieved): if doc in relevant: reciprocal_ranks.append(1 / (i + 1)) break else: reciprocal_ranks.append(0)

return sum(reciprocal_ranks) / len(reciprocal_ranks) `

NDCG (Normalized Discounted Cumulative Gain)

Prend en compte l'ordre des résultats et les scores de pertinence.

`python import numpy as np

def ndcg_at_k(relevances: list[float], k: int) -> float: relevances = np.array(relevances[:k])

DCG discounts = np.log2(np.arange(2, len(relevances) + 2)) dcg = np.sum(relevances / discounts)

IDCG (DCG idéal) ideal_relevances = np.sort(relevances)[::-1] idcg = np.sum(ideal_relevances / discounts)

return dcg / idcg if idcg > 0 else 0 `

Pièges courants et solutions Chunks trop grands

Symptôme : Le retrieval ramène des documents vaguement pertinents mais pas précis.

Solution : Réduire la taille des chunks ou utiliser le chunking hiérarchique. Vocabulaire de domaine

Symptôme : Les termes métier ne sont pas bien compris par les embeddings.

Solution : Fine-tuner le modèle d'embedding ou utiliser un vocabulaire de synonymes.

`python synonymes = { "ticket": ["demande", "requête", "incident"], "KB": ["base de connaissances", "knowledge base"], }

def expand_with_synonyms(query: str) -> str: for term, syns in synonymes.items(): if term.lower() in query.lower(): query += " " + " ".join(syns) return query ` Requêtes ambiguës

Symptôme : "Problème avec ma commande" ramène trop de résultats différents.

Solution : Utiliser le contexte conversationnel ou demander des précisions. Cold start

Symptôme : Peu de données au démarrage, retrieval peu pertinent.

Solution : Enrichir avec des données synthétiques ou FAQ générées.

Architecture de production

Pour un système de retrieval en production, voici une architecture recommandée :

` ┌─────────────────────────────────────────────────────────────┐ │ API Gateway │ └─────────────────────┬───────────────────────────────────────┘ │ ┌─────────────────────▼───────────────────────────────────────┐ │ Query Processor │ │ - Normalisation │ │ - Détection de langue │ │ - Query expansion │ └─────────────────────┬───────────────────────────────────────┘ │ ┌────────────┴────────────┐ ▼ ▼ ┌─────────────────┐ ┌─────────────────┐ │ Dense Search │ │ Sparse Search │ │ (Qdrant) │ │ (BM25) │ └────────┬────────┘ └────────┬────────┘ │ │ └──────────┬─────────────┘ ▼ ┌─────────────────┐ │ Fusion/Rerank │ └────────┬────────┘ ▼ ┌─────────────────┐ │ LLM Context │ └─────────────────┘ ``

Prochaines étapes

Maintenant que vous maîtrisez les fondamentaux du retrieval, approfondissez avec nos guides spécialisés : • Dense Retrieval : Recherche sémantique avec embeddings - Plongez dans les embeddings avancés • Sparse Retrieval et BM25 - Découvrez quand la recherche lexicale surpasse • Fusion hybride - Combinez le meilleur des deux mondes

Pour une vue d'ensemble du RAG, consultez notre Introduction complète au RAG.

---

Passez à la pratique avec Ailog

Implémenter un système de retrieval performant demande du temps et de l'expertise. Avec Ailog, bénéficiez d'une infrastructure RAG clé en main : • Chunking intelligent optimisé pour votre type de contenu • Modèles d'embedding multilingues (français/anglais natif) • Reranking automatique pour des résultats ultra-précis • Hébergement souverain en France, conforme RGPD

Testez gratuitement Ailog et déployez votre premier assistant RAG en 3 minutes.

Tags

  • RAG
  • retrieval
  • embeddings
  • recherche vectorielle
  • chunking
5. RetrievalIntermédiaire

Fondamentaux du Retrieval : Comment fonctionne la recherche RAG

15 janvier 2026
18 min de lecture
Équipe Ailog

Maîtrisez les bases du retrieval dans les systèmes RAG : embeddings, recherche vectorielle, chunking et indexation pour des résultats pertinents.

Fondamentaux du Retrieval : Comment fonctionne la recherche RAG

Le retrieval est le cœur battant de tout système RAG (Retrieval-Augmented Generation). Sans une recherche efficace, même le meilleur LLM du monde produira des réponses hors sujet ou incomplètes. Ce guide vous accompagne dans la compréhension approfondie des mécanismes de retrieval, de la théorie à l'implémentation pratique.

Pourquoi le retrieval est critique dans un système RAG

Un système RAG fonctionne en deux temps : d'abord récupérer les documents pertinents (retrieval), puis générer une réponse basée sur ces documents (generation). La qualité de la réponse finale dépend directement de la qualité des documents récupérés.

Imaginez un assistant qui doit répondre à "Quelle est votre politique de retour ?" Si le retrieval ramène des pages sur les conditions de livraison au lieu de la politique de retour, le LLM générera une réponse incorrecte ou inventera une politique fictive.

Les trois piliers du retrieval

  1. Représentation : Comment transformer le texte en vecteurs mathématiques
  2. Indexation : Comment organiser ces vecteurs pour une recherche rapide
  3. Recherche : Comment trouver les documents les plus pertinents

Comprendre les embeddings

Les embeddings sont des représentations vectorielles du texte. Chaque mot, phrase ou document est transformé en un vecteur de nombres (typiquement 384 à 1536 dimensions) qui capture son sens sémantique.

Comment fonctionnent les embeddings

DEVELOPERpython
from sentence_transformers import SentenceTransformer # Charger un modèle d'embedding model = SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2') # Créer des embeddings textes = [ "Comment retourner un produit ?", "Quelle est la politique de remboursement ?", "Horaires d'ouverture du magasin" ] embeddings = model.encode(textes) # Calculer la similarité from sklearn.metrics.pairwise import cosine_similarity similarites = cosine_similarity(embeddings) print("Similarité 'retour' vs 'remboursement':", similarites[0][1]) # ~0.85 print("Similarité 'retour' vs 'horaires':", similarites[0][2]) # ~0.25

Les deux premières phrases, bien que formulées différemment, ont une forte similarité car elles traitent du même sujet. La troisième est sémantiquement éloignée.

Choisir son modèle d'embedding

ModèleDimensionsPerformanceVitesseUsage recommandé
all-MiniLM-L6-v2384BonneRapidePrototypage, volumes importants
all-mpnet-base-v2768Très bonneMoyenneProduction généraliste
text-embedding-3-small1536ExcellenteRapide (API)Production avec budget API
text-embedding-3-large3072État de l'artMoyenne (API)Cas critiques haute précision
multilingual-e5-large1024Excellente multilingueMoyenneContenus FR/EN/multilingue

Pour un projet en français, privilégiez les modèles multilingues ou entraînés sur des corpus francophones :

DEVELOPERpython
# Excellent choix pour le français model = SentenceTransformer('intfloat/multilingual-e5-large') # Préfixe requis pour E5 query = "query: Comment fonctionne la garantie ?" documents = ["passage: La garantie couvre les défauts de fabrication pendant 2 ans..."]

Le chunking : découper intelligemment les documents

Le chunking est l'art de découper les documents en morceaux de taille appropriée. Trop grand, le chunk contient du bruit. Trop petit, il perd le contexte.

Stratégies de chunking

1. Chunking par taille fixe

La méthode la plus simple : découper tous les X caractères avec chevauchement.

DEVELOPERpython
from langchain.text_splitter import RecursiveCharacterTextSplitter splitter = RecursiveCharacterTextSplitter( chunk_size=500, # Taille cible chunk_overlap=50, # Chevauchement pour conserver le contexte separators=["\n\n", "\n", ". ", " ", ""] ) document = """ Politique de retour Vous avez 30 jours pour retourner un produit non utilisé dans son emballage d'origine. Procédure de retour : 1. Connectez-vous à votre espace client 2. Sélectionnez la commande concernée 3. Cliquez sur "Demander un retour" 4. Imprimez l'étiquette de retour Les frais de retour sont à votre charge sauf en cas de produit défectueux. Remboursement Une fois le retour réceptionné et validé, le remboursement est effectué sous 5 jours ouvrés sur le moyen de paiement utilisé lors de l'achat. """ chunks = splitter.split_text(document) for i, chunk in enumerate(chunks): print(f"Chunk {i+1}: {chunk[:100]}...")

2. Chunking sémantique

Plus sophistiqué : découper aux frontières naturelles du texte (paragraphes, sections).

DEVELOPERpython
from langchain.text_splitter import MarkdownTextSplitter md_splitter = MarkdownTextSplitter( chunk_size=500, chunk_overlap=0 ) # Respecte la structure Markdown chunks = md_splitter.split_text(markdown_document)

3. Chunking par phrase avec fenêtre glissante

Idéal pour les FAQ et contenus courts :

DEVELOPERpython
import nltk nltk.download('punkt') def chunk_by_sentences(text, sentences_per_chunk=3, overlap=1): sentences = nltk.sent_tokenize(text, language='french') chunks = [] for i in range(0, len(sentences), sentences_per_chunk - overlap): chunk = " ".join(sentences[i:i + sentences_per_chunk]) chunks.append(chunk) return chunks

Tableau comparatif des stratégies

StratégieAvantagesInconvénientsCas d'usage
Taille fixeSimple, prévisibleCoupe au milieu des idéesDocuments homogènes
SémantiqueRespecte le sensPlus complexeDocumentation structurée
Par phrasePrécision fineChunks parfois trop courtsFAQ, support
HiérarchiqueContexte parent préservéComplexité accrueDocumentation technique

Indexation avec les bases vectorielles

Une fois les embeddings créés, il faut les stocker et les indexer pour permettre une recherche rapide. Les bases de données vectorielles sont optimisées pour cette tâche.

Qdrant : exemple d'implémentation

DEVELOPERpython
from qdrant_client import QdrantClient from qdrant_client.models import Distance, VectorParams, PointStruct # Connexion client = QdrantClient(host="localhost", port=6333) # Créer une collection client.create_collection( collection_name="knowledge_base", vectors_config=VectorParams( size=384, # Dimension de vos embeddings distance=Distance.COSINE ) ) # Indexer des documents points = [ PointStruct( id=i, vector=embedding.tolist(), payload={ "text": chunk, "source": "politique_retour.md", "category": "support" } ) for i, (embedding, chunk) in enumerate(zip(embeddings, chunks)) ] client.upsert( collection_name="knowledge_base", points=points )

Recherche vectorielle

DEVELOPERpython
def search(query: str, top_k: int = 5): # Encoder la requête query_embedding = model.encode(query) # Rechercher results = client.search( collection_name="knowledge_base", query_vector=query_embedding.tolist(), limit=top_k ) return [ { "text": hit.payload["text"], "score": hit.score, "source": hit.payload["source"] } for hit in results ] # Exemple resultats = search("Comment me faire rembourser ?") for r in resultats: print(f"Score: {r['score']:.3f} - {r['text'][:100]}...")

Métriques de similarité

Le choix de la métrique impacte les résultats de recherche.

Cosine similarity

La plus utilisée. Mesure l'angle entre deux vecteurs, indépendamment de leur magnitude.

DEVELOPERpython
import numpy as np def cosine_similarity(a, b): return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))

Avantages : Insensible à la longueur du texte original Inconvénients : Peut manquer des nuances de magnitude

Dot product (produit scalaire)

Plus rapide, mais sensible à la magnitude des vecteurs.

DEVELOPERpython
def dot_product(a, b): return np.dot(a, b)

Avantages : Plus rapide à calculer Inconvénients : Nécessite des vecteurs normalisés pour être comparable au cosine

Distance euclidienne

Mesure la distance "à vol d'oiseau" entre deux points.

DEVELOPERpython
def euclidean_distance(a, b): return np.linalg.norm(a - b)

Avantages : Intuitive géométriquement Inconvénients : Sensible aux outliers et à la dimensionnalité

Optimiser le retrieval

1. Query expansion

Enrichir la requête utilisateur pour améliorer le recall :

DEVELOPERpython
def expand_query(query: str, llm) -> list[str]: prompt = f""" Génère 3 reformulations de cette question pour améliorer la recherche : Question originale : {query} Reformulations : """ expansions = llm.generate(prompt) return [query] + expansions # Rechercher avec toutes les variantes def search_expanded(query: str, top_k: int = 5): queries = expand_query(query, llm) all_results = [] for q in queries: results = search(q, top_k=top_k) all_results.extend(results) # Dédupliquer et re-scorer return deduplicate_and_rerank(all_results)

2. Reranking

Utiliser un modèle de reranking pour affiner les résultats :

DEVELOPERpython
from sentence_transformers import CrossEncoder reranker = CrossEncoder('cross-encoder/ms-marco-MiniLM-L-6-v2') def rerank(query: str, documents: list[str], top_k: int = 3): pairs = [[query, doc] for doc in documents] scores = reranker.predict(pairs) # Trier par score décroissant ranked = sorted(zip(documents, scores), key=lambda x: x[1], reverse=True) return ranked[:top_k] # Pipeline complet def search_with_rerank(query: str): # 1. Recherche initiale (recall élevé) initial_results = search(query, top_k=20) # 2. Reranking (précision élevée) documents = [r["text"] for r in initial_results] reranked = rerank(query, documents, top_k=5) return reranked

3. Filtrage par métadonnées

Combiner recherche vectorielle et filtres classiques :

DEVELOPERpython
from qdrant_client.models import Filter, FieldCondition, MatchValue def search_filtered(query: str, category: str = None, top_k: int = 5): query_embedding = model.encode(query) # Construire le filtre filter_conditions = None if category: filter_conditions = Filter( must=[ FieldCondition( key="category", match=MatchValue(value=category) ) ] ) results = client.search( collection_name="knowledge_base", query_vector=query_embedding.tolist(), query_filter=filter_conditions, limit=top_k ) return results # Rechercher uniquement dans la catégorie "support" resultats = search_filtered("politique retour", category="support")

Évaluer la qualité du retrieval

Pour mesurer l'efficacité de votre système de retrieval, utilisez ces métriques :

Recall@k

Proportion de documents pertinents retrouvés parmi les k premiers résultats.

DEVELOPERpython
def recall_at_k(retrieved: list, relevant: list, k: int) -> float: retrieved_k = set(retrieved[:k]) relevant_set = set(relevant) return len(retrieved_k & relevant_set) / len(relevant_set)

MRR (Mean Reciprocal Rank)

Position moyenne du premier document pertinent.

DEVELOPERpython
def mrr(queries_results: list[tuple[list, list]]) -> float: reciprocal_ranks = [] for retrieved, relevant in queries_results: for i, doc in enumerate(retrieved): if doc in relevant: reciprocal_ranks.append(1 / (i + 1)) break else: reciprocal_ranks.append(0) return sum(reciprocal_ranks) / len(reciprocal_ranks)

NDCG (Normalized Discounted Cumulative Gain)

Prend en compte l'ordre des résultats et les scores de pertinence.

DEVELOPERpython
import numpy as np def ndcg_at_k(relevances: list[float], k: int) -> float: relevances = np.array(relevances[:k]) # DCG discounts = np.log2(np.arange(2, len(relevances) + 2)) dcg = np.sum(relevances / discounts) # IDCG (DCG idéal) ideal_relevances = np.sort(relevances)[::-1] idcg = np.sum(ideal_relevances / discounts) return dcg / idcg if idcg > 0 else 0

Pièges courants et solutions

1. Chunks trop grands

Symptôme : Le retrieval ramène des documents vaguement pertinents mais pas précis.

Solution : Réduire la taille des chunks ou utiliser le chunking hiérarchique.

2. Vocabulaire de domaine

Symptôme : Les termes métier ne sont pas bien compris par les embeddings.

Solution : Fine-tuner le modèle d'embedding ou utiliser un vocabulaire de synonymes.

DEVELOPERpython
synonymes = { "ticket": ["demande", "requête", "incident"], "KB": ["base de connaissances", "knowledge base"], } def expand_with_synonyms(query: str) -> str: for term, syns in synonymes.items(): if term.lower() in query.lower(): query += " " + " ".join(syns) return query

3. Requêtes ambiguës

Symptôme : "Problème avec ma commande" ramène trop de résultats différents.

Solution : Utiliser le contexte conversationnel ou demander des précisions.

4. Cold start

Symptôme : Peu de données au démarrage, retrieval peu pertinent.

Solution : Enrichir avec des données synthétiques ou FAQ générées.

Architecture de production

Pour un système de retrieval en production, voici une architecture recommandée :

┌─────────────────────────────────────────────────────────────┐
│                        API Gateway                           │
└─────────────────────┬───────────────────────────────────────┘
                      │
┌─────────────────────▼───────────────────────────────────────┐
│                   Query Processor                            │
│  - Normalisation                                             │
│  - Détection de langue                                       │
│  - Query expansion                                           │
└─────────────────────┬───────────────────────────────────────┘
                      │
         ┌────────────┴────────────┐
         ▼                         ▼
┌─────────────────┐      ┌─────────────────┐
│  Dense Search   │      │  Sparse Search  │
│   (Qdrant)      │      │   (BM25)        │
└────────┬────────┘      └────────┬────────┘
         │                        │
         └──────────┬─────────────┘
                    ▼
         ┌─────────────────┐
         │  Fusion/Rerank  │
         └────────┬────────┘
                  ▼
         ┌─────────────────┐
         │   LLM Context   │
         └─────────────────┘

Prochaines étapes

Maintenant que vous maîtrisez les fondamentaux du retrieval, approfondissez avec nos guides spécialisés :

Pour une vue d'ensemble du RAG, consultez notre Introduction complète au RAG.


Passez à la pratique avec Ailog

Implémenter un système de retrieval performant demande du temps et de l'expertise. Avec Ailog, bénéficiez d'une infrastructure RAG clé en main :

  • Chunking intelligent optimisé pour votre type de contenu
  • Modèles d'embedding multilingues (français/anglais natif)
  • Reranking automatique pour des résultats ultra-précis
  • Hébergement souverain en France, conforme RGPD

Testez gratuitement Ailog et déployez votre premier assistant RAG en 3 minutes.

Tags

RAGretrievalembeddingsrecherche vectoriellechunking

Articles connexes

Ailog Assistant

Ici pour vous aider

Salut ! Pose-moi des questions sur Ailog et comment intégrer votre RAG dans vos projets !