Architecture

RAGatm Open est une application web modulaire : une interface, une API, des workers, une base PostgreSQL avec pgvector, et une passerelle d’inférence qui est le seul chemin vers les modèles locaux.

Le parcours d’une question

Chaque réponse suit le même chemin, observable dans le code publié : import, extraction, découpage, embeddings, recherche hybride, reranking, génération, citations.

Parcours d’une question dans RAGatm OpenSchéma du parcours : de l’import des documents à la réponse citée, avec les modèles locaux appelés par la passerelle.Application (RAGatm Open)Modèles locaux (AI Gateway Open → Ollama / TEI)Parcours d’une question dans RAGatm Open01Utilisateurnavigateur, FR/EN02Espace documentairedroits, isolation, MFA03Importvalidation par signature04Extractiontexte, tableaux, OCR si construit05Découpagefragments ≤ 1 200 caractères06Embeddingsgranite 768 d, via passerelle07Recherche hybrideplein texte + vecteurs, RRF08Rerankingcross-encoder, repli lexical09Générationmodèle local, flux10Réponse citéesources typées, SSE
Alternative textuelle du schéma
  1. Utilisateur — navigateur, FR/EN
  2. Espace documentaire — droits, isolation, MFA
  3. Import — validation par signature
  4. Extraction — texte, tableaux, OCR si construit
  5. Découpage — fragments ≤ 1 200 caractères
  6. Embeddings — granite 768 d, via passerelle (modèle local via la passerelle)
  7. Recherche hybride — plein texte + vecteurs, RRF
  8. Reranking — cross-encoder, repli lexical (modèle local via la passerelle)
  9. Génération — modèle local, flux (modèle local via la passerelle)
  10. Réponse citée — sources typées, SSE
  • Les fichiers sont validés par leur signature binaire, jamais par leur seule extension.
  • Les fragments sont bornés à 1 200 caractères : la passerelle refuse un texte plus long à l’embedding.
  • La recherche combine PostgreSQL (plein texte) et pgvector (cosinus) par fusion RRF, puis un cross-encoder reclasse les 20 meilleurs passages ; si le reranker est indisponible, l’ordre RRF est conservé.
  • La génération est diffusée en flux : NDJSON entre la passerelle et le backend, SSE vers le navigateur, avec des sources typées (document, page ou diapositive, extrait).
  • Quand une dépendance manque, l’API répond une erreur explicite : jamais une réponse fabriquée.

Composants et responsabilités

Trois dépôts, neuf services dans le profil Compact.

Frontend — Next.js 15 / React 19

Interface FR/EN ; proxy même-origine vers l’API (le navigateur ne parle qu’au frontend).

Backend — Django 5.2 + Django REST Framework

API, authentification avec second facteur TOTP obligatoire, rôles par workspace (owner, admin, member, viewer), isolation par espace, ingestion, retrieval, chat SSE, journal d’audit.

Workers — Celery 5.6

Ingestion asynchrone, réindexation, maintenance, analyses ; planificateur beat pour les tâches périodiques.

PostgreSQL 16 + pgvector

Données, vecteurs 768 dimensions (index HNSW), recherche plein texte, identité des pipelines d’embeddings ; source de vérité des sauvegardes.

Redis 7.2

File de tâches, résultats, cache. Jamais une source de vérité.

AI Gateway Open — FastAPI

Unique chemin d’inférence : génération, embeddings, reranking ; registre de modèles strict (digests), erreurs typées, sondes de santé non inférentielles, limites de concurrence.

Ollama

Exécute localement le modèle de génération et le modèle d’embeddings ; joignable uniquement depuis la passerelle.

Text Embeddings Inference (TEI)

Sert le cross-encoder de reranking sur CPU, dans l’espace réseau de la passerelle.

AI Gateway Pool Open — facultatif

Routeur HTTP devant une ou plusieurs passerelles ; aucune inférence ; absent du profil Compact.

Topologie du profil Compact

Une machine, neuf services Docker Compose, cinq réseaux dont quatre internes.

Topologie du profil Compact (9 services)Les neuf services Docker Compose et leurs réseaux internes ; un seul port publié sur la boucle locale ; Ollama joignable uniquement par la passerelle.Hôte Linux — Docker Composedata (interne) · app (interne) · ai (interne)inference (interne)Navigateur → seul port publié : 127.0.0.1:18080frontendNext.jsbackendDjango / APIworkerCelerybeatCelery beatdbPostgreSQL + pgvectorredisRedis 7.2ai-gatewayAI Gateway Openollamagénération, embeddingsrerankerTEI, cross-encoderInternet : uniquement pendant l’approvisionnement des modèles
Alternative textuelle du schéma
  • Le navigateur atteint uniquement le frontend, publié sur 127.0.0.1:18080 (réseau edge).
  • frontend → backend (réseau app) ; backend, worker, beat → db et redis (réseau data).
  • backend et worker → ai-gateway (réseau ai) ; ai-gateway → ollama et reranker (réseau inference). Ollama n’est joignable que par la passerelle.
  • Aucune sortie Internet en fonctionnement nominal ; un réseau temporaire sert uniquement à télécharger les modèles.
  • Un seul port publié, sur la boucle locale (127.0.0.1:18080) : tout autre accès passe par un reverse proxy TLS que vous ajoutez.
  • Les réseaux app, data, ai et inference sont internes : aucune sortie Internet en fonctionnement nominal, vérifiée par un script (offline-check).
  • Les modèles sont téléchargés pendant une phase d’approvisionnement explicite, sur un réseau temporaire supprimé ensuite.
  • Toutes les images applicatives s’exécutent sans privilèges root ; les images de base sont épinglées par digest.
  • Aucune authentification entre services : la confiance repose sur le cloisonnement réseau de l’hôte.
Les 9 services du profil Compact et leurs budgets mémoire par défaut
ServiceTechnologieRôleRéseauxMémoire
frontendNext.js 15 / React 19 (node:22-alpine)Interface web FR/EN ; proxy même-origine vers l’API ; seul port publié (127.0.0.1:18080). — 127.0.0.1:18080edge, app512m
backendDjango 5.2 + DRF (python:3.12-slim)API REST, authentification avec MFA TOTP obligatoire, espaces et droits, ingestion, recherche hybride, génération avec citations (SSE).app, data, ai1536m
workerCelery 5.6Traitements asynchrones : ingestion, réindexation, maintenance, analyses ; concurrence 2.data, ai2g
beatCelery beatPlanificateur des tâches périodiques.data256m
dbPostgreSQL 16 + pgvectorDonnées relationnelles, vecteurs 768 dimensions (HNSW), recherche plein texte ; source de vérité des sauvegardes.data1g
redisRedis 7.2File Celery, résultats et cache ; pas une source de vérité.data256m
ai-gatewayAI Gateway Open — FastAPI (python:3.12-slim)Unique chemin d’inférence : génération (agrégée ou en flux), embeddings, reranking, registre de modèles strict, erreurs typées.ai, inference512m
ollamaOllama 0.30Exécution locale des modèles de génération et d’embeddings ; joignable uniquement par la passerelle.inference5g
rerankerText Embeddings Inference (CPU)Cross-encoder bge-reranker-v2-m3 partageant l’espace réseau de la passerelle (boucle locale).inference (namespace de la passerelle)6g

Mode Direct ou Pool

Le profil Compact appelle directement la passerelle. Le Pool est un composant séparé et facultatif qui relaie le même contrat d’API sans le modifier.

Mode d’inférence
Mode Direct : le backend appelle la passerelleRAGatm Open appelle directement AI Gateway Open pour la génération, les embeddings et le reranking.RAGatm Openbackend · workerHTTP/JSON · NDJSONAI Gateway Opengenerate · embeddings · rerankOllama / TEICPU / GPU
RAGatm Open appelle directement AI Gateway Open pour la génération, les embeddings et le reranking.
Mode Pool : un routeur HTTP devant une ou plusieurs passerellesAI Gateway Pool Open relaie les mêmes routes, choisit un nœud éligible, limite la concurrence et suspend un nœud saturé ; il ne fait aucune inférence.RAGatm Openbackend · workerAI Gateway Pool Openregistre de nœuds · max_inflightdisjoncteur · Retry-After · allowlistAI Gateway Openpasserelle 1Ollama / TEIAI Gateway Openpasserelle 2Ollama / TEIAI Gateway Openpasserelle 3…nOllama / TEInœuds 2…n : implémentés, testés sur nœuds simulés, non qualifiés matériellement
AI Gateway Pool Open relaie les mêmes routes, choisit un nœud éligible, limite la concurrence et suspend un nœud saturé ; il ne fait aucune inférence.
Alternative textuelle

Mode Direct : RAGatm Open (backend et worker) envoie ses requêtes HTTP/JSON à AI Gateway Open, qui appelle Ollama et TEI. Aucun autre composant.

Mode Pool : RAGatm Open envoie les mêmes requêtes à AI Gateway Pool Open, qui les relaie octet pour octet vers une AI Gateway Open éligible (nœud 1 qualifié en parité ; nœuds 2 à n implémentés mais non qualifiés matériellement). Le Pool n’exécute aucun modèle.

Contrat d’erreurs

Quand un composant manque, l’application le dit. Codes renvoyés par l’API RAGatm Open :

Codes d’erreur explicites (API RAGatm Open)
HTTPCodeSignification
503ai_gateway_unavailableLa passerelle est injoignable : aucune réponse fabriquée.
502ai_gateway_errorLa passerelle a répondu une erreur.
503dependency_unavailableUne dépendance (base, cache, modèle) est indisponible.

Montée en charge : ce qui est établi

Le code publié vise d’abord une machine. Voici les limites documentées.

  • Un worker Celery (concurrence 2) : ingestion séquentielle à l’échelle d’un poste.
  • Passerelle : 2 générations, 2 embeddings et 2 rerankings concurrents ; au-delà, réponse 503 avec Retry-After. Ollama sérialise les requêtes (OLLAMA_NUM_PARALLEL=1).
  • Les documents originaux vivent sur un volume local (ADR-001) : répartir le backend sur plusieurs hôtes imposerait un partage réseau ou un stockage objet.
  • Le Pool implémente des politiques multi-nœuds (round-robin pondéré, moins de requêtes en cours) testées sur des nœuds simulés ; la parité mono-nœud est qualifiée.

Profils de déploiement

Un profil testé, deux architectures cibles proposées. Les statuts sont explicites.

Compact

Testé

Une machine, 9 services
modèles locaux sur CPU
8 threads · 14 Go RAM · sans GPU

Qualification fonctionnelle exécutée (RC2). Variantes GPU 8 Go et 12 Go décrites, non qualifiées.

Standard

Proposé

Application et modèles séparés
même contrat gateway-api/1.0
ressources augmentées, GPU dédié possible

Architecture cible proposée par le projet, non décrite dans la documentation Open. Le stockage des originaux reste lié à un hôte (ADR-001).

Distributed

Proposé

Pool devant plusieurs passerelles
nœuds d’inférence répartis
capacité par nœud, disjoncteur

Politiques multi-nœuds implémentées et testées sur nœuds simulés ; multi-nœuds matériel non qualifié.

Alternative textuelle
  • Compact (Testé) — Une machine, 9 services ; modèles locaux sur CPU ; 8 threads · 14 Go RAM · sans GPU. Qualification fonctionnelle exécutée (RC2). Variantes GPU 8 Go et 12 Go décrites, non qualifiées.
  • Standard (Proposé) — Application et modèles séparés ; même contrat gateway-api/1.0 ; ressources augmentées, GPU dédié possible. Architecture cible proposée par le projet, non décrite dans la documentation Open. Le stockage des originaux reste lié à un hôte (ADR-001).
  • Distributed (Proposé) — Pool devant plusieurs passerelles ; nœuds d’inférence répartis ; capacité par nœud, disjoncteur. Politiques multi-nœuds implémentées et testées sur nœuds simulés ; multi-nœuds matériel non qualifié.

Contrat d’API de la passerelle

La passerelle expose 19 routes décrites par un contrat OpenAPI 3.1 (gateway-api/1.0.yaml, version 1.0.0-candidate.2). Le contrat est en statut candidat, non ratifié : il peut encore évoluer avant une version 1.0 finale. Chaque réponse porte un identifiant de requête (X-Request-ID) relayé de bout en bout.

gateway-api/1.0.yaml (lien externe) · Architecture du Pool (lien externe) · Architecture (dépôt) (lien externe)