5. RetrievalAvancé

MMR : Diversifier les Résultats de Recherche avec la Pertinence Marginale Maximale

15 novembre 2025
9 min de lecture
Équipe de Recherche Ailog

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

DEVELOPERpython
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

DEVELOPERpython
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

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

mmrrécupérationdiversitéredondance

Articles connexes

Ailog Assistant

Ici pour vous aider

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