From 5b2afa362922bd50e77721676de9777157e5f694 Mon Sep 17 00:00:00 2001 From: Dom Date: Fri, 5 Jun 2026 12:06:10 +0200 Subject: [PATCH] fix(p1w): make default VLM model DGX-safe (qwen2.5vl:7b-rpa) Sans env RPA_VLM_MODEL/VLM_MODEL, get_vlm_model() tombait sur le default gemma4:latest, qui peut etre absent du tunnel DGX (depull) -> 404 Ollama et echec de tout le pipeline VLM avant un test Lea humain. - core/detection/vlm_config.py : DEFAULT_VLM_MODEL gemma4:latest -> qwen2.5vl:7b-rpa (confirme present DGX, deja default reasoning + fallback bbox grounding). + DGX_SAFE_VLM_MODELS allow-list documentee. - tests/unit/test_vlm_default_dgx_safe.py : 5 tests (default != gemma4:latest, default in allow-list, no-env -> DGX-safe, env garde priorite). Logique de resolution inchangee, pas d'appel reseau a l'import. gemma4:latest reste accessible via env explicite. Co-Authored-By: Claude Opus 4.8 (1M context) --- core/detection/vlm_config.py | 20 +++++--- tests/unit/test_vlm_default_dgx_safe.py | 61 +++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 7 deletions(-) create mode 100644 tests/unit/test_vlm_default_dgx_safe.py diff --git a/core/detection/vlm_config.py b/core/detection/vlm_config.py index acd75bc43..32958535c 100644 --- a/core/detection/vlm_config.py +++ b/core/detection/vlm_config.py @@ -23,13 +23,19 @@ import requests logger = logging.getLogger(__name__) -# Modèle VLM par défaut — Gemma 4 latest (8B dense, Q4_K_M) -# Nécessite think=false dans le payload (sinon tokens vides sur Ollama >=0.20) -# Bench 2026-05-16 : tentatives qwen2.5vl:7b et :3b écartées (runtime Ollama -# avec context = 10-13 GB → débordent toutes en 100% CPU sur RTX 5070 12 GB). -# qwen3-vl:8b écarté : think:false ignoré → tout en thinking field, pas de réponse. -# gemma4:latest reste le seul stable malgré son cold start ~20s (1 fois par run). -DEFAULT_VLM_MODEL = "gemma4:latest" +# Modèle VLM par défaut — DGX-safe (P1.w, 2026-06-05). +# Historiquement `gemma4:latest`, mais ce modèle peut être absent du tunnel DGX +# (dépull) : sans env `RPA_VLM_MODEL`/`VLM_MODEL`, le fallback tombait alors en +# 404 Ollama et tout le pipeline VLM échouait avant un test Lea humain. +# `qwen2.5vl:7b-rpa` est confirmé présent sur DGX et déjà utilisé par les chemins +# reasoning (cf. get_reasoning_model) et bbox grounding (DEFAULT_GROUNDING_FALLBACK) +# → default cohérent et sûr. `gemma4:latest` reste accessible via env explicite. +DEFAULT_VLM_MODEL = "qwen2.5vl:7b-rpa" + +# Allow-list des modèles VLM généralistes confirmés présents sur le DGX et donc +# utilisables comme default sans risque de 404. `gemma4:31b-cloud` est réservé au +# benchmark P1.y (≈20 Go VRAM, latence élevée), pas au default runtime. +DGX_SAFE_VLM_MODELS = ("qwen2.5vl:7b-rpa", "qwen2.5vl:7b") # Modèles de fallback, testés dans l'ordre si le modèle principal n'est pas dispo FALLBACK_VLM_MODELS = ["qwen3-vl:8b", "0000/ui-tars-1.5-7b-q8_0:7b"] diff --git a/tests/unit/test_vlm_default_dgx_safe.py b/tests/unit/test_vlm_default_dgx_safe.py new file mode 100644 index 000000000..0541ab6cc --- /dev/null +++ b/tests/unit/test_vlm_default_dgx_safe.py @@ -0,0 +1,61 @@ +"""Tests P1.w — default `get_vlm_model()` DGX-safe. + +Sur le DGX, `gemma4:latest` peut être absent (dépull) ; si aucune env +`RPA_VLM_MODEL` / `VLM_MODEL` n'est posée, le fallback central ne doit plus +tomber sur `gemma4:latest` (risque 404 Ollama → tout le pipeline VLM échoue). +Le default doit appartenir à une allow-list de modèles confirmés présents sur DGX. +""" + +import pytest + +from core.detection import vlm_config + + +# Le default historique non-DGX-safe (absent du DGX si dépull). +NON_DGX_SAFE_DEFAULT = "gemma4:latest" + +_VLM_ENVS = ("RPA_VLM_MODEL", "VLM_MODEL") + + +@pytest.fixture +def clean_vlm_env(monkeypatch): + """Neutralise les env VLM et réinitialise le cache de résolution.""" + for var in _VLM_ENVS: + monkeypatch.delenv(var, raising=False) + vlm_config.reset_vlm_model_cache() + yield monkeypatch + vlm_config.reset_vlm_model_cache() + + +def test_default_vlm_model_is_dgx_safe(): + """Le default n'est plus `gemma4:latest` et appartient à l'allow-list DGX-safe.""" + assert vlm_config.DEFAULT_VLM_MODEL != NON_DGX_SAFE_DEFAULT + assert vlm_config.DEFAULT_VLM_MODEL in vlm_config.DGX_SAFE_VLM_MODELS + + +def test_allow_list_excludes_non_dgx_safe_default(): + """L'allow-list DGX-safe ne contient pas le default historique risqué.""" + assert NON_DGX_SAFE_DEFAULT not in vlm_config.DGX_SAFE_VLM_MODELS + + +def test_get_vlm_model_no_env_returns_dgx_safe(clean_vlm_env): + """Sans env, même Ollama injoignable, on retourne le default DGX-safe.""" + # Simule Ollama injoignable → get_vlm_model utilise le modèle configuré. + clean_vlm_env.setattr(vlm_config, "_list_ollama_models", lambda endpoint: None) + model = vlm_config.get_vlm_model() + assert model != NON_DGX_SAFE_DEFAULT + assert model == vlm_config.DEFAULT_VLM_MODEL + + +def test_get_vlm_model_env_override_keeps_priority(clean_vlm_env): + """RPA_VLM_MODEL garde la priorité, même vers un modèle non-DGX-safe explicite.""" + clean_vlm_env.setattr(vlm_config, "_list_ollama_models", lambda endpoint: None) + clean_vlm_env.setenv("RPA_VLM_MODEL", "gemma4:latest") + assert vlm_config.get_vlm_model() == "gemma4:latest" + + +def test_get_vlm_model_legacy_vlm_model_alias(clean_vlm_env): + """L'alias de compat VLM_MODEL est honoré avant le default.""" + clean_vlm_env.setattr(vlm_config, "_list_ollama_models", lambda endpoint: None) + clean_vlm_env.setenv("VLM_MODEL", "mon-modele:custom") + assert vlm_config.get_vlm_model() == "mon-modele:custom"