MMR : Diversifier les Résultats de Recherche avec la Pertinence Marginale Maximale
Réduisez la redondance dans la récupération RAG : utilisez MMR pour équilibrer pertinence et diversité pour une meilleure qualité de contexte.
- Auteur
- Équipe de Recherche Ailog
- Date de publication
- Temps de lecture
- 9 min de lecture
- Niveau
- advanced
- Étape du pipeline RAG
- Retrieval
Le problème de redondance
La recherche par similarité standard renvoie des documents similaires - souvent trop similaires :
`` Requête : "Comment fonctionne la photosynthèse ?"
Top 5 résultats : "La photosynthèse convertit la lumière en énergie..." "La photosynthèse est comment les plantes créent de l'énergie..." ← Redondant "Les plantes utilisent la photosynthèse pour créer..." ← Redondant "La chlorophylle permet la photosynthèse..." ← Aspect différent! "La photosynthèse se produit dans les chloroplastes..." ← Aspect différent! `
Vous gaspillez le contexte sur de la répétition.
Maximal Marginal Relevance (MMR)
MMR équilibre pertinence à la requête et diversité par rapport aux docs déjà sélectionnés.
Formule : ` MMR = argmax[λ Sim(Di, Q) - (1-λ) max Sim(Di, Dj)] Di ↑ ↑ pertinence requête similarité aux sélectionnés `
λ = 0.7 typique (70% pertinence, 30% diversité)
Implémentation
`python import numpy as np from sklearn.metrics.pairwise import cosine_similarity
def mmr_search(query_embedding, doc_embeddings, documents, k=10, lambda_param=0.7): """ Récupération MMR
Args: query_embedding: Vecteur de requête doc_embeddings: Tous les vecteurs de documents documents: Documents originaux k: Nombre de résultats lambda_param: Pertinence vs diversité (0-1) """ Calculer la similarité à la requête query_sim = cosine_similarity([query_embedding], doc_embeddings)[0]
selected_indices = [] remaining_indices = list(range(len(documents)))
Sélectionner le premier document (le plus similaire à la requête) first_idx = np.argmax(query_sim) selected_indices.append(first_idx) remaining_indices.remove(first_idx)
Sélectionner k-1 documents supplémentaires de manière itérative for _ in range(k - 1): mmr_scores = []
for idx in remaining_indices: Pertinence à la requête relevance = query_sim[idx]
Similarité max aux docs déjà sélectionnés selected_embeddings = doc_embeddings[selected_indices] diversity = max(cosine_similarity([doc_embeddings[idx]], selected_embeddings)[0])
Score MMR mmr_score = lambda_param relevance - (1 - lambda_param) diversity mmr_scores.append((idx, mmr_score))
Sélectionner le doc avec le score MMR le plus élevé best_idx = max(mmr_scores, key=lambda x: x[1])[0] selected_indices.append(best_idx) remaining_indices.remove(best_idx)
return [documents[i] for i in selected_indices] `
MMR intégré LangChain
`python from langchain.vectorstores import Chroma from langchain.embeddings import OpenAIEmbeddings
vectorstore = Chroma.from_documents(documents, OpenAIEmbeddings())
Recherche MMR results = vectorstore.max_marginal_relevance_search( query="photosynthèse", k=5, fetch_k=20, Récupérer 20 candidats, retourner 5 diversifiés lambda_mult=0.7 Poids de pertinence ) `
Quand utiliser MMR
Utiliser MMR quand : • Les documents ont un fort chevauchement • La fenêtre de contexte est limitée • Vous avez besoin d'une large couverture • Requêtes multi-aspects ("parlez-moi de X, Y et Z")
Ignorer MMR quand : • Les documents sont déjà diversifiés • La vitesse est critique (MMR est plus lent) • Requêtes à aspect unique
Réglage de Lambda
`python Tester différentes valeurs de lambda lambdas = [0.3, 0.5, 0.7, 0.9]
for lam in lambdas: results = mmr_search(query, embeddings, docs, lambda_param=lam)
Mesurer la diversité diversity = measure_diversity(results) relevance = measure_relevance(results, query)
print(f"λ={lam}: Pertinence={relevance:.2f}, Diversité={diversity:.2f}") `
Recommandations : • Domaine à forte redondance : λ = 0.5-0.6 • Usage général : λ = 0.7 • Précision critique : λ = 0.8-0.9
Optimisation des performances
MMR est O(k²) - lent pour k élevé :
`python Plus rapide : Récupérer d'abord les candidats def fast_mmr(query, vectordb, k=10, fetch_k=100, lambda_param=0.7): Obtenir fetch_k candidats (recherche vectorielle rapide) candidates = vectordb.search(query, k=fetch_k) Appliquer MMR sur un ensemble plus petit return mmr_search( query_embedding=query, doc_embeddings=[c['embedding'] for c in candidates], documents=[c['doc'] for c in candidates], k=k, lambda_param=lambda_param ) `
Combinaison avec le reranking
Pipeline : Récupération → MMR → Reranking
`python Récupération initiale candidates = vector_search(query, k=100) Diversifier avec MMR diverse_docs = mmr_search(query, candidates, k=20) Reranker pour la précision final_results = cross_encoder_rerank(query, diverse_docs, k=10) ``
MMR garantit que votre LLM voit un contexte varié et non redondant. Essentiel pour un RAG de haute qualité.