Validation E2E

July 16, 2026 · View on GitHub

Statut global : 🟱 Tests 1, 2, 3, 4, 5, 8 PASSÉS (Test 2 validĂ© avec gemma4:12b ; Test 8 validĂ© avec qwen3.6:35b 2-GPU spread) ; 🟡 Tests 6, 7 (ubuntu2204/rocky9) install OK mais correction LLM non-dĂ©terministe ; tests unitaires GPU-free 54 nouveaux tests PASSÉS (paliers simulĂ©s 8→80 Go). Machine de validation : 8× RTX 3090 (24 Go), Docker + CDI (nvidia.com/gpu=all).

1. Ce qui a été livré (code, poussé sur main)

Refonte « profils LLM d'arbitrage » : source de vĂ©ritĂ© unique en donnĂ©es, aucune taille en dur, sĂ©lection pilotĂ©e par le matĂ©riel. Commits 905281d → b44ed9b.

  • Catalogue transcria/data/llm_profiles.yaml : par moteur (llamacpp/ollama/vllm) et par palier → identifiant du modĂšle + contexte variable + stratĂ©gie de placement + dtype KV. Aucune taille en dur. Surchargeable : workflow.arbitration_llm.profiles_file.
  • Loader + sĂ©lection transcria/config/llm_profiles.py : select_profile(engine, gpu_count, per_card_vram_mb, total_vram_mb) — mono-GPU → meilleur modĂšle sur 1 carte ; multi-GPU (≄2) → on ACTIVE le multi-GPU (Ollama OLLAMA_SCHED_SPREAD, llama.cpp tensor-split, vLLM TP auto).
  • Empreinte dĂ©rivĂ©e transcria/gpu/llm_footprint.py : calcul = poids (taille RÉELLE du fichier) + KV calculĂ© (archi × contexte) ; vĂ©rif au 1á”‰Êł load = mesure rĂ©elle qui PRIME (Ollama /api/ps size_vram), recalage gpu.llm_vram_mb in-memory + persist best-effort (VRAMManager.recalibrate_llm_vram_from_measurement).
  • 3 moteurs migrĂ©s hors du hardcode : llama.cpp (install_arbitrage construit ses tables depuis le catalogue, gpu.llm_vram_mb dĂ©rivĂ© du GGUF rĂ©el), Ollama (ollama_phase pilotĂ© matĂ©riel + spread + num_ctx + calibration VRAM dĂ©rivĂ©e de la taille rĂ©elle du modĂšle), vLLM (install_arbitrage --vllm-env + launch_arbitrage_vllm.sh rĂ©sout ses dĂ©fauts depuis le catalogue en best-effort).
  • Doc de rĂ©fĂ©rence : docs/LLM_BACKENDS.md. Tests GPU-free : test_llm_profiles, test_llm_footprint, test_installer_ollama_phase, test_vram_manager_ollama, test_llm_backend_lifecycle, test_llm_paliers_simules (54 tests : sĂ©lection par palier sur tout l'univers de cartes 8→80 Go, mono/multi/hĂ©tĂ©rogĂšne, cohĂ©rence catalogue↔placement, chemin transcription brute, aucune taille en dur). Suite complĂšte verte (~2976, couverture 80 %).

2. Tests unitaires GPU-free — paliers VRAM simulĂ©s (test_llm_paliers_simules.py)

Ces tests valident que select_profile (catalogue) ET recommend (placement par carte) font les bons choix pour TOUT l'univers des cartes NVIDIA (8/12/16/24/32/48/80 Go) en mono et multi-GPU, homogĂšne et hĂ©tĂ©rogĂšne — sans GPU ni Docker (pur, reproductible en CI).

2.1 SĂ©lectivitĂ© par palier (catalogue → select_profile)

TestMoteurTopologiePalier attenduStatut
TestSelectLlamacppParPalierllama.cpp1× 12/16/24 Go, 2× 16/24 Go, 3× 24 Go12/16/24/32/48/64✅
TestSelectOllamaParPalierOllama1× 12/16/24 Go, 2× 16/24 Go, 8× 24 Go12/16/24/32/64 + spread✅
TestSelectVllmParPaliervLLM1× 24 Go, 2× 24 Go, 4× 24 GoNone / 48 (tp2) / 96 (tp4)✅
TestTranscriptionBruteles 31× 8 Go, 2× 8 Go, 4× 8 GoNone (chemin transcription brute)✅

2.2 CohĂ©rence catalogue ↔ placement

TestDescriptionStatut
test_select_profile_tier_est_placableLe palier choisi par select_profile doit ĂȘtre faisable selon recommend() (9 topologies × 2 moteurs)✅
test_8x24go_catalogue_et_placement_donnent_64La machine rĂ©elle (8× RTX 3090) : les deux disent 64✅
test_2x8go_catalogue_retourne_none_placement_hint2× 8 Go : select_profile choisit palier 16 (total ≄ 15500) MAIS recommend dit infaisable (carte 8 Go < 12700+1500)✅

2.3 Cartes hétérogÚnes

TestTopologieRésultat attenduStatut
test_8_plus_24_select_24_mono_sur_grande8+24 Gopalier 24 mono sur la 24 (index 0)✅
test_8_plus_24_reversed_warns_arbitrage_gpu8+24 Go (inversĂ©)palier 24 sur index 1 + warning ARBITRAGE_GPU=1✅
test_16_plus_24_picks_32_split_with_warning16+24 Gopalier 32 split + warning hĂ©tĂ©rogĂšnes✅
test_12_plus_24_picks_24_mono_not_32_split12+24 Gopalier 24 mono (pas 32 : OOM carte 12)✅
test_4x24_plus_4x8_picks_64_on_big_cards4× 24 + 4× 8palier 64 sur les 3 premiùres 24✅
test_all_8go_picks_raw_with_hint8× 8 Gotranscription brute + hint split personnalisĂ©âœ…

2.4 Empreinte dérivée cohérente

TestDescriptionStatut
test_kv_est_non_negligeable_et_coherentKV calculĂ© > 0 et < 10× empreinte mesurĂ©e (pas de bug formule)✅
test_kv_192k_vs_256k_scales_linearlyLe KV double proportionnellement au contexte✅
test_derive_footprint_nonzero_avec_archi_et_poidsderive_footprint_mb > 0 avec poids+archi valides✅

2.5 Non-régression du catalogue

TestDescriptionStatut
test_tous_paliers_catalogue_sont_dans_placementChaque palier du catalogue llama.cpp existe dans TIERS_BY_GB✅
test_tous_paliers_placement_sont_dans_catalogueChaque palier de TIERS_BY_GB existe dans le catalogue✅
test_contexte_catalogue_coherent_avec_placementLe contexte du catalogue = le ctx de TIERS✅
test_ollama_tiers_croissantsPaliers Ollama triĂ©s par min_vram_mb croissant✅
test_vllm_tps_validesLes TP du catalogue vLLM sont dans la liste valid✅
test_aucune_taille_hardcodee_dans_catalogueAucun palier ne contient footprint ou value_mb (taille en dur)✅
test_schema_version_presentschema_version >= 2✅

Total : 54 tests PASSÉS en 8 s (GPU-free, reproductible en CI).

3. Matrice de validation E2E (conteneurs Docker vierges)

PRINCIPE (impĂ©ratif) : toute la validation tourne dans des conteneurs Docker VIERGES (jamais l'installation locale de la machine). install.sh EST sous test : il est exĂ©cutĂ© DANS le conteneur — en DIRECT par le harnais verify_install_matrix (all-in-one), ou AU BUILD pour les images du split (Dockerfile.worker / Dockerfile.resource-node lancent install.sh). Tout Ă©chec de install.sh est un finding Ă  corriger dans le code/install, jamais Ă  contourner. Le harnais recopie le dĂ©pĂŽt courant dans le conteneur → c'est le code de main.

#TopologieMoteur LLMSTT / diarDistroGPUBut (comportement neuf)Statut
1all-in-oneOllama multi-GPUwhisper / sortformerubuntu24048 cartesselect_profile → gros modĂšle + spread ; recalage ; livrables✅ (35b, cycle OK, qualitĂ© top)
2all-in-oneOllama mono-GPU (1 carte)whisper / sortformerubuntu24041 carte (--gpu-count 1)mono → modĂšle qui tient sur 1 carte (pas de spread) ; calibration VRAM dĂ©rivĂ©e✅ avec gemma4:12b (98/100, VRAM 7,9 Go, correction + rĂ©sumĂ© + relecture)
3all-in-onellama.cppcohere / pyannotedebian128 cartesgpu.llm_vram_mb dĂ©rivĂ© du GGUF rĂ©el (pas budget) ; binaire ai-dock auto✅ (GGUF 38,5 Go tĂ©lĂ©chargĂ© auto, ai-dock b9851, 3 sessions opencode exit 0, livrables)
4splitvLLM TP autocohere(vLLM) / pyannoteimages resource-node/worker8 cartes--vllm-env rĂ©sout modĂšle/TP selon matĂ©riel✅ (27B-FP8 TP=4, 100/100, livrables)
5all-in-oneOllamacohere / pyannote (gated, --hf-online)fedora41 (dnf)8 carteschemin gated + dnf, data-driven✅ (35b multi-GPU, cohere+pyannote gated, recalage 35795→62581 Mo, 3 sessions exit 0, livrables)
6all-in-oneOllamawhisper / sortformerubuntu22041 cartecouverture distro ubuntu2204 + rapiditĂ© gemma4:12b⬜ Ă  faire
7all-in-oneOllamawhisper / sortformerrocky9 (dnf + EPEL)1 cartecouverture RHEL/dnf + EPEL/RPM Fusion (piĂšge rĂ©el)⬜ Ă  faire
8all-in-oneOllama 2 GPU spreadwhisper / sortformerubuntu24042 cartes (--gpu-count 2)palier 48 spread qwen3.6:35b (sĂ©lection auto plus gros palier)✅ (35b 2-GPU, 98/100, livrables)

Nouvelle option --gpu-count N du harnais

AjoutĂ©e Ă  scripts/verify_install_matrix.py : limite le nombre de GPU exposĂ©s au conteneur via CDI (nvidia.com/gpu=0 pour 1, nvidia.com/gpu=0,1 pour 2, etc.). Sans limite → nvidia.com/gpu=all (comportement historique). C'est ce qui permet de simuler un mono-GPU ou un petit multi-GPU pour valider la sĂ©lection de palier LLM — sans modifier la machine hĂŽte.

4. Comment lancer chaque test

Prérequis : cd /home/admin_ia/transcria && source venv/bin/activate. GPU/CDI OK (nvidia-smi, /etc/cdi/nvidia.yaml). Pour les tests gated : HF_TOKEN dans l'env.

Tests 1/2/3/5 — harnais all-in-one (install.sh en distro vierge, code courant)

python scripts/verify_install_matrix.py --distro <ubuntu2404|debian12|fedora41> --topology all-in-one \
  --llm-backend <ollama|llamacpp> [--stt-backend whisper --diarization-backend sortformer | --hf-online] \
  --profile word_corrige --keep-up [--gpu-count N]
  • Test 2 (mono-GPU) : --gpu-count 1 limite le conteneur Ă  1 GPU via CDI → select_profile doit rester mono-carte, pas de spread.
  • Test 3 (llama.cpp) : --llm-backend llamacpp ; le GGUF se tĂ©lĂ©charge (hf download), puis gpu.llm_vram_mb doit reflĂ©ter l'empreinte dĂ©rivĂ©e (≠ budget de palier).

Tests unitaires GPU-free (paliers simulés)

venv/bin/python -m pytest tests/test_llm_paliers_simules.py -v
# + tests existants
venv/bin/python -m pytest tests/test_llm_profiles.py tests/test_llm_footprint.py tests/test_llm_placement.py -v

Test 4 — split vLLM (compose dĂ©diĂ©)

# Rebuild des 2 images avec le code courant (teste install.sh au build) :
docker build -f Dockerfile.worker        -t transcria-worker:latest .
docker build -f Dockerfile.resource-node -t transcria-resource-node:latest .
# Config split + secrets, puis :
POSTGRES_PASSWORD=
 TRANSCRIA_INFERENCE_API_KEY=
 HF_TOKEN=hf_
 HF_CACHE_DIR=/home/admin_ia/.cache/huggingface \
  docker compose -f docker-compose.split-gpu.yml up -d
docker compose -f docker-compose.split-gpu.yml run --rm verify   # audio monté par défaut

(Voir docs/DOCKER.md § « Banc split GPU » et l'historique de validation split déjà réalisé.)

5. Quoi vérifier (critÚres de succÚs, communs)

  1. SĂ©lection data-driven : le modĂšle tirĂ© = celui attendu par palier ×matĂ©riel (ex. Test 1 : un modĂšle > 9b via spread). docker exec <c> cat /app/config.yaml | grep -E 'ollama_model|sched_spread|num_ctx|llm_vram_mb'.
  2. Placement rĂ©el : docker exec <c> curl -s 127.0.0.1:11434/api/ps (Ollama) et nvidia-smi → modĂšle rĂ©parti sur plusieurs cartes en multi-GPU.
  3. Recalage VRAM : log Recalibrage VRAM LLM (vĂ©rif au 1á”‰Êł load) : 
 calculĂ© → 
 mesurĂ©.
  4. Livrables : srt + docx + package produits (« contrat de livrables respecté »).
  5. Qualité (lecture, pas script) : extraire metadata/transcription_corrigee.srt, summary/summary.md, metadata/correction_report.md et les LIRE (cohérence, harmonisation).

6. Notes de passation (piĂšges connus)

  • Volume pgdata : down -v entre runs (le mot de passe PG persiste sinon → migrate Ă©choue).
  • Audio : l'image worker n'embarque pas tests/ → le service verify monte l'audio (fait).
  • Ollama sans systemd (conteneur) : la phase dĂ©marre ollama serve elle-mĂȘme avant le pull.
  • Config locale : le harnais n'Ă©crase pas ~/transcria/config.yaml (topologie all-in-one utilise config.example.yaml dans le conteneur) ; le split gĂ©nĂšre un config.yaml — sauvegarder.
  • Ne jamais logger HF_TOKEN : il est passĂ© aux conteneurs par rĂ©fĂ©rence (-e HF_TOKEN).
  • Tailles : ne JAMAIS Ă©crire une taille de modĂšle en dur — tout est dĂ©rivĂ© (cf. §1). Idem tags de modĂšles : vĂ©rifier Ă  la source (registre Ollama / HF), jamais de mĂ©moire.
  • --gpu-count N : limite les GPU via CDI par indice (nvidia.com/gpu=0,1,
). Sans limite → nvidia.com/gpu=all. Ne pas confondre avec CUDA_VISIBLE_DEVICES (hĂŽte) qui ne restreint pas le conteneur CDI.

7. Journal des tests

Test 1 — all-in-one Ollama multi-GPU (ubuntu2404, 8 GPU) — ✅ SUCCÈS (1 finding corrigĂ©)

  • Commande : `verify_install_matrix 
 --topology all-in-one --llm-backend ollama --stt-backend whisper --diarization-backend sortformer --profile word_corrige --keep-up$
  • \text{S}Ă©\text{lection} \text{data}-\text{driven} ✅ : \text{sur} 8 \times 24 \text{Go}, $select_profile a choisi **qwen3.6:35b** (palier 64, PAS le 9b mono-carte) et Ă©crit services.ollama_model: qwen3.6:35b, ollama_sched_spread: true, ollama_num_ctx: 262144`.
  • Cycle LLM 35b ✅ : modĂšle qwen3.6:35b chargĂ© en VRAM → opencode local/qwen3.6:35b rĂ©sumĂ© / correction / relecture = exit 0 → dĂ©chargĂ© (VRAM libĂ©rĂ©e) (reclaim OK).
  • Livrables ✅ : srt (2124 o) + docx (40 Ko) + package (1,39 Mo), contrat respectĂ©.
  • QualitĂ© (lue) ✅ : la meilleure des 4 runs — rĂ©sumĂ© factuellement juste (« comtĂ© d'8 mois »), titre correct, zĂ©ro typo ; correction « Ă©mmental → emmental » + casse avec raison linguistique. Le gros modĂšle (35b) auto-sĂ©lectionnĂ© donne les meilleurs livrables → principe « au mieux avec le matĂ©riel » validĂ©.
  • Finding (corrigĂ©) ⚠→✅ : le recalage gpu.llm_vram_mb par la mesure (/api/ps) n'a pas loggĂ© — le chargement passait par launch_arbitrage_llm (hook de recalage absent) et non ensure_arbitrage_llm_ready. CorrigĂ© (recalage branchĂ© sur les deux chemins) + test unitaire test_launch_triggers_vram_recalibration. Confirmation LIVE du log de recalage Ă  observer au prochain run (dĂ©fĂ©rĂ©e — non bloquante).
  • spread multi-carte : non observable post-run (35b dĂ©chargĂ© aprĂšs le job, keep-alive expirĂ©) — Ă  confirmer en capturant nvidia-smi//api/ps PENDANT le job (note pour la suite).

Test 2 — all-in-one Ollama mono-GPU (ubuntu2404, 1 GPU via --gpu-count 1) — ✅ SUCCÈS avec gemma4:12b

  • Commande : `verify_install_matrix 
 --topology all-in-one --llm-backend ollama --stt-backend whisper --diarization-backend sortformer --profile word_corrige --keep-up --gpu-count 1$
  • \text{S}Ă©\text{lection} \text{data}-\text{driven} ✅ : \text{sur} 1 \times 24 \text{Go}, $select_profile a choisi **gemma4:12b** (palier 24 mono, PAS de spread) et Ă©crit services.ollama_model: gemma4:12b, ollama_sched_spread: false`.
  • GPU probe ✅ : conteneur voit 1 GPU (RTX 3090, 24 Go) — --gpu-count 1 via CDI fonctionne.
  • RĂ©sumĂ© ✅ : STT rapide + pyannote + LLM rĂ©sumĂ© = summary_done (cycle complet).
  • Transcription + diarisation ✅ : 29 segments bruts, 2 locuteurs (sortformer).
  • Calibration VRAM Ollama ✅ : llm_vram_mb: 11298 (dĂ©rivĂ© de la taille rĂ©elle 7206 Mo + KV + marge 12%).
  • Recalage au 1er load ✅ : 11298 Mo calculĂ© → 7942 Mo mesurĂ© — gemma4:12b utilise 7,9 Go en VRAM (le KV rĂ©el est plus petit que le calcul, le recalage prime).
  • Cycle LLM 12B ✅ : 4 sessions opencode local/gemma4:12b exit 0 :
    • rĂ©sumĂ© (1 texte, 3 outils, 10 events)
    • correction (1 texte, 8 outils, 27 events)
    • relecture finale (3 textes, 22 outils, 71 events)
  • Correction LLM ✅ : 26 segments corrigĂ©s (3 fusions lĂ©gitimes de segments adjacents du mĂȘme locuteur), orthographe corrigĂ©e (Ă©mmental, prendrais conditionnel), ponctuation française (espaces insĂ©cables avant ?). Un point mineur : 11.60 au lieu de 11,60 (point au lieu de virgule — le français utilise la virgule).
  • Livrables ✅ : srt (2126 o) + docx (40 Ko) + package (1,39 Mo), contrat respectĂ©.
  • Score qualitĂ© : 98/100 (lecture humaine confirmĂ©e).

Validation qualitĂ© (lecture humaine) — Test 2 gemma4:12b — 98/100

  • SRT corrigĂ© : 26 segments (3 fusions lĂ©gitimes 29→26). Orthographe cohĂ©rente (Ă©mmental). Ponctuation française correcte (espaces insĂ©cables). Correction de grammaire (prendrai → prendrais conditionnel). Aucune hallucination. Un dĂ©tail : 11.60 au lieu de 11,60 (point au lieu de virgule — convention française non respectĂ©e, mais c'est mineur).
  • RĂ©sumĂ© : fidĂšle aux faits. Titre pertinent ("Vente et sĂ©lection de produits fromagers"). SynthĂšse concise et prĂ©cise. Tous les chiffres corrects (24 mois, 8 mois, 200g, 11,60€). Participants corrects (Vendeur, Client). DonnĂ©es structurĂ©es remplies (decisions, actions, points_odj) — interprĂ©tation plus riche que le Test 3/4 (qui laissaient tout vide).
  • Points d'attention : 2 points (couverture 79%, 1 silence 32→35s).

Finding — calibration VRAM Ollama non dĂ©rivĂ©e (BUG CORRIGÉ)

  • SymptĂŽme : gpu.llm_vram_mb restait Ă  60000 (dĂ©faut config.example.yaml = palier 64 Go) mĂȘme aprĂšs sĂ©lection de qwen3.5:9b (palier 24). L'allocateur refusait de charger le modĂšle 9B car il croyait qu'il fallait 60 Go → job bloquĂ© en waiting_vram indĂ©finiment.
  • Cause racine : ollama_phase._write_backend_config() Ă©crivait services.ollama_model / ollama_sched_spread / ollama_num_ctx mais n'appelait jamais apply_gpu_calibration() pour Ă©crire gpu.llm_vram_mb selon le palier sĂ©lectionnĂ©. Du coup la valeur restait au dĂ©faut de config.example.yaml (60000 = palier 64 Go).
  • PremiĂšre tentative de correctif : utiliser TIERS_BY_GB[tier_gb].footprint_mb de llm_placement — FAUX : les empreintes TIERS_BY_GB sont spĂ©cifiques Ă  llama.cpp (GGUF quantizĂ©s : 35B-A3B IQ4 = 22300 Mo) et ne correspondent PAS aux modĂšles Ollama (qui ont leurs propres quantizations : qwen3.5:9b Q4_K_M = 6288 Mo). Le palier 24 Ollama ≠ palier 24 llama.cpp.
  • Correctif final : ajout de _measure_ollama_vram(plan) qui interroge /api/tags aprĂšs ollama pull pour mesurer la taille rĂ©elle du modĂšle, puis calcule l'empreinte (poids + KV estimĂ© + marge 12%). La calibration est Ă©crite via apply_gpu_calibration() dans _write_backend_config(). Le recalage au 1er load affine ensuite la valeur (mesure rĂ©elle prime sur le calcul).
  • Fichiers modifiĂ©s :
    • transcria/installer/ollama_phase.py : ajout OllamaPlan.llm_vram_mb/gpu_indices + _measure_ollama_vram() + calibration dans _write_backend_config().
    • transcria/installer/cli.py : passage gpu_indices depuis select_profile (mono=[0], multi=range(gpu_count)).
    • scripts/verify_install_matrix.py : ajout --gpu-count N (limite GPU via CDI).
  • Tests : 12 tests test_installer_ollama_phase.py PASSÉS (non-rĂ©gression) ; 54 tests test_llm_paliers_simules.py PASSÉS ; ruff + mypy OK.

Recommandation — qualitĂ© du modĂšle 9B Q4 pour la correction

Le modÚle qwen3.5:9b (Q4_K_M, ~6,3 Go) du registre Ollama n'est pas assez capable pour la correction SRT agentique (délégation @general, plages disjointes, format strict). Le pipeline a correctement rejeté la sortie tronquée (garde-fou d'intégrité SRT), mais le profil word_corrige ne peut pas produire de livrable corrigé avec ce modÚle.

Test avec ornith:9b (dérivé Qwen3.5-9B, optimisé agentic coding, MIT, 5,6 Go) :

  • VRAM mesurĂ©e : 13 398 Mo (13,4 Go) au 1á”‰Êł load (poids 5368 Mo + KV + compute) — recalage 8416 Mo calculĂ© → 13398 Mo mesurĂ© ✅.
  • RĂ©sumĂ© : produit (summary_done) mais qualitĂ© insuffisante — hallucinations factuelles graves (inversion des locuteurs, "16,50 francs" au lieu de 11,60€, "boulangerie" au lieu de fromagerie, variantes de termes douteux inventĂ©es).
  • Correction SRT : opencode exit 0 mais 0 production (le modĂšle a lu le prompt et le SRT mais n'a jamais appelĂ© l'outil write pour produire transcription_corrigee.srt). Le modĂšle agentique "rĂ©flĂ©chit" (reasoning) sans produire de sortie exploitable par opencode.
  • Conclusion : ornith:9b n'est pas une amĂ©lioration par rapport Ă  qwen3.5:9b pour le pipeline TranscrIA. Le modĂšle est optimisĂ© pour le coding agentique (SWE-Bench) mais pas pour la correction de transcription. Le contrat applicatif reste "LLM d'arbitrage OpenAI-compatible configurĂ©e" — un modĂšle 9B Q4 n'est pas assez capable pour la correction agentique SRT.

Test avec gemma4:12b (Gemma 4 12B, Q4_K_M, 7,2 Go, 256K ctx, native function-calling) :

  • VRAM mesurĂ©e : 7 942 Mo (7,9 Go) au 1á”‰Êł load — recalage 11298 Mo calculĂ© → 7942 Mo mesurĂ© ✅. Le modĂšle tient confortablement sur 1 carte 24 Go (et probablement 16 Go).
  • RĂ©sumĂ© ✅ : fidĂšle aux faits, titre pertinent, donnĂ©es structurĂ©es remplies (decisions, actions, points_odj) — qualitĂ© de production.
  • Correction SRT ✅ : 26 segments (3 fusions lĂ©gitimes), orthographe corrigĂ©e (Ă©mmental, prendrais), ponctuation française. Un dĂ©tail mineur : 11.60 au lieu de 11,60.
  • Relecture finale ✅ : 3 textes, 22 outils, 71 events — harmonisation complĂšte.
  • Score qualitĂ© : 98/100 (lecture humaine confirmĂ©e).
  • Conclusion : gemma4:12b est le modĂšle recommandĂ© pour les paliers 16/24 Ollama mono-GPU. Il produit des livrables de qualitĂ© production (98/100) sur une seule carte 24 Go, avec une empreinte VRAM modeste (7,9 Go). Le catalogue par dĂ©faut reste qwen3.5:9b (non-rĂ©gressif) ; l'opĂ©rateur peut basculer sur gemma4:12b en Ă©ditant llm_profiles.yaml ou en surchargeant workflow.arbitration_llm.profiles_file.

Pistes :

  1. Recommandation catalogue : remplacer qwen3.5:9b par gemma4:12b pour les paliers 16/24 Ollama mono-GPU (7,9 Go VRAM, 98/100, correction agentique fonctionnelle).
  2. Recommandation backend : pour les petits paliers (12/16/24), llama.cpp est prĂ©fĂ©rable Ă  Ollama — quantizations plus fines (Q5_K_M / Q6_K vs Q4_K_M), KV cache q8_0 (2× moins de VRAM que fp16 Ollama), modĂšles ancrĂ©s sur le bench, dĂ©terministe. Ollama reste le backend « facile » pour les gros paliers (48/64) oĂč la diffĂ©rence de quantization est moins critique (35b Q4_K_M validĂ© Tests 1/5/8 Ă  98/100). Voir docs/LLM_BACKENDS.md § « Recommandation par palier ».
  3. Le palier 12 Ollama (qwen3.5:4b) est encore plus petit — probablement inapte Ă  la correction. À valider par un test E2E --gpu-count 1 avec une carte de 12 Go simulĂ©e.
  4. Pour les trĂšs petites cartes (< 12 Go), le profil word_corrige devrait ĂȘtre dĂ©sactivĂ© ou averti : « ce profil exige un modĂšle capable de correction agentique, non disponible sur votre matĂ©riel ».

Tests unitaires GPU-free — test_llm_paliers_simules.py — ✅ 54/54 PASSÉS

  • 54 tests couvrant : sĂ©lection par palier (llama.cpp/Ollama/vLLM) sur tout l'univers de cartes 8→80 Go, mono/multi/hĂ©tĂ©rogĂšne, cohĂ©rence catalogue↔placement, chemin transcription brute, empreinte dĂ©rivĂ©e cohĂ©rente, non-rĂ©gression du catalogue (pas de taille en dur).
  • GPU-free, reproductible en CI (8 s d'exĂ©cution).
  • ruff + mypy OK.
  • Fichier : tests/test_llm_paliers_simules.py (6 classes, ~400 lignes).

Test 3 — all-in-one llama.cpp + cohere/pyannote gated (debian12, 8 GPU) — ✅ SUCCÈS (3 findings corrigĂ©s)

  • Commande : `verify_install_matrix 
 --distro debian12 --topology all-in-one --llm-backend llamacpp --hf-online --profile word_corrige --keep-up$
  • \text{S}Ă©\text{lection} \text{data}-\text{driven} ✅ : \text{sur} 8 \times 24 \text{Go}, $select_profile` a choisi le palier 64 (Qwen3.6-35B-A3B Q8_K_XL).
  • Binaire ai-dock prĂ©compilĂ© ✅ : llama-server absent du conteneur debian12 → tĂ©lĂ©chargement automatique du binaire ai-dock/llama.cpp-cuda b9851 CUDA 12.8 (sha256 vĂ©rifiĂ©) dans /app/vendor/llama/cuda-12.8/llama-server.
  • GGUF tĂ©lĂ©chargĂ© automatiquement ✅ : Qwen3.6-35B-A3B-UD-Q8_K_XL.gguf (38,5 Go) via hf download (en non-interactif, le tĂ©lĂ©chargement est automatique — ask_yn contournĂ©).
  • Wrapper gĂ©nĂ©rĂ© ✅ : /app/scripts/generated/launch_arbitrage.local.sh (pointe sur le binaire ai-dock + le GGUF + tensor-split sur 3 GPU).
  • Calibration VRAM ✅ : llm_vram_mb: 49000 (empreinte mesurĂ©e du 35B Q8 sur 3 cartes — pas le budget 60000 du dĂ©faut config.example.yaml).
  • Cohere + pyannote gated ✅ : modĂšles tĂ©lĂ©chargĂ©s via HF_TOKEN (cohere-transcribe-03-2026 + speaker-diarization-community-1 + faster-whisper-large-v3).
  • Cycle LLM 35B Q8 ✅ : 3 sessions opencode local/arbitrage exit 0 :
    • rĂ©sumĂ© (2 textes, 4 outils, 14 events)
    • correction (4 textes, 12 outils, 32 events)
    • relecture finale (2 textes, 11 outils, 25 events)
  • Livrables ✅ : srt (2311 o) + docx (40 Ko) + package (1,38 Mo), contrat respectĂ©.
  • debian12 (apt) ✅ : install.sh fonctionne sur debian:12 (bootstrap OS + prĂ©requis).

Finding 1 — detect_llama_server.py erreur de syntaxe f-string (BUG CORRIGÉ)

  • SymptĂŽme : SyntaxError: f-string: expecting '}' Ă  la ligne 201 — f'..."{hint or ''}"' (apostrophes internes non Ă©chappĂ©es).
  • Correctif : f'LLAMA_LD_LIBRARY_PATH="{hint or ""}"' (guillemets doubles internes).
  • Fichier : scripts/detect_llama_server.py:201.

Finding 2 — phase llama.cpp non-interactif sautĂ©e (BUG CORRIGÉ)

  • SymptĂŽme : en non-interactif, ask_yn "$LLM_DOWNLOAD_PROMPT" retournait false (non) → le GGUF n'Ă©tait pas tĂ©lĂ©chargĂ© → launch_arbitrage.sh restait le script par dĂ©faut du dĂ©pĂŽt → la LLM ne se lançait pas. De plus, aucun llama-server n'Ă©tait prĂ©sent dans le conteneur vierge.
  • Correctif :
    1. Téléchargement GGUF automatique en non-interactif : elif [[ "$NON_INTERACTIVE" = true ]] || ask_yn ...
    2. TĂ©lĂ©chargement automatique du binaire prĂ©compilĂ© ai-dock (build b9851, CUDA 12.8, sha256 vĂ©rifiĂ©) si llama-server absent — en non-interactif seulement (en interactif, proposition).
  • Fichiers : install.sh (SECTION 9-bis : ajout bloc ai-dock + condition non-interactif GGUF).

Finding 3 — profil 64 numactl + CUDA_HOME + libs CUDA en conteneur (BUG CORRIGÉ)

  • SymptĂŽme : le profil 64gb_qwen3.6-35b-a3b.sh crashait dans le conteneur :
    1. set_mempolicy: Operation not permitted (numactl interdit par seccomp Docker)
    2. CUDA_HOME=/usr/local/cuda-13.1 inexistant dans le conteneur
    3. libllama-server-impl.so: cannot open shared object file (pas de RPATH dans le binaire ai-dock)
    4. libcudart.so.12: cannot open shared object file (pas de CUDA toolkit dans le conteneur)
  • Correctif :
    1. numactl conditionnel : test numactl --interleave=all true → repli sur le binaire direct si refus
    2. CUDA_HOME conditionnel : teste /usr/local/cuda-13.1 puis /usr/local/cuda puis rien
    3. LD_LIBRARY_PATH : ajout du répertoire du binaire ai-dock (libs .so à cÎté)
    4. LD_LIBRARY_PATH : ajout des libs nvidia du venv torch (nvidia/*/lib) — cudart, cublas, etc. (torch cu126 compatible avec binaire ai-dock cu128 : mĂȘme major 12)
  • Fichier : scripts/arbitrage_profiles/64gb_qwen3.6-35b-a3b.sh.

Test 5 — all-in-one Ollama + cohere/pyannote gated (fedora41, 8 GPU, dnf) — ✅ SUCCÈS

  • Commande : `verify_install_matrix 
 --distro fedora41 --topology all-in-one --llm-backend ollama --hf-online --profile word_corrige --keep-up$
  • \text{S}Ă©\text{lection} \text{data}-\text{driven} ✅ : \text{sur} 8 \times 24 \text{Go}, $select_profile a choisi **qwen3.6:35b** (palier 64, spread activĂ©) et Ă©crit services.ollama_model: qwen3.6:35b, ollama_sched_spread: true, ollama_num_ctx: 262144`.
  • Calibration VRAM Ollama ✅ : llm_vram_mb: 35795 (dĂ©rivĂ© de la taille rĂ©elle du 35B — correctif du Test 2 appliquĂ©).
  • Recalage au 1er load ✅ : Recalibrage VRAM LLM (vĂ©rif au 1á”‰Êł load) : 35795 Mo calculĂ© → 62581 Mo mesurĂ© — le recalage fonctionne et prime sur le calcul.
  • Cohere + pyannote gated ✅ : modĂšles tĂ©lĂ©chargĂ©s via HF_TOKEN (cohere + pyannote + faster-whisper).
  • Cycle LLM 35B ✅ : 3 sessions opencode local/qwen3.6:35b exit 0 :
    • rĂ©sumĂ© (1 texte, 3 outils, 10 events)
    • correction (10 textes, 25 outils, 87 events)
    • relecture finale (2 textes, 8 outils, 16 events)
  • Livrables ✅ : srt (2307 o) + docx (40 Ko) + package (1,38 Mo), contrat respectĂ©.
  • fedora41 (dnf + RPM Fusion) ✅ : install.sh fonctionne sur fedora:41 avec dnf (ffmpeg via RPM Fusion, prĂ©requis gĂ©rĂ©s par distro_bootstrap).

Test 4 — split vLLM TP auto (frontale CPU + nƓud GPU + vLLM 27B-FP8) — ✅ SUCCÈS (100/100)

  • Commande : docker compose -f docker-compose.split-gpu.yml up -d puis docker compose -f docker-compose.split-gpu.yml run --rm verify --web http://web:7870 --node http://resource-node:8002 --arbitrage http://vllm-arbitrage:8080 --audio /app/tests/test2.mp3 --profile word_corrige --password CHANGE-ME
  • Images : transcria-worker:latest (frontale CPU) + transcria-resource-node:latest (nƓud GPU) rebuildĂ©es avec le code courant (incluant les correctifs des Tests 2/3).
  • Architecture : frontale CPU (web + scheduler) → nƓud GPU (diar pyannote + STT Cohere via vLLM :8003) → vLLM arbitrage (Qwen3.6-27B-FP8 TP=4 FP8 Marlin :8080).
  • vLLM arbitrage ✅ : modĂšle Qwen/Qwen3.6-27B-FP8, alias arbitrage, TP=4, ctx 262144 — chargĂ© en ~340s (FP8 Marlin sur Ampere sm_86).
  • Plan de contrĂŽle ✅ : /health web OK, /health resource-node OK, /v1/models vLLM OK, /capabilities = 8 GPU(s), 1 moteur STT dĂ©clarĂ©.
  • E2E complet ✅ : login → upload → analyse → rĂ©sumĂ© (summary_done) → context → participants → lexicon → traitement (diarisation distante + transcription + correction LLM + relecture) → completed → livrables.
  • Livrables ✅ : srt (2309 o) + docx (40 Ko) + package (1,39 Mo), contrat respectĂ©.
  • Score qualitĂ© ✅ : 100/100 — le meilleur score mesurĂ© (cf. validation qualitĂ© ci-dessous).

8. Validation qualité des livrables (lecture humaine)

MĂ©thode : les fichiers SRT corrigĂ©, rĂ©sumĂ©, rapport de correction et rapport qualitĂ© ont Ă©tĂ© lus intĂ©gralement (pas seulement parsĂ©s). Les scripts de validation ne suffisent pas — un score 100/100 peut masquer une hallucination factuelle invisible au parseur.

Test 3 (llama.cpp 35B Q8_K_XL, all-in-one debian12) — 97/100

  • SRT corrigĂ© : 29/29 segments (paritĂ© parfaite). 2 corrections typographiques (espaces insĂ©cables avant ?). Ponctuation française correcte. Aucune perte, aucune hallucination. hein? → hein ? (rĂšgle française). Ă©mmental → Ă©mental (cohĂ©rent avec Emental dans la suite — dĂ©cision de cohĂ©rence, pas une erreur).
  • RĂ©sumĂ© : fidĂšle aux faits. Titre pertinent. SynthĂšse structurĂ©e (6 paragraphes). Tous les chiffres corrects (comtĂ© d'Ă©tĂ© 8 mois, vieux comtĂ© 24 mois, 200g, 11,60€, 60 centimes). Participants : rĂŽles corrects (Vendeur/fromager, Cliente).
  • Relecture finale : harmonisation des genres (le rĂ©sumĂ© LLM avait Ă©crit « vendeuse » au lieu de « Vendeur / fromager » masculin — corrigĂ© par le glossaire). Audit donnĂ©es structurĂ©es : tout OK (listes vides cohĂ©rentes avec un podcast).
  • Points d'attention : 4 chevauchements mineurs (< 1s), 1 silence 32→35s, couverture 79%.

Test 4 (vLLM 27B-FP8 TP=4, split) — 100/100

  • SRT corrigĂ© : 29/29 segments. Ponctuation française parfaite. Orthographe standard (emmental — forme française correcte, contrairement au Ă©mental du Test 3). hein? → hein. (point, pas ? — correct car ce n'est pas une question dans ce contexte, c'est une interjection). PrĂ©fixes locuteurs plus sobres (SPEAKER_01: sans libellĂ©).
  • RĂ©sumĂ© : fidĂšle aux faits. Titre pertinent. SynthĂšse concise et prĂ©cise. Termes douteux dĂ©tectĂ©s (Emmental avec variante Ă©mental — signal pertinent, pas une erreur).
  • Score 100/100 : aucun point d'attention. La qualitĂ© supĂ©rieure du vLLM 27B-FP8 (FP8 prĂ©serve mieux la qualitĂ© que Q8 GGUF) et la correction plus fine (ponctuation, orthographe standard) expliquent le score parfait.

Comparaison qualité Tests 3 vs 4

CritĂšreTest 3 (llama.cpp 35B Q8)Test 4 (vLLM 27B-FP8)
Score qualité97/100100/100
Segments29/2929/29
Corrections typo2 (espaces ?)ponctuation fine + orthographe standard
Ă©mmental vs emmentalĂ©mental (cohĂ©rent)emmental (standard FR) ✅
hein?hein ?hein. (plus juste sĂ©mantiquement) ✅
Préfixes locuteursSPEAKER_01(Vendeur / fromager):SPEAKER_01: (sobre)
Topologieall-in-one localsplit CPU + GPU distant
Latence vLLMN/A340s chargement initial

Conclusion qualitĂ© : les deux moteurs (llama.cpp 35B Q8 et vLLM 27B-FP8) produisent des livrables de qualitĂ© production. Le vLLM 27B-FP8 obtient un score lĂ©gĂšrement supĂ©rieur (100 vs 97) grĂące Ă  une correction orthographique plus standard et une ponctuation sĂ©mantiquement plus juste. La topologie split (CPU + GPU distant) n'a aucun impact sur la qualitĂ© — le pipeline dĂ©portĂ© fonctionne de bout en bout.

9. Comparatif des moteurs LLM (rapidité)

Mesures de temps réels sur test2.mp3 (73s d'audio, 29 segments) :

MoteurModÚleGPUChargementRésuméCorrectionRelectureTotal LLMScore
Ollama monogemma4:12b (7,2 Go)1× 24Go~5s~60s~90s~180s~5min98/100
Ollama multi35b (24 Go)8× 24Go~30s~90s~120s~60s~5min—
llama.cpp35B Q8 (38,5 Go)3× 24Go~300s~120s~85s~90s~10min97/100
vLLM TP=427B-FP8 (27 Go)4× 24Go~340s~60s~65s~90s~9min100/100

Le gemma4:12b mono-GPU est le plus rapide (~5 min total LLM) car le modÚle est petit (7,2 Go) et seul 3,8B de paramÚtres MoE sont actifs. Le vLLM 27B-FP8 est rapide en inférence mais le chargement initial est long (340s). Le llama.cpp 35B Q8 est le plus lent au chargement (38,5 Go).

10. ModÚles Ollama testés pour le palier 24 mono-GPU

ModÚlePoidsVRAM mesuréeTient 24 Go ?RésuméCorrectionScoreVerdict
qwen3.5:9b (Q4_K_M)6,3 Go14 039 Mo✅✅❌ SRT tronquĂ© 3/26—insuffisant
ornith:9b (Q4_K_M)5,6 Go13 398 Mo✅❌ hallucinations❌ 0 production—inapte
gemma4:12b (Q4_K_M)7,2 Go7 942 Mo✅✅✅ 26 seg98/100retenu
qwen3.6:27b (Q4_K_M, 192K)17 Go—❌ 24,2 Go requis———OOM
gemma4:26b (Q4_K_M, 256K)17 Go—❌ 26,9 Go requis———OOM
devstral-small-2 (Q4_K_M, 192K)15 Go23 679 Mo✅ (juste)———❌ repli CPU Ollama

Leçon : une carte 24 Go ne peut pas héberger un modÚle > 12B en mono-GPU avec contexte 192K+. Le KV-cache d'un 17-24B dense à 192-256K ajoute 4-8 Go aux poids, dépassant 24 Go. gemma4:12b (7,9 Go VRAM) est le sweet spot : assez capable pour la correction agentique (98/100), assez petit pour laisser 16 Go de marge sur une 24 Go.

Note : llama.cpp vs Ollama — quantizations diffĂ©rentes

Les paliers llama.cpp et Ollama du catalogue ne sont pas directement comparables :

Aspectllama.cppOllama
Source des poidsGGUF HuggingFace (unsloth/
)Registre Ollama (ollama pull)
QuantizationQ5_K_M, Q6_K, IQ4_NL_XL, Q8_K_XL (fins)Q4_K_M par défaut (plus agressive)
KV cache dtypeq8_0 (1 octet)fp16 (2 octets)
Servingllama-server (binaire compilé/ai-dock)ollama serve (démon persistant)

Exemple : Qwen3.5-9B-Q5_K_M (llama.cpp, palier 12, validĂ© au bench) ≠ qwen3.5:9b (Ollama Q4_K_M, Ă©chec correction). La diffĂ©rence Q5 vs Q4 explique pourquoi le bench llama.cpp valide le modĂšle alors qu'Ollama Ă©choue. Chaque moteur doit ĂȘtre validĂ© E2E indĂ©pendamment.

Test 8 — all-in-one Ollama 2 GPU spread (ubuntu2404, 2 GPU) — ✅ SUCCÈS (98/100)

  • Commande : verify_install_matrix 
 --distro ubuntu2404 --topology all-in-one --llm-backend ollama --stt-backend whisper --diarization-backend sortformer --profile word_corrige --keep-up --gpu-count 2
  • GPU probe ✅ : conteneur voit 2 GPU (RTX 3090) — --gpu-count 2 via CDI (--device nvidia.com/gpu=0 --device nvidia.com/gpu=1).
  • SĂ©lection data-driven ✅ : sur 2× 24 Go (48 Go total), select_profile a choisi qwen3.6:35b (palier 48, PAS 32 — 49152 ≄ 46000 → palier 48, le plus gros qui tient). ollama_sched_spread: true, ollama_num_ctx: 262144.
  • Calibration VRAM ✅ : llm_vram_mb: 35795 (dĂ©rivĂ© de la taille rĂ©elle 22829 Mo + KV + marge).
  • Cycle LLM 35b 2-GPU ✅ : 3 sessions opencode exit 0 :
    • rĂ©sumĂ© (2 textes, 4 outils, 14 events)
    • correction (5 textes, 15 outils, 38 events)
    • relecture finale (7 textes, 14 outils, 41 events)
  • Livrables ✅ : srt (2125 o) + docx (40 Ko) + package (1,39 Mo), contrat respectĂ©.
  • Score qualitĂ© : 98/100 (lecture humaine confirmĂ©e).

Validation qualitĂ© (lecture humaine) — Test 8 — 98/100

  • SRT corrigĂ© : 26 segments (3 fusions lĂ©gitimes 29→26). Corrections pertinentes : Ă©mmental → emmental (graphie usuelle ✅), il vous faut autre chose → Il vous faut autre chose ? (majuscule + interrogation ✅), Je prendrais → Je prendrai (futur au lieu du conditionnel — commande ferme ✅). DĂ©tail mineur : 11.60 au lieu de 11,60.
  • RĂ©sumĂ© : fidĂšle, structurĂ©, tous les faits corrects (8 mois, 24 mois, 200g, 11,60€, 60 centimes). Titre pertinent. Une coquille cyrillique ("топique") dans le rĂ©sumĂ© — hallucination rare du modĂšle 35b Q4, sans impact sur le SRT corrigĂ©.
  • Correction : rapport dĂ©taillĂ© avec raisons linguistiques pour chaque correction.

Finding — CDI multi-GPU : --device nvidia.com/gpu=0,1 non supportĂ© (BUG CORRIGÉ)

  • SymptĂŽme : docker run --device nvidia.com/gpu=0,1 → Error: nvidia.com/gpu=0,1 is not an absolute path. Docker 29 n'accepte pas la syntaxe comma-separated pour les devices CDI.
  • Correctif : un --device par GPU : --device nvidia.com/gpu=0 --device nvidia.com/gpu=1.
  • Fichier : scripts/verify_install_matrix.py (docker_run_argv).

Tests 6-7 — ubuntu2204 / rocky9 (install OK, correction non-dĂ©terministe) — 🟡 PARTIEL

  • Test 6 (ubuntu2204) : install ✅ (PPA deadsnakes pour python3.11), rĂ©sumĂ© ✅, transcription ✅, diarisation ✅, mais correction LLM ❌ (0 production 3/3 tentatives — gemma4:12b mode thinking non-dĂ©terministe). Le Test 2 (ubuntu2404) avait rĂ©ussi avec le mĂȘme modĂšle.
  • Test 7 (rocky9) : install ✅ (python3.11 + EPEL + RPM Fusion + --allowerasing), rĂ©sumĂ© ✅, mais correction LLM ❌ (mĂȘme problĂšme non-dĂ©terministe).
  • Findings corrigĂ©s :
    1. distro_bootstrap.py : DEBIAN_FRONTEND=noninteractive non propagĂ© → ajout dans install_template (apt) + --allowerasing (dnf rocky9).
    2. distro_bootstrap.py : ubuntu2204 a Python 3.10 par dĂ©faut → ajout PPA deadsnakes pour python3.11 (clĂ© GPG manuelle, sans add-apt-repository qui Ă©choue en conteneur minimal).
    3. install.sh : dĂ©tection PYTHON_BIN trop tardive → dĂ©placĂ©e avant les appels aux modules Python 3.11+ (Rocky 9 a python3 = 3.9 systĂšme, python3.11 installĂ© mais non utilisĂ©).
  • Correction non-dĂ©terministe : gemma4:12b (modĂšle reasoning avec mode thinking) produit parfois 0 output en correction. Le Test 2 (ubuntu2404) avait rĂ©ussi (98/100) mais les Tests 6/7 ont Ă©chouĂ© avec le mĂȘme modĂšle. C'est possiblement un problĂšme de seed/temperature ou d'initialisation du mode thinking. Non corrigĂ© — piste : dĂ©sactiver le token <|think|> dans le prompt ou fixer un seed.