14. Symptom Checking
Symptom checking systems help patients understand when to seek care and what specialty to consult. Local AI enables symptom triage that maintains privacy while providing guidance.
The challenge is calibration: symptom checkers must encourage appropriate care-seeking without causing unnecessary anxiety or false reassurance. Current systems typically err on the side of caution, recommending professional evaluation for anything beyond minor issues.
# symptom_checker.py
from dataclasses import dataclass
from typing import List, Optional
from enum import Enum
class UrgencyLevel(Enum):
EMERGENCY = "seek_emergency_care" # Call 911
URGENT = "seek_care_today" # Same-day appointment
SOON = "schedule_soon" # Within week
ROUTINE = "routine_care" # Schedule when convenient
SELF_CARE = "self_care_possible" # Monitor at home
@dataclass
class SymptomAssessment:
chief_symptoms: List[str]
associated_symptoms: List[str]
duration: str
severity: str
urgency: UrgencyLevel
recommendations: List[str]
red_flags_identified: List[str]
suggested_specialty: Optional[str]
class SymptomChecker:
"""Provide AI-assisted symptom assessment."""
ASSESSMENT_PROMPT = """Assess patient symptoms and provide care recommendations.
IMPORTANT: This is for educational purposes only. Not a medical diagnosis.
Always recommend professional evaluation for anything beyond minor, self-limiting conditions.
Symptoms reported:
{symptoms}
Duration: {duration}
Patient history (if provided):
{history}
Provide assessment including:
1. Likely urgency level (emergency/urgent/soon/routine/self-care)
2. Key symptoms identified
3. Red flags to watch for
4. General care recommendations
5. Suggested specialty if professional care needed
Be specific about red flags that warrant immediate evaluation.
Do NOT make definitive diagnoses.
Always include appropriate disclaimers."""
RED_FLAG_PROMPT = """Identify emergency indicators in these symptoms.
Look for:
- Chest pain, difficulty breathing (cardiac/respiratory emergency)
- Sudden weakness, speech changes, vision changes (stroke)
- Severe bleeding, uncontrolled
- High fever with stiff neck, confusion (CNS infection)
- Suicidal ideation
Symptoms: {symptoms}
Return JSON with red_flags array if any found, or empty array."""
def __init__(self, ollama_client):
self.ollama = ollama_client
def assess_symptoms(self, symptom_text: str,
duration: str = "unknown",
history: Optional[dict] = None) -> SymptomAssessment:
"""Assess reported symptoms and recommend care level."""
# Check for red flags first
red_flags = self._check_red_flags(symptom_text)
if red_flags:
return SymptomAssessment(
chief_symptoms=[],
associated_symptoms=[],
duration=duration,
severity="unknown",
urgency=UrgencyLevel.EMERGENCY,
recommendations=[
"Based on your symptoms, please seek emergency care immediately.",
"Call 911 or go to the nearest emergency room."
],
red_flags_identified=red_flags,
suggested_specialty="Emergency Medicine"
)
# Standard assessment
prompt = self.ASSESSMENT_PROMPT.format(
symptoms=symptom_text,
duration=duration,
history=history or "No history provided"
)
response = self.ollama.generate(prompt)
return self._parse_assessment(response, symptom_text, duration)
def follow_up_symptoms(self, initial_symptoms: str,
new_developments: str) -> SymptomAssessment:
"""Assess new or worsening symptoms after initial assessment."""
prompt = f"""Assess new symptoms reported during follow-up.
Initial symptoms: {initial_symptoms}
New developments: {new_developments}
Determine if there is:
1. Worsening that requires more urgent care
2. New symptoms suggesting different condition
3. Recovery progressing normally
Return assessment with updated recommendations."""
response = self.ollama.generate(prompt)
return self._parse_assessment(response, new_developments, "follow-up")
def suggest_specialty(self, symptoms: str) -> Optional[str]:
"""Suggest appropriate specialist based on symptoms."""
prompt = f"""Based on these symptoms, suggest the most appropriate medical specialty.
If symptoms suggest multiple specialties, list primary first.
If symptoms are minor and self-care possible, state "No specialist needed."
Symptoms: {symptoms}
Return: specialty name or "No specialist needed" """
response = self.ollama.generate(prompt)
return response.strip()
def _check_red_flags(self, symptom_text: str) -> List[str]:
"""Check for emergency symptoms that require immediate care."""
prompt = self.RED_FLAG_PROMPT.format(symptoms=symptom_text)
response = self.ollama.generate(prompt)
import json
try:
data = json.loads(response)
return data.get("red_flags", [])
except:
return []
def _parse_assessment(self, response: str,
symptom_text: str,
duration: str) -> SymptomAssessment:
"""Parse LLM response into structured assessment."""
import json
try:
data = json.loads(response)
urgency_map = {
"emergency": UrgencyLevel.EMERGENCY,
"seek_emergency_care": UrgencyLevel.EMERGENCY,
"urgent": UrgencyLevel.URGENT,
"seek_care_today": UrgencyLevel.URGENT,
"soon": UrgencyLevel.SOON,
"schedule_soon": UrgencyLevel.SOON,
"routine": UrgencyLevel.ROUTINE,
"self_care": UrgencyLevel.SELF_CARE
}
return SymptomAssessment(
chief_symptoms=data.get("symptoms", []),
associated_symptoms=data.get("associated_symptoms", []),
duration=duration,
severity=data.get("severity", "unknown"),
urgency=urgency_map.get(data.get("urgency", "routine"), UrgencyLevel.ROUTINE),
recommendations=data.get("recommendations", []),
red_flags_identified=data.get("red_flags", []),
suggested_specialty=data.get("specialty")
)
except:
return SymptomAssessment(
chief_symptoms=[symptom_text],
associated_symptoms=[],
duration=duration,
severity="评估失败",
urgency=UrgencyLevel.SOON,
recommendations=["Unable to complete assessment. Please consult healthcare provider."],
red_flags_identified=[],
suggested_specialty=None
)
Symptom checkers face liability concerns even when disclaimers are present. Courts may examine whether the system created false assurance that led to patient harm. Minimize this by calibrating toward over-triage—better to recommend professional care unnecessarily than to miss a serious condition.
Create a test set of 50 symptom scenarios spanning emergency (10), urgent (15), non-urgent (15), and self-care appropriate (10). Evaluate system accuracy at identifying urgency level and calculate false reassurance rate.