AvancéRAG
25 min de lecture10 vues

GraphRAG et Hybrid Search : BM25 + Vecteur

Le RAG vectoriel pur a ses limites. Hybrid search (BM25 + embedding) et GraphRAG résolvent les cas complexes — apprenez à les implémenter avec Agno et LanceDB.

Les Limites du RAG Vectoriel Pur

Le RAG vectoriel classique fonctionne très bien pour les questions directes où la réponse se trouve dans un seul chunk. Mais il échoue sur deux catégories de problèmes fréquents en production.

Problème 1 : Le "Needle in a Haystack"

Imaginez 10 000 documents techniques. L'utilisateur demande le numéro de référence exact d'une pièce : "SKU-78421-B". La recherche vectorielle cherche la proximité sémantique : mais un code produit n'a pas de sens sémantique. Il s'agit d'une correspondance exacte de chaîne de caractères.

Question : "Quel est le prix du composant SKU-78421-B ?"
Recherche vectorielle : trouve des documents sur "composants électroniques",
                        "références catalogue", "prix unitaires" : mais pas
                        nécessairement le document contenant exactement SKU-78421-B.
Recherche BM25 (keyword) : trouve EXACTEMENT les documents contenant "SKU-78421-B".

Problème 2 : Le Multihop Reasoning

L'utilisateur pose une question qui nécessite de combiner des informations provenant de plusieurs documents :

Question : "Quel est le responsable du projet qui utilise la technologie
            décrite dans le brevet déposé en 2023 ?"

Pour répondre, il faut :
  Doc A → Le brevet 2023 décrit la technologie X
  Doc B → La technologie X est utilisée dans le projet Alpha
  Doc C → Le responsable du projet Alpha est Marie Dupont.

Le RAG vectoriel récupère des chunks individuels.
Il ne reconstitue pas la chaîne de raisonnement A → B → C.

Ces deux problèmes représentent environ 20-30% des questions réelles en entreprise. Si votre RAG échoue sur ces cas, vos utilisateurs auront une mauvaise expérience sur précisément les questions les plus complexes : celles où l'IA devrait apporter le plus de valeur.


Hybrid Search : BM25 + Vectoriel

Pourquoi les Deux Sont Complémentaires

DimensionRecherche VectorielleBM25 (Keyword)
Force principaleCompréhension du sensCorrespondance exacte
SynonymesExcellentÉchoue
Codes / référencesÉchoueExcellent
Noms propresMédiocreExcellent
ReformulationsExcellentÉchoue
Termes techniques raresMédiocreExcellent

La recherche hybride combine les scores des deux approches pour obtenir le meilleur des deux mondes :

Score hybride = α × score_vectoriel + (1-α) × score_BM25

α est un paramètre de pondération (souvent 0.5 en point de départ).

Fonctionnement de BM25

BM25 (Best Match 25) est une variante améliorée de TF-IDF. Il mesure la pertinence d'un document pour une requête en comptant les occurrences des mots de la requête dans le document, avec une normalisation par la longueur du document.

Score BM25(doc, query) = Σ IDF(term) × (TF(term, doc) × (k1 + 1)) / (TF(term, doc) + k1 × (1 - b + b × |doc| / avgdl))

Où :
- IDF = importance du terme (rare = plus important)
- TF  = fréquence du terme dans le document
- k1, b = paramètres de saturation et normalisation
- avgdl = longueur moyenne des documents

Reranking : Raffiner les Résultats

Même avec la recherche hybride, les 20 premiers résultats peuvent contenir du bruit. Le reranking est une étape post-retrieval qui réordonne les résultats par pertinence réelle.

Pipeline avec Reranking

Types de Rerankers

Cross-encoders : modèles qui analysent la paire (question, document) ensemble pour scorer la pertinence. Plus précis mais plus lents.

Cohere Rerank : API de reranking de Cohere, très performante sur le multilingue. Modèle rerank-multilingual-v3.0 pour le français.

BGE Reranker : modèle open-source de BAAI, utilisable localement sans coût par token.


Micro-exercice : Hybrid Search avec Agno + LanceDB

Installation

pip install agno openai lancedb tantivy cohere pypdf
# tantivy est le moteur BM25 utilisé par LanceDB

Code Complet avec Hybrid Search et Reranking

# hybrid_search.py
import os
from agno.agent import Agent
from agno.knowledge.embedder.openai import OpenAIEmbedder
from agno.knowledge.knowledge import Knowledge
from agno.knowledge.reranker.cohere import CohereReranker
from agno.models.openai import OpenAIResponses
from agno.vectordb.lancedb import LanceDb, SearchType

os.environ["OPENAI_API_KEY"] = "sk-..."
os.environ["COHERE_API_KEY"] = "..."

knowledge = Knowledge(
    vector_db=LanceDb(
        uri="tmp/lancedb",
        table_name="docs_hybrid",
        search_type=SearchType.hybrid,          # BM25 + vectoriel
        embedder=OpenAIEmbedder(id="text-embedding-3-small"),
        reranker=CohereReranker(
            model="rerank-multilingual-v3.0",   # Excellent pour le français
            top_n=5,                             # Garder les 5 meilleurs après reranking
        ),
    ),
)

# Charger des documents
knowledge.insert(
    url="https://agno-public.s3.amazonaws.com/recipes/ThaiRecipes.pdf"
)

agent = Agent(
    model=OpenAIResponses(id="gpt-4o"),
    knowledge=knowledge,
    instructions=[
        "Utilise ta base de connaissances pour répondre.",
        "Sois précis et cite les informations clés.",
    ],
    markdown=True,
)

# Test avec une question nécessitant la précision keyword
agent.print_response(
    "Quels plats utilisent du lait de coco comme ingrédient principal ?",
    stream=True,
)

Comparer les SearchTypes

from agno.vectordb.lancedb import LanceDb, SearchType
from agno.knowledge.knowledge import Knowledge
from agno.knowledge.embedder.openai import OpenAIEmbedder

EMBEDDER = OpenAIEmbedder(id="text-embedding-3-small")
PDF_URL = "https://agno-public.s3.amazonaws.com/recipes/ThaiRecipes.pdf"

# Test des 3 modes
for search_type, label in [
    (SearchType.vector, "Vectoriel pur"),
    (SearchType.keyword, "BM25 pur"),
    (SearchType.hybrid, "Hybride"),
]:
    knowledge = Knowledge(
        vector_db=LanceDb(
            uri="tmp/lancedb",
            table_name=f"docs_{search_type.value}",
            search_type=search_type,
            embedder=EMBEDDER,
        ),
    )
    knowledge.insert(url=PDF_URL)

    results = knowledge.search("Tom Yum", num_documents=3)
    print(f"\n=== {label} ===")
    for doc in results:
        print(f"  → {doc.content[:150]}...")

Utilisez systématiquement SearchType.hybrid dans vos projets Agno. LanceDB + tantivy gèrent automatiquement la fusion BM25 + vectoriel. L'ajout du CohereReranker améliore encore la précision de 10-20% sur les cas difficiles.


GraphRAG : Représenter les Documents comme un Graphe

Concept

Le GraphRAG (Graph Retrieval Augmented Generation) représente les documents non plus comme une collection de chunks indépendants, mais comme un graphe de connaissances où les entités sont des nœuds et leurs relations sont des arêtes.

Document A : "Marie dirige le projet Alpha qui utilise TensorFlow."
Document B : "TensorFlow est un framework créé par Google."
Document C : "Google a investi 100M€ dans DeepMind en 2023."

Graphe :
Marie ──dirige──▶ Projet Alpha
Projet Alpha ──utilise──▶ TensorFlow
TensorFlow ──créé par──▶ Google
Google ──a investi dans──▶ DeepMind

Avec un graphe, la question "Qui dirige le projet qui utilise le framework de l'entreprise qui a investi dans DeepMind ?" peut être résolue en traversant le graphe : DeepMind ← Google → TensorFlow → Projet Alpha → Marie.

Microsoft GraphRAG

Microsoft a publié en 2024 le framework GraphRAG open-source. Il fonctionne en deux phases :

  1. Indexation : un LLM analyse les documents pour extraire les entités (personnes, lieux, concepts) et leurs relations, puis construit un graphe.
  2. Requête : deux modes de recherche : local (sous-graphe pertinent) et global (résumés de communautés du graphe entier).
pip install graphrag

# Initialiser un projet GraphRAG
python -m graphrag init --root ./my-graphrag

# Indexer les documents
python -m graphrag index --root ./my-graphrag

# Requête locale (précise, rapide)
python -m graphrag query --root ./my-graphrag --method local "Qui dirige le projet Alpha ?"

# Requête globale (vue d'ensemble, lente)
python -m graphrag query --root ./my-graphrag --method global "Quels sont les thèmes principaux ?"

LightRAG : Une Alternative Légère

LightRAG (2024) propose une approche similaire mais plus légère et plus rapide à indexer :

from lightrag import LightRAG, QueryParam
from lightrag.llm.openai import gpt_4o_mini_complete

rag = LightRAG(
    working_dir="./lightrag_data",
    llm_model_func=gpt_4o_mini_complete,
)

# Indexer
with open("documents.txt") as f:
    rag.insert(f.read())

# Requêtes en différents modes
print(rag.query("Qui est responsable du projet Alpha ?", param=QueryParam(mode="naive")))
print(rag.query("Qui est responsable du projet Alpha ?", param=QueryParam(mode="local")))
print(rag.query("Qui est responsable du projet Alpha ?", param=QueryParam(mode="global")))
print(rag.query("Qui est responsable du projet Alpha ?", param=QueryParam(mode="hybrid")))

L'indexation GraphRAG est coûteuse. Pour 100 documents, Microsoft GraphRAG peut consommer 50-100 dollars de tokens LLM. LightRAG est significativement moins cher. Évaluez le ROI avant de l'adopter.


Tableau Comparatif : RAG Classique vs Hybrid vs GraphRAG

DimensionRAG ClassiqueHybrid SearchGraphRAG
Questions simplesExcellentExcellentExcellent
Correspondances exactesMédiocreExcellentExcellent
Multihop reasoningMédiocreMédiocreExcellent
Vue d'ensembleMédiocreMédiocreExcellent
Coût d'indexationFaibleFaibleTrès élevé
Latence de requêteFaibleFaibleÉlevée
ComplexitéSimpleFaibleÉlevée
Mises à jourRapideRapideLente (re-indexation)
Cas d'usage80% des cas90% des casCorpus stables complexes

Quand Utiliser Quoi

Stratégie recommandée : commencez avec le hybrid search (SearchType.hybrid + CohereReranker). Cela résout 90% des cas de manière simple. Envisagez GraphRAG uniquement si vous avez un corpus stable et des besoins de raisonnement multi-documents avérés : le coût d'indexation et la complexité opérationnelle doivent être justifiés par le gain de qualité mesuré sur votre golden dataset.

Specialiste IA — Master Intelligence Artificielle

Diplome d'un Master en Intelligence Artificielle, je travaille au quotidien sur des projets IA en entreprise. J'ai cree IwanttolearnAI pour rendre l'apprentissage de l'IA accessible a tous, gratuitement.