Vortex-Flux / src /agent /query_planner.py
klydekushy's picture
Create agent/query_planner.py
790a141 verified
"""
MODULE: QUERY PLANNER (OAG)
===========================
Responsabilité : Analyser la question, vérifier le schéma réel,
et décider de la meilleure stratégie (SPARQL vs FAISS vs Multi-étapes).
"""
import json
import re
class QueryPlanner:
def __init__(self, rdf_store, schema_info):
self.rdf = rdf_store
self.schema = schema_info # Provient de SchemaExtractor.get_real_schema()
def analyze_and_plan(self, user_query):
"""
Détermine si la question est :
1. Sémantique (Recherche d'un dossier client/prêt spécifique)
2. Analytique (Comptage, Somme, Croisement global)
3. Invalide (Donnée absente du schéma)
"""
# 1. ANALYSE DES MOTS CLÉS (Simplifiée)
is_analytical = any(word in user_query.lower() for word in [
'combien', 'total', 'somme', 'moyenne', 'liste tous', 'liste les', 'nombre'
])
# 2. VÉRIFICATION DU SCHÉMA (Prévention d'hallucination)
# On regarde si les termes de la question match avec nos prédicats réels
available_preds = self.schema.get("predicates", [])
found_preds = [p for p in available_preds if p.lower() in user_query.lower()]
# 3. DÉCISION DE LA STRATÉGIE
# CAS A : Recherche d'un individu ou d'un dossier précis
if not is_analytical and not found_preds:
return {
"strategy": "OG-RAG",
"tool": "search_semantic",
"reason": "La question semble porter sur un individu ou un cas spécifique non défini par un prédicat exact.",
"steps": [f"Rechercher le bloc contextuel pour : {user_query}"]
}
# CAS B : Question de masse ou croisement (Analytique)
if is_analytical:
return {
"strategy": "OAG-SPARQL",
"tool": "execute_sparql",
"reason": "La question nécessite une agrégation ou un filtrage sur l'ensemble de la base.",
"steps": ["Traduire en requête SPARQL optimisée", "Valider les prédicats contre le schéma réel"]
}
# CAS C : Hybride (Par défaut)
return {
"strategy": "HYBRID",
"tool": "execute_sparql",
"reason": "Usage de prédicats identifiés dans le schéma réel.",
"steps": ["Générer SPARQL avec les prédicats validés"]
}
def get_planning_logs(self, plan):
"""Génère un affichage propre pour le chat utilisateur"""
log = f"🎯 **Stratégie adoptée** : `{plan['strategy']}`\n"
log += f"🤔 **Raisonnement** : {plan['reason']}\n"
log += "📋 **Plan d'exécution** :\n"
for i, step in enumerate(plan['steps'], 1):
log += f" {i}. {step}\n"
return log