Skip to content
Learn Agentic AI10 min read0 views

Patient Education AI Agent: Personalized Health Information Delivery

Build an AI agent that delivers personalized health education by retrieving condition-specific content, adapting reading levels, supporting multiple languages, and tracking patient comprehension.

Why Patient Education Needs AI

Nearly 9 out of 10 adults struggle to understand health information presented in its typical clinical form. When a physician says "you have been diagnosed with Type 2 diabetes mellitus," many patients leave the office without truly understanding what that means for their daily life. A patient education agent bridges this gap by delivering condition-specific information at the right reading level, in the right language, through the right channel — and checking whether the patient actually understood it.

Content Retrieval and Structuring

The agent draws from a curated library of clinical education materials and structures them for the specific patient context:

from dataclasses import dataclass, field
from enum import Enum
from typing import Optional

class ReadingLevel(Enum):
    ELEMENTARY = "elementary"       # Grade 3-5, Flesch-Kincaid 80-100
    MIDDLE_SCHOOL = "middle_school" # Grade 6-8, Flesch-Kincaid 60-80
    HIGH_SCHOOL = "high_school"     # Grade 9-12, Flesch-Kincaid 40-60
    COLLEGE = "college"             # College level, Flesch-Kincaid 20-40

class ContentFormat(Enum):
    TEXT = "text"
    BULLET_POINTS = "bullet_points"
    QA = "question_answer"
    VISUAL = "visual_guide"

@dataclass
class EducationContent:
    id: str
    condition: str
    topic: str
    content_text: str
    reading_level: ReadingLevel
    language: str = "en"
    format_type: ContentFormat = ContentFormat.TEXT
    sources: list[str] = field(default_factory=list)
    last_reviewed: str = ""

@dataclass
class PatientProfile:
    patient_id: str
    preferred_language: str = "en"
    reading_level: ReadingLevel = ReadingLevel.MIDDLE_SCHOOL
    conditions: list[str] = field(default_factory=list)
    allergies: list[str] = field(default_factory=list)
    preferred_format: ContentFormat = ContentFormat.BULLET_POINTS

class ContentRetriever:
    def __init__(self, content_library: list[EducationContent]):
        self._library = content_library

    def find_relevant_content(
        self, condition: str, patient: PatientProfile
    ) -> list[EducationContent]:
        matches = []
        for content in self._library:
            if content.condition.lower() != condition.lower():
                continue
            if content.language != patient.preferred_language:
                continue
            if content.reading_level != patient.reading_level:
                continue
            matches.append(content)
        return matches

Reading Level Adaptation

When content at the patient's reading level is not available, the agent adapts existing content. The Flesch-Kincaid readability score guides the transformation:

import re
import math

class ReadabilityAnalyzer:
    def flesch_kincaid_grade(self, text: str) -> float:
        sentences = self._count_sentences(text)
        words = self._count_words(text)
        syllables = self._count_syllables(text)

        if sentences == 0 or words == 0:
            return 0.0

        grade = (
            0.39 * (words / sentences) +
            11.8 * (syllables / words) -
            15.59
        )
        return round(grade, 1)

    def _count_sentences(self, text: str) -> int:
        return len(re.findall(r'[.!?]+', text)) or 1

    def _count_words(self, text: str) -> int:
        return len(text.split())

    def _count_syllables(self, text: str) -> int:
        words = text.lower().split()
        count = 0
        for word in words:
            word = re.sub(r'[^a-z]', '', word)
            if not word:
                continue
            vowels = re.findall(r'[aeiouy]+', word)
            syllables = len(vowels) if vowels else 1
            if word.endswith('e') and syllables > 1:
                syllables -= 1
            count += max(syllables, 1)
        return count

class ContentAdapter:
    SIMPLIFICATION_RULES = {
        "hypertension": "high blood pressure",
        "diabetes mellitus": "diabetes (high blood sugar)",
        "myocardial infarction": "heart attack",
        "cerebrovascular accident": "stroke",
        "dyspnea": "difficulty breathing",
        "edema": "swelling",
        "hyperlipidemia": "high cholesterol",
        "osteoarthritis": "joint wear and tear",
    }

    def __init__(self):
        self.analyzer = ReadabilityAnalyzer()

    def simplify(self, text: str, target_level: ReadingLevel) -> str:
        target_grade = {
            ReadingLevel.ELEMENTARY: 4.0,
            ReadingLevel.MIDDLE_SCHOOL: 7.0,
            ReadingLevel.HIGH_SCHOOL: 10.0,
            ReadingLevel.COLLEGE: 14.0,
        }[target_level]

        # Replace medical jargon with plain language
        simplified = text
        for term, replacement in self.SIMPLIFICATION_RULES.items():
            simplified = re.sub(
                re.escape(term), replacement, simplified, flags=re.IGNORECASE
            )

        # Break long sentences
        current_grade = self.analyzer.flesch_kincaid_grade(simplified)
        if current_grade > target_grade:
            simplified = self._break_long_sentences(simplified)

        return simplified

    def _break_long_sentences(self, text: str) -> str:
        sentences = re.split(r'(?<=[.!?])s+', text)
        result = []
        for sentence in sentences:
            words = sentence.split()
            if len(words) > 20:
                # Split at conjunctions
                midpoint = len(words) // 2
                first_half = " ".join(words[:midpoint]) + "."
                second_half = " ".join(words[midpoint:])
                result.extend([first_half, second_half])
            else:
                result.append(sentence)
        return " ".join(result)

Comprehension Tracking

Delivering information is not enough — the agent needs to verify the patient understood it:

See AI Voice Agents Handle Real Calls

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

@dataclass
class ComprehensionCheck:
    question: str
    correct_answer: str
    patient_answer: Optional[str] = None
    understood: Optional[bool] = None

class ComprehensionTracker:
    def generate_checks(self, content: EducationContent) -> list[ComprehensionCheck]:
        checks = []
        if "medication" in content.topic.lower():
            checks.append(ComprehensionCheck(
                question="Can you tell me in your own words when you should take this medication?",
                correct_answer="[Patient should mention timing and frequency]",
            ))
            checks.append(ComprehensionCheck(
                question="What should you do if you miss a dose?",
                correct_answer="[Patient should describe the missed-dose protocol]",
            ))
        if "diet" in content.topic.lower():
            checks.append(ComprehensionCheck(
                question="Can you name two foods you should limit based on what we discussed?",
                correct_answer="[Patient should identify restricted food categories]",
            ))
        return checks

    def evaluate_response(self, check: ComprehensionCheck, response: str) -> bool:
        # In production, use an LLM to semantically compare
        # the patient's response against the expected answer
        check.patient_answer = response
        check.understood = len(response.split()) >= 5  # Simplified heuristic
        return check.understood

Delivery and Follow-Up

The agent sends materials through the patient's preferred channel and follows up:

class EducationDelivery:
    def prepare_package(
        self, patient: PatientProfile, contents: list[EducationContent]
    ) -> dict:
        package = {
            "patient_id": patient.patient_id,
            "language": patient.preferred_language,
            "format": patient.preferred_format.value,
            "materials": [],
            "follow_up_date": "3 days",
        }
        for content in contents:
            package["materials"].append({
                "topic": content.topic,
                "content": content.content_text,
                "sources": content.sources,
            })
        return package

FAQ

How does the agent determine a patient's reading level?

The agent uses a combination of signals: the patient's self-reported education level from intake forms, the reading level of their message responses (analyzed with Flesch-Kincaid scoring), and provider notes about communication preferences. It defaults to a 6th-grade reading level, which is the recommended standard for patient health materials per the AMA.

Can the agent deliver education materials in languages other than English?

Yes, but with important caveats. The content library must contain clinically reviewed translations — not machine-translated versions. The agent should never auto-translate medical content with general-purpose translation tools, as medical terminology requires specialized translation. When content is not available in the patient's preferred language, the agent flags this for staff to arrange interpreter services.

How does the agent handle patients who do not want to engage with education materials?

The agent respects patient autonomy. It documents that education was offered and declined, which satisfies clinical documentation requirements. It can offer alternative formats (a short video instead of a document, for example) but does not repeatedly push materials on an uninterested patient.


#HealthcareAI #PatientEducation #HealthLiteracy #ContentPersonalization #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.