Bench 5 modèles × 5 scénarios × cold+warm sur RTX 5070 : - gemma4:latest : warm 2.9s, JSON 92%, détection 46% → gagnant - qwen2.5vl:7b : warm 6.6s, détection 23% (trop lent) - qwen2.5vl:3b : warm 2.0s, détection 8% (vérifie pour vérifier) - medgemma:4b : warm 0.5s, détection 0% (refuse de signaler) → mauvais défaut initial, corrigé - qwen3-vl:8b : 0% JSON valide (ignore format=json Ollama) → écarté Modifications safety_checks_provider.py : - RPA_SAFETY_CHECKS_LLM_MODEL défaut: medgemma:4b → gemma4:latest - RPA_SAFETY_CHECKS_LLM_TIMEOUT_S défaut: 5 → 7 (warm 2.9s + marge) Doc complète : docs/BENCH_SAFETY_CHECKS_2026-05-06.md Script : tools/bench_safety_checks_models.py (reproductible, ~10-15 min) Limite assumée : 46% de détection. À présenter en démo comme aide médecin, pas certification. Amélioration V2 = prompt plus dirigé sur champs à vérifier. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
96 lines
4.6 KiB
Markdown
96 lines
4.6 KiB
Markdown
# Bench QW4 safety_checks — sélection du LLM contextuel
|
||
|
||
**Date** : 2026-05-06
|
||
**Contexte** : QW4 du sprint mai. La fonction `_call_llm_for_contextual_checks`
|
||
appelle Ollama avec un screenshot + prompt court pour générer 0-3 checks de
|
||
vérification supplémentaires que l'humain doit acquitter avant la reprise
|
||
d'un replay en pause supervisée (`safety_level=medical_critical`).
|
||
|
||
## Méthodologie
|
||
|
||
- **5 scénarios** : screenshots synthétiques de dossiers patient avec UNE
|
||
anomalie volontaire chacun (date de naissance aberrante, IPP incohérent,
|
||
diagnostic vide, code CIM inadapté à l'âge, forfait incohérent avec durée).
|
||
- **5 candidats** : `gemma4:latest`, `qwen3-vl:8b`, `qwen2.5vl:7b`,
|
||
`qwen2.5vl:3b`, `medgemma:4b`.
|
||
- **Protocole par modèle** : déchargement VRAM (keep_alive=0 sur tous les
|
||
modèles loaded) → 1er appel = cold start chronométré → 4 autres screenshots
|
||
× 3 runs = 12 mesures warm.
|
||
- **Métriques** : cold start, warm avg, warm p95, % JSON valide, % détection
|
||
(anomalie cible présente dans label/evidence d'au moins un check renvoyé).
|
||
- **Script** : `tools/bench_safety_checks_models.py`.
|
||
|
||
## Résultats
|
||
|
||
| Modèle | Cold (s) | Warm avg (s) | Warm p95 (s) | JSON | Détection |
|
||
|---|---:|---:|---:|---:|---:|
|
||
| `gemma4:latest` | 10.6 | **2.9** | 3.4 | 92% (12/13) | **46% (6/13)** |
|
||
| `qwen3-vl:8b` | 5.6 | — | — | **0%** (0/12) | 0% (0/12) |
|
||
| `qwen2.5vl:7b` | 9.4 | 6.6 | 8.1 | 100% (13/13) | 23% (3/13) |
|
||
| `qwen2.5vl:3b` | 6.0 | 2.0 | 2.5 | 100% (13/13) | 8% (1/13) |
|
||
| `medgemma:4b` | 2.0 | 0.5 | 0.7 | 100% (13/13) | **0%** (0/13) |
|
||
|
||
## Lecture
|
||
|
||
- **`medgemma:4b` retourne systématiquement `[]`** sur les 13 mesures.
|
||
Trop obéissant à "Si rien d'inhabituel à signaler, retourne []", refuse
|
||
de pointer ne serait-ce qu'une date 1900-01-01. **Mauvais choix par défaut**
|
||
malgré sa rapidité et sa spécialisation médicale revendiquée.
|
||
- **`qwen3-vl:8b` ignore `format=json` Ollama** : 0 réponse parsable. À écarter
|
||
pour cette tâche tant que le tooling Ollama / le modèle ne convergent pas.
|
||
- **`qwen2.5vl:7b`** détecte mais 2× plus lent (warm 6.6s) que gemma4 et tend
|
||
à inventer des anomalies de format de date qui ne sont pas la vraie cible.
|
||
- **`qwen2.5vl:3b`** rapide mais détection 8% — il "vérifie pour vérifier"
|
||
(renvoie souvent "vérification de la date de naissance" même quand la date
|
||
est correcte).
|
||
- **`gemma4:latest` gagne** : meilleur taux de détection (46%) ET deuxième
|
||
meilleur warm (2.9s). Tend à raisonner cohérence motif/diagnostic plutôt
|
||
que valeurs aberrantes brutes.
|
||
|
||
## Détail détection par scénario
|
||
|
||
| Scénario | gemma4 | qwen2.5vl:7b | qwen2.5vl:3b | medgemma:4b |
|
||
|---|:---:|:---:|:---:|:---:|
|
||
| Date naissance aberrante (1900) | ❌ | ✅ | ✅ | ❌ |
|
||
| IPP incohérent (`ABC@@##XYZ`) | ❌ | ❌ | ❌ | ❌ |
|
||
| Diagnostic principal vide | ✅ | ❌ | ❌ | ❌ |
|
||
| Code CIM inadapté à l'âge | ✅ | ❌ | ❌ | ❌ |
|
||
| Forfait UHCD vs durée 1h | ❌ | ❌ | ❌ | ❌ |
|
||
|
||
Aucun modèle ne détecte les 5 scénarios. **L'IPP corrompu et le forfait
|
||
incohérent ne sont détectés par personne** — ces anomalies demanderaient
|
||
soit un prompt plus dirigé (liste explicite des champs à vérifier), soit
|
||
un modèle plus large.
|
||
|
||
## Décision
|
||
|
||
- **Défaut serveur** : `RPA_SAFETY_CHECKS_LLM_MODEL=gemma4:latest`
|
||
- **Timeout** : `RPA_SAFETY_CHECKS_LLM_TIMEOUT_S=7` (warm 2.9s + marge)
|
||
- **Persistance VRAM** : `OLLAMA_KEEP_ALIVE=24h` recommandé pour éviter le
|
||
cold start de 10s en démo
|
||
|
||
Modifications appliquées dans `agent_v0/server_v1/safety_checks_provider.py`.
|
||
|
||
## Limites & travail futur
|
||
|
||
1. **46% de détection est faible** : à présenter comme aide au médecin, pas
|
||
comme certification. Le médecin reste le décideur.
|
||
2. **Prompt actuel trop générique** : un prompt qui liste explicitement les
|
||
champs à vérifier (DDN, IPP, diagnostic, forfait, cohérence âge/diagnostic)
|
||
donnerait probablement de meilleurs résultats. À mesurer en V2.
|
||
3. **Bench sur 5 anomalies seulement** : à étendre dès qu'on a un corpus de
|
||
vrais dossiers Easily Assure avec anomalies confirmées par Pauline / Amina.
|
||
4. **Pas de test sur des dossiers SANS anomalie** (faux positifs) : à ajouter.
|
||
5. **Pas de bench des modèles cloud** (gemma3:27b-cloud, deepseek, gpt-oss)
|
||
par contrainte 100% local — mais à explorer si on lève cette contrainte
|
||
pour les checks contextuels (qui ne contiennent pas de PII si on
|
||
anonymise les screenshots).
|
||
|
||
## Reproductibilité
|
||
|
||
```bash
|
||
cd /home/dom/ai/rpa_vision_v3
|
||
.venv/bin/python tools/bench_safety_checks_models.py
|
||
# (BENCH_TIMEOUT=60 par défaut, ~10-15 min sur RTX 5070)
|
||
```
|