-
Input screen with example complaints and the always-visible safety disclaimer, showing an urgent-tier ankle-injury result.
-
Urgent tier: middle-severity calibration with cited source (sprain-strain). The system correctly avoids both over- and under-triage.
-
Input screen with example complaints and the always-visible safety disclaimer, showing an urgent-tier ankle-injury result.
-
Urgent tier: middle-severity calibration with cited source (sprain-strain). The system correctly avoids both over- and under-triage.
-
Plain-language input returns a calibrated self-care assessment with reasoning and next steps.
-
Self-care tier: correctly identifies a mild cold as home-manageable, grounded in cited guidance (common-cold).
What it does
Anyone who feels unwell faces the same question before they reach a clinician: how urgent is this, and where should I go? Search engines and generic chatbots answer this inconsistently and with no accountability — they'll wave off a heart attack as "probably stress," or send a common cold to the ER.
AI Symptom-Triage Assistant takes a patient's free-text complaint and returns a calibrated urgency level (emergency / urgent / routine / self-care), the specific red flags it detected, a recommended specialist, its step-by-step reasoning, and plain-language next steps — with each assessment citing the clinical guidance it relied on.
This is a triage navigation aid, not a diagnostic tool. Every response carries that disclaimer and defers to emergency services.
How I built it
The system is three deliberate layers, not a single model call:
1. Grounded reasoning (RAG). Each complaint is embedded (sentence-transformers, all-MiniLM-L6-v2) and matched against a curated 40-entry knowledge base of public triage guidance (NHS, CDC, WHO, MedlinePlus) using FAISS. Retrieved snippets are injected into the model's context, and every assessment cites the specific sources it used — so guidance is traceable, not conjured.
2. A deterministic safety layer. Because an LLM is probabilistic and can under-triage, a rule-based checker runs independently of the model. If it detects hard emergency patterns — cardiac chest pain with breathlessness, FAST stroke signs, anaphylaxis, severe bleeding, seizure, unresponsiveness — it forces an emergency classification regardless of what the model said. Critical symptoms can never be silently downgraded.
3. A measured evaluation. I built a 45-case labeled test set and an evaluation harness computing accuracy, a confusion matrix, and safety recall (the fraction of true emergencies correctly caught).
The backend is FastAPI serving one /triage endpoint (Groq, openai/gpt-oss-120b, JSON mode, schema-validated with Pydantic). The frontend is React + Vite + Tailwind.
What I learned
The evaluation surfaced a real failure I wouldn't have caught otherwise. An early version of my RAG corpus used alarm-heavy wording, which biased the model toward over-triage and actually lowered accuracy (83.3% grounded vs 91.7% ungrounded). Rather than hide it, I diagnosed the cause — retrieved snippets lexically priming the emergency cluster — rewrote the corpus to be tier-neutral, and re-measured. Grounding is now accuracy-neutral (91.7%, matching ungrounded) while adding source transparency, with 100% safety recall and zero dangerous under-triages.
The lesson: RAG isn't automatically an improvement, and without an eval I'd have shipped a version that made the system worse. Measuring your own work honestly is the feature.
Challenges
Getting the safety layer to fire on real emergencies without false-positiving on negated or mild cases ("no chest pain, just a cold") took careful combination-based rules rather than keyword matching. And free-tier API quotas forced a disciplined, batched evaluation approach.
Limitations
The only consistent errors are at the routine/self-care boundary — genuinely borderline cases the model rated one tier lower than my gold label. Notably, no error was a dangerous under-triage: safety recall on true emergencies stayed at 100%, and mistakes clustered at the lowest-stakes boundary, never near emergencies.
AI tools disclosure
Built solo, with AI tooling disclosed in full:
- Claude Code (Anthropic) — used as a pair-programming tool to implement the FastAPI backend, React frontend, retrieval module, safety-rule layer, and evaluation harness under my direction. The architecture, the RAG/safety/eval design, the corpus curation, the test-set labels, and all engineering decisions (including diagnosing and fixing the over-triage bias) were mine.
- Groq API —
openai/gpt-oss-120b— the runtime LLM performing triage reasoning (substitute for the decommissionedllama-3.3-70b-versatile). - sentence-transformers (all-MiniLM-L6-v2) and FAISS — local embeddings and vector search.
- The clinical knowledge base is my own concise summaries of publicly documented triage guidance, with source URLs — not reproduced verbatim.
Log in or sign up for Devpost to join the conversation.