feat: sanitisation déterministe des codes CIM-10 hors périmètre CPAM
Le LLM (deepseek) propose systématiquement des codes alternatifs (D62, T81.0, T80, R39.2) malgré l'interdiction dans le prompt. Ces codes déclenchaient des warnings CRITIQUE → Tier C automatique. Solution conforme au principe "LLM propose, moteur de règles dispose" : - _sanitize_unauthorized_codes() supprime les codes hors whitelist du texte de la réponse AVANT toute validation - Nettoyage propre : "D62 — libellé" → "libellé", "(D62)" → "" - _build_whitelist_prefixes() factorisé en helper partagé - Sanitisation appliquée après génération ET après correction - 9 tests unitaires couvrant tous les cas (parenthèses, tirets, multiple) Résultat live : 0 warning CRITIQUE "code hors périmètre" sur 3 dossiers (vs 6 warnings CRITIQUE avant). Le seul CRITIQUE restant est le score adversarial bas, qui reflète des limites de raisonnement du modèle. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -25,6 +25,7 @@ from .cpam_validation import (
|
||||
_validate_grounding,
|
||||
_validate_references,
|
||||
_validate_codes_in_response,
|
||||
_sanitize_unauthorized_codes,
|
||||
_build_correction_prompt,
|
||||
_format_response,
|
||||
_assess_quality_tier,
|
||||
@@ -39,7 +40,7 @@ from .cpam_context import ( # noqa: F401
|
||||
_build_bio_summary,
|
||||
_check_das_bio_coherence,
|
||||
)
|
||||
from .cpam_validation import _CIM10_CODE_RE, _validate_adversarial as _validate_adversarial, _assess_quality_tier as _assess_quality_tier, _fuzzy_match_ref as _fuzzy_match_ref # noqa: F401
|
||||
from .cpam_validation import _CIM10_CODE_RE, _validate_adversarial as _validate_adversarial, _assess_quality_tier as _assess_quality_tier, _fuzzy_match_ref as _fuzzy_match_ref, _sanitize_unauthorized_codes as _sanitize_unauthorized_codes # noqa: F401
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -150,17 +151,23 @@ def generate_cpam_response(
|
||||
logger.warning(" LLM non disponible — contre-argumentation non générée")
|
||||
return "", None, rag_sources
|
||||
|
||||
# 6. Validation des références RAG
|
||||
# 6. Sanitisation déterministe — supprime les codes CIM-10 hors périmètre
|
||||
sanitized = _sanitize_unauthorized_codes(result, dossier, controle)
|
||||
if sanitized:
|
||||
logger.info(" CPAM : %d code(s) hors périmètre supprimé(s) : %s",
|
||||
len(sanitized), ", ".join(sanitized))
|
||||
|
||||
# 7. Validation des références RAG
|
||||
ref_warnings = _validate_references(result, sources)
|
||||
if ref_warnings:
|
||||
logger.warning(" CPAM : %d référence(s) non vérifiable(s)", len(ref_warnings))
|
||||
|
||||
# 7. Validation grounding (preuves traçables vers le dossier)
|
||||
# 8. Validation grounding (preuves traçables vers le dossier)
|
||||
grounding_warnings = _validate_grounding(result, tag_map)
|
||||
if grounding_warnings:
|
||||
logger.warning(" CPAM : %d preuve(s) non traçable(s)", len(grounding_warnings))
|
||||
|
||||
# 7b. Validation codes fermée (périmètre dossier + UCR)
|
||||
# 8b. Validation codes fermée (périmètre dossier + UCR) — post-sanitisation
|
||||
code_warnings = _validate_codes_in_response(result, dossier, controle)
|
||||
if code_warnings:
|
||||
logger.warning(" CPAM : %d code(s) hors périmètre", len(code_warnings))
|
||||
@@ -202,7 +209,8 @@ def generate_cpam_response(
|
||||
logger.info(" Correction acceptée (score %s → %s)", score1, score2)
|
||||
result = corrected
|
||||
validation = validation2
|
||||
# Recalculer les warnings
|
||||
# Sanitiser + recalculer les warnings
|
||||
_sanitize_unauthorized_codes(result, dossier, controle)
|
||||
ref_warnings = _validate_references(result, sources)
|
||||
grounding_warnings = _validate_grounding(result, tag_map)
|
||||
code_warnings = _validate_codes_in_response(result, dossier, controle)
|
||||
|
||||
Reference in New Issue
Block a user