Regroupe le WIP non committé requis pour le clone/runtime DGX (Option A) : - api_stream.py : préflight replay + smoke santé modèles + handler 403 WP-B - de-hardcode VLM : vlm_config, gpu/*, vram_orchestrator, ollama_manager - stream_processor, semantic_matcher, agent_chat (app/planner/intent) - workflows.db (acquis ; le transfert artifacts le mettra à jour + rewrite chemins) - docs : plans DGX, benchmarks VLM/grounders, recherche SOTA, coordination 8 juin Snapshot destiné à la branche poc-dgx poussée sur Gitea pour cloner le DGX. Scan anti-secret : clean. graphify (repo embarqué) exclu. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
11 KiB
Benchmark grounders GUI SOTA via vLLM sur DGX Spark
Date : 2026-06-08
Infra : NVIDIA DGX Spark (GB10, aarch64, sm_121, 121 Go mémoire unifiée), aivanov@192.168.1.45
Moteur : vLLM vllm/vllm-openai:cu130-nightly (image arm64 déjà pullée, ID ffa30d66ff5c), API OpenAI-compatible
Modèles évalués : InfiGUI-G1-7B, Holo1.5-7B, Qwen3-VL-4B-Instruct (un seul servi à la fois, container recréé)
Harness : identique aux benchs gemma4/qwen2.5vl du 2026-06-08 — mêmes 16 cas LeaBench (benchmarks/computer_use/cases/leabench_extended_2026-05-24.jsonl), mêmes images, même scoreur (core.evaluation.computer_use_bench). Scripts jetables dans /tmp/vlm_bench/. Aucun code de production modifié, Ollama (:11434) non touché.
Résumé exécutif (verdict tranché)
- vLLM démarre proprement sur le DGX Spark (ARM64/Blackwell) pour les 3 modèles. Pas de blocage flash-attn : vLLM sélectionne
FLASH_ATTN v2et il fonctionne. Aucun flag exotique nécessaire — le seul piège réel a été la mémoire (voir §Montage).--enforce-eagernon nécessaire. - Gagnant net : Qwen3-VL-4B-Instruct. Avec garde-fou de présence : accuracy 0,875 (14/16), 1 seul clic dangereux, ~1,1 s/cas, cible démo « Enregistrer » 2/2. Meilleur que tous les gemma4 et que les deux grounders spécialisés, pour seulement 4B. Confirme le pari du leaderboard llm-stats sur écrans FR réels.
- Les grounders « spécialisés » (Holo1.5, InfiGUI-G1) sont d'excellents localisateurs mais de mauvais décideurs seuls. En sortie brute (raw, toujours-clic) ils visent juste sur les vraies cibles mais cliquent partout sur les écrans pièges → 9 à 12 clics dangereux. Leur sécurité dépend entièrement d'un gate externe.
- Reste-t-il sûr ? Non en standalone. Aucun modèle n'atteint 0 clic dangereux + haute accuracy seul. La cascade de validation existante (OCR/template + vérif état UI avant/après clic) reste obligatoire AU-DESSUS du grounder. Le grounder propose, la cascade vérifie.
- Moteur recommandé : vLLM
cu130-nightly,--gpu-memory-utilization 0.40(Ollama occupe ~42 Go de la mémoire unifiée). Vision native préservée (safetensors HF, pas de GGUF/mmproj) — exactement ce qu'il fallait après l'échec UI-TARS/Ollama.
Tableau comparatif (LeaBench 16 cas — même harness, comparaison directe)
Protocole « gated » = grounding natif + une passe de présence (yes/no) donnant au grounder pur une chance d'abstenir équitablement (identique au protocole du bench UI-TARS). « raw » = localisateur pur, toujours-clic si parsable (expose le comportement brut et les clics dangereux sans garde-fou).
| Modèle | Variante | Accuracy | Correct/16 | Clics dangereux | Cible démo « Enregistrer » | Latence/cas | Parsable | Licence |
|---|---|---|---|---|---|---|---|---|
| Qwen3-VL-4B-Instruct | gated | 0,875 | 14/16 | 1 | 2/2 ✅ | ~1,1 s | 14/16 | Apache-2.0 |
| Qwen3-VL-4B-Instruct | raw | 0,4375 | 7/16 | 9 | 2/2 ✅ | ~1,0 s | 14/16 | Apache-2.0 |
| Holo1.5-7B | gated | 0,5625 | 9/16 | 4 | 0/2 (gate trop strict) | ~3,2 s | 16/16 | Apache-2.0 |
| Holo1.5-7B | raw | 0,25 | 4/16 | 12 | 2/2 ✅ (localisation) | ~3,0 s | 16/16 | Apache-2.0 |
| InfiGUI-G1-7B | gated | 0,50 | 8/16 | 7 | 2/2 ✅ | ~14,6 s | 16/16 | Apache-2.0 |
| InfiGUI-G1-7B | raw | 0,3125 | 5/16 | 11 | 2/2 ✅ (localisation) | ~14,3 s | 16/16 | Apache-2.0 |
| — référence Ollama — | ||||||||
| gemma4:31b | — | 0,75 | 12/16 | 1 | (cf. rapport 31b) | (plus lent) | — | — |
| gemma4:26b | — | 0,6875 | 11/16 | 0 | 1/2 | (mesuré 06-08) | — | — |
| qwen2.5vl:7b-rpa | — | 0,5625 | 9/16 | 6 | (cf. rapport qwen) | (rapide) | — | — |
| qwen3vl:8b (Ollama) | — | 0,3125 | 5/16 | 0 | — | — | — | — |
| UI-TARS-1.5-7B (Ollama) | — | N/A (aveugle, import sans mmproj) | 0/16 | N/A | échec HTTP 500 | — | — | — |
Chiffres gemma4/qwen re-vérifiés via le scoreur sur les prédictions existantes (
gemma4:26b0,6875/0 dangereux ;gemma4:31b0,75/1 ;qwen2.5vl:7b-rpa0,5625/6 ;qwen3vl:8b0,3125/0). Latences vLLM = moyenne mesurée sur les 2 appels (grounding + présence) des 16 cas.
Montage vLLM (statut OK + flags utilisés)
Commande de référence (identique pour les 3 modèles, seul --model change) :
docker run -d --name vllm-grounder --device nvidia.com/gpu=all \
-p 8000:8000 -v ~/.cache/huggingface:/root/.cache/huggingface --ipc=host \
vllm/vllm-openai:cu130-nightly \
--model <repo> --port 8000 \
--gpu-memory-utilization 0.40 --max-num-seqs 4 --max-model-len 8192 \
--trust-remote-code
| Modèle | Repo HF | Démarrage | Détails |
|---|---|---|---|
| InfiGUI-G1-7B | InfiX-ai/InfiGUI-G1-7B |
OK | archi Qwen2_5_VLForConditionalGeneration, KV cache 496k tokens, init ~60 s |
| Holo1.5-7B | Hcompany/Holo1.5-7B |
OK | base Qwen2.5-VL, non-gated, download ~16 Go |
| Qwen3-VL-4B-Instruct | Qwen/Qwen3-VL-4B-Instruct |
OK | archi Qwen3VLForConditionalGeneration, KV cache 253k tokens, init ~63 s |
Pièges rencontrés et résolution :
- Mémoire (le vrai blocage, pas l'ARM). Avec
--gpu-memory-utilization 0.85(recommandation blog vLLM Spark) :ValueError: Free memory on device cuda:0 (79.65/121.63 GiB) ... less than desired (103.38 GiB). Ollama + autres process occupent ~42 Go de mémoire unifiée. Résolu en passant à 0.40 (un 7B + KV cache tient largement dans ~48 Go ; concurrence max 60×). - flash-attn : aucun problème. Contrairement à la crainte du doc recherche, vLLM cu130-nightly utilise
FLASH_ATTN v2sans crash sur sm_121.--enforce-eagernon nécessaire. - CUDA 13 / sm_121 : l'image
cu130-nightlygère nativement, aucune erreurlibcudart.so.12. - Aucun modèle gated, aucun token HF requis (warning rate-limit bénin).
Sanity vision confirmé pour chaque modèle (/v1/chat/completions, image base64 data-URI, HTTP 200, sortie non vide et au bon format coordonnées).
Format natif par modèle (le piège « prompt unifié » évité)
Chaque modèle a un format distinct — adapté individuellement, résolu empiriquement quand la doc était ambiguë.
- InfiGUI-G1-7B (model card HF) : système
<think></think>; userThe screen's resolution is {W}x{H}. Locate the UI element(s) for "{instr}", output ... [{"point_2d":[x,y]}]. Sortie = pixels de l'image envoyée + un bloc<think>de raisonnement (d'où sa latence ~10 s).x_frac = x/W. - Holo1.5-7B (hai-cookbook H Company) :
Localize an element on the GUI image according to the provided target and output a click position.+ cible. Sortie demandée en JSON{"action":"click_absolute","x","y}= pixels de l'image envoyée.x_frac = x/W. Pas de raisonnement → très rapide. - Qwen3-VL-4B : format de coordonnées ambigu dans la doc (issues QwenLM #1486/#1927 : pixels vs 0-1000). Résolu par sanity call : sur image 800×500, sortie
{"point_2d":[458,605]}→ en pixels y=605 impossible (>500) ; en 0-1000 normalisé → (0,458 ; 0,605) ≈ cible connue (0,448 ; 0,612). Donc coordonnées 0-1000,x_frac = x/1000. C'est exactement le piège à ne pas rater : un parsing pixel aurait donné des clics hors écran silencieux.
Particularité Qwen3-VL : il refuse nativement sur cible absente (« There are none. », 2/16 non parsables = vraies abstentions du grounder lui-même), ce que ni Holo ni InfiGUI ne font.
Licences (vérifiées)
| Modèle | Licence | Source |
|---|---|---|
| InfiGUI-G1-7B | Apache-2.0 | model card HF InfiX-ai/InfiGUI-G1-7B |
| Holo1.5-7B | Apache-2.0 | model card HF Hcompany/Holo1.5-7B (« License: apache-2.0 ») — note : le doc recherche le disait « open-weight », il est en réalité Apache-2.0, donc plus permissif qu'attendu |
| Qwen3-VL-4B-Instruct | Apache-2.0 | repo Qwen/Qwen3-VL-4B-Instruct |
Les 3 candidats sont Apache-2.0 → déployables en clinique sans friction licence. Bonne nouvelle : le fallback comme le gagnant sont tous deux permissifs.
Verdict tranché
Grounder recommandé : Qwen3-VL-4B-Instruct, servi par vLLM (cu130-nightly, --gpu-memory-utilization 0.40).
Justification chiffrée :
- Accuracy la plus haute du panel (0,875), 1 seul clic dangereux, devant gemma4:31b (0,75/1) et gemma4:26b (0,6875/0).
- Cible démo « Enregistrer » : 2/2 (les deux cas save-as), là où gemma4:26b n'en réussit qu'1/2. Coordonnées (0,458;0,605) et (0,428;0,573) bien dans le rayon.
- Le plus léger (4B) ET le plus rapide (~1 s/cas) → meilleur ratio précision/VRAM/latence, idéal multi-postes Léa via l'API vLLM.
- Apache-2.0, vision native (pas de GGUF), abstention partiellement native.
Holo1.5-7B = fallback / challenger. Localisateur brut excellent (vise juste sur les vraies cibles, 2/2 sur la démo en raw) et très rapide (3 s, pas de CoT), mais son jugement de présence séparé est trop strict (gate refuse 2 vraies cibles) → 0,5625 gated. À reconsidérer si on remplace la passe présence par la cascade interne du projet.
InfiGUI-G1-7B = écarté pour ce besoin. Bonne localisation mais le mode <think> impose ~14 s/cas (rédhibitoire temps-réel) et son gate de présence est faible (7 clics dangereux). Pas d'avantage face à Qwen3-VL-4B.
UI-TARS-1.5 : non rebenché (import Ollama cassé sans mmproj, cf. rapport dédié du 06-08). Le doc recherche le classait déjà dernier des spécialisés — confirmé non prioritaire.
Sécurité de clic (santé) — reste-t-il sûr ?
Non en standalone. Même le gagnant produit 1 clic dangereux/16 et dépend d'une passe de présence externe pour ne pas en produire 9 (cf. variante raw). Conserver impérativement la cascade de validation existante au-dessus du grounder (OCR/template + vérification état UI avant/après clic, garde-fou « ne clique pas si pas sûr à 100 % »). Le grounder VLM propose une coordonnée ; la cascade tranche. Choisir vLLM (vision fiable) plutôt qu'Ollama renforce ce contrat.
Reco moteur
vLLM vllm/vllm-openai:cu130-nightly sur le DGX Spark, épinglé au digest (pas le tag nightly mouvant), --gpu-memory-utilization 0.40 tant qu'Ollama cohabite. API OpenAI-compatible → un serveur central sert N postes Léa. Plan B x86 RTX 5070 inutile ici : la stack ARM a tenu sans contournement lourd.
Limites & honnêteté méthodo
- 16 cas seulement (notepad/save-as/menu Démarrer Windows FR), pas Easily Assure dense haute résolution. Les scores sont indicatifs, pas un verdict ScreenSpot-Pro. Re-bencher sur écrans Easily réels avant décision finale POC.
- Le protocole « gated » mélange grounding natif + une passe présence maison ; il avantage les modèles dont le jugement de présence est calibré (Qwen3-VL) et pénalise les localisateurs purs (Holo). En production, la passe présence sera remplacée par la cascade interne du projet → les chiffres « raw localisation » sont alors plus représentatifs de ce que le grounder apporte vraiment (et là Holo/Qwen3-VL/InfiGUI visent tous juste sur les vraies cibles).
- Latences = mémoire unifiée LPDDR5X du Spark, mono-requête. Le débit multi-postes réel reste à mesurer.
- Aucun secret/token/identité patient dans ce rapport. Container vLLM supprimé en fin de run (
docker rm -f vllm-grounder), Ollama vérifié intact (HTTP 200).