Voice agent for dentistry: pain triage + IDENT booking
A private dental clinic in St. Petersburg. The chief doctor personally responded to WhatsApp evenings and on weekends because 60% of inquiries were "acute pain" and the reception couldn't tell urgent from routine. A voice agent with a priority triage classifier and IDENT booking dropped reaction time from 47 minutes to 4.
Chief doctor responding on WhatsApp at 23:40
Private dentistry with two rooms. 60% of inquiries — "it hurts a lot, need it now". The rest — routine: cleaning, checkup, aesthetics. The cost of a triage error is high in both directions: missing acute pain means a lost patient and a medical issue; treating routine as urgent means a missed slot needed for an acute patient.
Daytime reception and WhatsApp at night and on weekends poorly distinguished one from the other. Scoring on "my tooth hurts" text gives nothing: the same phrase is written by someone who ate cold food yesterday and by someone with fever and a swollen cheek.
In the end, the chief doctor read every message and made the decision. That's 18 hours per week of personal time, half of which is evenings and weekends.
Priority 1/2/3 triage classifier → direct booking to IDENT
The voice agent collects a structured intake by 8 items: pain character, duration, radiation, temperature, swelling, response to temperature/pressure, previous interventions, medications. The GigaChat classifier assigns priority 1 (immediately), 2 (within 24 hours), or 3 (routine booking). IDENT receives the booking directly via an n8n workflow. Priority 1 goes to the chief doctor on Telegram at the same time.
Replacement number + WhatsApp bridge, voice or text by choice
GigaChat asks 8 structured questions about pain character
Classifier per medical prompt template + red-flag rules
Booking into the right time slot by priority; conflict resolution
P1 → Telegram to chief doctor; P2/P3 → SMS to patient with confirmation
Triage protocol assembled from 8 items
The prompt classifier doesn't analyze a single "it hurts" line — it leads a dialogue following a fixed template: pain character (sharp/dull/throbbing), duration (hours/days), radiation (does it radiate to jaw/temple/ear), body temperature, soft-tissue swelling, reaction to cold/hot/pressure, previous interventions in this area, medications taken. Output — structured JSON that feeds the priority classifier and the IDENT record.
Red flags override the model's decision
On top of GigaChat run deterministic red-flag rules: temperature > 38°C + swelling = automatic priority 1, bypassing the language model; inability to open the mouth = priority 1; tooth trauma in the last 6 hours = priority 1. The model cannot "change its mind" on these cases — that is the insurance against a hallucinated answer.
FZ-152: PII on RF servers, no identifiers in LLM
Patient PII (full name, phone, medical data) is stored in PostgreSQL on Selectel in RF. GigaChat receives de-identified data: age group ("45-55"), gender, symptoms — no name, phone, passport data. The session_id ↔ patient mapping is stored locally and doesn't leave the clinic perimeter. Before launch, consent for processing was obtained via the integrated consent flow.
Direct booking to IDENT via n8n
The n8n pipeline takes the classified request and writes to the IDENT API: picks the room, doctor, nearest priority-appropriate slot. If no slot is available for priority 1 — escalation to chief doctor on Telegram with info for manual decision (reschedule a routine, open an additional window, or redirect to a duty clinic).
FZ-152-compliant stack, no PII leaving the country
Voice channel: replacement number + bridge to clinic's WhatsApp channel
LLM intake and triage classifier; runs on de-identified data
Patient booking into the right room/slot, conflict checks
Pipeline: classifier → IDENT → escalation, conflict resolution
Priority 1 escalation to chief doctor with brief intake summary
Patient PII, session ↔ patient mapping — inside RF perimeter
PII processing consent before dialogue start; consent audit log
Deterministic red flags override LLM decision on acute cases
What changed in numbers
correctly classified P1 lands in the right slot
from first contact to confirmed booking
only real P1 + review of ambiguous cases
freed-up time = +1 working day/wk
The main win is medical quality: an acute patient gets into the chair in minutes, a routine one — into a convenient routine slot. No more "come in, we'll take a look" or "let me check and call you back within the hour".
Bonus we didn't bake into the KPI: the chief doctor now sees a dashboard distribution of P1/P2/P3 by day of week and hour — it became clear when extra slots are needed for emergencies and when for planning meetings and aesthetics.
Where else the same methodology applies
Universal pattern — "structured intake → triage → booking with escalation". Fits anywhere incoming flow is mixed by urgency and the cost of sorting errors is high:
- → Multi-specialty clinics — triage between specialists based on symptoms
- → Veterinary clinics — acute animal pain vs routine vaccination
- → Equipment service centers — breakdown stop vs preventive maintenance; urgent dispatch
- → Legal consultations — burning deadlines vs standard procedural questions
- → B2B technical support — production-down vs feature request
- Intake-prompt template with structured items and JSON-schema output
- Detect-rules layer: deterministic rules override LLM on critical cases
- FZ-152-compliant architecture: PII in RF, LLM gets de-identified data
- Escalation to Telegram or Slack with a short summary and action buttons
If your incoming flow is mixed by urgency and people make decisions manually — it can be automated
Medical and service scenarios with PII separately require FZ-152-compliant architecture — we know how to make do with LLM on de-identified data and store PII inside RF. Time to production — 5-7 weeks depending on CRM/medsystem integration complexity.
Deep dive:Personal data and LLMs: what reaches the model and how to check it
Related cases
Auto-prompt for Ya.Maps / 2GIS reviews + AI replies
A workflow fires when a work order is closed in 1C. 5★ → link to Ya.Maps, ≤3★ → form to owner. AI drafts…
Missed calls: auto-SMS with the real ship date
Cloud-telephony webhook → look up the customer and their order in Shopify → SMS with the actual ship date…
In-house AI sales assistant replacing a paid SaaS widget
Own RAG engine over a product fact corpus: SSE streaming, voice input, anti-abuse and grounding tests…
The 9,900 ₽ audit — with a concrete report and quote
I'll tell you what to deploy in your business first, what the payback looks like, and whether you need AI for the task at all (sometimes you don't).
Or just send your question — I reply within 2 hours