5. RetrievalAvancé

Knowledge Graph Embeddings : Quand les Graphes et les Vecteurs Fusionnent pour un RAG Surpuissant

5 septembre 2026
25 min de lecture
Équipe Ailog

Guide complet sur les Knowledge Graph Embeddings pour le RAG : TransE, RotatE, ComplEx, intégration Neo4j + vecteurs, recherche hybride graphe/vecteur et benchmarks multi-hop QA.

TL;DR

Le RAG vectoriel classique excelle pour les questions simples, mais échoue sur les questions multi-hop qui nécessitent de relier plusieurs informations ("Quel est le CEO de l'entreprise qui a acquis la startup fondée par le frère de Elon Musk ?"). Les Knowledge Graph Embeddings combinent la puissance des graphes de connaissances (relations explicites) avec les embeddings vectoriels (similarité sémantique). Résultat : +35% de précision sur les questions multi-hop et une désambiguïsation d'entités quasi parfaite.

Pourquoi les vecteurs seuls ne suffisent pas

Les limites du RAG vectoriel

Type de questionRAG vectorielRAG + Knowledge GraphDifférence
Factuelle simple89.2%90.1%+0.9%
Comparaison78.5%85.3%+6.8%
Multi-hop (2 sauts)62.1%83.7%+21.6%
Multi-hop (3+ sauts)38.5%71.2%+32.7%
Désambiguïsation71.3%94.8%+23.5%
Temporelle65.8%82.1%+16.3%
Agrégation45.2%78.5%+33.3%

Le problème illustré

Question : "Quels produits sont fabriqués dans le même pays
            que le siège social du fournisseur de notre composant X ?"

RAG vectoriel :
  → Cherche "composant X fournisseur pays produits"
  → Trouve des documents sur le composant X, d'autres sur des produits
  → Ne fait PAS le lien entre les entités
  → Réponse incorrecte ou hallucination

RAG + Knowledge Graph :
  → composant_X --fournisseur_de--> Entreprise_Y
  → Entreprise_Y --siège_social--> Allemagne
  → Allemagne --fabrique--> [Produit_A, Produit_B, Produit_C]
  → Réponse précise avec traçabilité complète

Comprendre les Knowledge Graph Embeddings

Qu'est-ce qu'un Knowledge Graph ?

Un graphe de connaissances stocke l'information sous forme de triplets (sujet, prédicat, objet) :

(Ailog, est_une, Plateforme_RAG)
(Ailog, basée_à, Paris)
(Ailog, fondée_en, 2024)
(Ailog, supporte, Shopify)
(Shopify, est_un, CMS_Ecommerce)
(Paris, est_dans, France)
(France, membre_de, Union_Européenne)

Pourquoi des embeddings pour les graphes ?

Les graphes stockent des relations explicites, mais ne gèrent pas la similarité sémantique. Les Knowledge Graph Embeddings projettent les entités et relations dans un espace vectoriel pour :

  1. Prédire des relations manquantes (link prediction)
  2. Trouver des entités similaires (entity similarity)
  3. Combiner recherche sémantique et traversée de graphe

Les modèles de KG Embeddings

ModèlePrincipeScore MRRComplexitéMeilleur pour
TransEh + r ≈ t (translation)0.463O(d)Relations 1-to-1
TransRProjection dans espace relation0.512O(d×k)Relations complexes
RotatEh ∘ r ≈ t (rotation complexe)0.533O(d)Relations symétriques/transitives
ComplExEspace complexe, Hermitian product0.551O(d)Relations antisymétriques
DistMultBilinear diagonal0.430O(d)Relations symétriques
ConvECNN sur embeddings0.491O(d×k)Grands graphes
TuckERTucker decomposition0.558O(d×d×d)Haute précision
NodePieceTokenization des nœuds0.525O(d)Très grands graphes

Comment fonctionne TransE (le plus intuitif)

Idée : si (Paris, capitale_de, France),
alors : embedding(Paris) + embedding(capitale_de) ≈ embedding(France)

           capitale_de
Paris ─────────────────→ France
  h    +       r        ≈    t

Entraînement :
- Minimiser ||h + r - t|| pour les vrais triplets
- Maximiser ||h + r - t'|| pour les faux triplets (négatifs)
DEVELOPERpython
import torch import torch.nn as nn class TransE(nn.Module): def __init__(self, num_entities, num_relations, dim=128): super().__init__() self.entity_embeddings = nn.Embedding(num_entities, dim) self.relation_embeddings = nn.Embedding(num_relations, dim) # Initialisation nn.init.xavier_uniform_(self.entity_embeddings.weight) nn.init.xavier_uniform_(self.relation_embeddings.weight) def forward(self, heads, relations, tails): h = self.entity_embeddings(heads) r = self.relation_embeddings(relations) t = self.entity_embeddings(tails) # Score = -||h + r - t|| score = -torch.norm(h + r - t, p=2, dim=-1) return score def predict_tail(self, head, relation, top_k=10): """Prédit les entités les plus probables.""" h = self.entity_embeddings(head) r = self.relation_embeddings(relation) # Score pour toutes les entités all_entities = self.entity_embeddings.weight scores = -torch.norm( h + r - all_entities, p=2, dim=-1 ) return torch.topk(scores, top_k)

Architecture hybride : Graph + Vecteurs

Le design pattern recommandé

┌──────────────────────────────────────────────────────┐
│                    REQUÊTE UTILISATEUR                  │
│  "Quels produits recommander aux clients qui achètent  │
│   des articles similaires au produit X ?"              │
└───────────────────────┬──────────────────────────────┘
                        │
              ┌─────────┴─────────┐
              │   QUERY ANALYSIS   │
              │   (Intent + Entités)│
              └────┬──────────┬───┘
                   │          │
        ┌──────────┘          └──────────┐
        ▼                                ▼
┌───────────────┐              ┌───────────────┐
│ GRAPH SEARCH  │              │ VECTOR SEARCH │
│               │              │               │
│ Neo4j Cypher  │              │ Qdrant/Pinecone│
│ - Traversée   │              │ - Similarité  │
│ - Relations   │              │ - Sémantique  │
│ - Multi-hop   │              │ - Fuzzy match │
└───────┬───────┘              └───────┬───────┘
        │                              │
        └──────────┬───────────────────┘
                   │
            ┌──────┴──────┐
            │   FUSION    │
            │  (Reranking │
            │  + Scoring) │
            └──────┬──────┘
                   │
            ┌──────┴──────┐
            │ GÉNÉRATION  │
            │    (LLM)    │
            └─────────────┘

Implémentation avec Neo4j + LangChain

DEVELOPERpython
from langchain_community.graphs import Neo4jGraph from langchain.chains import GraphCypherQAChain from langchain_openai import ChatOpenAI from langchain_community.vectorstores import Neo4jVector # Connexion au graphe Neo4j graph = Neo4jGraph( url="bolt://localhost:7687", username="neo4j", password="your-password" ) # Créer le schéma du graphe graph.query(""" CREATE CONSTRAINT IF NOT EXISTS FOR (p:Product) REQUIRE p.id IS UNIQUE """) # Peupler le graphe avec des relations graph.query(""" MERGE (p:Product {id: 'prod_001', name: 'Widget Pro'}) MERGE (c:Category {name: 'Electronics'}) MERGE (s:Supplier {name: 'TechCorp', country: 'Germany'}) MERGE (p)-[:BELONGS_TO]->(c) MERGE (p)-[:SUPPLIED_BY]->(s) MERGE (s)-[:LOCATED_IN]->(:Country {name: 'Germany'}) """) # Chaîne QA avec Cypher automatique llm = ChatOpenAI(model="gpt-4o", temperature=0) cypher_chain = GraphCypherQAChain.from_llm( llm=llm, graph=graph, verbose=True, validate_cypher=True, top_k=10, ) # Requête multi-hop result = cypher_chain.invoke({ "query": "Quels produits sont fournis par des entreprises " "situées en Allemagne ?" }) # → Cypher généré automatiquement : # MATCH (p:Product)-[:SUPPLIED_BY]->(s:Supplier) # -[:LOCATED_IN]->(c:Country {name: 'Germany'}) # RETURN p.name, s.name print(result["result"])

Recherche hybride Graph + Vecteur avec Neo4j

DEVELOPERpython
from langchain_openai import OpenAIEmbeddings embeddings = OpenAIEmbeddings(model="text-embedding-3-small") # Créer un index vectoriel dans Neo4j vector_store = Neo4jVector.from_existing_graph( embedding=embeddings, url="bolt://localhost:7687", username="neo4j", password="your-password", node_label="Product", text_node_properties=["name", "description"], embedding_node_property="embedding", ) def hybrid_graph_vector_search(query: str, top_k: int = 5): """Combine recherche vectorielle et traversée de graphe.""" # 1. Recherche vectorielle : trouver les entités proches vector_results = vector_store.similarity_search_with_score( query, k=top_k ) # 2. Enrichir avec le graphe : relations et contexte enriched_results = [] for doc, score in vector_results: node_id = doc.metadata.get("id") # Récupérer le voisinage du nœud neighbors = graph.query(f""" MATCH (n {{id: '{node_id}'}})-[r]-(m) RETURN type(r) as relation, labels(m)[0] as type, m.name as name LIMIT 20 """) enriched_results.append({ "entity": doc.page_content, "score": score, "relations": neighbors, "context": format_graph_context(neighbors) }) return enriched_results def format_graph_context(neighbors: list) -> str: """Formate le contexte du graphe pour le LLM.""" context_parts = [] for n in neighbors: context_parts.append( f"- {n['relation']}{n['type']}: {n['name']}" ) return "\n".join(context_parts)

Construction du Knowledge Graph

Extraction automatique d'entités et relations

DEVELOPERpython
import anthropic client = anthropic.Anthropic() def extract_knowledge_graph(text: str) -> dict: """Extrait les entités et relations d'un texte.""" response = client.messages.create( model="claude-sonnet-4-6", max_tokens=2000, messages=[{ "role": "user", "content": f"""Analyse le texte suivant et extrait : 1. Les entités (personnes, organisations, produits, lieux, concepts) 2. Les relations entre entités Retourne un JSON avec : {{ "entities": [ {{"id": "e1", "name": "...", "type": "Organization|Person|Product|Location|Concept"}} ], "relations": [ {{"source": "e1", "target": "e2", "type": "...", "properties": {{}}}} ] }} Texte : {text}""" }] ) return json.loads(response.content[0].text) def build_graph_from_documents(documents: list): """Construit le graphe à partir d'une liste de documents.""" all_entities = {} all_relations = [] for doc in documents: kg = extract_knowledge_graph(doc["text"]) # Dédoublonner les entités for entity in kg["entities"]: key = f"{entity['type']}:{entity['name'].lower()}" if key not in all_entities: all_entities[key] = entity else: # Fusionner les propriétés all_entities[key]["properties"] = { **all_entities[key].get("properties", {}), **entity.get("properties", {}) } all_relations.extend(kg["relations"]) # Insérer dans Neo4j insert_into_neo4j( list(all_entities.values()), all_relations ) def insert_into_neo4j(entities: list, relations: list): """Insère les entités et relations dans Neo4j.""" for entity in entities: graph.query(f""" MERGE (n:{entity['type']} {{name: $name}}) SET n += $properties """, { "name": entity["name"], "properties": entity.get("properties", {}) }) for rel in relations: graph.query(f""" MATCH (a {{name: $source}}) MATCH (b {{name: $target}}) MERGE (a)-[r:{rel['type']}]->(b) SET r += $properties """, { "source": rel["source"], "target": rel["target"], "properties": rel.get("properties", {}) })

Benchmarks : KG-only vs Vector-only vs Hybride

Test sur HotpotQA (questions multi-hop)

ApprocheExact MatchF1 ScoreLatenceCoût/requête
Vector-only (RAG classique)42.1%55.3%120ms$0.002
KG-only (Cypher)51.8%63.7%85ms$0.001
Hybride (KG + Vecteur)61.5%73.2%180ms$0.004
Hybride + Reranking65.2%76.8%250ms$0.008

Test sur des questions d'entreprise (corpus interne)

Type de questionVectorKGHybride
"Qui est responsable du projet X ?"85%95%96%
"Quels projets utilisent la techno Y ?"72%91%93%
"Quel est le budget total du département Z ?"45%82%85%
"Quelle relation entre personne A et projet B ?"38%88%91%
"Historique des décisions sur le sujet S ?"78%65%88%

Quand utiliser chaque approche

CritèreVector-onlyKG-onlyHybride
Questions simplesExcellentBonExcellent
Questions multi-hopFaibleExcellentExcellent
Texte non structuréExcellentFaibleBon
Données structuréesFaibleExcellentExcellent
Mise à jour en temps réelFacileComplexeComplexe
Coût de setupFaibleÉlevéÉlevé
ScalabilitéTrès hauteMoyenneHaute
ExplicabilitéFaibleExcellenteBonne

Cas d'usage avancés

Désambiguïsation d'entités

DEVELOPERpython
def disambiguate_entity(mention: str, context: str) -> dict: """Désambiguïse une mention d'entité via le graphe.""" # Chercher les candidats dans le graphe candidates = graph.query(""" MATCH (n) WHERE n.name CONTAINS $mention OR n.aliases CONTAINS $mention RETURN n, labels(n) as types, [(n)-[r]-(m) | {rel: type(r), node: m.name}] as relations LIMIT 10 """, {"mention": mention}) if len(candidates) <= 1: return candidates[0] if candidates else None # Utiliser le contexte pour désambiguïser scores = [] for candidate in candidates: # Score basé sur la similarité du contexte # avec les relations du candidat context_embedding = embed(context) candidate_context = " ".join( [f"{r['rel']} {r['node']}" for r in candidate["relations"]] ) candidate_embedding = embed(candidate_context) score = cosine_similarity(context_embedding, candidate_embedding) scores.append((candidate, score)) # Retourner le meilleur candidat return max(scores, key=lambda x: x[1])[0]

Raisonnement multi-hop avec chaîne de pensée

DEVELOPERpython
def multi_hop_reasoning(question: str, max_hops: int = 3): """Raisonnement multi-hop sur le knowledge graph.""" # Étape 1 : Identifier les entités de départ entities = extract_entities_from_question(question) # Étape 2 : Explorer le graphe pas à pas reasoning_chain = [] current_entities = entities for hop in range(max_hops): # Récupérer le voisinage neighborhood = graph.query(""" MATCH (n)-[r]-(m) WHERE n.name IN $entities RETURN n.name as source, type(r) as relation, m.name as target, labels(m)[0] as type """, {"entities": current_entities}) if not neighborhood: break # Demander au LLM quelles relations suivre next_step = select_relevant_relations( question, neighborhood, reasoning_chain ) reasoning_chain.append(next_step) current_entities = [step["target"] for step in next_step] # Étape 3 : Générer la réponse avec la chaîne de raisonnement answer = generate_answer_with_chain(question, reasoning_chain) return answer

Outils et frameworks

OutilTypeForcesLimitations
Neo4jGraph DBMaturité, écosystème, vector search natifCoût en production
Amazon NeptuneGraph DB (cloud)Serverless, intégration AWSLock-in AWS
Microsoft GraphRAGFramework RAGSummarization, community detectionCoût LLM élevé
LangChain GraphQAFrameworkCypher auto, facile à intégrerCypher parfois incorrect
LlamaIndex KGFrameworkProperty graph, multiple backendsComplexe
PyKEENKG Embeddings40+ modèles, recherchePas de production-ready
DGL-KEKG EmbeddingsScalable, GPULearning curve

FAQ

Knowledge Graph ou GraphRAG de Microsoft, quelle différence ?

Le Knowledge Graph est une base de données de faits structurés (entités + relations). GraphRAG de Microsoft est une approche spécifique qui construit automatiquement un graphe à partir de documents, crée des résumés hiérarchiques par communauté, et les utilise pour répondre aux questions. GraphRAG est plus adapté aux questions globales ("résumé du corpus"), tandis que le KG classique excelle pour les questions précises multi-hop. Voir notre guide sur GraphRAG.

Quel est le coût de construction d'un Knowledge Graph ?

La construction automatique avec LLM coûte environ $0.50-2 par document (extraction d'entités/relations). Pour 10 000 documents, comptez $5 000-20 000 pour la construction initiale. Le coût de Neo4j en production est de ~$65/mois pour une instance dédiée. L'alternative open-source est d'utiliser Neo4j Community Edition (gratuit) ou Amazon Neptune serverless.

Les KG Embeddings sont-ils nécessaires pour un RAG hybride ?

Non, pour un RAG hybride graph+vecteur simple, les requêtes Cypher suffisent. Les KG Embeddings deviennent utiles quand : 1) vous avez des millions de triplets et la traversée est lente, 2) vous voulez prédire des relations manquantes (link prediction), 3) vous combinez la similarité d'entités avec la recherche sémantique. Pour la plupart des cas d'usage, commencez sans KG Embeddings et ajoutez-les si nécessaire.

Comment maintenir un Knowledge Graph à jour ?

Trois approches : 1) Extraction incrémentale quand de nouveaux documents sont ajoutés, 2) Validation périodique des relations existantes, 3) Versioning du graphe pour tracer les changements. L'extraction incrémentale est la plus courante : chaque nouveau document passe par le pipeline d'extraction et les nouvelles entités/relations sont ajoutées au graphe existant.

Un Knowledge Graph est-il nécessaire pour mon cas d'usage ?

Un KG est recommandé si : vous avez des questions multi-hop fréquentes, votre domaine a des relations complexes entre entités (org charts, supply chains, réglementations), ou vous avez besoin d'explicabilité (traçabilité du raisonnement). Si vos questions sont principalement factuelles simples, le RAG vectoriel classique suffit. Voir notre guide sur les stratégies de retrieval pour choisir la bonne approche.


Les Knowledge Graph Embeddings représentent la prochaine frontière du RAG : au-delà de la simple similarité sémantique, vers un véritable raisonnement sur les relations entre entités. Testez Ailog pour voir comment notre approche hybride graph+vecteur répond à vos questions les plus complexes.

Tags

RAGknowledge graphembeddingsNeo4jGraphRAGTransEmulti-hopraisonnement

Articles connexes

Ailog Assistant

Ici pour vous aider

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