Context-Appropriate Global Health AI
Design, implementation, vendor evaluation, and infrastructure choices for AI in resource-constrained health systems. The material is maintained separately so each operational question has a stable, focused reference.
- Identify the evidence and controls relevant to this decision area
- Distinguish technical performance from operational and population impact
- Apply the included framework without extending claims beyond the cited evidence
Introduction
This focused reference is part of the broader Context-Appropriate Global Health AI overview. It preserves the detailed methods, examples, and exercises while reducing page size and improving direct navigation.
Context-Appropriate AI Design
Principles for Resource-Limited Settings
Effective AI in LMICs requires designing for constraints, not assuming ideal conditions.
1. Offline-First Design
Challenge: Internet connectivity is unreliable or absent in many settings.
Solution: Design AI systems that work offline, syncing when connectivity is available.
import sqlite3
import json
from datetime import datetime
class OfflineAISystem:
"""
Offline-first AI diagnostic system with sync capability
Designed for: Rural health clinics with intermittent connectivity
"""
def __init__(self, local_db_path='local_diagnostics.db'):
self.local_db = sqlite3.connect(local_db_path)
self.setup_local_database()
self.model = self.load_lightweight_model()
def setup_local_database(self):
"""Create local SQLite database for offline operation"""
cursor = self.local_db.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS diagnostics (
id INTEGER PRIMARY KEY AUTOINCREMENT,
patient_id TEXT,
image_path TEXT,
prediction TEXT,
confidence REAL,
timestamp TEXT,
synced INTEGER DEFAULT 0
)
''')
self.local_db.commit()
def load_lightweight_model(self):
"""Load compressed model for resource-limited devices"""
import tensorflow as tf
# Load quantized TFLite model (10-50x smaller)
interpreter = tf.lite.Interpreter(
model_path="malaria_detector_quantized.tflite"
)
interpreter.allocate_tensors()
return interpreter
def diagnose(self, patient_id: str, image_path: str):
"""
Run diagnosis entirely offline
No internet required - model runs on device
"""
# Preprocess image
image = self.preprocess_image(image_path)
# Run inference locally
input_details = self.model.get_input_details()
output_details = self.model.get_output_details()
self.model.set_tensor(input_details[0]['index'], image)
self.model.invoke()
prediction = self.model.get_tensor(output_details[0]['index'])[0]
# Store result locally
result = {
'patient_id': patient_id,
'image_path': image_path,
'prediction': 'Positive' if prediction[0] > 0.5 else 'Negative',
'confidence': float(prediction[0]),
'timestamp': datetime.now().isoformat()
}
self.save_local(result)
return result
def save_local(self, result):
"""Save result to local database"""
cursor = self.local_db.cursor()
cursor.execute('''
INSERT INTO diagnostics
(patient_id, image_path, prediction, confidence, timestamp, synced)
VALUES (?, ?, ?, ?, ?, 0)
''', (
result['patient_id'],
result['image_path'],
result['prediction'],
result['confidence'],
result['timestamp']
))
self.local_db.commit()
def sync_when_online(self, api_endpoint: str):
"""
Sync local results to central server when connectivity available
Designed to handle intermittent connectivity gracefully
"""
import requests
from requests.exceptions import ConnectionError, Timeout
cursor = self.local_db.cursor()
cursor.execute('SELECT * FROM diagnostics WHERE synced = 0')
unsynced_records = cursor.fetchall()
synced_count = 0
for record in unsynced_records:
try:
# Attempt to sync with timeout
response = requests.post(
api_endpoint,
json={
'patient_id': record[1],
'prediction': record[3],
'confidence': record[4],
'timestamp': record[5]
},
timeout=5 # Fail fast if connection is slow
)
if response.status_code == 200:
# Mark as synced
cursor.execute(
'UPDATE diagnostics SET synced = 1 WHERE id = ?',
(record[0],)
)
self.local_db.commit()
synced_count += 1
except (ConnectionError, Timeout):
# Connection failed - continue to next record
# Will retry on next sync attempt
continue
return synced_count
# Usage in rural clinic
system = OfflineAISystem()
# Works without internet
result = system.diagnose(
patient_id='P12345',
image_path='/images/blood_smear_001.jpg'
)
print(f"Diagnosis: {result['prediction']} (confidence: {result['confidence']:.2%})")
# Later, when internet available (even briefly)
try:
synced = system.sync_when_online('https://api.health.gov/diagnostics')
print(f"Synced {synced} records to central database")
except:
print("Sync failed - will retry later")Key design principles: - Local inference - Model runs on device, no internet needed - Local storage - SQLite database stores results - Opportunistic sync - Syncs when connectivity available - Fail gracefully - Continues working if sync fails - Lightweight models - Quantized TFLite models (10-50x smaller)
2. Low-Power Design
Challenge: Unreliable electricity, battery-powered devices.
Solution: Optimize for minimal power consumption.
import tensorflow as tf
import numpy as np
class LowPowerOptimizer:
"""
Optimize AI models for low-power operation
Target: Run on battery-powered tablets or phones in field settings
"""
@staticmethod
def quantize_model(model_path: str, output_path: str):
"""
Int8 quantization can reduce model size and improve inference efficiency.
Measure accuracy, latency, memory, and power on the target hardware.
"""
converter = tf.lite.TFLiteConverter.from_saved_model(model_path)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.target_spec.supported_types = [tf.int8]
tflite_quant_model = converter.convert()
with open(output_path, 'wb') as f:
f.write(tflite_quant_model)
return output_path
@staticmethod
def prune_model(model, target_sparsity=0.5):
"""
Remove 50% of weights with minimal impact on accuracy
Result: 50% less computation, 40-60% less power
"""
import tensorflow_model_optimization as tfmot
# Define pruning schedule
pruning_schedule = tfmot.sparsity.keras.PolynomialDecay(
initial_sparsity=0.0,
final_sparsity=target_sparsity,
begin_step=0,
end_step=1000
)
# Apply pruning
pruned_model = tfmot.sparsity.keras.prune_low_magnitude(
model,
pruning_schedule=pruning_schedule
)
return pruned_model
@staticmethod
def batch_inference(images: list, model, batch_size=1):
"""
Single inference is most power-efficient
Process multiple images? Batch them to amortize overhead
"""
results = []
# Process in small batches to minimize memory
for i in range(0, len(images), batch_size):
batch = images[i:i+batch_size]
batch_array = np.array(batch)
# Single inference call for batch
predictions = model.predict(batch_array)
results.extend(predictions)
return results
@staticmethod
def estimate_battery_life(
model_size_mb: float,
inferences_per_day: int,
battery_capacity_mah: int = 10000
):
"""
Estimate battery life for field device
Args:
model_size_mb: Model size in MB
inferences_per_day: Expected daily usage
battery_capacity_mah: Device battery capacity
Returns:
Estimated days of operation
"""
# Power estimates (rough)
idle_power_mw = 100 # Screen off, background processes
inference_power_mw = 1000 + (model_size_mb * 2) # ~2mW per MB model size
inference_time_sec = 0.1 + (model_size_mb * 0.01) # ~10ms per MB
# Daily power consumption
inference_energy_mwh = (
inference_power_mw * inference_time_sec / 3600 * inferences_per_day
)
idle_energy_mwh = idle_power_mw * 24 # 24 hours
total_daily_mwh = inference_energy_mwh + idle_energy_mwh
# Battery capacity in mWh (assuming 3.7V nominal)
battery_mwh = battery_capacity_mah * 3.7
# Days of operation
days = battery_mwh / total_daily_mwh
return days
# Compare model options
original_model_size = 100 # MB
quantized_model_size = 25 # MB
original_battery = LowPowerOptimizer.estimate_battery_life(
original_model_size,
inferences_per_day=50,
battery_capacity_mah=10000
)
quantized_battery = LowPowerOptimizer.estimate_battery_life(
quantized_model_size,
inferences_per_day=50,
battery_capacity_mah=10000
)
print(f"Original model: {original_battery:.1f} days battery life")
print(f"Quantized model: {quantized_battery:.1f} days battery life")
print(f"Improvement: {quantized_battery - original_battery:.1f} additional days")Output example:
Original model: 3.2 days battery life
Quantized model: 4.8 days battery life
Improvement: 1.6 additional days
Design implications: - Quantization can reduce memory and energy use, but battery effects must be measured on the target device and workload - Model size matters - Smaller models = less power - Batch processing when possible to amortize overhead - Sleep modes between uses to conserve power
Beyond quantization and pruning, two additional techniques enable AI deployment in resource-limited settings:
Knowledge distillation: Train a smaller “student” model to mimic a larger “teacher” model’s predictions. Performance retention depends on the teacher, student, task, data, and evaluation. Measure it on the intended target hardware and population.
Federated learning: Train models across distributed devices without centralizing sensitive data. Each device trains locally and shares only model weight updates (not raw data) with a central server. Critical for privacy-preserving collaboration across health facilities that cannot share patient data. A 2024 systematic review found federated models can achieve similar accuracy to centralized models while providing stronger privacy protections. A 2026 Nature Medicine review extends this logic to infectious disease surveillance and modeling: federated approaches can let outbreak data remain local while analyses run across distributed datasets, but adoption remains limited and depends on governance, standards, and local analytic capacity (Khurana et al., 2026).
These techniques matter for public health because cloud-dependent AI excludes settings with unreliable connectivity. Edge AI runs entirely on local devices, enabling real-time diagnostics without internet access.
3. Robust to Low-Quality Data
Challenge: Data in LMICs often has: - Poor image quality (low-resolution cameras, poor lighting) - Missing values (incomplete records) - Inconsistent formats (lack of standardization) - Limited labeled data (no specialist time for labeling)
Solution: Design models that are robust to data quality issues.
import tensorflow as tf
import numpy as np
class RobustDataHandler:
"""
Handle common data quality issues in LMIC settings
"""
@staticmethod
def augment_for_poor_quality(image):
"""
Augmentation strategy for low-quality images
Train model on artificially degraded images so it handles
poor quality gracefully in deployment
"""
augmentations = tf.keras.Sequential([
# Simulate poor lighting
tf.keras.layers.RandomBrightness(0.3),
tf.keras.layers.RandomContrast(0.3),
# Simulate low resolution
tf.keras.layers.Resizing(64, 64), # Downsample
tf.keras.layers.Resizing(224, 224), # Upsample back
# Simulate blur (camera shake, focus issues)
tf.keras.layers.GaussianNoise(0.1),
# Simulate color variations (different cameras)
tf.keras.layers.Lambda(
lambda x: tf.image.random_hue(x, 0.1)
),
])
return augmentations(image)
@staticmethod
def handle_missing_features(df, strategy='median'):
"""
Robust handling of missing clinical data
Common in settings with:
- Incomplete laboratory testing (cost constraints)
- Paper records (transcription errors)
- Limited diagnostic capacity
"""
import pandas as pd
from sklearn.impute import SimpleImputer
if strategy == 'median':
imputer = SimpleImputer(strategy='median')
elif strategy == 'indicator':
# Create missingness indicators - may be informative
# (e.g., missing lab test → test not available at facility)
imputer = SimpleImputer(strategy='median', add_indicator=True)
imputed = imputer.fit_transform(df)
return imputed
@staticmethod
def few_shot_learning_setup(base_model, n_examples=10):
"""
Learn from very few labeled examples
Scenario: Specialist can only label 10-50 examples
Solution: Transfer learning + few-shot learning
"""
# Freeze base model (pre-trained on large dataset)
base_model.trainable = False
# Add small trainable head
model = tf.keras.Sequential([
base_model,
tf.keras.layers.GlobalAveragePooling2D(),
tf.keras.layers.Dense(128, activation='relu'),
tf.keras.layers.Dropout(0.5), # High dropout for small data
tf.keras.layers.Dense(1, activation='sigmoid')
])
# Use aggressive regularization for small data
model.compile(
optimizer=tf.keras.optimizers.Adam(learning_rate=0.0001),
loss='binary_crossentropy',
metrics=['accuracy']
)
return model
@staticmethod
def semi_supervised_learning(labeled_data, unlabeled_data, model):
"""
Use abundant unlabeled data
Scenario:
- 100 labeled examples (specialist time is scarce)
- 10,000 unlabeled examples (easy to collect)
Solution: Pseudo-labeling / self-training
"""
# Train initial model on labeled data
X_labeled, y_labeled = labeled_data
model.fit(X_labeled, y_labeled, epochs=50, verbose=0)
# Predict on unlabeled data
X_unlabeled = unlabeled_data
pseudo_labels = model.predict(X_unlabeled)
# Keep high-confidence predictions as pseudo-labels
confidence_threshold = 0.9
high_conf_mask = np.max(pseudo_labels, axis=1) > confidence_threshold
X_pseudo = X_unlabeled[high_conf_mask]
y_pseudo = (pseudo_labels[high_conf_mask] > 0.5).astype(int)
# Retrain on labeled + pseudo-labeled data
X_combined = np.vstack([X_labeled, X_pseudo])
y_combined = np.hstack([y_labeled, y_pseudo])
model.fit(X_combined, y_combined, epochs=50, verbose=0)
return model
# Example: Train robust model for malaria detection
# with limited, poor-quality data
# Simulate limited labeled data
n_labeled = 50
X_train_small = X_train[:n_labeled]
y_train_small = y_train[:n_labeled]
# Load pre-trained base model
base_model = tf.keras.applications.MobileNetV2(
input_shape=(224, 224, 3),
include_top=False,
weights='imagenet'
)
# Setup for few-shot learning
handler = RobustDataHandler()
model = handler.few_shot_learning_setup(base_model)
# Add augmentation for robustness to poor quality
train_dataset = tf.data.Dataset.from_tensor_slices(
(X_train_small, y_train_small)
).map(
lambda x, y: (handler.augment_for_poor_quality(x), y)
).batch(8)
# Train with limited data
model.fit(train_dataset, epochs=50)
# Optionally: Use semi-supervised learning with unlabeled data
X_unlabeled = X_train[n_labeled:] # Remaining data without labels
model = handler.semi_supervised_learning(
labeled_data=(X_train_small, y_train_small),
unlabeled_data=X_unlabeled,
model=model
)Key strategies: - Augmentation simulates poor quality during training - Imputation handles missing clinical data - Few-shot learning works with 10-100 labeled examples - Semi-supervised learning uses unlabeled data - Transfer learning from models trained on larger datasets
4. Culturally and Linguistically Appropriate
Challenge: Most AI health systems are designed in English for Western contexts.
Solution: Localize for language, culture, and local health practices.
class LocalizedHealthAI:
"""
AI system adapted for local language and cultural context
"""
def __init__(self, language='en', region='global'):
self.language = language
self.region = region
self.load_local_resources()
def load_local_resources(self):
"""Load language-specific and region-specific resources"""
# Load local language model
if self.language != 'en':
# Use multilingual model or local language model
self.language_model = self.load_multilingual_model()
# Load local disease terminology
self.local_terms = self.load_disease_terminology(self.region)
# Load culturally appropriate guidance
self.cultural_guidance = self.load_cultural_guidelines(self.region)
def load_multilingual_model(self):
"""
Load model that supports local languages
Options:
- mBERT: 104 languages
- XLM-RoBERTa: 100 languages
- AfriClip: African languages
- IndicBERT: Indian languages
"""
from transformers import AutoModelForSequenceClassification, AutoTokenizer
# Example: Multilingual clinical text classifier
model_name = "xlm-roberta-base"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForSequenceClassification.from_pretrained(model_name)
return {'tokenizer': tokenizer, 'model': model}
def load_disease_terminology(self, region):
"""
Map local disease terms to standard terminology
Example: Local names for diseases
- "Malaria" → "Homa" (Swahili), "Paludisme" (French), "Malária" (Portuguese)
- "Tuberculosis" → "Kifua kikuu" (Swahili), "TB" (Global)
"""
terminology_maps = {
'east-africa': {
'homa': 'malaria',
'kifua kikuu': 'tuberculosis',
'kipindupindu': 'cholera',
'ukimwi': 'hiv/aids'
},
'west-africa-french': {
'paludisme': 'malaria',
'tuberculose': 'tuberculosis',
'choléra': 'cholera',
'sida': 'hiv/aids'
},
'south-asia': {
'malaria': 'malaria', # English widely used
'tb': 'tuberculosis',
'hiv': 'hiv/aids'
}
}
return terminology_maps.get(region, {})
def load_cultural_guidelines(self, region):
"""
Culturally appropriate health guidance
Example considerations:
- Gender norms (who makes health decisions?)
- Traditional medicine integration
- Religious considerations
- Dietary restrictions/norms
"""
guidelines = {
'global': {
'gender_sensitivity': 'moderate',
'traditional_medicine': 'acknowledge',
'religious_considerations': 'respect',
},
'south-asia': {
'gender_sensitivity': 'high', # May need male family member involvement
'traditional_medicine': 'integrate', # Ayurveda widely practiced
'religious_considerations': 'dietary_restrictions', # Vegetarian options
},
'middle-east': {
'gender_sensitivity': 'high',
'traditional_medicine': 'acknowledge',
'religious_considerations': 'prayer_times', # Schedule around prayers
}
}
return guidelines.get(region, guidelines['global'])
def translate_symptoms(self, symptoms_text):
"""
Translate symptom description to English for processing
Then translate recommendations back to local language
"""
if self.language == 'en':
return symptoms_text
# Use local language model or translation API
# Example: Google Translate API, Azure Translator, or local model
translated = self.translate_to_english(symptoms_text)
return translated
def generate_recommendation(self, diagnosis, confidence):
"""
Generate culturally appropriate health recommendation
"""
# Base recommendation
recommendation = f"Diagnosis: {diagnosis} (confidence: {confidence:.0%})"
# Add culturally appropriate guidance
if self.cultural_guidance['traditional_medicine'] == 'integrate':
recommendation += "\n\nThis recommendation can complement traditional treatments. Consult both your healthcare provider and traditional healer."
if self.cultural_guidance['gender_sensitivity'] == 'high':
recommendation += "\n\nPlease discuss this with your family before making treatment decisions."
# Translate back to local language
if self.language != 'en':
recommendation = self.translate_from_english(
recommendation,
target_language=self.language
)
return recommendation
# Example: Deploy in rural Kenya (Swahili-speaking, East Africa)
system = LocalizedHealthAI(language='sw', region='east-africa')
# User reports symptoms in Swahili
symptoms_swahili = "Nina homa kali na kichwa kinaniuma"
# Translation: "I have severe fever and headache"
# System processes in local language
symptoms_english = system.translate_symptoms(symptoms_swahili)
diagnosis, confidence = system.diagnose(symptoms_english)
# Generate culturally appropriate recommendation in Swahili
recommendation = system.generate_recommendation(diagnosis, confidence)
print(recommendation)Localization checklist: - Language: Support local languages, not just English - Terminology: Use local disease names and terms - Cultural norms: Respect gender roles, family decision-making - Traditional medicine: Acknowledge and integrate where appropriate - Religious considerations: Respect dietary restrictions, prayer times - Health literacy: Adjust communication complexity to education level
Successful Global Health AI Implementations
Case Study 1: Portable Eye Exam System (India)
Context: India has 8 million blind people from preventable causes. Only 1 ophthalmologist per 100,000 people (WHO recommends 4 per 100,000).
Solution: AI-powered diabetic retinopathy screening system deployed in rural primary care clinics (Gulshan et al., 2016, JAMA).
Key design decisions: - Offline operation - Works without internet - Low-cost hardware - Portable fundus camera (<$5,000 vs $50,000) - Minimal training - Nurses can operate after 1-day training - Immediate results - Diagnosis in 30 seconds - Automated referral - High-risk cases automatically flagged
class RetinopathyScreeningSystem:
"""
Diabetic retinopathy screening for rural India
Based on: Google's DR screening system deployed in Aravind Eye Hospitals
"""
def __init__(self):
self.model = self.load_model()
self.sensitivity_threshold = 0.95 # High sensitivity to avoid missing cases
def screen_patient(self, patient_id, fundus_image):
"""
Screen for diabetic retinopathy
Returns:
- grade: None, Mild, Moderate, Severe, Proliferative
- referral_urgency: Routine, Urgent, Emergency
- confidence: Model confidence
"""
# Preprocess image
image = self.preprocess_fundus_image(fundus_image)
# Predict DR grade
prediction = self.model.predict(image)
grade = self.interpret_prediction(prediction)
# Determine referral urgency
urgency = self.determine_urgency(grade, prediction)
# Log result locally
self.log_screening_result(patient_id, grade, urgency)
return {
'grade': grade,
'referral_urgency': urgency,
'confidence': float(prediction.max()),
'recommendation': self.generate_recommendation(grade, urgency)
}
def determine_urgency(self, grade, prediction):
"""Determine referral urgency based on grade"""
if grade in ['Severe', 'Proliferative']:
return 'Emergency' # Refer within 1 week
elif grade == 'Moderate':
return 'Urgent' # Refer within 1 month
elif grade == 'Mild':
return 'Routine' # Refer within 3 months
else:
return 'None' # Rescreen in 1 year
def generate_recommendation(self, grade, urgency):
"""Generate action plan in local language (Hindi/English)"""
recommendations = {
'Emergency': "तत्काल नेत्र विशेषज्ञ को दिखाएं (Urgent: See eye specialist immediately)",
'Urgent': "एक महीने में नेत्र विशेषज्ञ से मिलें (See eye specialist within 1 month)",
'Routine': "3 महीने में नेत्र विशेषज्ञ से मिलें (See eye specialist within 3 months)",
'None': "एक साल बाद फिर से जांच करवाएं (Rescreen in 1 year)"
}
return recommendations.get(urgency, recommendations['None'])
# Populate these fields only from an evaluation of the exact deployed workflow
evaluation_fields = [
'eligible_population',
'images_graded',
'ungradable_image_rate',
'sensitivity_and_specificity_against_reference_standard',
'referral_completion',
'patient_outcomes',
'resource_use'
]Evidence boundary: The cited JAMA paper evaluated algorithm performance on retinal photographs; it did not establish the deployment counts, cost reduction, or blindness-prevention outcomes shown in the illustrative record. Google has separately reported that its automated retinal-disease assessment system has supported more than 200,000 screenings globally, a vendor-reported deployment count rather than a clinical-outcome estimate (Google, 2024).
Key success factors: 1. Designed for constraints - Works offline, low-cost hardware 2. Task-shifting - Nurses can operate, not just ophthalmologists 3. Integration - Integrated into existing primary care workflow 4. Local partnership - Developed with Aravind Eye Hospitals (local expertise) 5. Continuous improvement - Model updated based on local data
Case Study 2: Chest X-Ray AI (Sub-Saharan Africa)
Context: Tuberculosis remains a major cause of illness and death, and access to expert chest-radiograph interpretation is constrained in many settings.
Solution: AI system for TB screening from chest X-rays, deployed on low-cost portable X-ray machines (Murphy et al., 2020, Scientific Reports).
class TBScreeningSystem:
"""
TB screening from chest X-rays in resource-limited settings
Deployed: Kenya, Uganda, South Africa, Nigeria
"""
def __init__(self, deployment_mode='offline'):
self.model = self.load_quantized_model() # Lightweight for tablets
self.deployment_mode = deployment_mode
def screen_for_tb(self, xray_image, patient_demographics=None):
"""
Screen chest X-ray for TB
Args:
xray_image: Chest X-ray (portable X-ray machine)
patient_demographics: Age, HIV status (high-risk groups)
Returns:
- tb_likelihood: Probability of active TB
- confidence: Model confidence
- recommendation: Next steps
"""
# Preprocess X-ray
image = self.preprocess_xray(xray_image)
# Predict TB likelihood
tb_probability = self.model.predict(image)[0][0]
# Adjust for high-risk populations (e.g., HIV+)
if patient_demographics:
tb_probability = self.adjust_for_risk_factors(
tb_probability,
patient_demographics
)
# Generate recommendation
recommendation = self.generate_recommendation(tb_probability)
return {
'tb_likelihood': float(tb_probability),
'confidence': self.calculate_confidence(tb_probability),
'recommendation': recommendation
}
def adjust_for_risk_factors(self, base_probability, demographics):
"""
Adjust probability for high-risk groups
TB prevalence 20-30x higher in HIV+ populations
"""
risk_multiplier = 1.0
if demographics.get('hiv_positive'):
risk_multiplier *= 1.5 # Increase concern threshold
if demographics.get('age', 0) > 65:
risk_multiplier *= 1.2 # Elderly at higher risk
if demographics.get('previous_tb'):
risk_multiplier *= 1.3 # Previous TB increases risk
return min(base_probability * risk_multiplier, 0.99)
def generate_recommendation(self, tb_probability):
"""Generate action plan"""
if tb_probability > 0.7:
return {
'action': 'Immediate sputum test and clinical evaluation',
'urgency': 'High',
'explanation': 'High likelihood of active TB - requires confirmatory testing'
}
elif tb_probability > 0.4:
return {
'action': 'Sputum test recommended',
'urgency': 'Moderate',
'explanation': 'Possible TB - confirmatory testing needed'
}
else:
return {
'action': 'No immediate action, monitor symptoms',
'urgency': 'Low',
'explanation': 'Low likelihood of active TB'
}
# Deployment hardware fields to verify before procurement
deployment_config = {
'xray_device_and_version': None,
'purchase_and_service_cost': None,
'weight_and_transport_requirements': None,
'power_and_battery_requirements': None,
'compute_device': None,
'model_version': None,
'measured_inference_time': None
}
# Populate performance only from the exact version, threshold, population,
# reference standard, and workflow under evaluation.
performance = NoneEvidence boundary: Murphy and colleagues evaluated CAD4TB version 6 on 5,565 chest radiographs. The paper does not support the multi-country deployment counts, site counts, cost claims, or workload reduction shown in the illustrative record (Murphy et al., 2020).
Innovation: “AI + human” workflow - AI provides immediate preliminary reading - Flagged cases reviewed by radiologist remotely (via phone connectivity when available) - Measure radiologist workload, missed cases, confirmatory-testing demand, and time to treatment in the intended workflow
Case Study 3: Malaria Diagnosis (Southeast Asia)
Context: Microscopy is gold standard for malaria diagnosis but requires trained microscopist (scarce in rural areas). Rapid diagnostic tests (RDTs) less accurate.
Solution: Smartphone-based microscopy with AI analysis (Yang et al., 2020, IEEE J Biomed Health Inform).
class SmartphoneMalariaDetection:
"""
Malaria detection from smartphone microscopy images
Hardware requirements depend on the validated imaging setup
"""
def __init__(self):
self.model = self.load_lightweight_model()
self.quality_checker = self.load_quality_model()
def analyze_blood_smear(self, smartphone_image):
"""
Analyze blood smear image from smartphone microscope
Challenges:
- Variable image quality (lighting, focus)
- Different smartphone cameras
- User variation in slide preparation
"""
# Step 1: Check image quality
quality_score = self.quality_checker.predict(smartphone_image)
if quality_score < 0.6:
return {
'status': 'poor_quality',
'message': 'Please retake image with better focus/lighting',
'guidance': self.image_quality_tips()
}
# Step 2: Detect parasites
parasite_detected = self.model.predict(smartphone_image)
parasite_count = self.count_parasites(smartphone_image)
# Step 3: Calculate parasitemia (parasite density)
parasitemia = self.calculate_parasitemia(parasite_count)
# Step 4: Generate diagnosis
diagnosis = self.generate_diagnosis(parasite_detected, parasitemia)
return diagnosis
def calculate_parasitemia(self, parasite_count, rbc_count=5000):
"""
Calculate parasite density per μL
WHO classification:
- <1%: Low
- 1-5%: Moderate
- >5%: Severe
"""
parasitemia_percent = (parasite_count / rbc_count) * 100
return parasitemia_percent
def generate_diagnosis(self, parasite_detected, parasitemia):
"""Generate diagnosis and treatment recommendation"""
if not parasite_detected:
return {
'diagnosis': 'Negative',
'severity': None,
'treatment': 'No antimalarial treatment needed',
'follow_up': 'If symptoms persist, repeat test in 24 hours'
}
# Classify severity
if parasitemia > 5:
severity = 'Severe'
treatment = 'URGENT: IV artesunate, hospitalization required'
elif parasitemia > 1:
severity = 'Moderate'
treatment = 'Oral artemisinin-based combination therapy (ACT)'
else:
severity = 'Mild'
treatment = 'Oral artemisinin-based combination therapy (ACT)'
return {
'diagnosis': 'Positive',
'severity': severity,
'parasitemia': f'{parasitemia:.2f}%',
'treatment': treatment,
'follow_up': 'Repeat test on day 3 to confirm parasite clearance'
}
def image_quality_tips(self):
"""Provide guidance for better image quality"""
return """
Tips for better images:
1. Clean the smartphone camera lens
2. Ensure good lighting (use phone flashlight if needed)
3. Hold phone steady (use stand if available)
4. Focus on thin area of blood smear
5. Take multiple images from different areas
"""
# Hardware requirements to verify for the intended device and workflow
hardware = {
'microscope_attachment_and_version': None,
'validated_phone_and_camera': None,
'purchase_and_service_cost': None,
'weight': None,
'power': None,
'maintenance_and_quality_control': None
}
# Populate only from a field evaluation of the exact device and comparator
field_results = NoneEvidence boundary: The cited paper supports an image-analysis method, not the four-country deployment, worker-training, testing-volume, speed, or cost outcomes shown in the illustrative record. Populate these fields only from a field study of the exact device, workflow, and comparator.
Key innovation: Quality control - AI checks image quality before analysis - Provides real-time feedback to improve image capture - Reduces false results from poor-quality images
Case Study 4: SMS-Based Disease Surveillance (Uganda mTRAC)
Context: Uganda developed mTRAC to strengthen routine health-facility reporting and feedback using basic mobile phones.
Solution: mTRAC is an SMS-based reporting system integrated with DHIS2 and preset threshold alerts (UNICEF Uganda). It is enabling digital infrastructure, not evidence of an AI deployment.
How it Works:
- Weekly SMS Reports: Health workers send standardized SMS with disease counts
- Example:
DIAR 15 MAL 23 PNE 3(Diarrhea 15 cases, Malaria 23, Pneumonia 3) - Works on basic feature phones (not smartphones)
- No internet required (SMS via 2G network)
- Automated Data Processing:
- Structured SMS formats capture case counts
- Validates data (flags impossible values, missing reports)
- Aggregates to district/national levels in real-time
- Automated Outbreak Detection:
- Compares current cases to historical baselines
- Flags anomalies (statistical outliers)
- Prioritizes alerts by severity and confidence
- Sends alerts to district health teams within hours
- Feedback Loop:
- Health workers receive confirmation SMS
- District teams get weekly summary reports
- System prompts non-reporters automatically
Deployment Scale: UNICEF reported 4,431 facilities, more than 62,000 registered health workers, and nearly 80% complete and on-time weekly reporting in the second quarter of 2016 (UNICEF Uganda).
Monitoring record:
# Use verified program records for the specified period and denominator
monitoring_fields = [
'facilities_expected_to_report',
'facilities_reporting_completely_and_on_time',
'message_delivery_failures',
'data_quality_exceptions',
'alerts_generated_and_investigated',
'time_from_alert_to_action',
'program_and_facility_costs'
]Why This Succeeded:
- Context-Appropriate Technology:
- SMS works on basic phones (no smartphone needed)
- Functions with 2G networks (reliable even in rural areas)
- Minimal training required (standardized format)
- Offline-capable (SMS queues when no signal)
- Simple, Sustainable:
- Uses a standardized reporting format
- Can be integrated with national information systems
- Requires local operational ownership and support
- Integrated with existing workflows (weekly reporting)
- Government Ownership:
- Uganda Ministry of Health owns system
- Hosted on government servers
- Ugandan team provides support
- Sustainable beyond donor funding
- Evidence of Impact:
- UNICEF reports the program’s facility and health-worker reach and its 2016 reporting completeness and timeliness
- The cited source does not establish causal effects on outbreak detection, costs, or health outcomes
- Transfers to other countries or reporting domains require separate verification
Lessons for Other LMICs:
- Start simple: SMS before apps, basic phones before smartphones
- Build on existing: Weekly reporting already routine, just digitized process
- Government ownership: Sustainability requires local control and capacity
- Demonstrate value: Early wins (outbreak detection) secured long-term support
- Plan for scale: Designed for national deployment from start, not pilot projects
Expansion Beyond Disease Surveillance: - Stock-out reporting (medicines, vaccines) - Birth and death registration - Maternal health monitoring - Community health worker supervision - Supply chain logistics
Key Innovation: The alerting component uses preset thresholds rather than a documented machine-learning model. This supports: - Transparent (health teams understand how alerts generated) - Maintainable (local IT teams can update thresholds) - Reliable (does not fail due to model drift or data shifts) - Trustworthy (health workers trust what they understand)
Advantages Over Smartphone Apps: - Broad device compatibility - Basic phones can support structured reporting without requiring smartphones - Lower hardware requirements - Existing feature phones may avoid a smartphone procurement requirement - Reliable - 2G SMS works where 3G/4G internet unreliable - Familiar - Health workers already use SMS, minimal learning curve - Battery efficient - Feature phones last days/weeks vs hours for smartphone apps - Maintainable - Simpler technology, local teams can support
When to Use SMS vs Apps: - SMS - Structured reporting, high coverage priority, infrastructure limited - Apps - Complex data, multimedia needed, smartphone penetration high
The best technology is the one that actually works in your context, not the most sophisticated.
Case Study 5: Open-Source NLP for Clinical Note Surveillance (Brazil)
Context: Brazil’s Unified Health System (SUS) generates millions of unstructured free-text clinical notes annually. Critical public health signals, including underreported conditions such as gender-based violence, remain buried in narrative text that traditional surveillance systems cannot process.
Solution: Vital Strategies’ Brazil team deployed open-source NLP to convert unstructured clinical notes into structured surveillance data within SUS (Vital Strategies, February 2026; WHO & IndiaAI, AI Health Casebook, 2026).
How It Works:
- NLP extraction: Open-source language models parse free-text clinical notes, identifying diagnoses, risk factors, and social determinants not captured in structured fields
- Structured output: Extracted data is mapped to standardized public health categories, enabling integration with existing surveillance pipelines
- Surveillance enrichment: Conditions typically underreported in structured data (notably gender-based violence) surface through narrative text analysis
Scale:
- 39 million clinical notes processed in the pilot phase
- Deployed within Brazil’s existing public health infrastructure (SUS)
- Uses open-source models, reducing licensing costs and enabling local adaptation
Why This Matters for LMICs:
- Resource-efficient: Open-source tools avoid vendor lock-in and recurring license fees
- Builds on existing data: Does not require new data collection; it unlocks value already in clinical records
- Addresses underreporting: Surfaces conditions that patients disclose in clinical encounters but that never reach surveillance systems through structured reporting
- Reproducible: The open-source approach allows adaptation to other health systems with similar free-text documentation
This case study was featured in the WHO-supported Casebook on Real-World Impact of AI in Health, launched at the India AI Impact Summit in February 2026. The same event saw the release of Version 2.0 of Vital Strategies’ Foundations & Futures report, which assessed AI readiness across 63 countries and introduced an AI Use-Case Prerequisites Matrix distinguishing minimum conditions for safe initiation from the foundations required for sustained, population-level integration.
For a related discussion of NLP applied to surveillance data streams, see the Syndromic Surveillance section in the Surveillance chapter.
Interpreting Global Health AI Implementation Cases
Implementation cases should be read as connected claims, not as product catalogs. A diagnostic-accuracy paper can support a statement about performance for the evaluated model, threshold, population, and reference standard. It cannot by itself support a deployment count, cost per screening, workforce reduction, patient-outcome effect, or national scale-up claim. Those outcomes require separate operational or comparative evidence.
Before adapting a case, record the exact model and hardware version, site, period, eligible population, data exclusions, comparator, reference standard, workflow, and endpoint. Then map every reported number to the source that measured it. If a field is unknown, leave it unknown rather than borrowing a value from another implementation. This prevents a common error in global health writing: combining plausible details from several programs into one apparently documented success story.
The local decision should also test whether the downstream pathway exists. A screening system has limited value if confirmatory testing, referral, treatment, maintenance, or replacement parts are unavailable. An SMS reporting system can improve timeliness without being an AI system. A simple threshold may be preferable to machine learning when it is transparent, maintainable, and adequate for the response. Technology category should never substitute for evidence that the complete service pathway works.
For pilots, prespecify technical reliability, data completeness, subgroup performance, referral or response completion, staff workload, recurrent cost, and failure recovery. Preserve the preexisting workflow until the replacement is shown to be dependable. Scale only after the site can operate, monitor, and repair the system without relying on an informal external rescue pathway.
Practical Action Framework for Implementing AI in Resource-Limited Settings
Concrete, actionable steps for public health practitioners considering AI implementation in low-resource contexts:
Phase 1: Assessment and Planning (1-3 months)
For a validated multi-country readiness framework, see Vital Strategies’ Foundations & Futures (Version 2.0, 2026), which evaluated AI readiness across 63 countries along five dimensions: governance, data systems, connectivity, human capacity, and sustainable financing (Vital Strategies, February 2026).
Phase 2: Technology Selection (1-2 months)
Use this decision tree:
START: What problem are you solving?
├─ STRUCTURED REPORTING (counts, yes/no, select options)
│ ├─ Smartphone penetration >80%?
│ │ └─ YES → Mobile app (ODK, CommCare, DHIS2)
│ │ └─ NO → SMS-based system (RapidPro, FrontlineSMS, mTRAC-style)
│
├─ IMAGE-BASED DIAGNOSIS (X-rays, microscopy, dermatology)
│ ├─ Reliable internet?
│ │ └─ YES → Cloud AI (Azure, AWS, Google)
│ │ └─ NO → On-device AI (TensorFlow Lite, Edge deployment)
│ ├─ Existing imaging equipment quality?
│ │ └─ High → Standard models may work
│ │ └─ Low → Retrain on local equipment + augment for image quality
│
├─ OUTBREAK DETECTION / SURVEILLANCE
│ ├─ Real-time reporting exists?
│ │ └─ YES → Add anomaly detection layer
│ │ └─ NO → First digitize reporting (SMS/app), then add AI
│ ├─ Data quality sufficient?
│ │ └─ YES (>80% complete, timely) → AI feasible
│ │ └─ NO (<80%) → Fix data collection first, AI later
│
├─ RISK PREDICTION / STRATIFICATION
│ ├─ Electronic health records exist?
│ │ └─ YES → Train on local data (performance, fairness crucial)
│ │ └─ NO → Paper-based → Digitize first, AI later
│ ├─ External model available?
│ │ └─ MUST validate on local population before deployment
│ │ └─ Expect 20-40% performance drop, retrain if needed
│
└─ LANGUAGE/TEXT TASKS (translation, information extraction)
├─ Language supported by major LLMs?
│ └─ YES (English, Spanish, French, etc.) → LLMs viable
│ └─ NO (low-resource language) → Likely requires custom solution
├─ PHI involved?
└─ YES → Local models only (Llama 2, Mistral, on-premise)
└─ NO → Enterprise LLMs with BAAs acceptable
Key Selection Principles:
- Offline-first when internet unreliable
- TensorFlow Lite, ONNX Runtime, Edge deployment
- Data sync when connectivity available
- Avoid: Cloud-only solutions
- Low-power when electricity limited
- Efficient models (MobileNet, SqueezeNet, quantized models)
- Battery-powered devices
- Avoid: High-compute models (GPT-4, large vision models)
- Simple when local capacity limited
- Rule-based systems, statistical methods
- Transparent, interpretable models
- Open-source with active communities
- Avoid: Proprietary black boxes
- Avoid: Complex deep learning if cannot maintain
- Government-owned when sustainability matters
- In-country data hosting
- Open-source, customizable
- Local team trained to maintain
- Avoid: Vendor lock-in
- Avoid: Dependency on external servers
Phase 3: Implementation (3-6 months)
Pilot-First Approach:
Month 1-2: Small Pilot (5-10 sites) - Select diverse sites (urban/rural, high/low-performing) - Intensive support (weekly check-ins) - Rapid iteration based on feedback - Measure: Usability, data quality, acceptability, early impact
Month 3-4: Expanded Pilot (20-50 sites) - Scale to more sites with less intensive support - Train local supervisors to provide support - Refine training materials based on pilot 1 - Measure: Same metrics + sustainability indicators
Month 5-6: Regional Scale (100+ sites) - Deploy to entire district/region - Minimal external support (local team leads) - Integrate into routine supervision - Measure: All above + cost-effectiveness
Success Criteria for Each Phase:
| Metric | Pilot 1 Target | Pilot 2 Target | Scale Target |
|---|---|---|---|
| Adoption rate | >80% | >85% | >90% |
| Data completeness | >75% | >85% | >90% |
| Data timeliness | <7 days | <3 days | <24 hours |
| User satisfaction | >70% satisfied | >80% satisfied | >85% satisfied |
| System uptime | >90% | >95% | >99% |
| Cost per site | Higher (learning) | Decreasing | Sustainable |
Go/No-Go Decision Points:
After each pilot phase, assess: - ☐ Metrics meeting targets? - ☐ Users finding it valuable? - ☐ Technical issues manageable? - ☐ Cost sustainable? - ☐ Government committed to scale?
If NO to ≥2 questions: PAUSE, troubleshoot, revise before scaling
Phase 4: Monitoring and Adaptation (Ongoing)
Continuous Improvement Cycle:
Monthly: - Usage statistics (adoption, data quality, errors) - User feedback (health workers, supervisors, analysts) - Technical performance (uptime, response time, accuracy)
Quarterly: - Impact assessment (health outcomes, efficiency, cost) - Fairness audit (performance across subgroups, facilities) - Capacity assessment (local team skills, independence) - Financial sustainability check
Annually: - Thorough evaluation (peer-reviewed study if possible) - Cost-effectiveness analysis - Scale-up planning (new regions, new use cases) - Technology refresh (update models, infrastructure)
1. Technology-First Thinking - Avoid: “We have this great AI model, let’s find a problem” - Better: “We have this urgent problem, what’s the simplest effective solution?”
2. Pilot Syndrome - Avoid: Successful 6-month pilot → funding ends → system abandoned - Better: Plan for sustainability from day 1, government ownership essential
3. Ignoring Context - Avoid: Importing solutions from high-income settings without adaptation - Better: Design for local constraints (internet, power, skills, workflows)
4. Over-Engineering - Avoid: Complex deep learning when simple statistics would work - Better: Start simple, add complexity only if clearly beneficial
5. Poor Data Quality - Avoid: Building AI on incomplete, inaccurate, delayed data - Better: Fix data collection process first, then add AI
6. Capacity Neglect - Avoid: External experts build system, locals cannot maintain after departure - Better: Build local capacity from start, plan for handover
7. No Feedback Loop - Avoid: Deploy and forget - Better: Continuous monitoring, user feedback, iterative improvement
8. Fairness Blindness - Avoid: Assuming AI works equally well for all populations - Better: Test performance across subgroups, address disparities
DHIS2: The Global Standard for Health Information
DHIS2 (District Health Information Software 2) is the world’s most widely used health information management system, deployed in over 80 countries and covering 3.2 billion people. Understanding DHIS2 is essential for anyone working on AI in LMIC contexts.
Why DHIS2 Matters for AI
Scale and adoption: - Used by 80+ countries for national health information systems - Covers 3.2 billion people (40% of world population) - Free, open-source, actively maintained by University of Oslo
AI integration opportunities: - Standardized data structure enables cross-country learning - API access for automated data extraction and analysis - Built-in analytics that AI can augment - Community health worker apps (DHIS2 Capture) provide mobile data collection
Common use cases: - Disease surveillance and outbreak detection - Immunization tracking and coverage analysis - Supply chain management and stock prediction - Health facility performance monitoring
DHIS2 + AI Integration Patterns
# Example: Extract DHIS2 data for anomaly detection
import requests
def get_dhis2_disease_data(base_url, username, password, dataset_id, period):
"""
Extract disease surveillance data from DHIS2 for AI analysis
"""
# DHIS2 API endpoint for analytics
endpoint = f"{base_url}/api/analytics.json"
params = {
'dimension': f'dx:{dataset_id}',
'dimension': f'pe:{period}',
'dimension': 'ou:LEVEL-3', # District level
'skipMeta': 'true'
}
response = requests.get(
endpoint,
params=params,
auth=(username, password)
)
return response.json()
# Feed into anomaly detection pipeline
# disease_data = get_dhis2_disease_data(...)
# anomalies = detect_outbreaks(disease_data)Resources: - DHIS2 Developer Portal - DHIS2 Academy - Free training courses - DHIS2 Community - Implementation support
Implementation Evidence from Lao PDR
Lao PDR piloted a DHIS2 Tracker-based electronic immunisation registry in one district hospital in November 2022, expanded it to two provinces in 2023, and completed nationwide rollout in 2024. A mixed-methods evaluation in the two earliest implementation regions combined surveys of 26 healthcare workers, 18 stakeholder interviews, workflow observation, and a data-quality assessment of 849,055 unique vaccination events (Patel et al., 2026).
The evaluation found high user acceptance alongside material data and implementation limits. Vaccine type was missing for 15.66% of events, vaccination date was missing for 14.91%, and only 15.26% of vaccinations were recorded within three days. Workforce capacity, electricity, connectivity, governance, and sustainable financing therefore remain prerequisites for using registry data in forecasting or coverage analysis (Patel et al., 2026).
Simplified AI Vendor Evaluation for Resource-Limited Settings
Health departments with limited technical capacity need a streamlined evaluation process. Use this one-page checklist before adopting any AI tool.
Before you begin: If you cannot answer “yes” to the first three questions, do not proceed.
Must-Have Requirements (All must be YES)
| # | Question | YES/NO |
|---|---|---|
| 1 | Can the system work offline or with intermittent connectivity? | |
| 2 | Is the system validated on populations similar to yours? | |
| 3 | Can your staff operate it with less than 1 week of training? | |
| 4 | Does the vendor provide local language support? | |
| 5 | Is pricing transparent and sustainable for your budget? |
Red Flags (Any YES = Reconsider)
| # | Question | YES/NO |
|---|---|---|
| 1 | Does the vendor require your data to leave the country? | |
| 2 | Is the system “black box” with no explainability? | |
| 3 | Does the contract lock you in for >2 years? | |
| 4 | Has the vendor never deployed in a similar setting? | |
| 5 | Does the vendor dismiss questions about bias/fairness? |
Key Questions to Ask Vendors
- “Where has this been deployed in similar settings?”
- Get specific country/facility references
- Contact those sites directly
- “What happens when internet is unavailable?”
- Acceptable: “Works offline, syncs when connected”
- Unacceptable: “Requires constant connectivity”
- “How was the model validated on our population?”
- Acceptable: “Validated on [similar LMIC population]”
- Unacceptable: “Validated in US/Europe, should generalize”
- “What is the total cost of ownership for 5 years?”
- Include: licensing, training, maintenance, infrastructure
- Watch for hidden costs (API calls, storage, support)
- “What happens when the contract ends?”
- Data portability
- Transition support
- Local capacity built
Decision Matrix
| Score | Recommendation |
|---|---|
| 5/5 Must-Have + 0/5 Red Flags | Proceed with pilot |
| 4/5 Must-Have + 0-1 Red Flags | Request modifications, re-evaluate |
| <4 Must-Have OR >1 Red Flag | Do not proceed |