← Documentation API Reference

Runtime Local-First AISIA

Version : 4.15.0 Société : AISIA — Structure juridique en cours de création URL publique : https://aisia.fr/

---

Table des matières

1. Philosophie local-first 2. Les 4 runtimes locaux 3. Catalogue des 83 modèles locaux (52 activés) 4. Calcul de confiance 5. Self-consistency sampling 6. Routage local : sélection des modèles 7. Hot-reload à chaud 8. Ollama edge distribué 9. GPU Jetson Xavier AGX 10. Configuration complète 11. Monitoring et diagnostics 12. Fallback vers le cloud

---

1. Philosophie local-first

Le mode local-first est un principe fondamental d'AISIA : **privilégier les modèles locaux** avant de recourir aux providers cloud.

Avantages

AspectLocal-firstCloud-only
ConfidentialitéDonnées restent sur siteDonnées envoyées à un tiers
Latence<1s pour modèles légers1-5s selon le provider
CoûtGratuit (infra propre)Payant (API tokens)
DisponibilitéIndépendant d'InternetDépendant du provider
ContrôleTotalDépendant des CGU

Quand le local est-il utilisé ?

Le mode local-first s'active quand : 1. AUTONOMOUS_LOCAL_ENABLED=true dans la configuration 2. Au moins un modèle local est disponible (health() == True) 3. La confiance de la réponse locale dépasse le seuil (0.75 par défaut)

Si la confiance est insuffisante, la requête est transmise aux providers cloud (fallback transparent pour l'utilisateur).

---

2. Les 4 runtimes locaux

AISIA supporte 4 runtimes d'inférence pour les modèles locaux, chacun ayant ses forces :

Ollama

Fichier : app/local_runtime/ollama.py

Le runtime principal, conçu pour la simplicité d'utilisation sur ARM64 (Raspberry Pi).

CaractéristiqueValeur
ProtocoleHTTP REST (/api/generate)
Endpoint défauthttp://localhost:11434
ArchitecturesARM64, AMD64
Formats modèlesGGUF (quantisés)
Usage principalInférence CPU sur RPi

vLLM

Fichier : app/local_runtime/vllm.py

Runtime haute performance utilisant PagedAttention pour une inférence GPU optimisée.

CaractéristiqueValeur
ProtocoleHTTP REST compatible OpenAI (/v1/completions)
ArchitecturesAMD64, ARM64 (avec GPU CUDA)
Formats modèlesHuggingFace, AWQ, GPTQ
Usage principalInférence GPU (Jetson, NVIDIA)

llama.cpp

Fichier : app/local_runtime/llamacpp.py

Inférence optimisée pour CPU, écrite en C/C++. Idéal pour les modèles quantisés.

CaractéristiqueValeur
ProtocoleHTTP REST (/completion)
ArchitecturesToutes (x86, ARM, Apple Silicon)
Formats modèlesGGUF
Usage principalInférence CPU optimisée

TGI (Text Generation Inference)

Fichier : app/local_runtime/tgi.py

Runtime de Hugging Face pour la génération de texte à grande échelle.

CaractéristiqueValeur
ProtocoleHTTP REST (/generate)
ArchitecturesAMD64, ARM64
Formats modèlesHuggingFace natif
Usage principalInférence distribuée

Contrat commun : LocalRuntimeAdapter

Tous les runtimes implémentent l'interface LocalRuntimeAdapter :

class LocalRuntimeAdapter(ABC):
    async def start(self) -> None:       # Initialise la session HTTP
    async def close(self) -> None:       # Ferme la session
    async def warmup(self) -> None:      # Pré-chauffe le modèle
    async def health(self) -> bool:      # Vérifie la disponibilité
    async def is_available(self) -> bool: # Test de base
    async def generate(
        self,
        prompt: str,
        max_tokens: int,
        n_samples: int,
        temperature: float = 0.7,
    ) -> list[str]:                      # Génère N échantillons
    def status_dict(self, available: bool) -> dict:  # Statut JSON

---

3. Catalogue des 83 modèles locaux (52 activés)

Les modèles sont définis dans local_models.yaml à la racine du projet.

Structure d'un modèle

- model_id: "ollama-llama3.2-3b"
  display_name: "Llama 3.2 3B (Ollama)"
  runtime: "ollama"
  endpoint: "http://aisia_ollama:11434"
  model_name: "llama3.2:3b"
  priority: 100
  enabled: true
  preferred_tasks: ["general", "creative"]
  modalities: ["text"]
  max_context_tokens: 32768
  confidence_threshold: 0.75
  support_tier: "golden"
  validation_status: "validated"
  warmup: false

Attributs des modèles

AttributTypeDescription
model_idstringIdentifiant unique
display_namestringNom d'affichage
runtimestringRuntime utilisé (ollama/vllm/llamacpp/tgi)
endpointstringURL du serveur d'inférence
model_namestringNom du modèle pour le runtime
priorityintPriorité de base (plus élevé = plus prioritaire)
enabledboolModèle activé (surchargeable via DB)
preferred_taskslistTâches préférées (general, coding, creative, reasoning, realtime)
modalitieslistModalités supportées (text, image, audio)
max_context_tokensintTaille maximale du contexte
confidence_thresholdfloatSeuil de confiance spécifique (optionnel)
support_tierstringNiveau de support (golden, silver, catalog)
validation_statusstringStatut de validation (validated, declared, deprecated)
warmupboolPré-chauffe au démarrage

Modèles par défaut

Si local_models.yaml n'existe pas, deux modèles par défaut sont créés :

{
    "model_id": "ollama-primary",
    "runtime": "ollama",
    "model_name": settings.autonomous_primary_model,  # llama3.2:3b
    "priority": 100,
    "preferred_tasks": ["general", "creative"],
},
{
    "model_id": "ollama-fallback",
    "runtime": "ollama",
    "model_name": settings.autonomous_fallback_model,  # llama3.2:1b
    "priority": 90,
    "preferred_tasks": ["reasoning", "coding", "general"],
}

---

4. Calcul de confiance

Principe

Le calcul de confiance détermine si une réponse locale est suffisamment fiable pour être retournée à l'utilisateur sans passer par le cloud.

Formule

if cache_score > 0:
    confidence = 0.7  cache_score + 0.3  consistency_score
else:
    confidence = consistency_score

Deux composantes contribuent à la confiance :

Cache score (poids 70%)

Compare la réponse générée avec les réponses similaires stockées dans Qdrant.

def _cache_score(prompt, response, qdrant_store):
    # 1. Cherche les K réponses les plus similaires dans Qdrant
    results = qdrant_store.search_knowledge(
        query=prompt,
        limit=settings.autonomous_cache_lookup_limit,  # 5
        score_threshold=0.25,
    )
    
    # 2. Encode la réponse candidate
    candidate_vector = qdrant_store.encode(response)
    
    # 3. Encode les réponses cachées
    cached_vectors = [qdrant_store.encode(text) for text in cached_texts]
    
    # 4. Calcule le centroid des réponses cachées
    centroid = np.mean(cached_vectors, axis=0)
    centroid = centroid / np.linalg.norm(centroid)
    
    # 5. Similarité cosinus avec le centroid
    return np.dot(centroid, candidate_vector)

Un cache_score élevé signifie que la réponse est cohérente avec les meilleures réponses précédentes pour des questions similaires.

Consistency score (poids 30% ou 100% si pas de cache)

Mesure la cohérence entre les N échantillons générés par self-consistency.

def _consistency_score(samples, qdrant_store):
    # Si embeddings disponibles : similarité cosinus paire à paire
    # Sinon : similarité lexicale (Jaccard)
    
    for i, first in enumerate(embeddings):
        for second in embeddings[i + 1:]:
            scores.append(np.dot(first, second))
    
    return np.mean(scores)

Un score de cohérence élevé signifie que le modèle produit des réponses consistantes pour la même question (signe de confiance).

Seuil de confiance

SeuilVariableDéfautEffet
GlobalAUTONOMOUS_CONFIDENCE_THRESHOLD0.75Seuil par défaut
Par modèleconfidence_threshold dans YAMLnull (hérite du global)Seuil spécifique
ConfianceInterprétationAction
-----------------------------------
>= 0.75Bonne confianceRéponse locale retournée
0.50 - 0.74Confiance modéréeFallback cloud
< 0.50Faible confianceFallback cloud

Paramètres du cache

VariableDéfautDescription
AUTONOMOUS_CACHE_LOOKUP_LIMIT5Nombre de résultats Qdrant à consulter
AUTONOMOUS_CACHE_SCORE_THRESHOLD0.92Seuil de similarité pour le cache
---

5. Self-consistency sampling

Principe

Pour chaque requête locale, AISIA génère N échantillons (réponses) à partir du même prompt et mesure leur cohérence mutuelle.

Configuration

VariableDéfautDescription
AUTONOMOUS_SELF_CONSISTENCY_SAMPLES3Nombre d'échantillons
AUTONOMOUS_MAX_TOKENS1024Tokens max par échantillon

Processus

1. Le prompt est envoyé N fois au modèle local (temperature > 0 pour variabilité) 2. Le premier échantillon non-vide est sélectionné comme réponse principale 3. La cohérence entre les N échantillons est mesurée : - Avec embeddings Qdrant : similarité cosinus paire à paire - Sans Qdrant : similarité lexicale Jaccard

Similarité lexicale (fallback)

Quand Qdrant/embeddings ne sont pas disponibles :

def _lexical_similarity(first, second):
    first_tokens = set(first.lower().split())
    second_tokens = set(second.lower().split())
    overlap = len(first_tokens & second_tokens)
    union = len(first_tokens | second_tokens)
    return overlap / union  # Jaccard index

---

6. Routage local : sélection des modèles

Algorithme de scoring

Le AutonomousLocalRouter utilise un système de scoring pour classer les modèles candidats :

def _score_model(definition, features):
    # Vérification des modalités
    if not requested_modalities.issubset(supported_modalities):
        return None  # Modèle exclu
    
    score = definition.priority  # Score de base (100 par défaut)
    
    # Bonus tâche préférée
    if task_type in definition.preferred_tasks:
        score += 100
    elif "general" in definition.preferred_tasks:
        score += 25
    
    # Bonus contextuels
    if features.get("has_code") and "coding" in preferred_tasks:
        score += 10
    if features.get("is_creative") and "creative" in preferred_tasks:
        score += 10
    if features.get("is_realtime") and "realtime" in preferred_tasks:
        score += 10
    if features.get("length_bucket") == "long" and max_context >= 32000:
        score += 5
    
    return score

Cascade de modèles

Les modèles sont triés par score décroissant. AISIA essaie chaque modèle dans l'ordre jusqu'à obtenir une réponse suffisamment confiante :

for definition in candidates:
    adapter = self.adapters.get(definition.model_id)
    if adapter is None or not await adapter.health():
        continue
    
    samples = await adapter.generate(prompt, max_tokens, n_samples)
    confidence = self._compute_confidence(samples, ...)
    
    if confidence >= threshold:
        return result  # Réponse locale suffisamment confiante
    
    if best_result is None or confidence > best_result.confidence:
        best_result = result  # Garder la meilleure tentative

Si aucun modèle n'atteint le seuil, la meilleure tentative est retournée (avec confident=False), signalant au routeur principal de basculer vers le cloud.

---

7. Hot-reload à chaud

Endpoint

POST /admin/autonomy/reload
Authorization: Bearer TOKEN_ADMIN

Processus détaillé

async def hot_reload(self):
    # 1. Invalide le cache des providers et modèles locaux
    invalidate_providers_cache()
    
    # 2. Ferme tous les adaptateurs existants (timeout 5s par adaptateur)
    await self.close()
    self.adapters = {}
    
    # 3. Relit local_models.yaml depuis le disque
    raw_models = get_active_local_models()
    
    # 4. Crée les nouvelles définitions
    self.local_models = [
        LocalModelDefinition.from_dict(model)
        for model in raw_models
        if model.get("enabled", True)
    ]
    
    # 5. Initialise les nouveaux adaptateurs
    await self.start()
    
    # 6. Incrémente le compteur de rechargement
    self.reload_count += 1
    self.last_reload_at = datetime.now(UTC)
    
    # Timeout global : 30 secondes

Réponse

{
  "available": true,
  "model_count": 74,
  "available_model_count": 12,
  "runtimes": ["llama.cpp", "ollama", "tgi", "vllm"],
  "reload_count": 3,
  "last_reload_at": "2026-04-19T10:30:00Z",
  "last_route": {
    "ok": true,
    "confident": true,
    "model": "llama3.2:3b",
    "model_id": "ollama-llama3.2-3b",
    "runtime": "ollama",
    "confidence": 0.82,
    "latency_ms": 1200.5,
    "timestamp": "2026-04-19T10:29:30Z"
  },
  "models": [
    {
      "model_id": "ollama-llama3.2-3b",
      "display_name": "Llama 3.2 3B",
      "runtime": "ollama",
      "available": true,
      "last_error": ""
    }
  ]
}

---

8. Ollama edge distribué

Architecture

AISIA déploie 3 replicas Ollama sur des Raspberry Pi 4 du cluster :

Requête utilisateur
       │
       ▼
  AutonomousLocalRouter
       │
  ┌────┴────┐────────┐
  ▼         ▼        ▼
RPi-01    RPi-02   RPi-03
Ollama    Ollama   Ollama
(llama3.2) (llama3.2) (llama3.2)

Déploiement Swarm

Dans stack-poc-global-reuse.yml, le service Ollama est configuré avec :

Répartition de charge

Le routeur local essaie les modèles dans l'ordre de priorité. Chaque adaptateur Ollama pointe vers un endpoint spécifique ou vers le service Swarm (DNS round-robin automatique via le réseau overlay).

Pré-téléchargement des modèles

Les modèles doivent être téléchargés sur chaque noeud Ollama :

# Sur chaque noeud (via SSH ou script de maintenance)
ollama pull llama3.2:3b
ollama pull llama3.2:1b
ollama pull codellama:7b
ollama pull mistral:7b

Le script deploy/pull-models.sh automatise ce processus.

---

9. GPU Jetson Xavier AGX

Spécifications

Modèles GPU

Le noeud Jetson héberge 6 modèles de taille 7B-8B optimisés pour GPU :

ModèleTailleRuntimeUsage
Llama 3.1 8B8BvLLM / OllamaGénéral, raisonnement
CodeLlama 7B7BOllamaCode
Mistral 7B7BOllamaGénéral, multilingue
Llama 3.2 3B3BOllamaRapide, général
Phi-3 Mini3.8BOllamaCompact, raisonnement
Gemma 2B2BOllamaUltra-rapide

Accès SSH

# En LAN
ssh slambert@192.168.1.200

Hors LAN (via jump host)

ssh -J slambert@lambda.freeboxos.fr slambert@192.168.1.200

Configuration Swarm

# Label GPU sur le noeud Jetson
docker node update --label-add aisia.gpu=true nvidia
docker node update --label-add aisia.role=gpu nvidia

Le service aisia_gpu est déployé avec la contrainte :

placement:
  constraints:
    - node.labels.aisia.gpu == true

---

10. Configuration complète

Variables d'environnement

VariableDéfautDescription
AUTONOMOUS_LOCAL_ENABLEDfalseActive le mode local-first
AUTONOMOUS_LOCAL_HOSThttp://localhost:11434URL Ollama
AUTONOMOUS_PRIMARY_MODELllama3.2:3bModèle principal
AUTONOMOUS_FALLBACK_MODELllama3.2:1bModèle de secours
AUTONOMOUS_LOCAL_TIMEOUT_S15Timeout requête locale
AUTONOMOUS_CONFIDENCE_THRESHOLD0.75Seuil de confiance global
AUTONOMOUS_SELF_CONSISTENCY_SAMPLES3Échantillons self-consistency
AUTONOMOUS_MAX_TOKENS1024Tokens max par réponse
AUTONOMOUS_CACHE_LOOKUP_LIMIT5Nombre de résultats cache
AUTONOMOUS_CACHE_SCORE_THRESHOLD0.92Seuil similarité cache
LOCAL_MODELS_YAML./local_models.yamlChemin du catalogue modèles

Fichiers de configuration

FichierDescription
local_models.yamlCatalogue des 83 modèles locaux (52 activés)
providers.yamlRegistre des providers (inclut les locaux)
---

11. Monitoring et diagnostics

Statut des modèles locaux

GET /admin/autonomy/status
Authorization: Bearer TOKEN

Dernière route locale

L'objet last_route dans la réponse de statut montre la dernière décision de routage local :

{
  "ok": true,
  "confident": true,
  "model": "llama3.2:3b",
  "model_id": "ollama-llama3.2-3b",
  "runtime": "ollama",
  "confidence": 0.82,
  "attempted_models": ["ollama-llama3.2-3b"],
  "latency_ms": 1200.5,
  "error": "",
  "timestamp": "2026-04-19T10:30:00Z"
}

Diagnostiquer un modèle indisponible

Si un modèle affiche available: false, vérifiez :

1. Endpoint accessible : curl http://endpoint:port/ 2. Modèle téléchargé : ollama list sur le noeud 3. Espace disque : les modèles GGUF font 2-8 Go 4. Timeout : le modèle peut être trop lent au démarrage

Surcharges DB

Les modèles peuvent être activés/désactivés via l'interface admin. Ces surcharges sont stockées dans aisia_local_model_overrides (MariaDB) et prennent priorité sur local_models.yaml.

---

12. Fallback vers le cloud

Quand le fallback se déclenche

Le fallback cloud est activé quand :

1. Aucun modèle local disponible : tous les modèles sont hors ligne - error: "Aucun modèle local compatible avec la requête"

2. Confiance insuffisante : le meilleur modèle ne dépasse pas le seuil - confident: false, confidence: 0.62 - La réponse locale est retournée avec le flag confident=False - Le routeur principal (main.py) décide de passer au cloud

3. Aucune réponse exploitable : les modèles n'ont rien généré - error: "Aucun modèle local n'a produit de réponse exploitable"

Transparence pour l'utilisateur

Le fallback est transparent : l'utilisateur reçoit une réponse sans savoir si elle provient d'un modèle local ou cloud. L'information est disponible dans les métadonnées de la réponse (provider_id, runtime).

Métriques de fallback

Pour analyser le taux de fallback :

---

Document AISIA v4.21.0