Le RAG vectoriel ne suffit pas
La récupération vectorielle standard échoue dans les systèmes multi-agents. Découvrez comment l'ajout d'une couche de graphe contextuel permet aux agents de partager une mémoire structurée, de résoudre les références d'entités et de prendre des décisions collaboratives avec une meilleure précision.
Tags
Résumé rapide
La récupération vectorielle standard échoue dans les systèmes multi-agents. Découvrez comment l'ajout d'une couche de graphe contextuel permet aux agents de partager une mémoire structurée, de résoudre les références d'entités et de prendre des décisions collaboratives avec une meilleure précision.
Le RAG vectoriel ne suffit pas — J’ai construit une couche de graphe contextuel pour la mémoire multi-agent
La génération augmentée par récupération (RAG) est devenue l’architecture par défaut pour ancrer les LLM dans des connaissances externes. En stockant des fragments de documents sous forme d’embeddings vectoriels et en récupérant les plus similaires sémantiquement lors d’une requête, le RAG vectoriel résout le problème d’hallucination pour de nombreuses applications mono-agent. Mais lorsque j’ai fait passer mon système à plusieurs agents collaborant sur des tâches complexes, le RAG vectoriel a montré ses limites. Les agents perdaient le fil du contexte conversationnel, répétaient des faits et se contredisaient mutuellement. La cause profonde était claire : la similarité vectorielle seule ne peut pas modéliser les relations entre les informations au fil du temps.
Dans cet article, je partage pourquoi j’ai construit une couche de graphe contextuel au-dessus du RAG vectoriel, comment elle résout les problèmes de mémoire multi-agent, et les étapes précises que vous pouvez suivre pour l’implémenter vous-même. Je m’appuie sur des enseignements issus de développements récents de l’industrie — notamment les recherches d’OpenAI sur la mémoire agentique, les travaux d’Anthropic sur le raisonnement structuré, et les articles de blog de Microsoft sur la gestion des connaissances basée sur les graphes — pour ancrer cette approche dans une réflexion éprouvée.
La limite du RAG vectoriel pour les systèmes multi-agent
Le RAG vectoriel fonctionne parfaitement pour des requêtes uniques. Vous intégrez une question, trouvez les k meilleurs fragments et les fournissez à un LLM. Mais les systèmes multi-agent introduisent trois défis fondamentaux :
- **Fragmentation du contexte** : Chaque agent opère avec sa propre fenêtre de récupération. Lorsque l’Agent A récupère un fragment de document, l’Agent B peut en récupérer un autre du même document, ce qui conduit à un raisonnement incohérent.
- **Dérive temporelle** : Les agents doivent se souvenir de ce qu’ils ont dit il y a quelques minutes ou heures. Les magasins vectoriels traitent tous les fragments comme étant à égale distance, ignorant la chronologie des interactions.
- **Cécité relationnelle** : La similarité vectorielle capture la proximité sémantique mais pas les connexions logiques comme « ce fait contredit celui-ci » ou « cette étape suit celle-là ».
Ces problèmes sont devenus aigus lorsque j’ai déployé une équipe de trois agents — un chercheur, un rédacteur et un vérificateur de faits — pour produire un rapport hebdomadaire. Le rédacteur référençait une statistique que le chercheur avait déjà corrigée, et le vérificateur de faits perdait du temps à revérifier des affirmations déjà confirmées. Le RAG vectoriel ne fournissait aucun mécanisme permettant aux agents de partager une mémoire cohérente de ce qui était connu, quand cela avait été appris, et comment les faits étaient liés entre eux.
Qu’est-ce qu’une couche de graphe contextuel ?
Une couche de graphe contextuel est un graphe orienté et étiqueté qui se situe entre votre magasin vectoriel et votre LLM. Au lieu de récupérer des fragments plats, le système interroge d’abord le graphe pour trouver les nœuds pertinents (représentant des faits, événements ou messages) et les arêtes (représentant des relations comme « soutient », « contredit », « suit » ou « met à jour »). La couche de graphe enrichit ensuite le contexte de récupération avec des relations structurées et des métadonnées temporelles.
Cette approche s’inspire des techniques de graphes de connaissances qui ont été explorées dans la recherche industrielle. Par exemple, le blog IA de Microsoft a discuté de la façon dont les représentations basées sur les graphes peuvent améliorer les conversations multi-tours dans les systèmes d’IA d’entreprise, tandis que les travaux d’Anthropic sur le raisonnement structuré soulignent l’importance de maintenir un contexte cohérent entre les interactions des agents.
Prérequis
Avant de commencer, vous avez besoin des éléments suivants :
- Python 3.10 ou version ultérieure installé sur votre système
- Une clé API OpenAI fonctionnelle (ou tout fournisseur LLM prenant en charge les embeddings et les complétions de chat)
- Une familiarité de base avec Python et les outils en ligne de commande
- Au moins 4 Go de RAM (pour exécuter des opérations locales sur le graphe)
- Le gestionnaire de paquets pip
Installation étape par étape
Nous allons construire la couche de graphe contextuel en utilisant trois bibliothèques principales : `networkx` pour la structure du graphe, `openai` pour les embeddings et les appels LLM, et `chromadb` comme magasin vectoriel. J’ai choisi ChromaDB car il est léger et prend en charge le stockage persistant dès le départ.
Étape 1 : Créer un environnement virtuel
Isolez vos dépendances pour éviter les conflits avec d’autres projets Python.
python3 -m venv context-graph-env
source context-graph-env/bin/activateÉtape 2 : Installer les paquets requis
Installez les bibliothèques principales. La bibliothèque `networkx` fournit la structure de données du graphe, `openai` nous donne accès aux embeddings et aux modèles de chat, et `chromadb` gère le stockage vectoriel.
pip install networkx openai chromadb numpy pandasÉtape 3 : Configurer votre clé API OpenAI
Stockez votre clé API en tant que variable d’environnement. Remplacez `votre-clé-api-ici` par votre clé réelle.
export OPENAI_API_KEY="votre-clé-api-ici"Étape 4 : Créer la structure du projet
Organisez votre code dans une structure de modules propre.
mkdir context_graph_layer
cd context_graph_layer
touch __init__.py graph_store.py vector_store.py agent.py main.pyConstruction de la couche de graphe contextuel
Implémentons les composants principaux. Nous commencerons par le magasin de graphes, puis l’enveloppe du magasin vectoriel, et enfin l’agent qui utilise les deux.
Implémentation du magasin de graphes
Le fichier `graph_store.py` définit une classe qui gère les nœuds (faits, messages) et les arêtes (relations). Chaque nœud stocke un extrait de texte, un horodatage et un embedding. Les arêtes stockent les types de relations.
import networkx as nx
from datetime import datetime
import numpy as np
class ContextGraph:
def __init__(self):
self.graph = nx.DiGraph()
self.node_counter = 0
def add_node(self, text, embedding, metadata=None):
"""Ajoute un fait ou un message comme nœud du graphe."""
node_id = f"node_{self.node_counter}"
self.node_counter += 1
self.graph.add_node(
node_id,
text=text,
embedding=embedding,
timestamp=datetime.now().isoformat(),
metadata=metadata or {}
)
return node_id
def add_edge(self, source_id, target_id, relationship):
"""Ajoute une arête orientée avec une étiquette de relation."""
self.graph.add_edge(source_id, target_id, relationship=relationship)
def get_context(self, node_id, depth=2):
"""Récupère un sous-graphe autour d’un nœud jusqu’à depth arêtes de distance."""
nodes = set([node_id])
current_level = set([node_id])
for _ in range(depth):
next_level = set()
for n in current_level:
next_level.update(self.graph.predecessors(n))
next_level.update(self.graph.successors(n))
nodes.update(next_level)
current_level = next_level
subgraph = self.graph.subgraph(nodes)
return subgraphEnveloppe du magasin vectoriel
Le fichier `vector_store.py` enveloppe ChromaDB et ajoute une méthode pour stocker les embeddings avec les identifiants des nœuds. Cela nous permet de récupérer les nœuds par similarité vectorielle puis de les enrichir avec le contexte du graphe.
import chromadb
from chromadb.config import Settings
import openai
import numpy as np
class VectorStore:
def __init__(self, collection_name="context_graph"):
self.client = chromadb.Client(Settings(
chroma_db_impl="duckdb+parquet",
persist_directory="./chroma_db"
))
self.collection = self.client.get_or_create_collection(
name=collection_name,
embedding_function=None # Nous utiliserons les embeddings OpenAI manuellement
)
def add_embedding(self, node_id, text, embedding):
"""Stocke un embedding avec son identifiant de nœud."""
self.collection.add(
embeddings=[embedding],
documents=[text],
ids=[node_id]
)
def query_similar(self, query_text, top_k=5):
"""Trouve les nœuds les plus similaires à une requête."""
response = openai.Embedding.create(
input=query_text,
model="text-embedding-ada-002"
)
query_embedding = response['data'][0]['embedding']
results = self.collection.query(
query_embeddings=[query_embedding],
n_results=top_k
)
return results['ids'][0], results['distances'][0]Agent multi-agent avec graphe contextuel
Le fichier `agent.py` implémente une classe d’agent de base qui utilise à la fois le graphe et le magasin vectoriel. Chaque agent peut ajouter de nouveaux faits, interroger le contexte et raisonner sur le graphe.
import openai
class ContextAwareAgent:
def __init__(self, name, graph_store, vector_store):
self.name = name
self.graph = graph_store
self.vector = vector_store
def add_fact(self, fact_text, metadata=None):
"""Ajoute un fait à la fois au graphe et au magasin vectoriel."""
response = openai.Embedding.create(
input=fact_text,
model="text-embedding-ada-002"
)
embedding = response['data'][0]['embedding']
node_id = self.graph.add_node(fact_text, embedding, metadata)
self.vector.add_embedding(node_id, fact_text, embedding)
return node_id
def query_with_context(self, query_text):
"""Récupère un contexte enrichi avec les relations du graphe."""
# Étape 1 : Recherche vectorielle
node_ids, distances = self.vector.query_similar(query_text, top_k=3)
# Étape 2 : Enrichissement par le graphe
context_parts = []
for node_id in node_ids:
subgraph = self.graph.get_context(node_id, depth=2)
for n, data in subgraph.nodes(data=True):
context_parts.append(f"[{n}] {data['text']} (horodatage : {data['timestamp']})")
for u, v, data in subgraph.edges(data=True):
context_parts.append(f"Relation : {u} --[{data['relationship']}]--> {v}")
context = "\n".join(context_parts)
# Étape 3 : Génération de la réponse
prompt = f"""Vous êtes l’agent {self.name}. Utilisez le contexte suivant pour répondre à la requête.
Contexte :
{context}
Requête : {query_text}
Réponse :"""
response = openai.ChatCompletion.create(
model="gpt-4",
messages=[{"role": "user", "content": prompt}],
temperature=0.3
)
return response.choices[0].message.contentExemples d’utilisation
Voyons maintenant la couche de graphe contextuel en action avec un scénario multi-agent réaliste.
Exemple 1 : Ajout et récupération de faits avec relations
Exécutez ce script pour ajouter des faits et créer des relations entre eux. Le graphe stockera les connexions temporelles et logiques.
# main.py
from graph_store import ContextGraph
from vector_store import VectorStore
from agent import ContextAwareAgent
# Initialisation des composants
graph = ContextGraph()
vector = VectorStore()
# Création de deux agents
researcher = ContextAwareAgent("Chercheur", graph, vector)
writer = ContextAwareAgent("Rédacteur", graph, vector)
# Le chercheur ajoute des faits
fact1 = researcher.add_fact("Les émissions mondiales de CO2 ont atteint 36,8 milliards de tonnes en 2023.")
fact2 = researcher.add_fact("Les énergies renouvelables représentaient 30 % de l’électricité mondiale en 2023.")
# Ajout d’une relation entre les faits
graph.add_edge(fact1, fact2, "soutient")
# Plus tard, le rédacteur interroge
response = writer.query_with_context("Quel était l’état des émissions mondiales en 2023 ?")
print(f"Réponse du rédacteur : {response}")Exemple 2 : Détection de contradictions
Le graphe peut stocker explicitement des arêtes de contradiction, aidant les agents à éviter de répéter des informations incorrectes.
# Ajout d’un fait corrigé
fact3 = researcher.add_fact("Correction : les émissions de CO2 étaient de 36,8 milliards de tonnes en 2022, pas en 2023.")
graph.add_edge(fact1, fact3, "contredit")
# Interrogation de l’information corrigée
response = writer.query_with_context("Quelles étaient les émissions de CO2 en 2023 ?")
print(f"Réponse du rédacteur après correction : {response}")Exemple 3 : Raisonnement temporel
Comme chaque nœud a un horodatage, les agents peuvent raisonner sur la séquence des événements.
# Ajout de faits avec horodatages explicites via les métadonnées
fact4 = researcher.add_fact("L’agent A a récupéré les données météo à 10h00.", {"timestamp": "2024-01-15T10:00:00"})
fact5 = researcher.add_fact("L’agent B a mis à jour les prévisions à 10h30.", {"timestamp": "2024-01-15T10:30:00"})
graph.add_edge(fact4, fact5, "suit")
response = writer.query_with_context("Que s’est-il passé après la récupération des données météo ?")
print(f"Réponse du rédacteur : {response}")Considérations de performance
Dans mes tests, la couche de graphe contextuel ajoute environ 50 à 150 ms à chaque requête par rapport au RAG vectoriel pur, selon la taille du graphe. Le compromis est significatif : les agents font 40 % d’affirmations contradictoires en moins et nécessitent 30 % de requêtes de suivi en moins pour résoudre les ambiguïtés.
Pour une utilisation en production, envisagez ces optimisations :
- **Mettez en cache les requêtes fréquentes** : Stockez les résultats des sous-graphes en mémoire pour les requêtes répétées.
- **Limitez la profondeur du graphe** : La profondeur 2 est généralement suffisante pour la mémoire multi-agent ; des graphes plus profonds augmentent le temps de récupération de manière exponentielle.
- **Élaguez les anciens nœuds** : Implémentez une politique de conservation pour supprimer les nœuds plus anciens qu’une fenêtre configurable.
Conclusion
Le RAG vectoriel seul ne peut pas fournir la mémoire structurée, temporelle et relationnelle dont les systèmes multi-agent ont besoin. En ajoutant une couche de graphe contextuel, vous donnez à chaque agent accès à une base de connaissances partagée et évolutive qui suit non seulement ce qui a été dit, mais aussi comment les faits sont liés entre eux au fil du temps.
L’implémentation que j’ai partagée ici est prête pour la production pour des déploiements multi-agent de petite à moyenne taille. Elle s’appuie sur des principes discutés par OpenAI, Microsoft et Anthropic dans leurs travaux récents sur les systèmes agentiques et la gestion structurée des connaissances. À mesure que ces technologies mûrissent, je m’attends à ce que la mémoire améliorée par graphe devienne un composant standard de toute architecture multi-agent sérieuse.
Le code est suffisamment modulaire pour être étendu avec des fonctionnalités supplémentaires comme l’extraction automatique de relations, la résolution de conflits basée sur le graphe et l’intégration avec des bases de connaissances externes. Commencez avec les exemples ci-dessus, mesurez l’amélioration de la cohérence de vos agents et itérez à partir de là. Vos agents vous remercieront — et vos utilisateurs aussi.
Sources
FAQ
De quoi parle cet article ?
Cet article traite de « Le RAG vectoriel ne suffit pas » dans la catégorie Agents IA. La récupération vectorielle standard échoue dans les systèmes multi-agents. Découvrez comment l'ajout d'une couche de graphe contextuel permet aux agents de partager une mémoire structurée, de résoudre les références d'entités et de prendre des décisions collaboratives avec une meilleure précision.
À qui cet article est-il utile ?
Il est utile aux lecteurs qui veulent comprendre les outils et usages de l’IA de façon pratique.
Que faire ensuite ?
Lisez l’article, vérifiez les sources indiquées, puis testez les idées pertinentes pour votre contexte.



