Avancé 11 minSanté

Synthèse de dossiers médicaux

Réponse directe

Pour résumer un dossier médical avec un LLM local, extrayez les faits par du code (lot FHIR ou document CDA R2), numérotez-les, faites rédiger la synthèse à partir d'eux seuls en citant la référence de chaque ligne, vérifiez par programme que chaque référence et chaque nombre existent dans la source, puis faites valider par un médecin. Le local protège la confidentialité, pas contre les hallucinations : une étude de 2025 en relève 1,47 % par phrase.

Un dossier de santé est exact mais fragmenté, et les modèles de langage rédigent des synthèses fluides qui peuvent contenir des erreurs graves. Ce guide décrit un pipeline local où le code extrait les faits, le modèle les rédige en citant ses sources, et un contrôle mécanique puis un médecin valident le résultat. Il rappelle aussi le cadre à vérifier : secret médical, hébergement de données de santé, finalité de l'outil.

Par Mohamed Meguedmi·Màj 2026-09-30·Testé sur Windows, macOS, Linux

#Le problème : des dossiers exacts mais illisibles

Un praticien qui reprend un patient doit parcourir des comptes rendus, des résultats de biologie, des ordonnances et des courriers, souvent produits par plusieurs logiciels. Un modèle local peut préparer une synthèse de reprise de dossier en une page. La méthode qui tient la route en contexte médical est toujours la même : extraire les données structurées par du code déterministe, faire rédiger la synthèse à partir de ces faits seuls, faire citer à chaque ligne l'identifiant du fait d'origine, contrôler la synthèse par programme, puis la faire valider par un médecin.

Un point de vocabulaire évite une confusion fréquente. En France, les documents de santé échangés et partagés, notamment via le Dossier Médical Partagé, suivent le cadre d'interopérabilité des systèmes d'information de santé (CI-SIS) de l'Agence du numérique en santé, dont les volets décrivent des documents au format CDA R2, un standard HL7 fondé sur XML. Le HL7 version 2 est un autre standard, à base de messages en texte délimité par des barres verticales, qui sert au transport. Enfin FHIR, en JSON, est la norme d'échange la plus récente et la plus simple à traiter, que l'on rencontre surtout dans les échanges entre applications. Votre première tâche est donc de savoir ce que votre logiciel vous fournit.

i
Accès au dossier partagé
Un script ne se connecte pas librement au DMP : l'accès passe par un logiciel de professionnel de santé ou une plateforme d'intermédiation autorisée. Le volet de transmission d'un document CDA-R2 du CI-SIS décrit justement la possibilité pour un logiciel métier de déléguer à une plateforme d'intermédiation les échanges avec le DMP et la messagerie MSSanté. Ce guide part donc de documents déjà exportés depuis votre logiciel.

#Cadre : secret médical, hébergement et responsabilité

Le kit IA Locale

Ton ChatGPT privé et gratuit sur ta machine en 1 heure — LM Studio, Ollama, Open WebUI, tes documents, sans cloud.

  • Espace en ligne à vie
  • PDF + fichiers
  • Mises à jour à vie

Trois questions se posent avant tout code. La première est le secret médical et la protection des données de santé, qui imposent de traiter ces données sur une infrastructure maîtrisée : le local en est la traduction pratique, mais il faut aussi chiffrer les disques, restreindre les accès et journaliser. La deuxième est l'hébergement de données de santé. L'article L. 1111-8 du code de la santé publique prévoit que toute personne qui héberge des données de santé à caractère personnel sur support numérique doit être certifiée à cet effet, lorsqu'elle le fait pour le compte d'un responsable de traitement ou du patient.

Cette obligation ne joue pas comme on le croit toujours. D'après l'Agence du numérique en santé, citée par un assureur spécialisé, la certification d'hébergeur n'est pas une obligation réglementaire quand tous les systèmes d'une structure ne stockent que des données de ses propres patients, sauf si elle exerce une activité d'hébergement pour le compte de tiers. Autrement dit, un cabinet qui exécute l'outil chez lui, pour ses patients, n'est pas dans le même cas qu'un éditeur qui propose ce service à d'autres cabinets. Faites confirmer votre situation par votre conseil ou votre délégué à la protection des données.

La troisième question est la finalité. Un logiciel qui produit des informations destinées à éclairer une décision médicale peut relever de la réglementation sur les dispositifs médicaux, selon la finalité annoncée. Une synthèse de reprise de dossier présentée comme une aide à la lecture, validée par le médecin, n'a pas la même portée qu'un outil qui suggère un traitement. Ce guide reste du côté de la première formulation.

#La pile locale

Trois briques suffisent. Du Python pour lire les documents : le module json pour un lot FHIR, lxml pour un document CDA, la bibliothèque hl7 pour d'éventuels messages version 2, qui s'annonce comme un analyseur de messages HL7 v2.x. Ollama pour servir le modèle : Qwen 3.5 en 9 milliards de paramètres pèse 6,6 Go, avec 256 000 tokens de contexte annoncés ; Mistral Small 24B pèse 14 Go et annonce 32 000 tokens. Enfin le schéma JSON d'Ollama, pour obliger le modèle à répondre dans un format contrôlable.

Aucun de ces modèles n'a été validé pour un usage clinique par leurs éditeurs. Leur capacité en français médical se mesure sur vos propres dossiers, avec le protocole plus bas. Une carte de 8 Go suffit pour le premier ; le second demande plus de mémoire vidéo, surtout si le contexte est long.

#Lire les documents : lot FHIR et document CDA

Pour un lot FHIR, qui est un conteneur d'une collection de ressources, le plus simple est de lire le JSON tel quel et d'aller chercher les ressources par type. Cela évite de dépendre d'une bibliothèque dont les versions de FHIR varient. Chaque fait retenu reçoit un identifiant court (F1, F2...) et un texte lisible : c'est ce qui permettra ensuite de retrouver la source de chaque phrase de la synthèse.

Extraire des faits d'un lot FHIR (R4)
import json

def libelle(cc):
    if not cc:
        return None
    if cc.get('text'):
        return cc['text']
    c = (cc.get('coding') or [{}])[0]
    return c.get('display') or c.get('code')

def faits_fhir(chemin):
    lot = json.load(open(chemin, encoding='utf-8'))
    faits = []
    for e in lot.get('entry', []):
        r = e.get('resource', {})
        t = r.get('resourceType')
        if t == 'Condition':
            texte = f"Diagnostic : {libelle(r.get('code'))} (début {r.get('onsetDateTime', 'date inconnue')})"
        elif t == 'MedicationStatement':
            dose = (r.get('dosage') or [{}])[0].get('text', 'posologie non précisée')
            texte = f"Traitement : {libelle(r.get('medicationCodeableConcept'))}, {dose}"
        elif t == 'Observation':
            v = r.get('valueQuantity', {})
            texte = f"Résultat : {libelle(r.get('code'))} = {v.get('value')} {v.get('unit', '')} ({r.get('effectiveDateTime', 'date inconnue')})"
        elif t == 'AllergyIntolerance':
            texte = f"Allergie : {libelle(r.get('code'))}"
        elif t == 'Procedure':
            texte = f"Acte : {libelle(r.get('code'))} ({r.get('performedDateTime', 'date inconnue')})"
        else:
            continue
        faits.append({'ref': f'F{len(faits) + 1}', 'type': t, 'texte': texte})
    return faits

Pour un document CDA, le texte utile se trouve dans les sections du corps structuré : chaque section porte un titre, un code et un bloc de texte narratif. Le code ci-dessous les extrait avec leur titre, sans embarquer l'en-tête du document, qui contient l'identité du patient. Les espaces de noms de CDA sont ceux de HL7 version 3.

Extraire les sections d'un document CDA R2
from lxml import etree

NS = {'h': 'urn:hl7-org:v3'}

def sections_cda(chemin):
    racine = etree.parse(chemin).getroot()
    for s in racine.iterfind('.//h:structuredBody//h:section', NS):
        texte = s.find('h:text', NS)
        if texte is None:
            continue
        code = s.find('h:code', NS)
        yield {
            'titre': (s.findtext('h:title', default='', namespaces=NS) or '').strip(),
            'code': code.get('code') if code is not None else None,
            'texte': ' '.join(''.join(texte.itertext()).split()),
        }
→
Extraire avant de résumer
Ne donnez jamais un document brut au modèle. Un document XML est en grande partie fait de balises et d'identifiants : il consomme du contexte et noie l'information utile. Le pipeline transforme d'abord le dossier en une liste de faits numérotés, puis c'est cette liste qui est résumée.

#Quels faits retenir, et avec quelle prudence

Ressources FHIR utiles pour une synthèse de reprise
RessourceCe qu'on y litPiège fréquent
ConditionDiagnostic, date de début, statutUn diagnostic résolu ou erroné peut rester dans l'historique
MedicationStatementMédicament, posologie, périodeUn traitement arrêté peut ne pas être marqué comme tel
ObservationRésultat de biologie ou de mesure, unité, dateComparer des valeurs sans leurs unités ni valeurs de référence
AllergyIntoleranceSubstance, réaction, gravitéAbsence de saisie ne veut pas dire absence d'allergie
ProcedureActe réalisé et sa dateDates approximatives ou manquantes
DocumentReferencePièce jointe, souvent un compte renduContenu encodé ou renvoyé vers un lien à récupérer séparément

La dernière colonne compte plus que les autres. Un modèle lit les faits que vous lui donnez et ne sait pas ce qui manque : si un traitement arrêté n'est pas marqué comme tel, il apparaîtra comme en cours dans la synthèse. Le code doit donc porter le statut et la date, et le prompt doit demander de signaler les faits sans date ou de statut incertain. L'absence d'information n'est pas une information : la synthèse doit le dire.

#Rédiger une synthèse qui cite ses sources, puis la contrôler

Le prompt donne les faits numérotés et exige que chaque ligne de la synthèse se termine par les références des faits utilisés, par exemple [F3][F7]. Il ne contient pas le nom du patient : l'âge et le sexe suffisent, et l'identité reste dans le logiciel métier. La réponse est libre en forme mais structurée en sections, ce qui la rend lisible en une page.

Synthèse à partir des faits numérotés
import requests

SYSTEM = open('system_med.txt', encoding='utf-8').read()

def synthese(faits, age, sexe, modele='qwen3.5:9b'):
    liste = '\n'.join(f"[{f['ref']}] {f['texte']}" for f in faits)
    r = requests.post('http://localhost:11434/api/chat', json={
        'model': modele, 'stream': False,
        'messages': [{'role': 'system', 'content': SYSTEM},
                     {'role': 'user', 'content': f'Patient : {age} ans, {sexe}.\n\nFAITS :\n{liste}'}],
        'options': {'temperature': 0.1, 'num_ctx': 16384}})
    return r.json()['message']['content']

Le contrôle vient ensuite, en code. Deux vérifications attrapent l'essentiel des erreurs graves : chaque référence citée doit exister dans la liste de faits, et chaque nombre de la synthèse doit figurer dans les faits. Un chiffre apparu de nulle part est le signe typique d'une invention ou d'une erreur de recopie, notamment sur une valeur biologique ou une posologie.

Contrôle mécanique de la synthèse
import re

def verifier(synthese, faits):
    refs_ok = {f['ref'] for f in faits}
    citees = set(re.findall(r'\[(F\d+)\]', synthese))
    def nombres(t):
        t = re.sub(r'\[F\d+\]', ' ', t).replace(',', '.')
        return set(re.findall(r'\d+(?:\.\d+)?', t))
    source = nombres(' '.join(f['texte'] for f in faits))
    return {
        'references_inconnues': sorted(citees - refs_ok),
        'nombres_absents_de_la_source': sorted(nombres(synthese) - source),
        'lignes_sans_reference': [l for l in synthese.split('\n') if l.strip().startswith('-') and not re.search(r'\[F\d+\]', l)],
    }

#Le prompt système

system_med.txt
Tu prépares une synthèse de reprise de dossier pour un médecin.
Tu ne poses AUCUN diagnostic, tu ne proposes AUCUN traitement ni modification de traitement.
Tu utilises UNIQUEMENT les faits fournis. Tu n'ajoutes aucune donnée.
Chaque ligne de la synthèse se termine par les références des faits utilisés, par exemple [F3][F7].
Si un fait n'a pas de date, ou si un statut est incertain, tu l'écris explicitement.
Si des faits semblent contradictoires, tu les signales sans trancher.
Si une information attendue est absente, écris : non renseigné.

SECTIONS : Pathologies, Traitements en cours, Allergies, Derniers résultats,
Actes et antécédents, Points à vérifier.

La section « Points à vérifier » est la plus utile en pratique. Elle transforme les zones grises (traitement sans date de fin, résultat sans unité, deux valeurs contradictoires) en questions posées au médecin, au lieu de les lisser dans une phrase fluide.

#Évaluer la fiabilité avant tout usage

La confiance ne se décrète pas. Une étude publiée en 2025 dans npj Digital Medicine a mesuré les erreurs de modèles de langage sur la génération de notes cliniques : sur 12 999 phrases annotées par des cliniciens, elle observe 1,47 % de phrases avec hallucination et 3,45 % d'omissions, dont 44 % d'hallucinations jugées majeures, c'est-à-dire susceptibles d'affecter le diagnostic ou la prise en charge si elles ne sont pas corrigées. Ces chiffres portent sur une autre tâche, avec d'autres modèles : ils ne sont pas les vôtres. Ils montrent qu'un taux d'erreur faible par phrase reste préoccupant à l'échelle d'un document.

Une synthèse de trente lignes avec 1,5 % d'erreur par ligne, en supposant les erreurs indépendantes, contient au moins une erreur dans environ un tiers des cas. C'est un ordre de grandeur pédagogique, pas une prévision. D'où le protocole suivant, qui remplace le critère « zéro erreur sur 50 dossiers » : ce critère ne prouve pas grand-chose, car zéro erreur observée sur 50 dossiers est compatible avec un taux réel d'environ 6 % au niveau de confiance de 95 % (règle des trois, 3 divisé par 50).

  1. 01
    Constituer un échantillon de dossiers anonymisés
    Prenez des dossiers variés : patients polypathologiques, traitements nombreux, résultats anciens. Retirez l'identité et les données inutiles avant tout usage hors cadre de soin.
  2. 02
    Faire annoter par un médecin
    Chaque phrase de synthèse est classée : correcte, imprécise, omission, erreur. Distinguez les erreurs qui pourraient changer une décision clinique.
  3. 03
    Compter par catégorie et par gravité
    Le nombre d'erreurs majeures par dossier compte plus que le taux moyen. Fixez un seuil avec le médecin responsable avant de commencer.
  4. 04
    Mesurer aussi les omissions
    Une synthèse qui oublie une allergie ou un traitement est plus dangereuse qu'une phrase maladroite.
  5. 05
    Rejouer à chaque changement
    Modèle, prompt ou format d'export : chaque modification impose de rejouer l'évaluation.
!
Pas de prescription assistée
N'utilisez jamais cet outil pour proposer un traitement, une posologie ou un ajustement. La synthèse est une aide à la lecture, et le médecin qui la valide en garde la responsabilité.

#Mise en production : traces, accès et périmètre

Journaliser chaque génération
Conservez la date, la version du modèle, la liste de faits fournie et la synthèse produite, dans un espace protégé : c'est ce qui permet de reconstituer ce que le médecin a lu.
Contrôler les accès
Le serveur d'inférence ne doit pas être joignable depuis l'extérieur ; les disques sont chiffrés ; les comptes sont nominatifs.
Afficher les sources
L'interface montre la synthèse avec, pour chaque ligne, le fait d'origine. Un médecin qui peut vérifier en un clic vérifie réellement.
Limiter le périmètre
Commencez par un usage interne au cabinet ou à la structure, avec un petit nombre d'utilisateurs, avant toute extension. Un service proposé à d'autres structures change votre statut au regard de l'hébergement.
Prévoir la validation humaine visible
La synthèse est signée ou validée par le praticien avant d'entrer dans le dossier, faute de quoi elle ne doit pas y figurer.
FAQ
Peut-on résumer un dossier médical avec un LLM local ?+
Oui, techniquement, en extrayant d'abord les données structurées par du code et en faisant rédiger la synthèse à partir de ces faits seuls. Il faut aussi contrôler la synthèse par programme, la faire valider par un médecin et évaluer le système sur des dossiers annotés. Le local règle la confidentialité, pas la fiabilité.
Le DMP fournit-il ses documents en FHIR ?+
Les volets du cadre d'interopérabilité français décrivent des documents de santé au format CDA R2, fondé sur XML, et leur transmission vers le DMP ou MSSanté. FHIR sert surtout aux échanges entre applications. Vérifiez ce que votre logiciel exporte, car votre pipeline dépend de ce format, pas de la source d'origine.
Faut-il un hébergeur certifié HDS pour un outil interne au cabinet ?+
Pas nécessairement : d'après l'ANS citée par Relyens, la certification n'est pas obligatoire quand la structure stocke uniquement les données de ses propres patients. Elle le devient si vous hébergez pour le compte de tiers. Faites confirmer votre cas précis par un conseil ou par votre délégué à la protection des données.
Quel modèle local choisir pour des textes médicaux ?+
Deux points de départ : Qwen 3.5 9B (6,6 Go, 256 000 tokens annoncés) sur une carte de 8 Go, ou Mistral Small 24B (14 Go) avec plus de mémoire. Aucun n'est validé cliniquement. Choisissez en comparant leurs synthèses sur vos dossiers, annotées par un médecin, et suivez surtout les omissions et les erreurs majeures.
Un LLM peut-il inventer un résultat de biologie ?+
Oui : les études sur la génération de notes cliniques observent des hallucinations, dont une part importante jugée majeure. C'est pourquoi le pipeline impose une référence par ligne, vérifie que chaque nombre de la synthèse figure dans les faits sources, et signale au médecin ce qui reste douteux. La validation humaine reste indispensable.
Un tel outil est-il un dispositif médical ?+
Cela dépend de sa finalité annoncée. Une aide à la lecture de dossier, validée par le médecin, n'est pas un outil qui propose un diagnostic ou un traitement, et la réglementation ne s'y applique pas de la même manière. Faites qualifier votre outil par un spécialiste de la réglementation avant tout déploiement au-delà d'un usage interne.
Ce guide vous a aidé ?

Un retour, une erreur, une précision ? Faites-nous signe, ça améliore le guide pour tout le monde.