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.
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 :
1. "La photosynthèse convertit la lumière en énergie..."
2. "La photosynthèse est comment les plantes créent de l'énergie..." ← Redondant
3. "Les plantes utilisent la photosynthèse pour créer..." ← Redondant
4. "La chlorophylle permet la photosynthèse..." ← Aspect différent!
5. "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
DEVELOPERpythonimport 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
DEVELOPERpythonfrom 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
DEVELOPERpython# 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é :
DEVELOPERpython# Plus rapide : Récupérer d'abord les candidats def fast_mmr(query, vectordb, k=10, fetch_k=100, lambda_param=0.7): # 1. Obtenir fetch_k candidats (recherche vectorielle rapide) candidates = vectordb.search(query, k=fetch_k) # 2. 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
DEVELOPERpython# 1. Récupération initiale candidates = vector_search(query, k=100) # 2. Diversifier avec MMR diverse_docs = mmr_search(query, candidates, k=20) # 3. 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é.
Tags
Articles connexes
Stratégies de Récupération Avancées pour le RAG
Au-delà de la recherche de similarité basique : recherche hybride, expansion de requêtes, MMR et récupération multi-étapes pour de meilleures performances RAG.
Recherche Hybride : Combiner Recherche Sémantique et par Mots-clés
Augmentez la Précision de Récupération de 20-30% : Combinez la Recherche Vectorielle avec le Matching par Mots-clés BM25 pour des Performances RAG Supérieures.
Expansion de Requêtes : Récupérer des Résultats Plus Pertinents
Améliorer le recall de 40% : expandez les requêtes utilisateur avec des synonymes, des sous-requêtes et des variations générées par LLM.