Un sistema di supporto alle decisioni cliniche, visto dal lato del software, è un motore a regole più un aggancio ai dati del paziente. Il motore — la parte che valuta le condizioni e ricava le conclusioni — è un problema che decenni di lavoro sui sistemi di produzione hanno già chiuso; l’aggancio ai dati è il punto su cui la standardizzazione clinica si è arenata più volte. Provo a tenere separati i due livelli prendendo come riferimento un motore che con la sanità non c’entra nulla: Drools 4.0, uscito il 25 luglio 2007.
Contesto
I formalismi nati dentro la sanità per scrivere logica clinica — Arden Syntax (standard HL7/ASTM), GELLO, GLIF, PROforma — hanno prodotto specifiche solide sul piano tecnico ma con una diffusione operativa modesta. Arden Syntax scrive le regole come Medical Logic Module (MLM) e da quindici anni si porta dietro un difetto noto come curly braces problem: i riferimenti ai dati clinici locali stanno dentro parentesi graffe { } e la sintassi che li interroga la decide il singolo sistema cartella, quindi non sono portabili. Un MLM scritto per un ospedale non gira altrove se prima non si riscrive il contenuto delle graffe. GELLO, linguaggio di espressione e interrogazione a oggetti, nasce anche per questo: fissare un modello di dati comune su cui scrivere le condizioni. Resta però un linguaggio con pochissime implementazioni in produzione.
L’industria IT generalista, intanto, ha costruito motori a regole indifferenti al dominio, con basi d’utenza larghe e strumenti maturi. Sulla JVM il più diffuso in ambito Open Source è Drools, avviato da Bob McWhirter nel 2001, accolto dalla comunità JBoss nel 2005 e finito in Red Hat con l’acquisizione di JBoss del 2006. La domanda concreta è se un motore generalista copra il livello “motore” di un sistema clinico meglio dei formalismi nati apposta.
Architettura
Drools tiene i fatti e le regole ben separati. I fatti sono semplici oggetti Java (POJO, Plain Old Java Object) che l’applicazione chiamante inietta in una working memory; le regole si scrivono in DRL (Drools Rule Language) come coppie condizione-azione. Una regola ha questa forma:
rule "warfarin + FANS, rischio emorragico"
when
$p : Paziente()
$w : FarmacoAttivo(principio == "warfarin", paziente == $p)
$f : FarmacoAttivo(classe == "FANS", paziente == $p)
then
insert(new Avviso($p, "Interazione: anticoagulante + FANS", Livello.ALTO));
end
Il blocco when è la Left-Hand Side: una sequenza di pattern che il motore prova a unificare contro i fatti in memoria. Il blocco then è la Right-Hand Side: le azioni che modificano la working memory o chiamano servizi esterni. L’applicazione carica i fatti, chiama fireAllRules() e raccoglie le conclusioni.
Dentro, Drools applica l’algoritmo Rete, che Charles Forgy ha descritto in un working paper del 1974, nella tesi del 1979 e nel paper formale del 1982 (Rete: A Fast Algorithm for the Many Pattern/Many Object Pattern Match Problem, Artificial Intelligence 19). Rete costruisce una rete di discriminazione fra le condizioni di tutte le regole, dentro cui i fatti vengono propagati e filtrati a piccoli passi. Quando aggiungi o ritiri un fatto non si rivaluta tutto da capo: si tocca solo la porzione di rete interessata dal cambiamento. È questa gradualità a rendere Rete adatto a una working memory che cambia spesso, cioè il caso di una cartella attiva con farmaci che entrano ed escono e referti che arrivano.
Drools 4.0 riscrive l’implementazione di Rete con gli strumenti di contorno, aggiunge elementi condizionali (from, predisposto per sorgenti Hibernate, più collect, accumulate, forall), un meccanismo DSL per costruire sopra a DRL una sintassi più vicina al linguaggio di dominio, le decision table su foglio di calcolo e un BRMS web (poi Guvnor) per scrivere le regole in modo collaborativo. La licenza è Apache 2.0.
Il punto critico
Il livello “motore” è coperto. Quello che resta scoperto è il binding ai dati, e Drools lo butta interamente fuori dal proprio perimetro: i fatti sono POJO qualsiasi, quindi tocca all’applicazione tradurre i dati di cartella in oggetti Java prima di iniettarli. Drools non impone nessun modello clinico.
È il curly braces problem sotto un’altra veste. Arden lascia il binding implicito dentro le graffe; Drools lo lascia esplicito ma vuoto, da riempire con codice di adapter. In tutti e due i casi il pezzo che decide se una libreria di regole è portabile — il modello di dati su cui le regole sono scritte — non lo dà il motore. Due ospedali che adottano Drools con due modelli di fatti diversi non possono scambiarsi le regole, proprio come due MLM Arden con interrogazioni diverse dentro le graffe.
La strada per chiudere il problema non passa dal motore ma da un modello di dati comune da iniettare come fatti. Le discussioni in corso indicano l’HL7 virtual Medical Record (vMR) come candidato: un insieme di oggetti standard — anagrafica, farmaci attivi, problemi, esiti di laboratorio — che un adapter riempie a partire dalla cartella e che le regole danno per acquisito. Le regole diventano portabili nella misura in cui sono scritte contro il vMR e non contro le entity locali. È uno sforzo di standardizzazione del dato, non del motore.
Implicazioni
Tenere separati i due livelli ha conseguenze pratiche. Il motore di esecuzione smette di essere un problema di ricerca clinica e torna a essere una scelta ingegneristica con i criteri di sempre: prestazioni, licenza, ecosistema. Rete su Drools regge migliaia di regole su working memory da decine di migliaia di fatti; la licenza Apache 2.0 lascia incorporare il motore in prodotti che dovranno qualificarsi come dispositivi medici, con il lavoro regolatorio che ne deriva; l’integrazione con stack Java enterprise è diretta. Sono affermazioni che si possono verificare, non promesse.
Alcune linee di adozione sperimentale si accordano bene con questa separazione: valutare in automatico i criteri di inclusione ed esclusione di un trial al momento dell’arruolamento; controllare le interazioni farmaco-farmaco alla prescrizione; far scattare promemoria temporali su screening e follow-up; verificare l’aderenza ai percorsi diagnostico-terapeutici per le patologie croniche. In alcuni progetti accademici Drools non fa da linguaggio clinico ma da motore che esegue modelli più astratti (GLIF, PROforma) compilati verso regole: il motore generalista sta sotto al formalismo clinico, non al suo posto.
Limiti
La separazione ha un prezzo. Il modello a fatti POJO è espressivo ma non sa nulla di clinica: niente in Drools sa cosa sia un farmaco o una diagnosi, e tutta la terminologia (codifiche, unità, intervalli di riferimento) finisce nel codice che costruisce i fatti. Il curly braces problem è spostato, non risolto: senza un vMR davvero adottato, ogni progetto si ricostruisce il proprio modello e le librerie di regole non circolano. Quello che manca di più nell’ecosistema CDS non è il motore ma una libreria di regole cliniche condivisa e mantenuta, e nessun motore la produce da solo. L’autoring DRL, infine, resta un mestiere da sviluppatore: la DSL e le decision table avvicinano il testo al clinico ma non tolgono il bisogno di qualcuno che ne governi correttezza e ciclo di vita.
Quanto un vMR davvero implementato sposti l’equilibrio è ancora da vedere. Finché il modello di dato è cucito su misura per ogni progetto, Drools risolve la metà facile del problema.
- https://blog.kie.org/2007/07/jboss-drools-4-0-released.html
- https://www.infoq.com/news/2007/08/drools/
- https://en.wikipedia.org/wiki/Rete_algorithm
- https://www.noze.it/insights/drools-regole-clinica/
Immagine di copertina: Albero di decisione disegnato con simboli di diagramma di flusso: rombi di condizione che si diramano in percorsi sì/no verso… — diagramma di IPWAI, CC BY-SA 3.0 — https://commons.wikimedia.org/wiki/File:Decision_tree_using_flow_chart_symbols.jpg