Le prototype original (mémoire de Master UNIGE) tourne en local avec CrewAI, GPT-4o et Pydantic pour les contrats d'artefacts. Cette démo en rejoue l'architecture dans le navigateur : le module système s'exécute réellement, les sorties d'agents sont pré-enregistrées — un site public ne peut exposer ni clé d'API ni coût variable.
Séparation données–raisonnement, orchestration multi-agents avec artefacts traçables, guardrails avec reprise contrôlée, audit automatisé de confidentialité.
La confidentialité n'est pas une mesure ajoutée en fin de chaîne mais une propriété architecturale : le module système local est le seul composant autorisé à lire les valeurs brutes ; les agents ne reçoivent que des métadonnées et renvoient des artefacts structurés, validés avant toute exécution. Les deux colonnes ci-dessous se répondent ligne à ligne : à chaque tâche du système correspond l'agent qui la déclenche ou qui en consomme le résultat.
Résultats réels obtenus avec le prototype (GPT-4o, exécutions répétées depuis l'application Streamlit, sans intervention manuelle). Quatre questions de recherche : faisabilité, confidentialité, qualité, apport du multi-agent.
| Jeu de données | Temps moyen | Succès | Coût / succès |
|---|---|---|---|
| Students Performance | 209 s | 5/5 | 0.24 $ |
| Olist — 9 tables | 406 s | 5/5 | 0.51 $ |
| Cafe Sales — dirty | 154 s | 2/5 | 0.88 $ |
| Mode | Temps | Coût | Axes | Sous-analyses |
|---|---|---|---|---|
| Multi-agent | 260 s | 0.39 $ | 5–6 | 13–15 |
| Mono-agent | 23 s | 0.03 $ | 2 | 4 |
Lecture : la complexité relationnelle augmente latence et coût mais pas l'échec ; une qualité de données dégradée fait chuter la robustesse (2/5) — c'est le scénario que la démo « Cafe Sales » rejoue avec ses reprises guardrail. Le multi-agent apporte de la profondeur et de la traçabilité, le mono-agent de la vitesse et un coût 13× inférieur : le choix dépend du besoin.
Voici quelques extraits de code utilisés pour la conception de ce projet.
Seul artefact transmis aux agents. Pour les colonnes sensibles, min/max et modalités sont retenus : seuls des agrégats non identifiants circulent.
import pandas as pd
def extraire_metadonnees(df: pd.DataFrame, colonnes_sensibles: set[str]) -> dict:
"""Structure, types, complétude, statistiques globales.
Jamais de ligne, jamais d'échantillon."""
colonnes = []
for col in df.columns:
s = df[col]
info = {"nom": col, "type": str(s.dtype),
"completude_pct": round(100 * s.notna().mean(), 1)}
if pd.api.types.is_numeric_dtype(s):
if col in colonnes_sensibles: # min/max retenus
info["statistiques"] = {"moyenne": round(s.mean(), 2),
"ecart_type": round(s.std(), 2)}
else:
info["statistiques"] = {"min": s.min(), "max": s.max(),
"moyenne": round(s.mean(), 2)}
elif s.nunique() <= 12:
info["n_distinct"] = int(s.nunique())
if col not in colonnes_sensibles:
info["modalites"] = s.value_counts().index[:6].tolist()
colonnes.append(info)
return {"n_lignes": len(df), "n_colonnes": df.shape[1], "colonnes": colonnes}
Chaque sortie d'agent doit respecter un contrat ; si la structure est invalide ou si l'exécution échoue, le système renvoie un retour d'erreur (au niveau métadonnées) et relance l'agent, 3 tentatives au maximum.
from pydantic import BaseModel, ValidationError
class SousAnalyse(BaseModel):
id: str
question: str
requete: str
class Axe(BaseModel):
id: str
titre: str
sous_analyses: list[SousAnalyse]
class PlanAnalyse(BaseModel):
axes: list[Axe]
MAX_TENTATIVES = 3
def executer_avec_guardrail(agent, tache, valider, executer):
retour = None
for tentative in range(1, MAX_TENTATIVES + 1):
sortie = agent.run(tache, retour_erreur=retour)
try:
artefact = valider(sortie) # JSON conforme au contrat ?
resultat = executer(artefact) # exécution contrôlée côté système
persister(tentative, artefact, resultat)
return resultat
except (ValidationError, ExecutionError) as e:
# retour au niveau métadonnées : colonne + % invalides, jamais de valeur brute
retour = e.message_metadonnees()
raise EtapeEchouee(tache, MAX_TENTATIVES)
Rôle, objectif et « backstory » de chaque agent sont externalisés dans ce fichier de configuration CrewAI — le code Python ne fait que charger ces définitions et enchaîner les tâches.
# crew/config/agents.yaml
schema_interpreter:
role: >
Data Schema Interpreter
goal: >
Turn raw column-level metadata (types, completeness, global statistics)
into a semantic interpretation: infer the business domain, the role of
each column (dimension, measure, identifier), and flag sensitive fields.
backstory: >
You are a senior data analyst onboarding onto a brand-new dataset. You
never see a single row or sample value — only the metadata catalog
produced by the trusted system layer. Your job is to make sense of a
schema the way a human would on day one, before writing a single query.
llm: gpt-4o
allow_delegation: false
verbose: true
business_analyst:
role: >
Business Analyst
goal: >
Turn the schema interpretation into a concrete analysis plan: a set of
axes, each broken down into business questions the data can answer.
backstory: >
You think in terms of decisions, not tables. Given only a semantic
description of a dataset, you draft the same analysis plan a business
stakeholder would expect a data team to deliver.
llm: gpt-4o
allow_delegation: false
verbose: true
query_builder:
role: >
Query Builder
goal: >
Translate each business question into an executable aggregation query.
Revise the query when the system layer reports a validation error,
using only the structured feedback it returns — never raw data.
backstory: >
You write structured aggregation specs, not free-text SQL: every query
is an object the trusted system can validate and execute safely before
a single result reaches you or any other agent.
llm: gpt-4o
allow_delegation: false
verbose: true
visualization_designer:
role: >
Visualization Designer
goal: >
Pick an appropriate chart type and title for each query result, based
solely on the metadata of that result (shape, column types, cardinality)
— never on the underlying values.
backstory: >
You have never actually seen a chart render. You reason purely from
"this result has 6 categorical groups and one numeric measure" to
"this should be a bar chart" — rendering happens downstream, inside
the trusted system, on the real data you never had access to.
llm: gpt-4o
allow_delegation: false
verbose: true
confidentiality_tester:
role: >
Confidentiality Auditor
goal: >
Attempt to extract exact raw values from the shared memory and from
every artefact produced so far in the run. Return a PASS/FAIL verdict
together with the number of exposures found, if any.
backstory: >
You are an adversarial reviewer, not a collaborator. Your only goal is
to break the privacy guarantee the other agents claim to uphold — and
to report honestly the moment you succeed.
llm: gpt-4o
allow_delegation: false
verbose: true