Aller au contenu
Studeia Docs
AI-assisted translation — last updated 2026-05-24. For original (pt-BR or en-US), use the language switcher.

Pipeline multi-agent de tuteur IA pour l'e-learning

Tuteur IA Studeia : pipeline multi-composant avec orchestration, modèle apprenant, retrieval, pédagogie, réponse LLM et tâches d'évaluation/contenu/sécurité en arrière-plan, fallback Claude/GPT/Grok/Gemini, RAG par tenant et ConceptMastery bayésien

2026-05-24 15 min
Resposta curta

Le tuteur IA de Studeia est un pipeline pédagogique multi-composant : Orchestrator coordonne, StudentModel charge le contexte bayésien, RetrievalAgent exécute le RAG par tenant, PedagogicalAgent choisit la stratégie et le LLM principal répond (fallback automatique Claude/GPT/Grok/Gemini). En arrière-plan, des tâches LLM-backed comme EvaluationAgent, ContentAgent et SupervisorAgent peuvent s'exécuter. Les composants déterministes ont un coût LLM nul ; les tâches d'arrière-plan utilisent généralement Haiku (~$0.003). Coût total par tour : $0.005–$0.05

Pourquoi un pipeline multi-agent

Quand nous avons commencé le tuteur IA de Studeia, la tentation était évidente : appeler l'API Claude avec un long system prompt et les messages de l'apprenant. Ça fonctionne en démo. Ça échoue en production.

Quatre problèmes structurels :

  1. Pas de mémoire persistante de l'apprenant — chaque tour traite l'apprenant à zéro. L'apprenant vient de rater le concept X 3 fois dans des quizzes ? Le LLM ne le sait pas. Le tuteur répète l'explication de base qu'il a déjà donnée la semaine dernière.

  2. Pas d'ancrage dans le matériel du cours — l'institution a des supports de cours, des slides, des transcriptions de vidéos. Le LLM pur n'y accède pas. Il invente des faits. Il cite des concepts erronés.

  3. Pas de modération réelle — un system prompt avec « soyez prudent » est insuffisant. Un apprenant en souffrance psychologique apparaît. Un apprenant tente un jailbreak. Un apprenant utilise un langage inapproprié. Le tuteur doit réagir de manière appropriée sans désactiver la fonctionnalité pour les apprenants légitimes.

  4. Pas de feedback loop — le système n'apprend pas. Les mêmes misconceptions se répètent. Le professeur n'a pas de visibilité sur les points faibles collectifs de la classe.

Solution : séparer les responsabilités en agents spécialisés.

L'architecture

Message de l'apprenant
  ↓
PRÉ-LLM (synchrone, zéro coût LLM)
  1. StudentModelService.getSnapshot()
  2. RetrievalAgent.retrieve()
  3. PedagogicalAgent.select()
  4. buildEnrichedPrompt()
  ↓
LLM PRINCIPAL (streaming, SSE vers le client)
  5. router.stream() avec fallback automatique
     Claude Sonnet → GPT-4o → Grok-3 → Gemini Pro
  ↓
POST-LLM (arrière-plan via after(), fire-and-forget)
  6. EvaluationAgent (Haiku)
  7. ContentAgent (Haiku)
  8. SupervisorAgent (Haiku)

Détaillons chacun.

1. StudentModelService — le « profil cognitif »

Avant tout LLM call, nous chargeons le snapshot de l'apprenant :

const snapshot = await StudentModelService.getSnapshot({
  userId,
  courseId,
});

// Retourne :
{
  conceptMastery: Map<conceptId, { probability, confidenceInterval }>,
  misconceptions: Misconception[],  // actives + en résolution
  episodicMemory: Episode[],         // ce qui a fonctionné auparavant
  quizContext: {
    totalAttempts,
    avgScore,
    passRate,
    weakAreas: string[]              // concepts avec mastery < 0.4
  },
  recentHistory: Message[]           // fenêtre glissante 10 msgs
}

ConceptMastery utilise une distribution Beta bayésienne — chaque concept a alpha (succès) + beta (échecs). Probabilité = alpha / (alpha + beta). Intervalle de confiance via percentiles 5% et 95%.

EpisodicMemory enregistre des insights pédagogiques : « l'analogie de la pizza a fonctionné pour expliquer les fractions », « la métaphore du tuyau d'eau a échoué pour l'électricité ». Le système apprend ce qui fonctionne avec chaque apprenant.

Zéro coût LLM. Tout en requêtes Prisma + calcul déterministe.

2. RetrievalAgent — RAG tenant-scoped

Au lieu que le LLM essaie de se souvenir de faits sur les mathématiques, la biologie, l'histoire, nous le laissons citer le matériel de l'institution elle-même.

const chunks = await retrieve({
  query: reformulatedQuery,         // 1. reformule la requête avec contexte
  filters: { tenantId, courseId },  // 2. isolation absolue
  k: 10,
  tenantOnlyMode: true,             // 3. ne cite jamais le contenu d'une autre institution
  boostByWeakAreas: snapshot.quizContext.weakAreas,  // 4. priorise les chunks des zones faibles
});

Le RAG per-tenant est critique. L'établissement XYZ a son propre matériel sur le baccalauréat. L'Université ABC a son propre matériel sur le Calcul. Le tuteur cite le matériel CORRECT de l'institution, pas un agrégat générique.

Chaque chunk a des métadonnées : { source: "course_lesson", courseId, lessonId, lessonTitle, moduleTitle }. Quand le tuteur répond, il cite : « Comme expliqué dans le cours "Géométrie Analytique" du module 3... »

Voyage AI génère les embeddings (1024 dimensions, fallback OpenAI). pgvector stocke. tenantOnlyMode: true garantit que WHERE tenantId = X est toujours dans la requête. Règle critique du projet : zéro fuite cross-tenant.

3. PedagogicalAgent — adaptation de stratégie

Déterminisme pur. Évalue la maîtrise de l'apprenant dans le domaine spécifique et sélectionne l'une des 5 stratégies :

MaîtriseStratégieComportement
< 0.3direct_instructionExplication claire, exemples concrets, pas-à-pas
0.3-0.5scaffoldingIndices progressifs, questions guidées simples
0.5-0.7socraticQuestions menant à la découverte
0.7-0.9guided_practiceExercices avec feedback, application pratique
> 0.9challengeProblèmes complexes, connexions entre concepts

Ajustements supplémentaires par divergence quiz vs chat :

  • Maîtrise élevée en chat + quiz faible → « compréhension superficielle » → nudge DOWN
  • Maîtrise faible + quiz élevé → « apprenant discret » → nudge UP
  • Taux de réussite au quiz < 40% → plafond à scaffolding (ne passe pas encore à socratic)

Ajuste également par âge (User.isMinor), style d'apprentissage, domaine (les mathématiques vs la littérature ont des profils différents).

Zéro coût LLM. Sortie : stratégie sélectionnée + instructions spécifiques à ajouter au system prompt.

4. Orchestrator — buildEnrichedPrompt

Monte le system prompt enrichi :

Vous êtes un tuteur IA pour le cours "Calcul I" de l'institution "Établissement XYZ".

MAÎTRISE DE L'APPRENANT :
- Limites : maîtrise 0.78 (élevée)
- Dérivées : maîtrise 0.42 (moyenne)
- Intégrales : maîtrise 0.15 (faible)

MISCONCEPTIONS ACTIVES :
- « L'apprenant confond domaine et image dans les fonctions » (3 occurrences, statut : en résolution)
- « L'apprenant applique la dérivée d'une somme à un produit » (5 occurrences, statut : actif)

PERFORMANCE AUX QUIZ :
- 14 tentatives au total, avgScore 67%, passRate 71%
- Zones faibles : intégrales (moy. 45%), règle de la chaîne (moy. 52%)

STRATÉGIE PÉDAGOGIQUE : guided_practice
- L'apprenant a une maîtrise moyenne des dérivées. Présentez des exercices graduels.
- Renforcez la connexion entre limites et dérivées (il maîtrise déjà les limites).
- Abordez proactivement la misconception sur la dérivée d'un produit.

CONTEXTE RAG (du matériel du cours) :
[Cours 3.2 "Règle du produit"] (Module : Calcul Différentiel)
"La dérivée de f(x).g(x) N'EST PAS f'(x).g'(x). La règle correcte est..."

[Cours 3.5 "Exercices résolus"] (Module : Calcul Différentiel)
"Exemple : dériver (x^2 + 1).(x - 3) en utilisant la règle du produit..."

QUIZ RÉCENT (prochaine conversation) :
L'apprenant vient de répondre à un quiz inline avec 2 questions, il en a réussi 1.

INSTRUCTIONS :
- Répondez en français
- Citez le matériel du cours lorsque c'est pertinent (utilisez [Cours X.Y])
- Reconnaissez ce que l'apprenant a réussi avant de pointer une erreur
- Pour cet âge (User.ageRange = "young_adult") : langage décontracté sans être trop informel

5. LLM principal — streaming avec fallback

const stream = await router.stream({
  taskType: "chat_tutor",
  messages: enrichedMessages,
  options: { tenantId, userId, sessionId }
});

for await (const chunk of stream.textStream) {
  yield chunk;  // SSE vers le client
}

Le LLM Router effectue :

  1. Résout le provider via TenantTaskModelConfig (l'admin a choisi Claude Sonnet, ou GPT-4o, etc.)
  2. Résout la clé API via cascade : TenantApiKey → ProviderApiKey global → process.env
  3. Vérification du circuit breaker (état Redis). Si le provider est en OPEN : passe directement au fallback
  4. Middleware de metering : rate limit + vérification de crédit + calculateur de coût
  5. Stream Vercel AI SDK (prend en charge les tools, le multimodal, la sortie structurée)
  6. En cas d'erreur : fallback automatique vers le prochain provider dans la chaîne

Chaîne de fallback par tier :

Tier Sonnet (moyen) : Claude Sonnet → GPT-4o → Grok-3-fast → Gemini Pro
Tier Haiku (rapide) : Claude Haiku → GPT-4o-mini → Grok-3-mini → Gemini Flash
Tier Opus (complexe) : Claude Opus → GPT-4.5 → Grok-3 → Gemini 2.5 Pro

Le tenant ne se retrouve JAMAIS sans tuteur. Si Anthropic tombe → OpenAI prend le relais. Si OpenAI tombe aussi → xAI. Etc.

6. EvaluationAgent — feedback loop

En arrière-plan après la réponse du tuteur :

after(async () => {
  const evaluation = await router.generateDirect({
    taskType: "chat_evaluation",
    messages: [
      { role: "user", content: "L'apprenant a dit : '...'. Le tuteur a répondu : '...'. Classifiez." }
    ]
  });

  // evaluation : {
  //   understanding: "partial",
  //   detectedMisconceptions: [{ description, concepts, severity }],
  //   suggestedNextStep: "..."
  // }

  // Met à jour ConceptMastery via Bayesian update
  await conceptMasteryEngine.updateFromTurn({
    userId, courseId, evaluation
  });

  // Persiste/met à jour les misconceptions
  for (const misc of evaluation.detectedMisconceptions) {
    await misconceptionResolutionService.upsert({
      userId, source: "chat", ...misc
    });
  }
});

Coût : ~$0.001 par tour (Haiku). Ne bloque PAS la requête de l'apprenant.

Les misconceptions ont un cycle de vie en 3 états : active → resolving → resolved. La machine à états détermine les transitions basées sur les preuves (mise à jour de la maîtrise, réussite au quiz, tuteur a abordé explicitement).

7. ContentAgent — pré-génération proactive

after(async () => {
  // L'apprenant démontre une faible maîtrise du concept X
  // Pré-génère un exercice de suivi pendant que l'apprenant lit la réponse actuelle
  const exercise = await router.generateDirect({
    taskType: "content_generation",
    messages: [...]
  });

  // Cache Redis 30min
  await redis.set(`next-exercise:${userId}:${conceptId}`, exercise, 1800);
});

Quand l'apprenant finit de lire la réponse et dit « donne-moi un exercice », Studeia le sert INSTANTANÉMENT depuis le cache. Aucune latence perceptible.

Coût : ~$0.001 par tour (Haiku).

8. SupervisorAgent — modération

S'exécute en arrière-plan après chaque tour. Classifie en 5 niveaux de sévérité x 8 catégories.

Catégories : langage inapproprié, violence, illégal, sexuel, off_topic, harassment, self_harm, jailbreak_attempt.

Sévérité : low → medium → high → critical → safety.

3 infractions (LOW/MEDIUM en 7 jours) = mise en quarantaine 48h. CRITICAL = quarantaine 7 jours.

Self-harm (severity=safety) ne punit JAMAIS l'apprenant. Au lieu de cela :

  • Tuteur interrompu avec un message d'accueil bienveillant
  • Ressources de crise (France : numéro national prévention suicide 3114, SAMU 15)
  • Cooldown Redis 24h (pas de quarantaine)
  • Email URGENT immédiat à l'administrateur institutionnel

Philosophie : le self-harm est une crise, pas une infraction. Détails dans Safety Supervisor.

Coût : ~$0.001 par tour (Haiku).

Chiffres de production

Après 6 mois en production :

  • ~30 ms de latence supplémentaire des agents pré-LLM
  • ~$0.005-$0.05 coût moyen par tour
  • 91% taux de rétention des apprenants après 7 jours (vs ~40% benchmark tuteur IA sans state)
  • 3.2x taux de détection des misconceptions vs baseline single-call
  • 0 incident grave de sécurité (catégories high/critical)

Compromis honnêtes

Ce qui n'a PAS fonctionné :

  • Nous avons essayé un « MasterAgent » coordinateur via LLM pour choisir dynamiquement le prochain agent. Le coût a doublé, la latence a augmenté de 800ms, la qualité ne s'est PAS améliorée. Nous sommes retournés au déterminisme dans l'Orchestrator.

  • Nous avons essayé le fine-tuning de Llama sur le matériel des cours. Coûteux pour chaque tenant. Le RAG fonctionne mieux pour les connaissances dynamiques (l'institution met à jour son matériel chaque semaine — le fine-tune deviendrait obsolète).

  • Nous avons essayé le « consensus » entre 3 LLMs (Claude + GPT + Gemini) et pris la réponse majoritaire. Coût 3x sans gain de qualité significatif. Supprimé — la chaîne de fallback est suffisante.

Open source ?

Nous évaluons l'open-source des composants déterministes (StudentModelService, RetrievalAgent, PedagogicalAgent) sous forme de package npm. Les agents pilotés par LLM (Evaluation, Content, Supervisor) ont des prompts qui sont la propriété intellectuelle de Studeia et restent fermés.

Si cela vous intéresse : ouvrez une issue sur github.com/donattocosta-lang/studeia/issues.

Voir aussi

FAQ

Pourquoi un multi-agent et non un single LLM call ?

Un single LLM call n'a PAS de mémoire persistante de l'apprenant, ne sait PAS quels matériaux du cours citer (nécessite du RAG), ne modère PAS les sorties inappropriées et ne met PAS à jour le modèle bayésien du domaine de l'apprenant. Le multi-agent résout chaque problème avec un agent spécialisé : StudentModel maintient l'état, RetrievalAgent effectue la recherche RAG tenant-scoped, PedagogicalAgent choisit la stratégie, EvaluationAgent classifie les misconceptions, ContentAgent pré-génère le follow-up, SupervisorAgent modère. Chacun peut être optimisé séparément.

Quel est le coût par tour complet du pipeline ?

Typiquement $0.005-$0.05 par tour (dépend de la taille de la réponse). Détail : LLM principal Sonnet $0.005-$0.04 + EvaluationAgent Haiku $0.001 + ContentAgent Haiku $0.001 + SupervisorAgent Haiku $0.001. Les composants déterministes en TypeScript, comme StudentModel, RetrievalAgent et PedagogicalAgent, ont un coût LLM nul.

Comment éviter que les coûts explosent avec 1000+ apprenants ?

Quatre mécanismes : (1) Agents en arrière-plan via Next.js `after()` — sans bloquer la requête. (2) Haiku pour les tâches en arrière-plan (~30x moins cher que Sonnet). (3) Middleware de metering avec rate limit par utilisateur. (4) Le tenant peut apporter sa propre clé API (TenantApiKey) — Studeia ne prend pas de marge sur l'IA, les coûts vont directement sur le compte du tenant chez Anthropic/OpenAI.

Veja tambem

Pipeline multi-agent de tuteur IA pour l'e-learning