openIMIS-AI - 6. Specification

Summary

Claim AI-based Adjudication System

In the Claim-AI project, we are covering the following use cases.

@startuml
left to right direction

skinparam rectangle {
BackgroundColor<< Claim-AI >> DarkSeaGreen
BorderColor<< Claim-AI >> DarkSlateGray
}

actor ClaimAdmin as CA
actor MedicalOfficer as MO
actor DataScientist as DS

rectangle "Claim Module Scope" {
usecase "Search Claims" as CM0
usecase "Enter Claims" as CM1
usecase "Submit Claims" as CM2
usecase "Review Claims" as CM3
}

rectangle "Claim-AI Modules Scope" << Claim-AI >>{
usecase "Prepare Claims for AI" as AI1
usecase "Report Misclassifications" as AI4
usecase "Search Claims per \nMedical Items/Services\nHide non AI-categorized Claims" as AI5
usecase "Adjudicate Claims with AI" as AI6
usecase "Develop AI Model" as AI7
}

CA --> CM1
CA --> CM2
CA --> CM0
MO --> CM3
MO --> AI5

(CM2) <.. (AI1) : extends
(CM0) <.. (AI5) : extends
(CM2) .> (CM1) : depends
(CM3) .> (CM2) : depends

(AI6) .> (AI1) : depends
(CM3) .> (AI6) : depends
(AI4) .> (CM3) : depends
(AI6) .> (AI7) : depends

AI4 <-- DS
AI7 <-- DS

@enduml

The aim is to develop the Claim-AI module, which satisfy the Adjudicate Claims with AI use case, and Claim-AI Quality Module that will satisfy the other three use cases and manage the integration of the openIMIS instance with the Claim-AI module that will run independently.

AI-based Claim Adjudication Process

The following activity diagram specifies the Claim adjudication process update integrating the Claim-AI modules.

@startuml

|Claim Module|

start
if () then

:Enter Claim;
:Receive <<DjangoMutation>> SubmitClaimMutation <
partition "Rule Engine Check" {
:Rule Engine Check;
#red:Sent <<signal_mutation_module_after_mutating>>
SubmitClaimsMutation >
}

partition "MO Manual Adjudication/Validation" {
if (SelectedForReview Claims available?) is (No) then
:Select Claims for Review;
else (Yes)
endif
while (ForEach SelectedForReview Claim)
:Get SelectedForReview Claim;
if (Valid AI Adjudication?) is (No) then
:Correct/Fix Claim Adjudication;
else (Yes)
endif
:Valuate Claim;
endwhile
}

stop
break

|#lightpink|Claim-AI Quality Module|
else
if () then
if () then
#red:Receive <<signal_mutation_module_after_mutating>>
SubmitClaimsMutation <

partition "Prepare Claims for AI-Check" {
while (For Each Submitted Claim)
:Get Checked Claim from DB;
if (Claim Rejected?) is (Yes) then

else (No)
:Add Claim.json_ext.claim_ai_quality
was_categorized=false to avoid review by MO;
endif
endwhile
}

if (Event-based activation?) is (No) then
stop
break

else (Yes)

endif

else (Scheduled task activation)
#HotPink:Receive <<DjangoSchedulerStart>> Adjudicate New Claims
Scheduled task triggered automatically <

endif

partition "Build FHIR-Claim Bundle" {
while (For Each Claim with was_categorized==false)
:Remove Rejected Items from Claim;
:Convert Claim to FHIR Claim\nwith Contained Resources;
:Add FHIR Claim to Bundle;
endwhile
}

#lightgreen:Sent FHIR Claim Bundle >

if () then
#lightgray:Receive ClaimValidationError <
else
#yellow:Receive FHIR ClaimResponse Bundle <
:Convert FHIR ClaimResponse to Claim;
endif

partition "Update Claim"{
:Update Claim was_categorized=true;
:Add/Set in ClaimItem/ClaimService
json_ext.claim_ai_quality.ai_result;
if (Items Rejected?) is (Yes) then
:Set Claim.ReviewStatus to SelectedForReview;
else (No)
endif
:Update Claim in DB;
}

:Send <<Signal>> ClaimAIChecked
(to be validated) >

stop
break

|#lightblue|Claim-AI Module|
else

#lightgreen:Receive FHIR Claim Bundle <
if (Valid FHIR Claim Bundle?) is (No) then
#lightgray:Send ClaimValidationError >
stop
break
else (Yes)
endif

partition Preprocessing {
:Convert FHIR Claim Bndle to AIInputModel;
:Sanity Check;
:Categorical to numerical conversion;
:Normalization;
}

:AI Model Execution;

partition "Build ClaimResponse" {
:Build ClaimResponse;
if (ClaimItem Rejected?) is (No) then
:Set item.adjudication.category to 0;
else (Yes)
:Set item.adjudication.category to 1;
endif
}

#yellow:Send ClaimResponse Bundle >
stop
break

@enduml

Claim-AI Module

Claim-AI Responsibilities

  • WebSocket API accepting FHIR Claim Bundle and responding with FHIR ClaimRespose

  • Categorize Claims based on a ML model

WebSocked API

The Claim-AI module will implement a WebSocked API (WebSocket vs REST article).

WebSocket API connection

This endpoint allows the client to connect to the WebSocket and sent the FHIR Claim Bundle to be adjudicated.

ws://<server_IP>/claim_ai

The connection to the WebSocket API is persistent and needs to be closed by the client. In case multiple clients connect to the WS, a new connection is created for each client.

Authentication

The client authentication is based on authentication key defined in the module configuration. This key represents a list of strings that is empty by default (= no authentication required). If the list contains at least one API key (string), the authentication is activated and the client needs to provide an API key that matches one of the strings from the list.

Communication protocol

The WS API accepts FHIR R4 Claim Bundle with Contained Resources and responds with FHIR R4 ClaimResponse Bundle.

The FHIR R4 Claim and ClaimResponse is part of the openIMIS FHIR R4 Profile that defines the mapping of standard FHIR R4 resources with additional extensions.

The communication is asynchronous. If the Client sends the Claim Bundles paginated/grouped, all Claim Bundles are added to a queue which, once treated, will send back the same grouped Claims as ClaimResponse. The update on the Client side will be done based on the Claim’s UUID.

To allow more claims to be send in one request, the payload can be compressed using ZIP. This will be activated based on the zip Module Configuration key. This option should be available on the Client too.

The communication protocol between the Client (Claim-AI Quality Module) and the server (Claim-AI Module) is described in the following sequence diagram.

@startuml

box "openIMIS Instance" #lightpink
participant "FHIR Module" as FHIR
participant "Claim-AI Quality Module" as Quality
end box

box "Claim-AI Instance" #lightblue
participant "Claim-AI Module" as AI
participant "FHIR Module" as FHIR_AI
end box

autonumber

[-> Quality: Scheduled/Event signal
activate Quality

Quality->AI: WebSocket Connect
activate AI

Quality->FHIR: Build FHIR Claim Bundle
activate FHIR
return FHIR Claim Bundle\nwith Contained Resources

Quality->AI: Send FHIR Claim Bundle\nwith Contained Resources

AI->AI: Validate FHIR Claim Bundle

alt FHIR Claim Bundle valid

AI->AI: Add FHIR Claim\nBundle to Queue
AI->Quality: ClaimBundle Accepted

else FHIR Claim Bundle not valid

AI->Quality: ClaimValidationError

end

AI->AI: Process FHIR Claim Bundle

AI->FHIR_AI: Build FHIR ClaimResponse Bundle
activate FHIR_AI
return FHIR ClaimResponse Bundle

AI->Quality: Send FHIR ClaimResponse Bundle
Quality->AI: FHIR ClaimResponse Bundle Received

Quality->AI: WebSocket Disconnect
deactivate AI

Quality->Quality: Update ClaimResponses status

Quality->FHIR: Save FHIR ClaimResponse Bundle
activate FHIR
return FHIR ClaimResponse Bundle Saved

deactivate Quality

@enduml

Claim data preparation

As explained in page, not all Claim data/fields is used for the AI Model generation. The remaining Moreover, this Claim data needs to go through a preparation process that includes conversion to AI input model, sanity check, categorical to numerical conversion and normalization. This process is the same used in data preparation for AI Algorithm execution and will be copied.

The AI input model is represented by a matrix having on each row one Medical Item/Service from a Claim. If the FHIR Claim Bundle contains multiple Claims then the AI input model will contain all Items/Services from all Claims. Each row contains the following informations (either FHIR Medical OR ActivityDefinition, representing an Item in FHIR Claim):

identifier (ItemUUID)

identifier (ServiceUUID)

identifier (ClaimUUID)

identifier (InsureeUUID, CHFID)

identifier (HfUUID)

extension.unitPrice

unitPrice

billablePeriod (start, end)

birthDate (to calculate age)

location (HFLocationUUID)

frequency

frequency

created

gender

category

extension.useContext (ItemPatCat)

useContext (ServicePatCat)

type

extension.isHead

type

type (always “Medication”)

type (always “ActivityDefinition”)

item.quantity

extension.povertyStatus

 

 

 

item.unitPrice

extension.locationCode (LocationUUID)

 

 

 

diagnosis.diagnosisReference (for icd_0 get ICDID)

extension.group (FamilyUUID)

 

 

 

diagnosis.diagnosisReference (for icd_1 get ICDID)

 

 

 

 

enterer (ClaimAdminUUID)

 

 

As in FHIR Claim each Item represents either Medication or ActivityDefinition, each row in the AI input model contains only a Medication or ActivityDefinition.

FHIR Contained Resources are used to include in the FHIR Claim resource all necessary information required in the above table.

AI Model execution

The research activities from this project has the objective to identify the appropriate AI/ML algorithm, develop the algorithm based on the data received from Nepal openIMIS implementation and to train and generate the AI Model that will be used in production to categorize new Claims (see also Deployment architecture). The AI Model contains the hyperparameters which are “calculated” based on the input dataset. It will be saved as a file on the server running the Claim-AI implementation.

In this project, the generated AI Model is only valid for Nepal openIMIS implementation. Any usage in other context/implementation will give wrong categorization responses. For other context/implementation, the retraining of the AI Model, based on already categorized Claims, is mandatory.

Several data files are to be loaded and saved during the AI Model execution:

  • encoded fields data file

  • scalling file

  • AI model file

The AI Model file name with full path (or relative path) is configured in the modules configuration key ai_model_file. Each time the model is executed, the model file is loaded, allowing to change the filename on execution in the configuration (hot-reload).

For the execution, the selected AI methods will be used.

Build FHIR ClaimResponse

The response of the API is a ClaimResponse with the adjudication results generated by the AI Model execution. In addition to FHIR Claim resource, the FHIR ClaimResponse resource contains the adjudication entry for each item in the Claim. The following structure is defined for the adjudication entry:

{ "resourceType": "Bundle", "entry": [ { "fullUrl": "http://localhost:8001/api_fhir_r4/ClaimResponse/UUID", // Same UUID as Claim.id "resource": { "resourceType": "ClaimResponse", "status": string, // Same as Claim.status "type": { "text": string // Same as Claim.type }, "use": "claim", // Same as Claim.use "patient": { "reference": "Patient/UUID" // Same as Claim.patient }, "created": shortdate, // Current Date "insurer": { "reference": "Organization/openIMIS-Claim-AI" // Value of "claim_response_organization" field from module configuration. Default: openIMIS-Claim-AI }, "id": string, // Same as Claim.id "request": { "reference": "Claim/UUID", // Same UUID as Claim.id }, "outcome": "complete", // Always as "complete" "item": [ // One Item per Item and Service { "itemSequence": integer, // Increment number "adjudication": [ { "category": { "coding": [ { "code": "-2" // Always as "-2" (Rejected by AI Model) } ], "text": string // Always as "AI" }, "reason": { "coding": [ { "code": string // result from the AI Model execution - "0": Accepted, "1": Rejected } ], "text": string // Description of the result as "accepted" or "rejected" }, "amount": { "currency": string, // Default currency defined in the Core module configuration "value": float // Same as Claim.item.unitPrice }, "value": float // Same as Claim.item.quantity } ], "extension": [ { "url": string, // Based on Item type: "Medication" or "ActivityDefinition" "valueReference": { "reference": "ItemType/UUID" // Reference to either Medication or ActivityDefinition. Same as Claim.item.extension. } } ], } ] } } ] }
{ "resourceType": "Bundle", "entry": [ { "fullUrl": "http://localhost:8001/api_fhir_r4/ClaimResponse/FCD34CB1-2630-4E21-88EE-C38521C09F0D", "resource": { "resourceType": "ClaimResponse", "status": "Not Selected", "type": { "text": "O" }, "use": "claim", "patient": { "reference": "Patient/39418469-FC67-4363-BB51-B59B19FDBB47" }, "created": "2021-01-18", "insurer": { "reference": "Organization/openIMIS-Claim-AI" }, "id": "FCD34CB1-2630-4E21-88EE-C38521C09F0D", "request": { "reference": "Claim/FCD34CB1-2630-4E21-88EE-C38521C09F0D", }, "outcome": "complete", "item": [ { "itemSequence": 1, "adjudication": [ { "category": { "coding": [ { "code": "-2" } ], "text": string }, "reason": { "coding": [ { "code": "0" } ], "text": "accepted" }, "amount": { "currency": "$", "value": 80.0 }, "value": 1.0 } ], "extension": [ { "url": "ActivityDefinition", "valueReference": { "reference": "ActivityDefinition/3B4193F7-37EA-4B6E-BD5E-87F08752526A" } } ], } ] } } ] }

 

Module Configuration

The following module configuration is defined:

Each configuration key usage is explained in previous sections.

Claim-AI Quality Module

Claim-AI Quality Responsibilities

  • Contribute to Claim Review Search with Medical Item/Service and AI-categorized filters

  • Prepare the new checked claims for AI categorisation

  • Push Claims to Claim-AI module on scheduled task and/or event-based activation and update Claims based on the response

  • Reports Claim adjudication misclassifications

Claim-AI Adjudication Activation Methods

Two activation methods, allowing to start the Claim-AI module processing, are available in the Claim-AI Quality module.

Event-based activation

This activation is based on the openIMIS mutation signal signal_mutation_module_after_mutating on SubmitClaimMutation mutation (red AcceptSignalAction in AI-based Claim Adjudication Process). First, this event allows to prepare the Claims for the Claim-AI adjudication processing. Second, it would allow to push the Claims to Claim-AI module for the actual adjudication. Because we are interested to activate the processing using this event, we propose to define the module configuration variable event_based_activation, allowing to push the checked Claims immediately after Rule Engine check.

The event-based activation allows a continuously communication flow between the openIMIS implementation and the Claim-AI implementation.

Schedule Task activation

This activation is using the DjangoScheduler to schedule the sending of Claim to Claim-AI module (pink AcceptSignalAction in AI-based Claim Adjudication Process). Compared to the Event-based activation, this trigger is only pushing the checked Claims (the ones prepared during Event-based activation) to Claim-AI module.

In case the Event-based activation is activated (event_based_activation=True), the triggering of the Schedule Task will not do anything because all the checked Claims have already been sent immediately after the Rule Engine execution.

Claims Preparation

In case the Schedule Task activation is used, the time-lapse from when the Claims are submitted and automatically checked by the Rule Engine and when they are adjudicated by the Claim-AI module can be very long. During this time-lapse, the Medical Officers reviewing manually the Claims should not be allowed to select any checked Claim that was not processed by the Claim-AI module. To realize this mechanism, we are adding additional JSON extension (see Models) and additional filter based on the JSON extension (see Custom Claim Review Search Filters).

Pushing Claims to Claim-AI Module

Connecting to the Claim-AI Instance

Because the communication is done through WebSocket protocol (see WebSocked API section), the Claim-AI Quality module needs first to connect to the Claim-AI module (see Communication protocol section). This connection is persistant and remains opened until all responses are received.

Build FHIR Claim Bundle

The Claim-AI module is accepting FHIR Claim Bundle resource and respond with FHIR ClaimResponse Bundle resource (see WebSocked API). Before calling the Claim-AI API, we are transforming all prepared Claims to FHIR Claim Bundle (see partition Build FHIR-Claim Bundle in AI-based Claim Adjudication Process).

FHIR Contained Resources

FHIR Contained Resources feature allows to integrate the referred resourced. Because AI-model is requiring information from other resources referenced by the Claim, these resources must to be accessible from the Claim sent by Claim-AI Quality module. In case of FHIR Claim, these are Patient, Condition, Medication, HealthcareService, Practitioner, ActivityDefinition. The mechanism to build Claim resource with Contained Resources is developed in the openIMIS FHIR R4 module. In FHIR R4 module, the inclusion of Contained Resources should be possible based on the query variable contained=true/false (default false).

Pagination

Based on se server configuration (mainly the available memory), the total number of new checked Claims (more than 10,000 Claims) and integration of Contained Resources, the number of Claims sent should be limited. This means splitting the checked Claims in groups. The module configuration variable page_limit will allow to define the maximum number of Claims per Claim Bundle.

Getting the ClaimResponse from Claim-AI Module

After the categorisation by the Claim-AI Module, the second sends back the response as ClaimResponse. The ClaimResponse is then converted to Claim and is updated into the DB.

The Build FHIR ClaimResponse section show the different attributes that are modified by the Claim-AI module. Based on the response, the Claim-AI Quality will update the following fields in the DB:

  • Claim.ReviewStatus: updated to “Selected for Review” (value 4) if the ClaimResponse contains rejected items

  • ClaimItem.Status/ClaimService.Status: updated to “rejected” (value 2) for each ClaimResponse.item where adjudication.category equal to 1

  • ClaimItem.RejectionReason/ClaimService.RejectionReason: updated to “rejected by AI” (value -2) for each ClaimResponse.item where adjudication.category equal to 1

  • json_ext.claim_ai_quality.was_categorized: updated to True

  • json_ext.claim_ai_quality.ai_result: updated to ClaimResponse.item.adjudication.category + 1 (DB values 1-Accepted, 2-Rejected)

The following state diagram corresponds to the Claim fields status with the updated adjudication process.

To ease the conversion from FHIR ClaimResponse to openIMIS Claim and saving into the DB, we have implemented the HTTP PUT method for ClaimResponse resource into openIMIS FHIR R4 Module.

Models

The new Claim-AI adjudication process is executed between Rule-based engine and the manual adjudication (see Getting the ClaimResponse from Claim-AI Module section). Because we decided not to add additional statuses to Claim, requiring to modify the Claim module, we will to use the JSON extensions that can be added and updated from the Claim-AI Quality module.

The following JSON extensions will be created to support the Claim AI-based Categorisation:

  • to add information on Claim. The field was_categorized allow to filter automatically checked Claim that have not been categorized by AI and ‘hide’ them for manual adjudication.

  • to add information on ClaimItem and ClaimService. This is used to store AI categorisation result to allow the misclassification report.

Because currently ClaimItem and ClaimService doesn’t support custom fields, these classes will also extend the ExtendableModel class.

Migrations

Because the Claim-AI modules are activated after Claims have been adjudicated (the data used for the training), a migration script needs to be created to insert the JSON fields into the available data. The following initializations will be used:

If Claim.ClaimStatus == Entered (Value 2) Then don’t add Claim.json_ext.claim_ai_quality

If Claim.ClaimStatus == Checked (Value 4) Then add

If Claim.ClaimStatus == Rejected (Value 1) Then add

If Claim.ClaimStatus in [Reviewed/Processed (Value 8), Valuated (Value 16)] Then add

Module Configuration

The following module configuration is accepted:

Custom Claim Review Search Filters - Frontend

The following contributor filters to claim.ReviewsFilter are defined:

  • ClaimFilterMedicalItem allows Medical Officers to filter the Claims list based on a specific Medical Item (only one from autocomplete list)

  • ClaimFilterMedicalService allows Medical Officers to filter the Claims list based on a specific Medical Service (only one from autocomplete list)

  • ClaimFilterAIProcessed allows Medical Officers to display or hide the non AI-processed Claims (dropdown with options: Show all, AI-Categorized Claim Only, Not AI-Categorized Claims Only, default AI-Categorized Claim Only)

Custom Claim Review Search Results - Frontend

The following column will be added to the claim.Searcher result list:

  • ClaimResultsAIProcessed will display the value of Claim.json_ext.claim_ai_quality.was_categorized as True/False.

AI Categorisation Misclassification Report

A PDF report is generated that provides the following information (output based on manual reviewed Claims):

  • total number of Claims

  • accuracy score ( Accuracy = (TP+TN)/(TP+TN+FP+FN) )

  • number of True Positives results

  • number of True Negative results

  • number of False Positive results

  • number of False Negative results

  • Table with Claim that were fixed (ClaimItem.json_ext.claim_ai_quality.ai_result != ClaimItem.ClaimItemStatus - same for ClaimService)

    • same format as Claim Overview report with Scope as ‘Claim and All Details’

    • For each Item and Service will be added:

      • json_ext.claim_ai_quality.ai_result column

      • Medical Officer name from AuditUserIDReview (same as for ClaimAdmin)

To generate this report, the user will have have to filter through the Review Claims search form and trigger the report through a button (label is “AI Misclassification Report”). Only the filtered Claims will be considered for the report.

The button should be hidden if ClaimStatus is Entered or Checked.

Deployment architecture

The two modules should be implemented as follow:

  • Claim-AI Quality module (FE and BE) should be activated on the openIMIS instance managing the full Health Financing processes, especially the Claim adjudication. This module is dependent on other modules like Claim and FHIR R4 modules.

  • Claim-AI module (only BE) should be activated on a different instance of openIMIS. However, depending on the server resources, it could be possible to activate on the same openIMIS instance managing the full Health Financing processes.

  • The Claim-AI ML Algorithm is executed only when new training is required and could be done offline.

Testing

Testing the WebSocket from JavaScript console

The following JavaScript code could be executed from your browser developer tools console.

 

Did you encounter a problem or do you have a suggestion?

Please contact our Service Desk



This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License. https://creativecommons.org/licenses/by-sa/4.0/