From 6c036ed7f18f3d13d4c47f85d88dfdace2581a0b Mon Sep 17 00:00:00 2001 From: dom Date: Fri, 20 Feb 2026 07:53:43 +0100 Subject: [PATCH] =?UTF-8?q?fix:=20garde-fous=20qualit=C3=A9=20Phase=201=20?= =?UTF-8?q?=E2=80=94=20codes=20invalides=20et=20raisonnements=20vides?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Ajout R33, R33.0, R33.8, R33.9, F17.1, F17.2 au dictionnaire supplémentaire - Rejet des codes CIM-10 avec raisonnement ET justification vides (corrélation hallucinations) - Validation du code contre le dictionnaire CIM-10 avant copie suggestion → final Co-Authored-By: Claude Opus 4.6 --- data/cim10_supplements.json | 8 +++++++- src/medical/rag_search.py | 9 +++++++++ src/quality/decision_engine.py | 15 ++++++++++++++- 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/data/cim10_supplements.json b/data/cim10_supplements.json index f4dafcb..ae90058 100644 --- a/data/cim10_supplements.json +++ b/data/cim10_supplements.json @@ -55,5 +55,11 @@ "Z93.3": "Colostomie", "Z93.0": "Trachéostomie", "Z98.0": "État consécutif à une dérivation intestinale ou à une anastomose", - "Z98.1": "État consécutif à une arthrodèse" + "Z98.1": "État consécutif à une arthrodèse", + "R33": "Rétention d'urine", + "R33.0": "Rétention d'urine due à un obstacle mécanique", + "R33.8": "Autre rétention d'urine", + "R33.9": "Rétention d'urine, sans précision", + "F17.1": "Troubles mentaux et du comportement liés à l'utilisation de tabac, utilisation nocive pour la santé", + "F17.2": "Troubles mentaux et du comportement liés à l'utilisation de tabac, syndrome de dépendance" } diff --git a/src/medical/rag_search.py b/src/medical/rag_search.py index a3b207b..d57c25c 100644 --- a/src/medical/rag_search.py +++ b/src/medical/rag_search.py @@ -494,6 +494,15 @@ def _apply_llm_result_diagnostic(diagnostic: Diagnostic, llm_result: dict) -> No if code: code = normalize_code(code) + # Garde-fou : rejeter un code sans raisonnement ni justification + # (corrélation forte avec les hallucinations LLM) + if not raisonnement and not justification: + logger.warning( + "RAG : code %s rejeté pour « %s » — raisonnement et justification vides", + code, diagnostic.texte, + ) + code = None + if code: is_valid, _ = cim10_validate(code) if is_valid: diagnostic.cim10_suggestion = code diff --git a/src/quality/decision_engine.py b/src/quality/decision_engine.py index 2bba36c..6b1f386 100644 --- a/src/quality/decision_engine.py +++ b/src/quality/decision_engine.py @@ -12,6 +12,8 @@ import re import unicodedata from typing import Optional +import logging + from ..config import ( CodeDecision, Diagnostic, @@ -21,6 +23,9 @@ from ..config import ( load_bio_rules, rule_enabled, ) +from ..medical.cim10_dict import validate_code as cim10_validate + +logger = logging.getLogger(__name__) # --- Règles "étiologiques" : ne pas affirmer sans preuve spécifique --- @@ -317,7 +322,15 @@ def apply_decisions(dossier: DossierMedical) -> None: def _set_default_final(diag: Diagnostic): if diag.cim10_suggestion and diag.cim10_final is None: - diag.cim10_final = diag.cim10_suggestion + is_valid, _ = cim10_validate(diag.cim10_suggestion) + if is_valid: + diag.cim10_final = diag.cim10_suggestion + else: + logger.warning( + "Code %s absent du dictionnaire CIM-10 pour « %s » — cim10_final non rempli", + diag.cim10_suggestion, diag.texte, + ) + diag.cim10_final = None # DP if dossier.diagnostic_principal: