AI-Перевірка симптомів у мобільних застосунках
Symptom Checker—одна з найвідповідальніших AI-задач у мобільній розробці. Помилковий висновок «мабуть, просто втома» при симптомах, що вимагають негайної допомоги, може коштувати життя. Це не перебільшення—це архітектурна вимога.
Юридичні та медичні обмеження
Перед написанням коду—базові обмеження, що диктують архітектуру:
- Застосунок не ставить діагнози. Виводить «ймовірні причини», «рекомендується медична консультація»
- Симптоми високого ризику (біль у грудях, утруднене дихання, ознаки інсульту)—автоматичний редирект на 911, без AI-аналізу
- Дані про симптоми—медичні дані, вимагають шифрування рівня HealthKit / HIPAA
- Відмова від відповідальності видима до першого запиту, не дрібним шрифтом
На iOS використовуйте HealthKit для зберігання анамнезу з авторизацією HKHealthStore. На Android використовуйте Health Connect із HealthPermission.READ_STEPS та подібними дозволами.
Детермінована перевірка критичних симптомів
Перед будь-яким LLM-викликом—жорсткий фільтр за критичними симптомами:
struct CriticalSymptomChecker {
// Симптоми, що вимагають негайної медичної допомоги
static let emergencySymptoms = [
"chest pain", "біль у грудях",
"difficulty breathing", "утруднене дихання", "не можу дихати",
"sudden severe headache", "раптова сильна головна біль",
"face drooping", "numbness arm", "speech difficulty", // FAST-тест інсульту
"loss of consciousness", "втрата свідомості",
"severe bleeding", "сильна кровотеча",
"choking", "поданість"
]
static func requiresEmergency(_ symptomText: String) -> Bool {
let lowercased = symptomText.lowercased()
return emergencySymptoms.contains { lowercased.contains($0) }
}
}
// Перевіряйте ПЕРЕД відправкою в LLM
func processSymptoms(_ userInput: String) async {
if CriticalSymptomChecker.requiresEmergency(userInput) {
showEmergencyAlert() // Кнопка 911, заблокувати продовження
return
}
await analyzeWithAI(userInput)
}
Це не AI—детермінована логіка. Не можна довіряти LLM рішення про виклик скорої допомоги.
Структурований збір симптомів
Вільний ввід тексту—не ідеальний UX для медичного контексту. Користувачі в стресі пишуть неточно. Краще—чат із уточнювальними запитаннями за протоколом.
// Протокол збору симптомів (адаптація OPQRST для мобільного)
enum SymptomQuestion: CaseIterable {
case onset // коли почалося
case provocation // що посилює/ослабляє
case quality // характер (гостра, тупа, тискуча)
case radiation // куди віддає
case severity // шкала 1-10
case time // як давно, постійно/періодично
var prompt: String {
switch self {
case .onset: return "Коли з'явився симптом? (недавно, кілька годин тому, кілька днів тому)"
case .severity: return "Оцініть інтенсивність за шкалою від 1 до 10"
// ...
}
}
}
AI генерує наступне уточнююче запитання на основі попередніх відповідей—адаптивна анкета, не фіксований список.
Запит для аналізу симптомів
func buildSymptomAnalysisPrompt(
symptoms: SymptomCollection,
patientContext: PatientContext
) -> String {
return """
You are a medical triage assistant. Analyze symptoms and suggest possible conditions.
IMPORTANT: Always recommend consulting a qualified doctor. Never provide a definitive diagnosis.
If symptoms suggest any serious condition, clearly state urgency level.
Patient context:
- Age: \(patientContext.age)
- Known conditions: \(patientContext.knownConditions.joined(separator: ", "))
- Current medications: \(patientContext.medications.isEmpty ? "none" : patientContext.medications.joined(separator: ", "))
Symptoms:
- Main complaint: \(symptoms.mainComplaint)
- Duration: \(symptoms.duration)
- Severity (1-10): \(symptoms.severity)
- Character: \(symptoms.quality)
- Associated symptoms: \(symptoms.associated.joined(separator: ", "))
Return JSON:
{
"urgency": "emergency|urgent|routine",
"possible_conditions": [{"name": "", "likelihood": "high|medium|low", "brief_explanation": ""}],
"recommended_action": "call_911|er_today|see_doctor_soon|see_doctor_routine|home_care",
"home_care_advice": "",
"red_flags": ["symptoms to watch for that require immediate care"],
"disclaimer": "This is not a medical diagnosis..."
}
"""
}
urgency: emergency у відповіді LLM—додатковий тригер для показу кнопки 911, навіть якщо детермінований фільтр його пропустив.
Відображення результатів
Медична інформація вимагає спеціальної подачі в UI:
@Composable
fun SymptomCheckResult(result: SymptomAnalysis) {
Column(modifier = Modifier.fillMaxSize().padding(16.dp)) {
// Рівень терміновості—першим, крупно
UrgencyBanner(urgency = result.urgency)
Spacer(Modifier.height(16.dp))
// Рекомендоване дійство—другим
RecommendedActionCard(action = result.recommendedAction)
Spacer(Modifier.height(16.dp))
// Можливі причини—з застереженнями
Text("Possible Causes", style = MaterialTheme.typography.titleMedium)
Text(
"Information is for informational purposes and is not a diagnosis",
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
result.possibleConditions.forEach { condition ->
ConditionCard(condition)
}
// Червоні прапори—окремий розділ
if (result.redFlags.isNotEmpty()) {
RedFlagsSection(flags = result.redFlags)
}
// Відмова від відповідальності—обов'язкова, не дрібним шрифтом
DisclaimerCard(text = result.disclaimer)
}
}
Інтеграція телемедицини
Якщо застосунок пов'язаний із телемедичними сервісами, кнопка «Проконсультуватися з лікарем» з'являється в результатах. Контекст з Symptom Checker (структуровані симптоми, анамнез) передається лікарю автоматично—економить 10–15 хвилин опитування.
Орієнтири за часом
Базовий Symptom Checker із чатом, детермінованим фільтром надзвичайних ситуацій та AI-аналізом—2–3 тижні. Повна реалізація з адаптивним опитуванням, HealthKit/Health Connect, профілем пацієнта, інтеграцією телемедицини й дотриманням GDPR/HIPAA—2–3 місяці.







