diff --git a/src/config.py b/src/config.py index cf9aac1..0209586 100644 --- a/src/config.py +++ b/src/config.py @@ -36,9 +36,7 @@ NER_CONFIDENCE_THRESHOLD = float(os.environ.get("T2A_NER_THRESHOLD", "0.80")) OLLAMA_URL = os.environ.get("OLLAMA_URL", "http://localhost:11434") OLLAMA_MODEL = os.environ.get("OLLAMA_MODEL", "gemma3:12b") -OLLAMA_MODEL_CPAM = os.environ.get("OLLAMA_MODEL_CPAM", "gemma3:27b") OLLAMA_TIMEOUT = int(os.environ.get("OLLAMA_TIMEOUT", "120")) -OLLAMA_TIMEOUT_CPAM = int(os.environ.get("OLLAMA_TIMEOUT_CPAM", "300")) OLLAMA_CACHE_PATH = BASE_DIR / "data" / "ollama_cache.json" OLLAMA_MAX_PARALLEL = int(os.environ.get("OLLAMA_MAX_PARALLEL", "2")) diff --git a/src/control/cpam_response.py b/src/control/cpam_response.py index dd6f834..8c890ee 100644 --- a/src/control/cpam_response.py +++ b/src/control/cpam_response.py @@ -4,7 +4,7 @@ from __future__ import annotations import logging -from ..config import ControleCPAM, DossierMedical, RAGSource, OLLAMA_MODEL_CPAM, OLLAMA_TIMEOUT_CPAM +from ..config import ControleCPAM, DossierMedical, RAGSource from ..medical.ollama_client import call_anthropic, call_ollama logger = logging.getLogger(__name__) @@ -221,7 +221,11 @@ def _build_cpam_prompt( sources_text += (src.get("extrait", "")[:800]) + "\n\n" return f"""Tu es un médecin DIM (Département d'Information Médicale) expert en contentieux T2A. -Tu dois contre-argumenter la décision de la CPAM (UCR) en mobilisant trois axes : médical, asymétrie d'information, et réglementaire. +Tu dois produire une analyse ÉQUILIBRÉE ET CRÉDIBLE de la contestation CPAM, puis contre-argumenter en mobilisant trois axes : médical, asymétrie d'information, et réglementaire. + +IMPORTANT — CRÉDIBILITÉ DE L'ANALYSE : +Une contre-argumentation crédible reconnaît TOUJOURS au moins un point valide dans le raisonnement adverse. +Répondre "Aucun point d'accord" décrédibilise l'ensemble de l'argumentation. Tu DOIS identifier au moins un élément où la CPAM a un point légitime (même partiel), puis expliquer pourquoi cela ne suffit pas à invalider le codage. DOSSIER MÉDICAL DE L'ÉTABLISSEMENT : {dossier_str} @@ -242,11 +246,15 @@ SOURCES RÉGLEMENTAIRES (Guide méthodologique, CIM-10) : CONSIGNES : +ÉTAPE 1 — ANALYSE HONNÊTE (avant de contre-argumenter) : +- Identifie ce que la CPAM a compris correctement dans le dossier +- Reconnais les points où leur raisonnement est fondé, même partiellement +- Explique ENSUITE pourquoi ces points ne justifient pas leur conclusion + AXE MÉDICAL : - Analyse le bien-fondé médical du codage de l'établissement - CITE les éléments cliniques EXACTS du dossier : valeurs bio précises (ex: CRP 180 mg/L), résultats imagerie verbatim, traitements avec molécules et posologies - Confronte l'argumentation CPAM aux sources CIM-10 et Guide Méthodologique fournies -- Identifie les points où la CPAM a éventuellement raison - Ne mentionne que les éléments réellement présents dans le dossier fourni AXE ASYMÉTRIE D'INFORMATION : @@ -266,8 +274,8 @@ AXE RÉGLEMENTAIRE : Réponds UNIQUEMENT avec un objet JSON au format suivant : {{ "analyse_contestation": "Résumé de ce que conteste la CPAM et sur quelle base", - "points_accord": "Points où la CPAM a raison (ou 'Aucun')", - "contre_arguments_medicaux": "Argumentation médicale en faveur du codage", + "points_accord": "Points CONCRETS où la CPAM a raison ou partiellement raison (JAMAIS 'Aucun' — il y a toujours au moins un point légitime à reconnaître)", + "contre_arguments_medicaux": "Argumentation médicale en faveur du codage, en expliquant pourquoi les points d'accord ne suffisent pas à invalider le codage", "preuves_dossier": [ {{"element": "biologie|imagerie|traitement|acte|clinique", "valeur": "valeur exacte du dossier", "signification": "explication clinique"}} ], @@ -276,7 +284,7 @@ Réponds UNIQUEMENT avec un objet JSON au format suivant : "references": [ {{"document": "nom du document source", "page": "numéro de page", "citation": "citation verbatim du passage"}} ], - "conclusion": "Synthèse et position recommandée" + "conclusion": "Synthèse : points reconnus à la CPAM, mais pourquoi le codage initial est néanmoins justifié" }}""" @@ -418,24 +426,15 @@ def generate_cpam_response( # 2. Construction du prompt prompt = _build_cpam_prompt(dossier, controle, sources) - # 3. Appel LLM — Mode hybride : Ollama CPAM (27b) > Haiku > Ollama défaut - result = None - if OLLAMA_MODEL_CPAM: - logger.info(" Contre-argumentation via Ollama %s (mode hybride)", OLLAMA_MODEL_CPAM) - result = call_ollama( - prompt, temperature=0.1, max_tokens=4000, - model=OLLAMA_MODEL_CPAM, timeout=OLLAMA_TIMEOUT_CPAM, - ) + # 3. Appel LLM — Ollama (modèle par défaut) > Haiku fallback + result = call_ollama(prompt, temperature=0.1, max_tokens=4000) if result is not None: - logger.info(" Contre-argumentation via Ollama %s", OLLAMA_MODEL_CPAM) + logger.info(" Contre-argumentation via Ollama") else: - logger.info(" Ollama CPAM indisponible → fallback Anthropic Haiku") + logger.info(" Ollama indisponible → fallback Anthropic Haiku") result = call_anthropic(prompt, temperature=0.1, max_tokens=4000) if result is not None: logger.info(" Contre-argumentation via Anthropic Haiku") - else: - logger.info(" Haiku indisponible → fallback Ollama défaut") - result = call_ollama(prompt, temperature=0.1, max_tokens=3000) # 4. Conversion des sources RAG rag_sources = [