An AI routing service: a message with a refill and a new symptom is split and sent to the nurse and clinician queues. It suggests a route, never a diagnosis.
Overview
What this is and why it matters, in plain English.
An AI routing service: a message with a refill and a new symptom is split and sent to the nurse and clinician queues. It suggests a route, never a diagnosis.
AI that reads patient messages and sends each request to the right team, in under 2 seconds.
The situation
What was going on before, and why it needed fixing.
Patient messages often mixed a refill request with a new symptom. One label sent the whole thread to one desk, and urgent symptoms waited behind billing.
One message often held a refill and a new symptom. A single label sent the whole thread to the wrong desk, and urgent swelling waited behind billing.
What it needed to do
The outcomes the project had to deliver.
- Split mixed messages into separate intents.
- Route each intent to a queue the clinic actually staffs.
- Return a route, never a diagnosis or treatment.
What I did
My part of the work and who I worked with.
I built the Node.js service, the prompts for Claude and ChatGPT, the closed label set and RBAC map, and the Redis routing cache.
How it works
The main building blocks, from the screen people use to the data underneath.
A Node service calls Claude or ChatGPT with a fixed label set, stores the route in Redis for the shift, and refuses labels outside the clinic’s RBAC map.
- 01
REST endpoint
Accepts a patient message and returns one route per intent.
- 02
LLM classification
Claude or ChatGPT splits intents and labels each from a fixed set.
- 03
RBAC label map
Filters out any label the clinic has not mapped to a staffed queue.
- 04
Redis
Stores routes for the shift so queues read quickly.
Key choices and trade-offs
Every build involves trade-offs. These are the important ones and what each one cost.
| Decision | Trade-off |
|---|---|
| Closed enum of labels. | New intents need a config change, but the model cannot invent a queue. |
| Routes, not advice. | Less automation, but triage stays a sorting step and clinical judgment stays with people. |
Under the hood
Implementation details for technical readers, with a code sample.
- Routing in under 2 seconds.
- Closed label set enforced after the model.
- Automatic first-pass inbox sort.
const labels = ['refill', 'symptom', 'billing', 'scheduling'] as const;
export async function triage(message: string) {
const raw = await llm.json({
system: 'Split intents. Use only the allowed labels. No diagnosis.',
input: message,
schema: { intents: labels },
});
return raw.intents.filter((item) => labels.includes(item.label));
}Problems solved
What got in the way, and how each problem was fixed.
- 01
Mixed intents had to split instead of picking the first sentence.
The prompt asks for all intents, and the schema expects a list, so a message with a refill and a symptom produces two routes.
- 02
The model could not invent a queue the clinic did not staff.
Model output is filtered against the clinic’s RBAC map; unmapped labels are refused.
- 03
A triage suggestion is not a diagnosis, so the API returns a route, not a treatment.
The API returns a route only and the prompt forbids diagnosis, keeping triage separate from treatment.
Security, speed and growth
How data is protected, and how the system stays fast as usage grows.
Security
RBAC controls which queues exist per clinic, and only routes are stored, not clinical conclusions.
Speed & growth
Each message routes in under 2 seconds, with shift routes cached in Redis.
Quality and releases
How changes were tested and shipped safely.
Message fixtures with mixed intents, out-of-set labels, and requests for advice, each with expected routes.
Tech stack
The tools and technologies used, for recruiters and technical reviewers.
Results
Measured outcomes recorded for this project.
| Metric | Result |
|---|---|
| Route time | <2 sec |
| Label set | closed enum |
| Inbox sort | auto first pass |
Questions
Plain answers first, then the detail a technical reviewer would ask about.
Common questions
- Does it give patients medical advice?
- No. It only decides which team should see a message. Clinical decisions stay with clinicians.
- What does it change for staff?
- Messages reach the right queue in under 2 seconds, so nurses and clinicians spend less time sorting the inbox.
For your tech lead
- What if a message has two requests?
- Each intent becomes its own route to its own queue.
- Does it give medical advice?
- No. It returns a route only.
Key takeaways
- •AI that reads patient messages and sends each request to the right team, in under 2 seconds.
- •Built with Node.js, Claude, ChatGPT, Redis, RBAC, REST.