ninabot Nina Atelier — architecture
Document technique · v0.1 · confidentiel

Architecture Nina Atelier

Document destiné à la partie technique du garage et à toute revue d'ingénierie. Chiffres tirés du benchmark ninjob en production (ROG1, RTX 2080 Ti, i9-9980XE). Rien n'est reproduit à l'aveugle — chaque composant est déjà opéré ailleurs.

01 Vue d'ensemble (C4 Context)

Nina Atelier est un système de recherche assistée par IA ancré sur le corpus documentaire IVECO du garage. Trois populations d'utilisateurs distinctes, un opérateur (ninabot), une source amont (IVECO).

graph LR meca["👨‍🔧 Mécanicien
mobile · borne atelier"]:::user chef["👤 Chef d'atelier
desktop · reporting"]:::user mag["📦 Magasinier
références pièces"]:::user nina[["Nina Atelier
plateforme SaaS ou on-prem"]]:::sys iveco[/"IVECO
portail EASY / RMI"/]:::ext ninabot["⚙️ ninabot Sàrl
opérations"]:::user meca -- "cherche procédure,
scanne VIN" --> nina chef -- "reporting usage,
quality control" --> nina mag -- "cherche références,
alternatives" --> nina iveco -- "procédures, TSB,
schémas (updates)" --> nina ninabot -- "opère, surveille,
met à jour" --> nina classDef user fill:#181D2B,stroke:#2E3648,color:#E6E8EC classDef sys fill:#7C3AED,stroke:#06B6D4,color:#0B0D12,stroke-width:2px classDef ext fill:#232937,stroke:#5B6479,color:#8A93A6
C4 Context — 3 personas garage, 1 source amont (IVECO), 1 opérateur (ninabot).

02 Composants (C4 Container)

À l'intérieur, six containers logiques. Rien d'exotique — la même architecture que ninjob.ch en production depuis 2026-04, adaptée au corpus IVECO et au VIN comme filtre principal.

graph TB subgraph client["📱 Côté client (mécanicien)"] front["Frontend PWA
Next.js · Authentik SSO
installable, cache offline"]:::c end subgraph app["⚙️ Backend applicatif"] api["API Retrieval
FastAPI
orchestration requête"]:::c llm["LLM Router
Kimi K2.6 → Sonnet 4.6"]:::c ing["Ingestion Worker
Celery
Docling · OCR · versionning"]:::c end subgraph data["🗄️ Stockage"] pg[("Postgres
pgvector · pg_bm25
corpus + vecteurs + méta")]:::db blob[("Object storage
MinIO / R2
PDF sources + images")]:::db end subgraph gpu["🎮 GPU"] emb["Embeddings
BGE-M3 multilingue
~3000 vec/s"]:::c rerank["Reranker
bge-reranker-v2-m3
cross-encoder"]:::c end auth[/"Authentik
OIDC · rôles"/]:::ext front --> api front -.->|SSO| auth api --> pg api --> emb api --> rerank api --> llm api --> blob ing --> pg ing --> emb ing --> blob classDef c fill:#181D2B,stroke:#2E3648,color:#E6E8EC classDef db fill:#131722,stroke:#7C3AED,color:#C4B5FD classDef ext fill:#232937,stroke:#5B6479,color:#8A93A6
C4 Container — 6 unités logiques déployables séparément (PWA, API, worker ingestion, DB, blob, GPU).

03 Pipeline ingestion

Un document IVECO arrive (PDF, HTML, XML). Il est identifié par sa clé Print No. + révision. S'il existe déjà en cette révision, on ne fait rien. Sinon, on archive l'ancienne (recherchable en mode « historique »), on découpe la nouvelle, on embed, on indexe.

flowchart LR src[/"Doc IVECO
(PDF · HTML · XML)"/] --> ident{Identifier
Print No. + rev} ident -->|"déjà indexé"| skip["skip"] ident -->|"nouvelle rev"| arch["Archive rev N-1
(historique)"] arch --> layout["Layout parsing
Docling · figures/tables/callouts"] layout --> ocr["OCR blocs schémas
Tesseract fallback"] ocr --> chunk["Chunking sémantique
par section IVECO"] chunk --> meta["Enrichissement méta
modèle · MY · moteur · DTC · groupe"] meta --> emb["Embeddings BGE-M3
multilingue"] emb --> pg[("pgvector
+ méta")] layout --> blob[("Blob
PDF + images extraites")] meta --> bm25[("BM25 tsvector")] classDef proc fill:#181D2B,stroke:#2E3648,color:#E6E8EC classDef db fill:#131722,stroke:#7C3AED,color:#C4B5FD
Pipeline ingestion — dédup par Print+rev, archivage sans perte, chunking sémantique.
Choix clé — la dédup se fait sur le Print No., pas sur le hash de contenu
Un hash de contenu classerait mal les révisions mineures constructeur. On indexe l'entier des révisions successives, seule la dernière est active dans l'index de production, les précédentes restent interrogeables avec un flag historical=true. Utile pour « quel couple était donné avant la révision 07/2024 ? ».

04 Pipeline requête

Une requête utilisateur transporte trois choses : la question en langage naturel, le VIN scanné (optionnel mais très structurant), et un filtre facultatif (groupe fonctionnel, langue).

sequenceDiagram autonumber participant M as Mécanicien (PWA) participant A as API Retrieval participant D as VIN Decoder participant E as Embeddings GPU participant P as pgvector + BM25 participant R as Reranker GPU participant L as LLM Router M->>A: query + VIN + filtres A->>D: décoder VIN D-->>A: modèle · MY · moteur · options A->>E: embed query E-->>A: vecteur dense (1024) A->>P: hybrid search (dense + BM25)
filtré par sous-corpus VIN P-->>A: top-12 chunks A->>R: cross-encoder rerank R-->>A: top-5 chunks A->>L: prompt + top-5 + citations obligatoires L-->>A: JSON strict (réponse + [refs]) A-->>M: réponse structurée
docs · procédure · schémas · synthèse
Pipeline requête — hybride dense/sparse, rerank, LLM avec citations JSON strictes.

Détail du filtre VIN

Le VIN IVECO Daily décodé (positions 4-8) donne modèle et MY, position 10 le moteur. Un cache local — dérivé du VDS/VIS constructeur — évite un aller-retour réseau. Le VIN restreint typiquement le corpus de ~4 800 documents à ~250-400 documents applicables, soit un facteur 12× à 19× de gain de recall.

Ce que ce pipeline garantit
  • Aucune réponse LLM sans [refs] dans le JSON — si le modèle n'en fournit pas, on rejoue le prompt avec instruction plus stricte (max 2 tentatives, puis erreur explicite).
  • Un mécanicien peut cliquer sur une citation et ouvrir le PDF original à la bonne page, avec le passage surligné.
  • Les métriques (chunks retrieved, top-k reranking, latences) sont exposées à l'utilisateur — pas une boîte noire.

05 Modèle sécurité & légal

Auth & RBAC

SSO Authentik (OIDC), même stack que ninjob et payeh. Trois rôles : mécanicien (recherche), chef d'atelier (+ reporting), magasinier (+ références pièces). WebAuthn optionnel.

Confidentialité corpus

Le corpus IVECO reste propriété du garage sous licence R2R. ninabot agit comme sous-traitant technique (DPA). Option on-prem : le corpus ne sort jamais de l'atelier.

Traçabilité

Chaque requête est loggée avec : user, VIN, query, docs cités, réponse LLM. Rétention 90 j par défaut, ajustable. Facilite les audits qualité et la défense en cas de litige.

Point à valider avant démarrage
La licence R2R (Right to Repair, UE 2018/858) que le garage a avec IVECO autorise l'accès au contenu technique pour les besoins de réparation. La clause « no redistribution / no derivative works » est standard : elle n'empêche pas l'indexation interne pour l'usage des mécaniciens du garage. Nous demandons une copie du contrat en pré-cadrage — c'est un point que Sébastien peut aider à clarifier côté IVECO.

06 Options hébergement

OptionOù tourne-t-il ?AvantagesContraintes
On-prem (recommandé) Bundle matos au garage : mini-PC Intel + GPU RTX 4060 Ti 16 Go. Rien ne sort de l'atelier, latence <100 ms sur LAN, fonctionne même si internet tombe. Payback bundle en 4-14 mois vs Cloud. Bundle 9 800 CHF one-shot (install site + 24 mois garantie matos incluse). Maintenance à distance ninabot via VPN Tailscale/WireGuard.
Full Cloud Tenant isolé sur infra ninabot (ROG1 ou serveur dédié). Zéro matos client, ninabot opère tout, mises à jour transparentes. Idéal pilote ou <3 mécanos. Dépendance internet garage. Latence 20-40 ms. Corpus + extraits sortent du garage (couvert par DPA).
Hybride Cache offline PWA + backend cloud. Compromis : dernières procédures consultées disponibles hors ligne, reste online. Cache offline limité (200 dernières procédures par utilisateur).

Choix du LLM de synthèse — dimension orthogonale

L'hébergement ci-dessus concerne le retrieval. Le LLM de synthèse est un choix distinct : la même infra peut faire tourner l'un ou l'autre. La démo en ligne montre la bascule en direct via le toggle Cloud / On-prem.

ModeModèleQualité (indicatif)LatenceCoûtConfidentialité
Cloud Kimi K2.6 (Moonshot) → Sonnet 4.6 API tiers Excellente (1T param MoE) ~800 ms ~40 CHF/mécano/mois Extraits doc envoyés au provider en zero-retention.
On-prem Qwen 2.5 32B Q4 · fallback Phi-4 14B Q4 (Ollama) GPU garage Très bonne (32B suffit largement au use case) 1-2 s 0 variable · bundle matos 9 800 CHF one-shot Rien ne sort de l'atelier.
Position par défaut · On-prem
Le use case (procédures FR/EN/IT bornées au corpus, réponses courtes structurées, prompt déjà ancré sur extraits retriever-filtrés) est largement à la portée d'un Qwen 32B Q4. Kimi K2.6 apporte un mieux marginal, pas décisif.

Économiquement : abo On-prem 99 CHF/mécano/mois vs Full Cloud 329 CHF — diff 230 CHF/mécano/mois amortit le bundle matos (9 800 CHF) en 4-14 mois selon la taille de l'atelier (3 à 10 mécanos). Cloud pertinent surtout en pilote ou pour les ateliers <3 mécanos.

07 Estimation ressources

ComposantRessource cibleCharge attendue
API Retrieval 2 vCPU · 4 Go RAM ~100 req/min à 10 mécaniciens actifs (peak 400 req/min).
Postgres pgvector + BM25 4 vCPU · 16 Go RAM · 200 Go SSD Corpus 5 000 docs = ~250 000 chunks = 1 Go vecteurs + 40 Go blob.
GPU (embeddings + rerank) RTX 4060 Ti 16 Go (min) — RTX 4090 24 Go (idéal) BGE-M3 fits 8 Go. Reranker cross-encoder fits 4 Go. VRAM tête bas.
Object storage 100 Go — MinIO on-prem ou Cloudflare R2 PDF sources originaux + images extraites indexées.
LLM synthèse — Cloud Kimi K2.6 (Moonshot) · fallback Sonnet 4.6 ~2 000 tokens/req · budget mensuel ~40 CHF/mécanicien actif. Zero-retention configuré. Extraits doc envoyés au provider.
LLM synthèse — On-prem Qwen 2.5 32B Q4 (Ollama) · fallback Phi-4 14B Q4 Tourne sur GPU garage. RTX 4060 Ti 16 Go tient Qwen 32B Q4 en 1-2 s/req. Coût variable nul. Rien ne sort de l'atelier.
Ingestion worker 2 vCPU · 4 Go RAM · GPU partagé 1 doc IVECO moyen (PDF 50 p.) = ~90 s ingestion full pipeline.

08 Stack et versions

Le tableau qui compte pour la revue technique — versions réelles utilisées.

CoucheTechnologieVersionOrigine / statut
OS hostUbuntu Server24.04 LTSProd ninjob ROG1
Runtime containerDocker + Composev5Prod ninjob
BasePostgres pgvectorpg16 · pgvector 0.7Prod ninjob-db
Ingestion parsingDocling≥ 2.xOpen source IBM
Ingestion PDFPyMuPDF1.24+Standard
OCR fallbackTesseract5.xStandard
EmbeddingsBGE-M3v1.5BAAI · MIT license · multilingue
Rerankerbge-reranker-v2-m3v2BAAI · MIT license
LLM cloud primaryKimi K2.6 (Moonshot)APIProd ninjob depuis 2026-04
LLM cloud fallbackClaude Sonnet 4.6APIPII overflow ninjob
LLM on-prem primaryQwen 2.5 32B Q4 · Ollamavia Ollama 0.3+Prod ninjob PII tier (ROG1)
LLM on-prem fallbackPhi-4 14B Q4 · Ollamavia Ollama 0.3+Prod ninjob PII tier (ROG1)
BackendFastAPI · Celery · Redis0.115 · 5.4 · 7Prod ninjob-backend
FrontendNext.js PWA15.xProd ninjob-frontend
AuthAuthentik OIDC2026.xProd ninabot (identity.ninabot.ch)
ObservabilitéPrometheus + Grafana + Loki2.55 · 11.3 · 3.2Prod ninabot (grafana.ninabot.ch)
Pourquoi c'est reproductible
Aucune ligne du tableau ci-dessus n'est nouvelle chez ninabot — chaque composant tourne déjà en production sur ninjob.ch, avec observabilité complète (Grafana + Prometheus + Loki) et un runbook. Nina Atelier est essentiellement ninjob avec un corpus différent et un filtre VIN devant le retriever. Le risque projet est donc principalement documentaire (licence R2R, format d'ingestion des sources), pas d'ingénierie.
Voir la démo interactive One-pager commercial Retour accueil