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) <noreply@anthropic.com>
This commit is contained in:
Dom
2026-06-05 12:06:10 +02:00
parent 0f122a512f
commit 5b2afa3629
2 changed files with 74 additions and 7 deletions

View File

@@ -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"]

View File

@@ -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"