Skip to content
Learn Agentic AI12 min read0 views

Symptom Triage AI Agent: Helping Patients Navigate Care Options

Learn how to build an AI symptom triage agent that assesses urgency, recommends care levels, and routes patients appropriately — with proper liability disclaimers and clinical protocol adherence.

What Symptom Triage AI Can and Cannot Do

A symptom triage agent is not a diagnostic tool. It does not tell patients what is wrong with them. Instead, it helps patients understand the urgency of their symptoms and directs them to the appropriate level of care: emergency room, urgent care, same-day appointment, or routine scheduling.

This distinction is critical both clinically and legally. The agent follows established triage protocols — the same decision trees that nurse triage lines use — rather than making novel medical judgments.

The Triage Protocol Engine

Clinical triage protocols are rule-based decision trees. The agent's job is to walk patients through the right questions and map their answers to a care recommendation:

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

class CareLevel(Enum):
    EMERGENCY_911 = "emergency_911"
    EMERGENCY_ROOM = "emergency_room"
    URGENT_CARE = "urgent_care"
    SAME_DAY_APPOINTMENT = "same_day"
    ROUTINE_APPOINTMENT = "routine"
    SELF_CARE = "self_care"

@dataclass
class TriageQuestion:
    id: str
    text: str
    options: list[str]
    red_flag_answers: list[str] = field(default_factory=list)
    next_question_map: dict[str, Optional[str]] = field(default_factory=dict)

@dataclass
class TriageResult:
    care_level: CareLevel
    reasoning: str
    disclaimer: str
    follow_up_instructions: list[str]
    escalate_to_nurse: bool = False

class TriageProtocol:
    def __init__(self, protocol_name: str, questions: list[TriageQuestion]):
        self.protocol_name = protocol_name
        self.questions = {q.id: q for q in questions}
        self.answers: dict[str, str] = {}

    def get_first_question(self) -> TriageQuestion:
        return self.questions[list(self.questions.keys())[0]]

    def process_answer(self, question_id: str, answer: str) -> Optional[TriageQuestion]:
        self.answers[question_id] = answer
        question = self.questions[question_id]

        # Immediate escalation for red flag answers
        if answer in question.red_flag_answers:
            return None  # Signals immediate result needed

        next_id = question.next_question_map.get(answer)
        if next_id and next_id in self.questions:
            return self.questions[next_id]
        return None  # No more questions, ready for assessment

Building a Headache Triage Protocol

Here is a concrete example of how clinical protocols translate into agent logic:

def build_headache_protocol() -> TriageProtocol:
    questions = [
        TriageQuestion(
            id="onset",
            text="When did the headache start?",
            options=["Within the last hour", "Today", "Past few days", "Recurring"],
            red_flag_answers=[],
            next_question_map={
                "Within the last hour": "severity",
                "Today": "severity",
                "Past few days": "severity",
                "Recurring": "frequency",
            },
        ),
        TriageQuestion(
            id="severity",
            text="On a scale of 1-10, how severe is the pain?",
            options=["1-3 (mild)", "4-6 (moderate)", "7-8 (severe)", "9-10 (worst ever)"],
            red_flag_answers=["9-10 (worst ever)"],
            next_question_map={
                "1-3 (mild)": "associated_symptoms",
                "4-6 (moderate)": "associated_symptoms",
                "7-8 (severe)": "associated_symptoms",
            },
        ),
        TriageQuestion(
            id="associated_symptoms",
            text="Are you experiencing any of the following?",
            options=[
                "Stiff neck and fever",
                "Vision changes",
                "Weakness on one side",
                "Nausea only",
                "None of these",
            ],
            red_flag_answers=["Stiff neck and fever", "Vision changes", "Weakness on one side"],
            next_question_map={
                "Nausea only": "history",
                "None of these": "history",
            },
        ),
        TriageQuestion(
            id="history",
            text="Do you have a history of migraines or similar headaches?",
            options=["Yes, diagnosed migraines", "Similar headaches before", "This is new"],
            red_flag_answers=[],
            next_question_map={},
        ),
    ]
    return TriageProtocol("headache_triage", questions)

Urgency Assessment and Routing

Once the protocol completes, the agent assesses the collected answers and generates a recommendation:

See AI Voice Agents Handle Real Calls

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

class TriageAssessor:
    RED_FLAG_CARE_LEVEL = CareLevel.EMERGENCY_911
    DISCLAIMER = (
        "This assessment is not a medical diagnosis. It is intended to help you "
        "determine the appropriate level of care. If you believe you are experiencing "
        "a medical emergency, call 911 immediately."
    )

    def assess(self, protocol: TriageProtocol) -> TriageResult:
        # Check for any red flag answers first
        for q_id, answer in protocol.answers.items():
            question = protocol.questions[q_id]
            if answer in question.red_flag_answers:
                return self._emergency_result(question, answer)

        # Score based on severity and symptoms
        severity = protocol.answers.get("severity", "")
        if "7-8" in severity:
            return TriageResult(
                care_level=CareLevel.URGENT_CARE,
                reasoning="Severe headache without emergency red flags.",
                disclaimer=self.DISCLAIMER,
                follow_up_instructions=[
                    "Visit an urgent care center today",
                    "If symptoms worsen, go to the emergency room",
                    "Bring a list of current medications",
                ],
            )

        history = protocol.answers.get("history", "")
        if "diagnosed migraines" in history:
            return TriageResult(
                care_level=CareLevel.SAME_DAY_APPOINTMENT,
                reasoning="Symptoms consistent with known migraine history.",
                disclaimer=self.DISCLAIMER,
                follow_up_instructions=[
                    "Contact your neurologist for a same-day appointment",
                    "Use prescribed migraine medications as directed",
                ],
            )

        return TriageResult(
            care_level=CareLevel.ROUTINE_APPOINTMENT,
            reasoning="Mild to moderate headache without concerning features.",
            disclaimer=self.DISCLAIMER,
            follow_up_instructions=[
                "Schedule a routine appointment with your primary care provider",
                "Rest and hydrate in the meantime",
            ],
        )

    def _emergency_result(self, question: TriageQuestion, answer: str) -> TriageResult:
        return TriageResult(
            care_level=CareLevel.EMERGENCY_911,
            reasoning=f"Red flag symptom detected: {answer}",
            disclaimer=self.DISCLAIMER,
            follow_up_instructions=["Call 911 or go to the nearest emergency room immediately"],
            escalate_to_nurse=True,
        )

Liability and Disclaimers

Every triage interaction must include clear disclaimers. The agent is not practicing medicine — it is applying standardized protocols. Key legal requirements include displaying a disclaimer before and after the assessment, logging every interaction for audit purposes, offering the option to speak with a human nurse at any point, and never using language like "you have" or "your diagnosis is."

FAQ

Can an AI triage agent replace nurse triage lines?

No. AI triage agents supplement nurse triage lines by handling the initial question flow and routing clear-cut cases. Complex or ambiguous cases should always escalate to a registered nurse. The agent reduces the volume of calls nurses must handle, allowing them to spend more time on cases that genuinely need clinical judgment.

How do you validate that the triage protocols are clinically accurate?

Protocols must be reviewed and approved by licensed clinical staff before deployment. The agent should use published triage protocols such as Schmitt-Thompson guidelines rather than inventing its own clinical logic. Any updates to protocols require clinical review and versioned deployment.

What if the patient provides conflicting answers?

The agent should detect contradictions (for example, reporting no pain but rating severity as 9 out of 10) and ask clarifying questions. If contradictions persist, the agent escalates to a human nurse rather than attempting to resolve the conflict algorithmically.


#HealthcareAI #SymptomTriage #ClinicalProtocols #PatientSafety #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.