Avanzado 11 minSalud

Síntesis de expedientes médicos

Respuesta directa

Para resumir un historial médico con un LLM local, extrae los hechos mediante código (un lote FHIR o un documento CDA R2), numéralos, haz que se redacte la síntesis únicamente a partir de ellos, citando la referencia de cada línea, comprueba mediante un programa que cada referencia y cada número existan en la fuente y, después, haz que un médico valide la síntesis. La ejecución en local protege la confidencialidad, pero no protege frente a las alucinaciones: un estudio de 2025 detecta una tasa del 1,47 % por frase.

Una historia clínica es exacta pero está fragmentada, y los modelos de lenguaje redactan síntesis fluidas que pueden contener errores graves. Esta guía describe un pipeline local en el que el código extrae los hechos, el modelo los redacta citando sus fuentes y el resultado se valida primero mediante una comprobación automatizada y después por un médico. También recuerda el marco que hay que verificar: secreto médico, alojamiento de datos de salud y finalidad de la herramienta.

Por Mohamed Meguedmi·Actualización 2026-09-30·Probado en Windows, macOS y Linux

#El problema: expedientes precisos pero ilegibles

Un profesional sanitario que se hace cargo de un paciente debe revisar informes, resultados de laboratorio, recetas y correspondencia, a menudo generados por varios programas. Un modelo local puede preparar un resumen de la historia clínica en una página para retomar la atención del paciente. El método que funciona en contextos médicos siempre es el mismo: extraer los datos estructurados mediante código determinista, hacer que el modelo redacte el resumen únicamente a partir de esos hechos, hacer que cada línea cite el identificador del hecho original, verificar el resumen mediante un programa y luego hacer que un médico lo valide.

Una aclaración terminológica evita una confusión frecuente. En Francia, los documentos de salud intercambiados y compartidos, especialmente a través del Dossier Médical Partagé, siguen el marco de interoperabilidad de los sistemas de información de salud (CI-SIS) de la Agence du numérique en santé, cuyos apartados describen documentos en formato CDA R2, un estándar HL7 basado en XML. HL7 versión 2 es otro estándar, basado en mensajes de texto delimitados por barras verticales, que sirve para el transporte. Por último, FHIR, en JSON, es la norma de intercambio más reciente y más sencilla de procesar, que se encuentra sobre todo en los intercambios entre aplicaciones. Por tanto, tu primera tarea es saber qué te proporciona tu software.

i
Acceso al expediente compartido
Un script no se conecta libremente al DMP: el acceso se realiza a través de un software para profesionales sanitarios o de una plataforma de intermediación autorizada. El apartado de transmisión de un documento CDA-R2 del CI-SIS describe precisamente la posibilidad de que un software profesional delegue en una plataforma de intermediación los intercambios con el DMP y la mensajería MSSanté. Esta guía parte, por tanto, de documentos ya exportados desde tu software.

#Marco: secreto médico, alojamiento y responsabilidad

El kit de IA Local

Tu ChatGPT privado y gratuito en tu máquina en 1 hora — LM Studio, Ollama, Open WebUI, tus documentos, sin nube.

  • Espacio en línea de por vida
  • PDF + archivos
  • Reembolsado 30 j

Hay tres cuestiones que abordar antes de escribir código. La primera es el secreto médico y la protección de los datos de salud, que exigen tratar estos datos en una infraestructura controlada: el procesamiento local es su aplicación práctica, pero también hay que cifrar los discos, restringir los accesos y mantener registros. La segunda es el alojamiento de datos de salud. El artículo L. 1111-8 del Código de Salud Pública establece que toda persona que aloje datos de salud de carácter personal en soporte digital debe estar certificada para ello cuando lo haga por cuenta de un responsable del tratamiento o del paciente.

Esta obligación no siempre se aplica como se suele creer. Según la Agence du numérique en santé, citada por una aseguradora especializada, la certificación como proveedor de alojamiento no es una obligación reglamentaria cuando todos los sistemas de una entidad almacenan únicamente datos de sus propios pacientes, salvo que esa entidad preste servicios de alojamiento por cuenta de terceros. En otras palabras, un consultorio que ejecuta la herramienta en sus propias instalaciones, para sus pacientes, no se encuentra en la misma situación que un proveedor de software que ofrece este servicio a otros consultorios. Haz que tu asesor o tu delegado de protección de datos confirme tu situación.

La tercera cuestión es la finalidad. Un software que produce información destinada a orientar una decisión médica puede estar sujeto a la normativa sobre dispositivos médicos, según la finalidad declarada. Un resumen para retomar un expediente, presentado como una ayuda a la lectura y validado por el médico, no tiene el mismo alcance que una herramienta que sugiere un tratamiento. Esta guía se limita a la primera formulación.

#Pila local

Bastan tres componentes. Python para leer los documentos: el módulo json para un lote FHIR, lxml para un documento CDA y la biblioteca hl7 para posibles mensajes de la versión 2, que se presenta como un analizador de mensajes HL7 v2.x. Ollama para servir el modelo: Qwen 3.5, con 9 mil millones de parámetros, pesa 6,6 GB y anuncia un contexto de 256 000 tokens; Mistral Small 24B pesa 14 GB y anuncia 32 000 tokens. Por último, el esquema JSON de Ollama, para obligar al modelo a responder en un formato que se pueda comprobar.

Ninguno de estos modelos ha sido validado para uso clínico por sus editores. Su capacidad en francés médico se mide con tus propios expedientes, siguiendo el protocolo que aparece más abajo. Una tarjeta de 8 GB basta para el primero; el segundo requiere más memoria de vídeo, especialmente si el contexto es largo.

#Leer los documentos: lote FHIR y documento CDA

Para un lote FHIR, que es un contenedor de una colección de recursos, lo más sencillo es leer el JSON tal como está y buscar los recursos por tipo. Esto evita depender de una biblioteca cuyas versiones de FHIR varían. Cada hecho seleccionado recibe un identificador corto (F1, F2...) y un texto legible: esto permitirá luego recuperar la fuente de cada frase de la síntesis.

Extraer hechos de un lote 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

Para un documento CDA, el texto útil se encuentra en las secciones del cuerpo estructurado: cada sección tiene un título, un código y un bloque de texto narrativo. El código a continuación extrae esas secciones con sus títulos, sin incluir la cabecera del documento, que contiene la identidad del paciente. Los espacios de nombres de CDA son los de HL7 versión 3.

Extraer las secciones de un documento 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()),
        }
→
Extraer antes de resumir
Nunca le des al modelo un documento sin procesar. Un documento XML está compuesto en gran parte por etiquetas e identificadores: consume contexto y oculta la información útil entre elementos irrelevantes. El pipeline transforma primero el expediente en una lista de hechos numerados y después se resume esa lista.

#Qué hechos conservar y con qué cautela

Recursos FHIR útiles para un resumen de recuperación
RecursoLo que se lee allíError frecuente
ConditionDiagnóstico, fecha de inicio, estadoUn diagnóstico resuelto o erróneo puede quedar en el historial
MedicationStatementMedicamento, pauta posológica, periodoUn tratamiento interrumpido puede no estar marcado como tal
ObservationResultado de análisis de laboratorio o de medición, unidad, fechaComparar valores sin sus unidades ni valores de referencia
AllergyIntoleranceSustancia, reacción, gravedadQue no haya ningún dato registrado no significa que no haya alergia
ProcedureActo realizado y su fechaFechas aproximadas o faltantes
DocumentReferenceAdjunto, normalmente un informeContenido codificado o disponible mediante un enlace para recuperarlo por separado

La última columna importa más que las demás. Un modelo lee los hechos que tú le proporcionas y no sabe qué falta: si un tratamiento suspendido no está marcado como tal, aparecerá como en curso en la síntesis. El código debe incluir, por tanto, el estado y la fecha, y el prompt debe pedir que se señalen los hechos sin fecha o con un estado incierto. La ausencia de información no es información: la síntesis debe indicarlo.

#Escribir un resumen que cite sus fuentes, luego revisarlo

El prompt proporciona los hechos numerados y exige que cada línea de la síntesis termine con las referencias de los hechos utilizados, por ejemplo [F3][F7]. No contiene el nombre del paciente: la edad y el sexo son suficientes, y la identidad permanece en el software de gestión profesional. La respuesta tiene un formato libre, pero está estructurada en secciones, lo que permite leerla en una página.

Síntesis a partir de los hechos numerados
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']

La comprobación se realiza después, mediante código. Dos verificaciones detectan la mayor parte de los errores graves: cada referencia citada debe existir en la lista de hechos y cada número de la síntesis debe aparecer en los hechos. Una cifra que aparece de la nada es una señal típica de una invención o de un error de copia, especialmente cuando se trata de un valor biológico o de una pauta posológica.

Comprobación automatizada de la síntesis
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)],
    }

#El prompt de sistema

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 sección «Puntos a verificar» es la más útil en la práctica. Transforma las zonas grises (tratamiento sin fecha de finalización, resultado sin unidad, dos valores contradictorios) en preguntas planteadas al médico, en lugar de suavizarlas en una frase fluida.

#Evaluar la fiabilidad antes de cualquier uso

La confianza no se decreta. Un estudio publicado en 2025 en npj Digital Medicine midió los errores de modelos de lenguaje en la generación de notas clínicas: en 12.999 frases anotadas por profesionales clínicos, observa un 1,47 % de frases con alucinaciones y un 3,45 % de omisiones; el 44 % de las alucinaciones se consideran graves, es decir, susceptibles de afectar al diagnóstico o a la atención clínica si no se corrigen. Estas cifras corresponden a otra tarea, con otros modelos: no son las tuyas. Muestran que una tasa de error baja por frase sigue siendo preocupante a escala de un documento.

Una síntesis de treinta líneas con un 1,5 % de error por línea, suponiendo que los errores sean independientes, contiene al menos un error en aproximadamente un tercio de los casos. Es un orden de magnitud pedagógico, no una predicción. De ahí el siguiente protocolo, que reemplaza el criterio «cero errores en 50 historias clínicas»: este criterio no demuestra gran cosa, ya que observar cero errores en 50 historias clínicas es compatible con una tasa real de alrededor del 6 % con un nivel de confianza del 95 % (regla de los tres, 3 dividido por 50).

  1. 01
    Preparar una muestra de expedientes médicos anonimizados
    Selecciona expedientes variados: pacientes con múltiples patologías, numerosos tratamientos, resultados antiguos. Elimina los datos identificativos y los datos innecesarios antes de cualquier uso fuera del ámbito asistencial.
  2. 02
    Encargar la anotación a un médico
    Cada frase de síntesis se clasifica: correcta, imprecisa, omisión, error. Distingue los errores que podrían cambiar una decisión clínica.
  3. 03
    Contar por categorías y por gravedad
    El número de errores graves por expediente importa más que la tasa media. Fija un umbral con el médico responsable antes de comenzar.
  4. 04
    Medir también las omisiones
    Un resumen que omite una alergia o un tratamiento es más peligroso que una frase mal redactada.
  5. 05
    Volver a ejecutar con cada cambio
    Modelo, prompt o formato de exportación: cada modificación exige repetir la evaluación.
!
Sin prescripción asistida
Nunca uses esta herramienta para proponer un tratamiento, una pauta de dosificación o un ajuste. La síntesis es una ayuda para la lectura, y el médico que la valida conserva la responsabilidad sobre ella.

#Puesta en producción: registros, acceso y alcance

Registrar cada generación
Guarda la fecha, la versión del modelo, la lista de hechos proporcionada y la síntesis generada en un espacio protegido: así se puede reconstruir lo que leyó el médico.
Controlar accesos
El servidor de inferencia no debe ser accesible desde el exterior; los discos están cifrados; las cuentas son nominativas.
Mostrar fuentes
La interfaz muestra la síntesis junto con el dato original correspondiente a cada línea. Un médico que puede comprobarlo con un clic realmente lo comprueba.
Limitar el alcance
Empieza por un uso interno en la consulta o en la organización, con un pequeño número de usuarios, antes de cualquier ampliación. Un servicio ofrecido a otras organizaciones cambia tu condición en lo relativo al alojamiento.
Prever que la validación humana quede visible
El profesional firma o valida la síntesis antes de incorporarla al expediente clínico; de lo contrario, no debe incluirse en él.
FAQ
¿Se puede resumir un expediente médico con un LLM local?+
Sí, técnicamente, extrayendo primero los datos estructurados mediante código y encargando la redacción de la síntesis a partir únicamente de esos hechos. También hay que comprobar la síntesis mediante un programa, hacer que un médico la valide y evaluar el sistema con expedientes anotados. La ejecución en local resuelve la confidencialidad, no la fiabilidad.
¿El DMP proporciona sus documentos en FHIR?+
Los apartados del marco de interoperabilidad francés describen documentos sanitarios en formato CDA R2, basado en XML, y su transmisión al DMP o a MSSanté. FHIR se utiliza principalmente para los intercambios entre aplicaciones. Verifica qué exporta tu software, ya que tu pipeline depende de ese formato, no de la fuente original.
¿Se necesita un proveedor de alojamiento certificado HDS para una herramienta interna en la consulta?+
No necesariamente: según la ANS citada por Relyens, la certificación no es obligatoria cuando la entidad almacena únicamente los datos de sus propios pacientes. Sí se vuelve obligatoria si alojas datos por cuenta de terceros. Pide a un asesor o a tu delegado de protección de datos que confirme tu caso concreto.
¿Qué modelo local elegir para textos médicos?+
Dos puntos de partida: Qwen 3.5 9B (6,6 GB, 256 000 tokens anunciados) en una tarjeta de 8 GB, o Mistral Small 24B (14 GB) con más memoria. Ninguno ha sido validado clínicamente. Elige comparando sus síntesis de tus expedientes, anotadas por un médico, y realiza un seguimiento especialmente de las omisiones y los errores graves.
¿Puede un LLM inventar un resultado de un análisis clínico?+
Sí: los estudios sobre la generación de notas clínicas observan alucinaciones, una proporción importante de las cuales se considera grave. Por eso, el pipeline exige una referencia por línea, verifica que cada número de la síntesis figure en los hechos de origen y señala al médico lo que sigue siendo dudoso. La validación humana sigue siendo indispensable.
¿Es este tipo de herramienta un dispositivo médico?+
Depende de su finalidad declarada. Una ayuda para leer historiales médicos, validada por el médico, no es una herramienta que proponga un diagnóstico o un tratamiento, y la normativa no se le aplica de la misma manera. Haz que un especialista en normativa determine la clasificación de tu herramienta antes de cualquier despliegue que vaya más allá del uso interno.
¿Esta guía te ha ayudado?

¿Un comentario, un error, una precisión? Avísanos, eso mejora la guía para todos.