OrgGraph AI : Un graphe de connaissances agent sans codage manuel pour les données RH.
Comment un LLM découvre un schéma de graphe à partir de tout fichier Excel ou CSV, le charge dans Neo4j à l’aide de Cypher dynamique, et répond aux questions relatives au recrutement grâce à un agent de chat LangGraph.
Sources: Building a Fully Agentic Employee Knowledge Graph: **OrgGraph AI — using LangGraph & Neo4j**
Les grandes entreprises détiennent plus de données sur leurs employés que jamais, mais la gestion des effectifs repose encore sur des suppositions. Les hiérarchies RH se trouvent dans Workday, les affectations de projets dans Jira. Les compétences, les niveaux de maîtrise et les certifications sont stockés dans d’anciens portails de formation. Puis un projet d’intelligence artificielle à haute priorité arrive, et le responsable de la livraison demande qui, au bureau de Mumbai ou de Pune, maîtrise bien Python, possède une certification AWS, connaît l’intelligence artificielle/machine learning, a travaillé sur des projets bancaires et dispose encore de capacités supplémentaires.
Obtenir une réponse prend environ une semaine, si c’est même possible. Les informations existent, mais elles sont enfouies dans des systèmes isolés qui ne peuvent pas analyser les relations entre eux.
OrgGraph AI est un système conçu pour combler cette lacune. Il accepte des données organisationnelles brutes sous n’importe quelle forme Excel ou CSV, un LLM détermine automatiquement le schéma du graphe, charge tout dans Neo4j puis répond aux questions en langage simple. Aucune logique de domaine n’est codée de manière fixe nulle part.
Les relations comptent plus que les enregistrements
Les outils RH standard reposent sur des tables SQL plates. Demander tous les employés de Bangalore ou toutes les personnes qui maîtrisent Python est facile pour eux. Ils se heurtent cependant aux questions intersectorielles, celles qui exigent de prendre en compte plusieurs dimensions de relations en même temps. Un graphe de connaissances permet quatre types d’opérations :
- Affectation précise des ressources. Trouver la seule personne possédant la compétence A, la certification B, située à C et disposant de capacités disponibles, en une seule recherche plutôt qu’avec quatre jointures distinctes.
Que signifie zéro codage en dur
La plupart des projets de graphes de connaissances partagent un secret délicat : le schéma est codé en dur. Un ingénieur lit le tableau, décide que les employés sont des nœuds, les compétences aussi, et qu’une arête HAS_SKILL les relie ; il écrit ensuite du Cypher personnalisé pour chaque entité avant de la déployer. Ensuite, le service des ressources humaines ajoute une feuille de calcul Certifications ou renomme PrimarySkill en TechStack, ce qui fait cesser le fonctionnement de tout le processus.
OrgGraph AI inverse cette logique. L’LLM décide quel devrait être le schéma. Pour n’importe quel fichier tabulaire, le système :
- analyse les données, y compris les types de colonnes, la cardinalité et les clés étrangères possibles
- déduit un schéma de graphe à partir des résultats structurés de l’LLM, validés par Pydantic
- génère et exécute dynamiquement des requêtes Cypher
MERGE - analyse le graphe final afin qu’un agent de conversation puisse y effectuer des requêtes
Nul ne crée de cartes manuellement, et aucun schéma n’est établi à l’avance. Remplacez demain les données RH par des informations liées à la logistique de la chaîne d’approvisionnement, et la même base de code générera un graphe complètement différent. L’ensemble de données de test était synthétique, composé d’environ une douzaine de feuilles, et le pipeline traite tout ce qui lui est fourni.
Quatre phases
Le système fonctionne en quatre phases, orchestrées à l’aide de Python, LangChain, LangGraph, Pydantic et Neo4j.
Phase 1 : analyse des métadonnées
Au préalable de toute utilisation d’un LLM, un MetadataProfiler analyse les données brutes localement et produit une empreinte structurelle compacte. Il s’agit d’une décision délibérée en matière de confidentialité : les vrais dossiers des employés ne parviennent jamais au modèle. Celui-ci obtient les noms de colonnes, les types de données, le nombre de valeurs distinctes présentes dans chaque colonne, ainsi que quelques valeurs d’échantillon.
Le tour de force le plus précieux du profileur est la détection automatique des clés étrangères. Il marque une colonne comme étant probablement une clé étrangère lorsque ses valeurs se trouvent principalement dans une colonne de clé primaire ailleurs :
# Simplified FK detection logic from profiler.py
overlap = col_values & ref_values
if len(overlap) / len(col_values) >= 0.8:
fk_candidates.append({
"source_table": tname,
"source_column": col,
"target_table": ref_table,
"target_column": ref_col,
"match_pct": round(len(overlap) / len(col_values) * 100, 1),
})
Dans l’ensemble de données RH, cela montre que Manager_Employee_ID dans la table Employees correspond à Employee_ID dans plus de 80 % des cas, ce qui suggère une relation REPORTS_TO auto-référentielle. L’indication est destinée à l’LLM, qui n’a pas pu déduire une hiérarchie à partir des seuls noms de colonnes.
Phase 2 : découverte du schéma
Le profil est transmis à un LLM, configurable entre OpenAI GPT-4o, Google Gemini et Groq, avec une instruction l’incitant à agir en tant qu’architecte principal de bases de données graphiques.
Le principal problème d’ingénierie réside dans le fait que les LLM génèrent du texte libre, tandis que les bases de données graphiques exigent une structure stricte. with_structured_output() de LangChain comble cette lacune en obligeant le modèle à retourner un objet Pydantic validé :
# The LLM is coerced to return this exact structure
class GraphMappingModel(BaseModel):
nodes: List[NodeMapping] # What becomes a Node?
relationships: List[RelationshipMapping] # What becomes an Edge?
notes: str # LLM's reasoning notes
class NodeMapping(BaseModel):
label: str # e.g., "Employee"
source_table: str # e.g., "Employees"
primary_key_column: str # e.g., "Employee_ID"
properties: List[PropertyMapping] # All columns to map
class RelationshipMapping(BaseModel):
type: str # e.g., "HAS_SKILL"
from_node_label: str # e.g., "Employee"
to_node_label: str # e.g., "Skill"
from_key_column: str # FK column in source table
to_key_column: str # PK column of target node
properties: List[PropertyMapping] # Edge properties
Ce GraphMappingModel sert de contrat pour l’ensemble du système. L’agent de schéma le génère et le moteur d’ingestion l’utilise. En cas d’échec de validation, la demande est renvoyée à l’LLM, de sorte qu’aucun schéma mal formaté n’atteint Neo4j.
Phase 3 : ingestion dynamique de Cypher
Avec un schéma validé, le moteur écrit en temps réel des commandes Cypher paramétrées. Il n’y a ni modèles ni instructions conditionnelles par type d’entité. Il lit la correspondance et crée des commandes MERGE ainsi que des commandes SET pour chaque type de nœud et de relation :
# Dynamically generated Cypher from the mapping — zero hardcoding
UNWIND $rows AS row
MERGE (n:Employee {employee_id: row.employee_id})
SET n.full_name = row.full_name,
n.designation = row.designation,
n.date_of_joining = row.date_of_joining,
n.annual_ctc_lpa = toFloat(row.annual_ctc_lpa)
Puisque les noms de schéma inférés désignent des clés primaires, le moteur utilise MERGE et non CREATE, ce qui rend le pipeline idempotent. Le fait de l’exécuter trois fois sur les mêmes données produit le même graphe sans doublons. Il effectue également des conversions de types (toInteger(), toFloat()), transforme NaN en None et ignore les lignes dont la clé primaire est nulle.
Le jeu de données de démonstration n’est pas un exemple simplifié : 151 employés répartis sur 13 tables interconnectées, comprenant 935 correspondances de compétences, 285 affectations à des projets, 107 certifications, 313 avis et 453 entrées de formation, répartis dans 10 départements et 10 bureaux mondiaux.
Phase 4 : le chat GraphRAG agent
La couche de chat est bien plus qu’un traducteur texte vers Cypher. Il s’agit d’une machine à états LangGraph à quatre nœuds dotée d’un mécanisme de récupération des erreurs intégré :
User Question
↓
┌─────────────┐
│ Planner │ → Analyzes intent, extracts entities, maps to schema
└──────┬──────┘
↓
┌─────────────┐
│ CypherGen │ → Generates Cypher query using schema + few-shot examples
└──────┬──────┘
↓
┌─────────────┐ ┌─── Error? ───→ Retry CypherGen (up to 2x)
│ Executor │ ────┤
└──────┬──────┘ └─── Success ──→
↓
┌──────────────┐
│ Synthesizer │ → Formats raw graph data into natural language
└──────────────┘
Trois caractéristiques en font un outil adaptable.
Inspection dynamique du schéma.Lors du démarrage, l’agent récupère le schéma en temps réel depuis Neo4j, indiquant quels types de nœuds et de relations existent, leurs propriétés ainsi que la manière dont ils sont connectés. Ce schéma est intégré à chaque requête, de sorte que l’agent ne suppose jamais ce que contient la base de données.
Exemples auto-générés en few-shot.De nombreux systèmes GraphRAG utilisent des exemples Cypher codés en dur. Ici, le LLM crée ses propres exemples en few-shot à partir du schéma en temps réel et des données échantillonnées, et ceux-ci sont régénérés automatiquement lorsque un nouveau téléchargement modifie le schéma.
Réessais conscients des erreurs.Si une requête générée échoue, le message d’erreur est renvoyé au nœud CypherGen, qui corrige la requête et tente à nouveau, jusqu’à deux fois. Cela confère à l’agent une grande résilience face aux problèmes de syntaxe liés aux cas limites.
Préoccupations des entreprises
Confidentialité. Le LLM perçoit la structure, pas les personnes. Seuls les noms de colonnes, les types et la cardinalité quittent l’outil d’analyse, tandis que les données personnelles restent sur votre serveur.
Flexibilité du fournisseur. Un modèle LLM Factory permet de passer d’OpenAI à Gemini ou Groq en modifiant une seule variable d’environnement :
# .env: LLM_PROVIDER=gemini | openai | groq
llm = get_llm() # Returns the configured ChatModel
Aucune modification de code et pas d’entrave liée au fournisseur.
Données désordonnées. Les feuilles de calcul d’entreprise ne sont jamais propres. Le moteur d’ingestion gère les espaces blancs en fin de ligne, les formats de dates mixtes, les valeurs NaN inattendues et les clés primaires nulles, en sautant ou en convertissant les lignes problématiques au lieu de planter.
De l’upload aux réponses
L’interface utilisateur est un tableau de bord Streamlit. L’utilisateur télécharge un fichier Excel ou CSV dans la barre latérale et observe en direct le déroulement du processus : analyse, découverte du schéma, ingestion, puis initialisation de l’agent. Après cela, il suffit de discuter.
Une démo distincte utilise Vis.js pour l’affichage de graphes basés sur des lois physiques et GSAP pour des animations déclenchées par le scroll. Les nœuds s’affichent progressivement sous l’effet de forces de gravité et de répulsion. En cliquant sur un nœud, un panneau s’ouvre affichant ses propriétés ainsi que les relations qui le relient. Un chat simulé présente à la fois la réponse en langage naturel et la requête Cypher générée en arrière-plan.
Au-delà des ressources humaines
Cette architecture n’est pas limitée aux ressources humaines. Le même code peut être utilisé pour créer un graphique de connaissances destiné à la gestion des actifs informatiques, permettant de cartographier les serveurs, les applications, les équipes et leurs dépendances. Il peut également suivre les fournisseurs, les matériaux, les entrepôts et les itinéraires logistiques au sein d’une chaîne d’approvisionnement, ou relier les chercheurs, les articles scientifiques, les institutions et les sources de financement au sein d’un réseau de recherche.
Les pipelines de données qui s’adaptent aux données, plutôt que les ingénieurs qui forcent ces dernières dans des schémas rigides, sont la direction vers laquelle évoluent les architectures agnitives, et ce projet en constitue un modèle concret.