MedOperatorAI
Голосовой ассистент регистратуры поликлиники
Главная задача кейса — быстрый ответ и меньше пропущенных звонков. Наше условие — ноль ошибочных записей. Ассистент лучше честно скажет «не удалось» и передаст звонок оператору, чем запишет не того пациента, не к тому врачу или не на то время.
Кратко
Мы делаем голосового ассистента для регистратуры поликлиники. Пациент звонит в поликлинику по IP/SIP. Ассистент понимает запрос и находит врача и свободное время. Он записывает, переносит или отменяет приём в системе «Регистратура». Каждое изменение выполняется только после явного подтверждения пациента. За рабочий день до приёма ассистент сам звонит пациенту и уточняет, придёт ли он. Жалобы, медицинские вопросы, острую боль и всё нестандартное ассистент передаёт человеку.
Как проходит звонок
Пример записи к врачу. Сверху — карта всей архитектуры: она подсвечивает компонент, который работает в эту секунду. Слева — разговор. Справа — что делает каждый компонент: Asterisk, медиашлюз, распознавание речи Whisper, языковая модель (LLM), сервер, адаптер стенда, синтез речи Piper и архив.
- Пациент
- Петрова Анна · 05.05.1990
- Врач
- Малахова Оксана Григорьевна · терапевт · каб. 106
- Приём
- 15.10.2026 14:20 (GMT+4)
Это иллюстрация сценария на вымышленных данных, а не запись реального звонка. Живой SIP-звонок появится на следующем этапе работы.
Проблема
Мы проанализировали журналы кейса: 17 772 звонка за три месяца и 35 470 приёмов за полгода. Данные подтверждают задачу.
| Показатель | Задание | Расчёт по журналам |
|---|---|---|
| Пропущенные звонки в часы пик | 30–40% | 24,9% (весь журнал — 20,7%) |
| Неявки на приём | 18–25% | 13,1% |
| Типовые обращения | около 60% | 70,6% — запись или справка |
| Разговор с записью | 4–5 мин | 166,6 с |
| Звонков в день | до 200 | 193 в среднем, до 359 |
Типовые звонки составляют основную долю. Значит, ассистент может снять большую часть нагрузки с регистраторов. Запись через ассистента должна занимать меньше 166,6 с. Регламент поликлиники ставит цель 2,5 минуты.
Что считаем успехом
Решение работает, если после голосового разговора в стенде «Регистратура» появляется нужное изменение. Изменение сделано токеном нашей команды, для того пациента, с которым говорил ассистент, и для врача, которого он просил. Наш первый приоритет — ноль ошибок в записи. Второй — как можно больше звонков без участия оператора.
| Действие | Что должно появиться в стенде |
|---|---|
| Запись | Новая запись: правильные пациент, врач, дата и время, статус «Запланирована» |
| Перенос | Тот же ID записи с новой датой или новым врачом |
| Отмена | Тот же ID записи со статусом «Отменена» |
Запрос к API сам по себе успехом не считается. Целевые показатели кейса мы считаем отчётом из журнала звонков:
| Показатель | Цель | Как считаем |
|---|---|---|
| Пропущенные звонки | ≤ 15% | Все входящие в окне замера |
| Неявки | ≤ 12% | Состоявшиеся и неявки, без отменённых |
| Звонки без человека | ≥ 60% | Только с подтверждённым результатом |
| Ожидание ответа | ≤ 30 с | Среднее, от поступления до первого ответа по сути |
| Оценка пациента | ≥ 4 из 5 | Добровольный опрос после звонка |
Пустая выборка даёт «не измерено», а не ноль. Результаты тестовых звонков мы не выдаём за эффект в реальной клинике.
Как работает ассистент
Входящий звонок
- Ассистент здоровается и называет себя виртуальным помощником.
- Пациент говорит своими словами. Меню «нажмите 1» нет.
- Ассистент определяет цель: запись, перенос, отмена, статус записи или справка.
- Пациент называет фамилию, имя и дату рождения. Ассистент находит или создаёт карточку в стенде.
- Ассистент предлагает свободное время: по регламенту не больше трёх вариантов за раз.
- Ассистент зачитывает полную сводку: врач, дата, время, кабинет. Пациент подтверждает её явно. «Спасибо» не считается подтверждением.
- Сервер выполняет изменение в стенде и сообщает пациенту фактический результат.
Исходящее напоминание
- Звонок за предыдущий рабочий день до визита: будни 10:00–19:00, не больше двух попыток с интервалом не меньше 2 часов.
- Пациент подтверждает визит, переносит его или отменяет.
- Если ответил другой человек или автоответчик, ассистент не называет данные записи.
- Недозвон не отменяет приём.
Перевод на человека
Перевод — обязательная возможность. Маршруты звонков мы взяли из матрицы маршрутизации регламента регистратуры поликлиники (РГ-ТЕЛ-01, раздел 7.3). В матрице 17 правил, R01–R17: каждое задаёт условие, адресата и приоритет. Главные правила:
| Правило | Ситуация | Что делает ассистент |
|---|---|---|
| R01, R11 | Угроза жизни, острое состояние | Сразу говорит «звоните 103 или 112» и переводит с наивысшим приоритетом. Обратный звонок запрещён |
| R02 | Просьба позвать человека (у нас ещё и клавиша «0») | Переводит сразу, без уговоров |
| R03 | Жалоба | Переводит старшему администратору |
| R04 | Медицинский вопрос | Не консультирует, переводит регистратору |
| R05 | Ассистент дважды не понял пациента | Предлагает оператора, на третий раз переводит сам |
| R06 | Сбой системы записи дважды | Переводит, незавершённая операция сохраняется |
Оператор получает карточку перевода: цель звонка, собранные данные, причину и приоритет. Пациенту не нужно повторять всё заново. Если оператор не отвечает, ассистент предлагает обратный звонок. В экстренных случаях обратный звонок запрещён.
Справки
Ассистент отвечает на вопросы о режиме работы, адресе, ценах и документах по базе знаний из регламента поликлиники. Результаты анализов ассистент не называет и не толкует.
Как мы обеспечиваем ноль ошибок
| Риск | Защита |
|---|---|
| Пациента поняли неправильно | Полная сводка и явное подтверждение. Отказ, условие или сомнение отменяют действие |
| Модель «решила» записать сама | Модель не может выполнить запись. Запись делает только сервер после проверок |
| Стенд не проверяет занятость | Наш календарь резервирует слот атомарно. Два звонка не займут одно время |
| Ответ стенда потерян | Запрос записи уходит один раз. Неизвестный исход сверяется по записям пациента. Слепого повтора и дубля нет |
| Чужие данные | Ассистент не называет данные записи, пока пациент сам не назвал свои |
| Лимит 10 запросов в минуту | Общий бюджет для всех звонков и кэш справочника врачей. Справочник врачей и расписание берём из локальной копии. В стенд уходят только поиск пациента и изменения |
| Медицинский риск | Проверка срочности на каждой фразе пациента. Нет диагнозов, лекарств и оценки симптомов |
Архитектура
PJSIP, очередь операторов, клавиша «0» для перехода к человеку. Команды и события звонка идут через ARI. Звук идёт через канал WebSocket, 16 кГц.
Шлюз собирает фразу пациента и отдаёт её на распознавание. Если пациент заговорил во время ответа, шлюз сразу останавливает речь бота командой FLUSH_MEDIA.
faster-whisper small на CPU: int8, beam 5, русский язык. Работает локально, звук не уходит за пределы контура.
Qwen3-4B (Q4_K_M) в llama.cpp на 127.0.0.1, temperature 0, ответ по строгой JSON-схеме. Срочность и намерение проверяются параллельно на каждой фразе, за 1,2 с. Для «да», «завершить» и «позовите человека» есть отдельная проверка действия.
Та же модель с вызовом функций, один вызов за шаг, ход до 12 с. Инструменты: поиск услуги и врача, разбор даты, свободные слоты, подготовка записи, переноса и отмены, записи пациента. Модель готовит сводку, но не может выполнить запись.
Права пациента, доставка сводки и согласие, маршрутизация R01–R17, календарь и резервы, журнал операций с однократной отправкой. Только сервер решает, выполнять ли действие.
Общий лимит 10 запросов в минуту, кэш справочника врачей, сверка неизвестного исхода. В стенде — пациенты, врачи и записи.
Шаблон сервера (приветствие, сводка, итог) или текст модели → одна очередь речи → синтез Piper → Asterisk.
Карточки звонков, операции и ошибки. Аудио и текст сохраняются только при включённой политике хранения.
| Компонент | Решение |
|---|---|
| Сервер | Python 3.13, ядро без внешних зависимостей, SQLite |
| Модели | Сейчас локально: faster-whisper small, Qwen3-4B, Piper. Для сравнения — другие локальные модели и облачные сервисы Yandex, Cloud.ru и SaluteSpeech. Готовы программа сравнения и адаптеры 9 языковых моделей, прогонов ещё нет. Реальные данные пациентов — только на платформе с уровнем защищённости УЗ-1 и аттестатом ИСПДн |
| Расписание | Файл Excel кейса: 85 врачей, 40 профилей, 136 973 слота на 25.06–31.12.2026, приёмы по 20–60 минут, отпуска и больничные. Файл уже прочитан и проверен. Пациенту предлагаем свободные слоты на 14 дней вперёд, не позже чем за 30 минут до начала |
| Панель | Веб-панель администратора: звонки, аудио, расшифровки, ошибки. Это рабочий инструмент администратора. Главный результат проекта — голосовой сценарий |
Основной стек открытый и работает локально. Облачные модели — только опция. При сбое облака звонок продолжит локальная модель.
Данные и 152-ФЗ
- В стенде только вымышленные пациенты. Реальные персональные данные в систему не попадают.
- Сейчас распознавание речи и диалог работают локально, в контуре команды. Бесплатные облачные сервисы распознавания мы не используем.
- Запись разговора выключена по умолчанию. Если её включить, ассистент предупреждает пациента. Пациент может отказаться.
- Номера телефонов для обзвона хранятся у нас, а не в стенде.
- Ключи и токены хранятся вне репозитория.
- Промышленная аттестация (УЗ-1, аттестат ИСПДн) — задача внедрения в реальной клинике. На хакатоне мы её не заявляем.
Что уже сделано
Мы разобрали задание и материалы кейса: журналы, регламент регистратуры, OpenAPI стенда. Все 97 утверждений задания мы сверили с проектом. Мы написали контракт продукта 2.2.0, таблицу маршрутизации R01–R17, 12 сценариев приёмки и 16 контрольных диалогов по регламенту. Мы выбрали телефонию: Asterisk 22 LTS.
Диалог, голос и модели офлайн
Маршрутизация R01–R17 и права вымышленных пациентов. Запись, перенос и отмена через имитацию речи и модели. Программа сравнения и адаптеры 9 языковых моделей
Запись в стенд офлайн
Чтение и проверка Excel-расписания. Календарь и подготовка записи. Создание записи с однократной отправкой. Перенос и отмена одним PATCH. Кодек API, общий лимит, поиск и создание пациента
Телефония офлайн
Управление звонком через ARI, аудиопоток с перебиванием, восстановление аудиосоединения, сетевой адаптер ARI. Живое подключение пока закрыто
Архив и панель офлайн
Карточки звонков, рабочие отметки, хранение аудио и расшифровок, журнал доступа, вход, список звонков, просмотр аудио и текста
Что ещё не сделано
- нетЖивого звонка. Asterisk ещё не развёрнут. Адаптеры проверены только на поддельном транспорте.
- нетЗапросов к стенду. Мы не получили токен команды. Без него нельзя сопоставить врачей стенда с графиком.
- не подтвержденоКачество голосового диалога. Последняя серия голосовых проверок прошла частично. Открыт дефект: короткое «спасибо» однажды приняли за согласие.
- не проведеноСравнение моделей. Готовы программа сравнения и адаптеры 9 языковых моделей. Адаптеры распознавания речи в работе, разметка корпуса не закончена. Прогонов ещё нет.
- не подключеноРаспознавание жалоб для перевода. Правила маршрутизации и серверная часть готовы.
- нетФонового обзвона. Планировщик готов, хранилища контактов нет.
- не сопоставленоВрачи расписания и стенда. Файл Excel прочитан и проверен. Сопоставить его врачей с врачами стенда можно после получения токена.
План до финала
Шаги идут по порядку. Сначала мы выбираем модели, затем собираем голос, телефонию и стенд.
| Шаг | Работа | Результат шага |
|---|---|---|
| 1 | Сравнение локальных и облачных моделей: LLM, распознавание и синтез речи. Один корпус: 20 сценариев и 16 контрольных диалогов | Выбор моделей по качеству, задержке и стоимости. Главный критерий — ноль ошибочных действий |
| 2 | Голосовой сценарий на реальных моделях: запись, перенос, отмена. Повторная проверка дефекта «спасибо» | Голосовой диалог проходит контрольные диалоги, задержки измерены |
| 3 | Asterisk на сервере, звонок с софтфона, перебивание, клавиша «0», очередь оператора | Живой SIP-звонок доходит до ассистента и до оператора |
| 4 | Подключение к стенду: токен, сопоставление врачей Excel и стенда, запись в стенд только через наш сервер | Первые запись, перенос и отмена в стенде из тестового контура |
| 5 | Исходящее напоминание и обратный звонок на софтфон | Подтверждение, перенос, отмена по звонку ассистента |
| 6 | Сквозная демонстрация: запись и напоминание, затем перенос, отмена, перевод. Отчёт KPI по тестовым звонкам | Звонок → изменение в стенде → запись в журнале API стенда. JSON-отчёт с явными знаменателями |
Сценарий показа жюри
- Участник звонит с софтфона и просит записать его к терапевту на завтра после обеда.
- Ассистент находит время, зачитывает сводку и получает «да».
- В панели стенда появляется новая запись.
- Второй звонок: перенос на другой день. У той же записи меняется время.
- Исходящее напоминание: пациент отказывается от визита. Запись получает статус «Отменена».
- Звонок с жалобой переводится на софтфон оператора с карточкой.
Риски
| Риск | Мера |
|---|---|
| Распознавание ошибается в именах и датах | Подтверждение полной сводки. Перевод после двух непонятых фраз |
| Локальные модели отвечают медленно | Цель: ответ без поиска — p50 ≤ 1,5 с, с поиском — p95 ≤ 5 с. Короткие фразы ожидания. Сравнение с облачными моделями. Замер на живом звонке |
| Лимит 10 запросов в минуту | Общий бюджет, кэш, локальная копия данных, приоритет входящих звонков |
| Потерян ответ стенда | Неизвестный исход и сверка, без повторной записи |
| Врачи в файле расписания и в стенде не совпадут | Точное сопоставление по ФИО и профилю. Без сопоставления ассистент не предлагает слот |
| Формат перевода на оператора для стенда не описан | Сейчас перевод идёт в очередь Asterisk с карточкой. Если у стенда появится API заявок, мы подключим его |
| Сложность телефонии | Решение зафиксировано. Адаптеры уже проверены без сети |
Что нам нужно от организаторов
- Токен команды для стенда.
- Список справочных вопросов, если он есть.
- Уточнение: перевод на оператора — живой звонок или заявка через API.
- Требования к серверу для сдачи.
Как сдаём
- Репозиторий с кодом, документацией, тестами и инструкцией запуска.
- Рабочее решение на сервере: Asterisk, голосовой сервер, сервер операций.
- Показ через софтфон. Внешний номер не обязателен.