fix: suppression mode hybride 27b, prompt CPAM nuancé pour gemma3:12b
Benchmark 4 modèles (gemma3:12b/27b, qwen3:14b, mistral-small3.2:24b) sur 3 dossiers CPAM : le 12b domine en vitesse (30s vs 231s) et densité argumentaire. Seul avantage du 27b : nuance (points d'accord 3/3 vs 1/3). Solution : prompt nuancé qui force l'analyse équilibrée (étape 1 honnête, points d'accord obligatoires, conclusion reconnaissant les points CPAM). Résultat 12b-v2 : 3/3 points d'accord, 26s, refs verbatim +17%. Supprime OLLAMA_MODEL_CPAM et OLLAMA_TIMEOUT_CPAM (gemma3:12b pour tout). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -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_URL = os.environ.get("OLLAMA_URL", "http://localhost:11434")
|
||||||
OLLAMA_MODEL = os.environ.get("OLLAMA_MODEL", "gemma3:12b")
|
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 = 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_CACHE_PATH = BASE_DIR / "data" / "ollama_cache.json"
|
||||||
OLLAMA_MAX_PARALLEL = int(os.environ.get("OLLAMA_MAX_PARALLEL", "2"))
|
OLLAMA_MAX_PARALLEL = int(os.environ.get("OLLAMA_MAX_PARALLEL", "2"))
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import logging
|
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
|
from ..medical.ollama_client import call_anthropic, call_ollama
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -221,7 +221,11 @@ def _build_cpam_prompt(
|
|||||||
sources_text += (src.get("extrait", "")[:800]) + "\n\n"
|
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.
|
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 MÉDICAL DE L'ÉTABLISSEMENT :
|
||||||
{dossier_str}
|
{dossier_str}
|
||||||
@@ -242,11 +246,15 @@ SOURCES RÉGLEMENTAIRES (Guide méthodologique, CIM-10) :
|
|||||||
|
|
||||||
CONSIGNES :
|
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 :
|
AXE MÉDICAL :
|
||||||
- Analyse le bien-fondé médical du codage de l'établissement
|
- 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
|
- 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
|
- 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
|
- Ne mentionne que les éléments réellement présents dans le dossier fourni
|
||||||
|
|
||||||
AXE ASYMÉTRIE D'INFORMATION :
|
AXE ASYMÉTRIE D'INFORMATION :
|
||||||
@@ -266,8 +274,8 @@ AXE RÉGLEMENTAIRE :
|
|||||||
Réponds UNIQUEMENT avec un objet JSON au format suivant :
|
Réponds UNIQUEMENT avec un objet JSON au format suivant :
|
||||||
{{
|
{{
|
||||||
"analyse_contestation": "Résumé de ce que conteste la CPAM et sur quelle base",
|
"analyse_contestation": "Résumé de ce que conteste la CPAM et sur quelle base",
|
||||||
"points_accord": "Points où la CPAM a raison (ou 'Aucun')",
|
"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",
|
"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": [
|
"preuves_dossier": [
|
||||||
{{"element": "biologie|imagerie|traitement|acte|clinique", "valeur": "valeur exacte du dossier", "signification": "explication clinique"}}
|
{{"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": [
|
"references": [
|
||||||
{{"document": "nom du document source", "page": "numéro de page", "citation": "citation verbatim du passage"}}
|
{{"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
|
# 2. Construction du prompt
|
||||||
prompt = _build_cpam_prompt(dossier, controle, sources)
|
prompt = _build_cpam_prompt(dossier, controle, sources)
|
||||||
|
|
||||||
# 3. Appel LLM — Mode hybride : Ollama CPAM (27b) > Haiku > Ollama défaut
|
# 3. Appel LLM — Ollama (modèle par défaut) > Haiku fallback
|
||||||
result = None
|
result = call_ollama(prompt, temperature=0.1, max_tokens=4000)
|
||||||
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,
|
|
||||||
)
|
|
||||||
if result is not None:
|
if result is not None:
|
||||||
logger.info(" Contre-argumentation via Ollama %s", OLLAMA_MODEL_CPAM)
|
logger.info(" Contre-argumentation via Ollama")
|
||||||
else:
|
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)
|
result = call_anthropic(prompt, temperature=0.1, max_tokens=4000)
|
||||||
if result is not None:
|
if result is not None:
|
||||||
logger.info(" Contre-argumentation via Anthropic Haiku")
|
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
|
# 4. Conversion des sources RAG
|
||||||
rag_sources = [
|
rag_sources = [
|
||||||
|
|||||||
Reference in New Issue
Block a user