Architecture de Mia
Vue technique condensée : instantané système, boucle temps réel, métriques, validation, positionnement. Active le mode ingénieur (bouton en haut à droite) pour afficher les données, logs et schémas bruts.
01Instantané système
Mia est un système de robotique cognitive temps réel combinant une tête robotique physique avec une architecture cognitive modulaire à base d'agents.
Hardware
- 28 servomoteurs (actionneurs faciaux)
- Structure mécanique sur mesure (imprimée 3D + peau latex)
- Contrôle moteur par microcontrôleur
Calcul
- Runtime : CPU seul — PC modeste, sans GPU
- Latence de boucle : ~350 ms (perception → décision → actionnement)
Architecture
- 6 engines centraux : perception, mémoire, arbitrage, planification, exécution, contrôle moteur
- 109 agents cognitifs (modules spécialisés)
Entrées
- Vision (caméra)
- État interne
- Texte (optionnel)
Sorties
- Commandes motrices (expressions faciales)
- Texte (dialogue)
- Mises à jour de l'état interne
Runtime
- Boucle continue (temps réel)
- Mémoire persistante activée
02Vue d'ensemble de l'architecture
Mia fonctionne comme une boucle continue perception → décision → action.
Engine de perception
Traite les entrées visuelles et extrait des signaux structurés.
Engine de mémoire
Maintient l'état interne persistant et les expériences passées.
Engine d'arbitrage
Sélectionne les signaux pertinents et résout les entrées concurrentes.
Engine de planification
Génère des actions candidates à partir de l'état courant.
Engine d'exécution
Transforme les décisions en commandes actionnables.
Engine de contrôle moteur
Traduit les commandes en mouvements synchronisés des servomoteurs.
┌─────────────────────────────────────────┐
│ MONDE PHYSIQUE │
│ (Zan, personnes, environnement) │
└────────────┬──────────────┬─────────────┘
│ lumière │ voix
▼ ▼
┌──────────────────────┐ ┌──────────────────────┐ ┌──────────────────┐
│ ESP32-CAM #1 œil G │ │ ESP32-CAM #2 œil D │ │ Micro (STT ?) │
│ 192.168.1.14/capture│ │ 192.168.1.15/capture│ │ (non implémenté)│
│ JPEG over HTTP │ │ JPEG over HTTP │ └──────────────────┘
└───────────┬──────────┘ └──────────┬───────────┘
│ JPEG │ JPEG
└────────────┬────────────┘
▼
╔══════════════════════════════════════════════════════════════════════════╗
║ PERCEPTION SERVICE (Python, process séparé, FastAPI/Uvicorn) ║
║ ───────────────────────────────────────────────────────────────── ║
║ ║
║ POST /analyze-image ║
║ ┌─────────────┐ ┌────────────────┐ ┌────────────────┐ ║
║ │ OpenCV │──▶│ InsightFace │──▶│ MediaPipe │ ║
║ │ décodage │ │ buffalo_l │ │ FaceLandmarker│ ║
║ │ BGR↔RGB │ │ RetinaFace + │ │ 478 landmarks │ ║
║ │ │ │ ArcFace 512-D │ │ 52 blendshapes│ ║
║ └─────────────┘ └───────┬────────┘ └───────┬────────┘ ║
║ │ embeddings │ blendshapes ║
║ ▼ ▼ ║
║ ┌───────────────────────────────┐ ║
║ │ FaceRegistry (identités) │ ║
║ │ stockage local disque │ ║
║ └───────────────────────────────┘ ║
║ POST /register-face GET /persons DELETE /persons/{id} /health ║
╚═══════════════════════╤══════════════════════════════════════════════════╝
│ JSON (faces[], landmarks[], blendshapes[])
│ HTTP localhost
▼
╔══════════════════════════════════════════════════════════════════════════════════╗
║ RUNTIME COGNITIF (.NET 9, ASP.NET Core, BackgroundService) ║
║ ───────────────────────────────────────────────────────────────────────── ║
║ ║
║ ┌────────────────────────────────────────────────────┐ ║
║ │ CognitiveRuntimeHostedService │ ║
║ │ PeriodicTimer 350 ms ─▶ TickAsync() │ ║
║ └──────────────────────┬─────────────────────────────┘ ║
║ │ snapshot (unique, passé à tous) ║
║ ▼ ║
║ ┌──────────────┐ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────┐ ║
║ │ SceneEngine │──▶│ MorphologyEngine│──▶│ GeneratorEmerg. │──▶│IntentionArb.│ ║
║ │ (entrées │ │ (dominance, │ │ Engine │ │ Engine │ ║
║ │ perçues) │ │ inhibition, │ │ (formes │ │ (scoring │ ║
║ │ │ │ valence) │ │ internes) │ │ pondéré + │ ║
║ └──────────────┘ └─────────────────┘ └─────────────────┘ │ jitter) │ ║
║ └──────┬──────┘ ║
║ 109 agents (en parallèle, séquentiels dans le tick) : │ ║
║ • affectifs • normatifs • identitaires • sociaux • mémoriels │ ║
║ • ponts (bridge) • révisions │ ║
║ intention gagnante ║
║ ┌────────────────────────────┐ ┌───────────────────────┐ │ ║
║ │ ReinforcementLearningEngine│◀─────│ CognitiveActionOutcome│ │ ║
║ │ 10 features → 7 poids │ │ (success/partial/fail,│ │ ║
║ │ REINFORCE, ε-greedy │ │ focus error, etc.) │ │ ║
║ │ buffer 64 exp, LR=0.005 │ └───────────────────────┘ │ ║
║ └──────────┬─────────────────┘ │ ║
║ │ gains multiplicatifs (Arbitration*Gain) │ ║
║ └──────────────────────────────────────────┐ │ ║
║ ▼ ▼ ║
║ ┌─────────────────────────────────────┐ ║
║ │ ActionExecutor │ ║
║ │ + SpeechOutputAgent │ ║
║ └────────┬───────────────┬────────────┘ ║
╚══════════════════════════════════════════════════╧═══════════════╧═════════════════╝
│ état + commandes │ texte à dire
│ (SignalR hub /cognitive-hub) │
│ ▼
│ ┌───────────────────────┐
│ │ CognitiveLlmService │
│ │ (prothèse langage) │
│ │ • HTTP transport │
│ │ • CLI transport │
│ │ (subprocess) │
│ └───────────┬───────────┘
│ │ prompt / réponse
│ ▼
│ ┌───────────────────────┐
│ │ API Claude │
│ │ (modèle externe) │
│ │ RAM only, éphémère │
│ └───────────────────────┘
│
┌────────────────────┼──────────────────────────────────────────────────────┐
▼ ▼ ▼
┌──────────────┐ ┌──────────────────┐ ┌─────────────────────┐
│ FRONT SPA │ │ HARDWARE BRIDGE │ │ PERSISTANCE │
│ JS vanilla │ │ ────────────── │ │ ───────────── │
│ modules ES │ │ • Série COM5 │ │ 14 stockages : │
│ wwwroot/ │ │ → Arduino Mega │ │ • SQLite (migration │
│ Cockpit, │ │ 2560 │ │ en cours : RL…) │
│ Corps, IA, │ │ → 27 servos │ │ • JSON atomique │
│ Mémoire… │ │ • HTTP ESP32 │ │ (.tmp → move + │
│ SignalR + │ │ • ROS-like sur │ │ .bak) │
│ REST │ │ RPi5 ??? │ │ • knowledge.json │
└──────────────┘ └─────────┬────────┘ │ • cognitive-state │
│ PWM / ordres │ • episodes… │
▼ └─────────────────────┘
┌──────────────────┐
│ Servos physiques │
│ (tête, yeux, cou,│
│ mâchoire, │
│ langue, lèvres) │
└──────────────────┘
════════════════════════════════════════════════════════════════════════════
FLUX NOMMÉS (analogues à des topics ROS)
════════════════════════════════════════════════════════════════════════════
/vision/frame JPEG brut ESP32 → .NET
/vision/analysis JSON faces+landmarks+id Python → .NET
/cognitive/tick snapshot interne, in-process, 350 ms
/cognitive/arbitration candidats + vainqueur
/cognitive/rl/update (features, reward) post-tick
/action/execute intention → commandes
ESP32 en Wi-Fi HTTP (latence réseau), Arduino en série (latence ms). Raspberry Pi 5 pas encore intégré au pipeline — rôle à définir (probable hub vision local ou orchestrateur bas niveau).
Pas de ROS, pas de DDS, pas de broker : toute l'IPC inter-processus est HTTP REST. Délibérément simple, au prix d'un plafond ~3 fps pour la vision lourde — largement suffisant ici.
RL dans la boucle : le seul « apprentissage » qui modifie vraiment le comportement tourne sur 7 poids scalaires — encart gauche, mis à jour après chaque action.
LLM hors persistance : volontairement détaché du graphe de mémoire — il parle, il ne laisse pas de trace.
Mia a une proprioception extéroceptive (webcam → MediaPipe blendshapes sur son propre visage), pas d'encodeurs internes — ça recadre l'analyse vers un pattern self-model visuel plutôt que robotique classique.
03Fondements formels
Traduction L3 de l'architecture ci-dessus : état vectoriel, fonction de transition, politique de mémoire, frontière LLM. Tous les poids du scoring restent auditables dans le code — aucun gradient ne bouge de manière opaque.
État du système
St = ( Pt, Mt, At, It, Dt, Xt )
Pt— features perceptives (landmarks, identité face, contexte scène)Mt— snapshot mémoire (14 domaines cognitifs typés, persistés JSON)At— affect (valence, arousal, climat cognitif)It— inhibitions actives (cooldown, normes, sécurité)Dt— décision couranteXt— plan d'exécution en attente
Dynamique & politique
S(t+1) = f( S(t), perception(t), memory(t) ) action(t) = π( S(t) )
Deux équations pour deux rôles distincts :
f— dynamique du système. L'état àt+1dépend de l'état courant, de la perception fraîche (frame caméra) et d'une lecture de la mémoire.π— politique d'arbitrage. Produit l'action à partir de l'état. Détail au bloc Arbitrage.
Période d'évaluation : 350 ms (.NET, soft real-time).
f est déterministe. π est déterministe sauf en un point unique : stochasticité contrôlée quand le top et le second sont trop proches (|top − second| < 0.12).
Les coefficients de f et π restent fixes à l'exécution. Seuls 5 gains multiplicatifs globaux de π sont appris, via un RL minimal borné et désactivable (voir bloc Apprentissage).
Mémoire — 14 domaines typés
Pas de graphe universel. Pas de base vectorielle. Mt est un tuple de 14 domaines cognitifs, chacun avec son schéma et son repository JSON : JsonCognitive<Domain>Repository.cs.
Écritures possibles dans Mt :
- Implicite — moyenne mobile exponentielle (EMA) des succès par pattern (
SuccessBiasScore,AttractorBiasScoreviaMemoryContribution) - Explicite — commande
teach→knowledge.json - Narrative —
journal-conversations.md
Oubli : décroissance exponentielle naturelle de l'EMA. Pas de purge.
Retrieval : clé directe par domaine. Pas de nearest-neighbor générique — chaque domaine a son API typée.
Apprentissage — RL minimal et auditable
Oui, il y a du reinforcement learning — mais pas ce qu'on pourrait craindre. CognitiveLearningService + JsonCognitiveRLRepository implémentent un policy gradient ultra-léger :
- 7 poids scalaires ajustés (dont les 5
Arbitration*Gain) - 10 features en entrée
- Update trivial en ~3 lignes de code
- Exploration bornée par construction (clamp min/max sur chaque poids)
- Pas de réseau de neurones, pas de gradient opaque, pas de tenseurs
Ce que le RL touche : les 5 gains multiplicatifs globaux de l'arbitrage, appliqués au profil via ApplyToProfile(profile). En parallèle, MemoryContribution maintient des biais statistiques (SuccessBiasScore, AttractorBiasScore) moyennés exponentiellement.
Ce que le RL ne touche pas : les poids atomiques du scoring (× 0.35, × 0.07…), la structure de T, l'extraction des features. Tout ça reste hardcodé et lisible.
L'apprentissage agit sur un seul étage : cinq gains multiplicatifs globaux.
Tout le reste du scoring reste fixe et auditable dans le code.
Kill-switch : SetEnabled(false) → tous les gains reviennent à 1.0 → l'arbitrage redevient purement heuristique. L'opérateur garde le contrôle manuel à chaud.
Arbitrage
Score multi-critère par action candidate :
score(ai) = Σk gk · ( Σj∈k wj · fj( St, ai ) )
Où :
wj— poids atomiques fixes (dans le code)gk— 5 gains multiplicatifs globaux (Arbitration*Gain), appris par RL, bornés, désactivables (gk = 1.0siSetEnabled(false))fj— features observées + biais mémoire via EMA
Règle d'arbitrage :
- Si
|top − second|≥ 0.12 →argmax(déterministe) - Sinon → échantillonnage pondéré parmi le top-k proche (stochasticité contrôlée)
Le seuil 0.12 modélise une incertitude irréductible : quand deux options sont trop proches, refuser de trancher arbitrairement est en soi une décision.
Frontière LLM — point différenciateur
Le LLM est hors de T, hors de S, hors du substrat. Ce n'est ni un engine, ni un agent, ni un composant de mémoire.
Il reçoit les sorties narratives de Mia et produit du langage en retour. Session non persistée (--no-session-persistence).
Deux canaux (et seulement deux) sont autorisés pour écrire dans Mt :
teach→knowledge.json— apprentissage explicite, sous contrôle humainjournal-conversations.md— écriture narrative, relue par Mia lors des cycles suivants
Conséquence : le LLM peut être changé (v1 → v2, fournisseur A → B) sans altérer le substrat. Mia reste Mia entre les générations de LLM.
04Agents cognitifs
Un agent est un module computationnel spécialisé, avec des entrées et sorties définies.
Exemples
- Agent de détection de visage
- Agent de mise à jour de l'état émotionnel
- Agent de notation de décision
- Agent de coordination motrice
ENGINE (ex. Perception) ┌─────────────────────────────┐ │ ENGINE CORE │ │ │ │ ┌───────────────┐ │ │ │ Agent 1 │ │ │ ├───────────────┤ │ │ │ Agent 2 │ │ │ ├───────────────┤ │ │ │ Agent 3 │ │ │ ├───────────────┤ │ │ │ ... │ │ │ ├───────────────┤ │ │ │ Agent N │ │ │ └───────────────┘ │ │ │ └─────────────────────────────┘
Les agents sont orchestrés à l'intérieur des engines et interagissent via un état partagé.
05Boucle temps réel
Cycle typique observé :
- t = 0 ms→Image capturée (caméra)
- t = 40 ms→Visage détecté
- t = 120 ms→État interne mis à jour
- t = 210 ms→Décision choisie (ex. « sourire »)
- t = 300 ms→Commandes motrices générées
- t = 350 ms→Expression faciale exécutée
06Démonstration en direct
Le système tourne en continu dans une boucle fermée perception–action.
Interaction typique
- Un stimulus visuel est détecté
- L'état interne évolue
- Une réponse comportementale est générée
- Les moteurs exécutent l'expression correspondante
07Métriques système
Latence de boucle
- Moyenne : ~350 ms
Stabilité runtime
- Fonctionnement continu : testé sur sessions étendues
Actionnement
- 28 canaux servomoteurs synchronisés
Architecture
- 109 agents actifs
- 6 engines coordonnateurs
08Approche de validation
Mia est conçue pour être testable et reproductible.
Validation future
- Expériences comportementales reproductibles
- Latence de réponse mesurable
- Stabilité du système en fonctionnement continu
L'objectif est de passer de la démonstration à l'évaluation rigoureuse.
09Positionnement
Mia n'est pas un système basé sur un modèle de langage. C'est une architecture cognitive incarnée temps réel combinant perception, état interne et actionnement physique.