Skip to content
Learn Agentic AI10 min read0 views

Building a Medication Reminder Agent: Adherence Support with AI

Build an AI agent for medication adherence that handles reminder scheduling, drug interaction checking, refill tracking, and caregiver notifications — with practical Python implementation.

The Medication Adherence Crisis

About half of all patients do not take their medications as prescribed. This leads to 125,000 preventable deaths annually in the United States alone and costs the healthcare system over 500 billion dollars per year. An AI medication reminder agent goes beyond simple alarm clocks — it understands medication schedules, checks for dangerous interactions, tracks refills, and alerts caregivers when adherence drops.

Modeling the Medication Schedule

The foundation of a reminder agent is an accurate medication model that captures dosing complexity:

from dataclasses import dataclass, field
from datetime import datetime, time, timedelta
from enum import Enum
from typing import Optional

class DoseFrequency(Enum):
    ONCE_DAILY = "once_daily"
    TWICE_DAILY = "twice_daily"
    THREE_TIMES_DAILY = "three_times_daily"
    EVERY_X_HOURS = "every_x_hours"
    AS_NEEDED = "as_needed"
    WEEKLY = "weekly"

class MealRelation(Enum):
    WITH_FOOD = "with_food"
    EMPTY_STOMACH = "empty_stomach"
    NO_RESTRICTION = "no_restriction"

@dataclass
class Medication:
    id: str
    name: str
    dosage: str
    frequency: DoseFrequency
    meal_relation: MealRelation
    prescribed_times: list[time] = field(default_factory=list)
    hour_interval: Optional[int] = None
    start_date: datetime = field(default_factory=datetime.utcnow)
    end_date: Optional[datetime] = None
    refill_date: Optional[datetime] = None
    pills_remaining: Optional[int] = None
    special_instructions: str = ""

@dataclass
class ReminderEvent:
    medication: Medication
    scheduled_time: datetime
    acknowledged: bool = False
    taken: bool = False
    skipped_reason: Optional[str] = None

Intelligent Reminder Scheduling

The scheduler accounts for time zones, meal timing, and spacing between medications that should not be taken together:

class ReminderScheduler:
    # Minimum gap between medications that interact
    MIN_INTERACTION_GAP_HOURS = 2

    def __init__(self, medications: list[Medication], wake_time: time, sleep_time: time):
        self.medications = medications
        self.wake_time = wake_time
        self.sleep_time = sleep_time

    def generate_daily_schedule(self, date: datetime) -> list[ReminderEvent]:
        events: list[ReminderEvent] = []
        for med in self.medications:
            if med.end_date and date > med.end_date:
                continue
            times = self._resolve_times(med)
            for t in times:
                scheduled = datetime.combine(date.date(), t)
                events.append(ReminderEvent(medication=med, scheduled_time=scheduled))

        events.sort(key=lambda e: e.scheduled_time)
        return self._adjust_for_interactions(events)

    def _resolve_times(self, med: Medication) -> list[time]:
        if med.prescribed_times:
            return med.prescribed_times
        if med.frequency == DoseFrequency.ONCE_DAILY:
            return [time(9, 0)]
        if med.frequency == DoseFrequency.TWICE_DAILY:
            return [time(9, 0), time(21, 0)]
        if med.frequency == DoseFrequency.THREE_TIMES_DAILY:
            return [time(8, 0), time(14, 0), time(20, 0)]
        return [self.wake_time]

    def _adjust_for_interactions(self, events: list[ReminderEvent]) -> list[ReminderEvent]:
        # Ensure minimum spacing between medications that interact
        for i in range(1, len(events)):
            prev = events[i - 1]
            curr = events[i]
            gap = (curr.scheduled_time - prev.scheduled_time).total_seconds() / 3600
            if gap < self.MIN_INTERACTION_GAP_HOURS:
                adjusted = prev.scheduled_time + timedelta(hours=self.MIN_INTERACTION_GAP_HOURS)
                curr.scheduled_time = adjusted
        return events

Drug Interaction Checking

Before confirming any schedule, the agent checks for known drug interactions:

See AI Voice Agents Handle Real Calls

Book a free demo or calculate how much you can save with AI voice automation.

@dataclass
class Interaction:
    drug_a: str
    drug_b: str
    severity: str  # "mild", "moderate", "severe", "contraindicated"
    description: str
    recommendation: str

class InteractionChecker:
    def __init__(self, interaction_db: list[Interaction]):
        self._interactions = interaction_db

    def check_all(self, medications: list[Medication]) -> list[Interaction]:
        found = []
        names = [m.name.lower() for m in medications]
        for i, name_a in enumerate(names):
            for name_b in names[i + 1:]:
                for interaction in self._interactions:
                    pair = {interaction.drug_a.lower(), interaction.drug_b.lower()}
                    if name_a in pair and name_b in pair:
                        found.append(interaction)
        return found

    def get_severe_interactions(self, medications: list[Medication]) -> list[Interaction]:
        return [
            i for i in self.check_all(medications)
            if i.severity in ("severe", "contraindicated")
        ]

Refill Tracking and Caregiver Alerts

The agent monitors pill counts and proactively notifies patients and caregivers when refills are needed or adherence drops:

from typing import Callable

@dataclass
class AdherenceStats:
    total_scheduled: int
    total_taken: int
    adherence_rate: float
    streak_days: int
    missed_medications: list[str]

class AdherenceMonitor:
    REFILL_WARNING_DAYS = 7
    LOW_ADHERENCE_THRESHOLD = 0.8

    def __init__(self, notify_patient: Callable, notify_caregiver: Callable):
        self.notify_patient = notify_patient
        self.notify_caregiver = notify_caregiver

    def check_refills(self, medications: list[Medication]) -> list[str]:
        warnings = []
        for med in medications:
            if med.pills_remaining is not None and med.pills_remaining <= self.REFILL_WARNING_DAYS:
                msg = f"{med.name}: {med.pills_remaining} doses remaining. Time to request a refill."
                warnings.append(msg)
                self.notify_patient(msg)
        return warnings

    def evaluate_adherence(self, events: list[ReminderEvent]) -> AdherenceStats:
        total = len(events)
        taken = sum(1 for e in events if e.taken)
        rate = taken / total if total > 0 else 0.0
        missed = list({e.medication.name for e in events if not e.taken and not e.skipped_reason})

        stats = AdherenceStats(
            total_scheduled=total,
            total_taken=taken,
            adherence_rate=rate,
            streak_days=self._calculate_streak(events),
            missed_medications=missed,
        )

        if rate < self.LOW_ADHERENCE_THRESHOLD:
            self.notify_caregiver(
                f"Adherence alert: {rate:.0%} over recent period. Missed: {', '.join(missed)}"
            )
        return stats

    def _calculate_streak(self, events: list[ReminderEvent]) -> int:
        streak = 0
        for event in reversed(events):
            if event.taken:
                streak += 1
            else:
                break
        return streak

FAQ

How does the agent handle as-needed medications like pain relievers?

As-needed medications are not scheduled with fixed reminders. Instead, the agent tracks when the patient reports taking a dose and enforces minimum intervals between doses. If the patient tries to log a dose too soon, the agent warns them about the minimum time between doses and the maximum daily limit.

What if a patient wants to stop a medication?

The agent never advises stopping medication. It acknowledges the patient's concern, logs the request, and recommends they discuss it with their prescribing provider. If the patient confirms they are stopping, the agent removes the reminders but flags the change in the patient's record for clinical review.

How are caregiver notifications authorized?

The patient must explicitly grant permission for caregiver notifications through a consent process. The agent stores a signed consent record specifying which caregiver, what information they receive (adherence rates but not specific medication names, for example), and under what conditions notifications are triggered.


#HealthcareAI #MedicationAdherence #Reminders #DrugInteractions #Python #AgenticAI #LearnAI #AIEngineering

Share this article
C

CallSphere Team

Expert insights on AI voice agents and customer communication automation.

Try CallSphere AI Voice Agents

See how AI voice agents work for your industry. Live demo available -- no signup required.