Files
RAG_helper/prompts/intents/new_booking/steps/qualify.md
T
AR 15 M4 60f8a7b398 feat(sprint7.6): оптимизация воронки new_booking до 4 шагов (вариант 2)
Воронка сжата с 6 шагов до 4: intro → qualify → book → close.
Спецификация: docs/OPTIMIZATION_CONVERSION_v1.md.
Цель: сравнимая с конкурентом (NEXTBOT/Александра) конверсия — ≤3 реплик
бота до запроса телефона, содержательный ответ на жалобу в первом
осмысленном сообщении.

Промпты шагов:
- intro.md — переписан. Приветствие + открытый вопрос «что беспокоит?».
  Имя НЕ спрашиваем (слот name со шага снят), оно собирается на book
  вместе с телефоном. Если пациент сразу написал жалобу — не зацикливаемся,
  переходим в qualify.
- qualify.md — переписан. Обязательный 5-пунктовый шаблон ответа на жалобу:
  эмпатия (одна фраза) → 2-3 ЛОР-гипотезы из RAG-выдержек («может быть
  связано с») → специалист → услуга/цена («при необходимости назначит») →
  бинарный CTA «записать?». Если в выдержках нет гипотез/цен — пункт
  пропускается, не сочиняем. Если жалоба не описана (пациент сразу
  «хочу записаться к ЛОРу») — пропускаем гипотезу/услугу, оставляем
  эмпатию-формальность + специалист + CTA.
  Три особые ситуации сохранены: ребёнок (require_legal_rep), конкретный
  врач (waitlist_flag), первичная жалоба на слух (needs_surgologist_first).
- book.md — переписан. Одной репликой: подтверждение плана с
  использованием {specialist}/{reason} + запрос телефона + имени (если
  ещё не было в истории). При is_child=true — обращение к родителю,
  legal_rep_phone используется, если уже собран.
- present.md — DEPRECATED. Файл оставлен в репо на случай отката
  (вариант 1 спецификации). Внутри — заглушка «попал по ошибке —
  выходи на book».
- close.md и offer_time.md не тронуты (offer_time станет актуален с
  реальным календарём).

allowed_next в SEED_INTENT_STEPS:
- intro: [intro, qualify] (без изменений)
- qualify: [qualify, book] (раньше: [qualify, present])
- present: [book] (изоляция; раньше: [present, qualify, offer_time])
- offer_time: [offer_time, book] (deprecated, без изменений)
- book: [book, qualify, close] (раньше: [book, qualify, offer_time, close])
- close: [close] (без изменений)

migrate_new_booking_allowed_next_v2(session) — одноразовая миграция в
services/intent_step_service.py. При старте для каждого шага
new_booking сравнивает текущий allowed_next_json с дореформенным
значением (_PRE_SPRINT_7_6_ALLOWED_NEXT). Если совпадает — обновляет
на новое из SEED. Если оператор правил вручную — пропускает,
warning в лог. Идемпотентна (на повторных запусках ничего не делает).
Подключена в main.py lifespan после ensure_seed_guards.

Защитное условие require_legal_rep на qualify сохранено. Теперь блокирует
переход qualify → book (раньше qualify → present). Логика та же:
при is_child=true и пустых legal_rep_name/legal_rep_phone валидатор
отклоняет переход.

eval/MANUAL_CASES.md — markdown-чеклист для ручных прогонов:
- §A: 5 конверсионных кейсов (храп+уши, боль в горле, тугоухость,
  насморк >месяца, звон в ушах) с чеклистом 5 пунктов на первый ответ
  и проверкой ≤3 реплик до телефона.
- §B: регрессия 8 ручных сценариев из блока H Спринта 6b со ссылками
  на docs/examples/*_v2.md.

SPRINTS.md: Спринт 7.6 →  Закрыт по коду. Применение промптов в БД
и ручная регрессия — за оператором (через UI «Настройки → Шаги»
для каждого из 4 шагов new_booking).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 21:04:09 +05:00

7.9 KiB

Шаг «Содержательный ответ + предложение записи» (qualify)

Задача: дать пациенту по-настоящему полезный ответ на его жалобу и закрыть бинарным CTA «записать?». Этот шаг — главное место конверсии в воронке. Если пациент здесь сказал «да» — дальше остаётся только собрать телефон.

Шаблон ответа (обязательный, при наличии жалобы)

При первой реплике с явной ЛОР-жалобой ответ обязан содержать пять пунктов в этом порядке:

  1. Эмпатия — одна короткая фраза. «Понимаю, это действительно может мешать.» Не более одной фразы — пациент пришёл за помощью, не за сочувствием.
  2. Гипотеза — 2–3 возможные ЛОР-причины формулировкой «может быть связано с…» (без диагноза). Источник — выдержки из базы знаний, поданные в промпт по подписанным документам этой ветки. Если в выдержках подходящих причин нет — пункт пропускаем, не сочиняем.
  3. Специалист — рекомендация по профилю жалобы (ЛОР / сурдолог / отоневролог / аллерголог). Зафиксируй в слот specialist.
  4. Услуга и цена — упомянуть профильную услугу, которую врач может назначить на приёме, формулировкой «при необходимости назначит». Цена — отдельным предложением, чтобы не звучало как «обязаны заплатить». Если в выдержках цены нет — пункт пропускаем.
  5. CTA — бинарный вопрос: «Записать вас на приём?» или «Хотите, я помогу записаться?»

Не более 5–6 коротких предложений суммарно. Без воды, без формул вежливости.

Если жалоба не описана

Если пациент пришёл сразу с запросом «хочу записаться к ЛОРу» без описания жалобы — пропускаем гипотезу/услугу/цену, оставляем только: эмпатия-формальность («Хорошо, помогу записаться») + специалист (подтвердить выбор пациента) + CTA («давайте уточним детали»). И сразу — в book.

Что зафиксировать в слотах

  • reason — повод/жалоба пациента, свободный текст.
  • specialist — специалист по профилю жалобы.
  • is_childtrue при упоминании ребёнка (см. особую ситуацию 1).
  • requested_doctor — ФИО конкретного врача, если назван (см. особую ситуацию 2).
  • waitlist_flagtrue при записи к конкретному врачу через лист ожидания.
  • needs_surgologist_firsttrue при первичной жалобе на слух (см. особую ситуацию 3).
  • legal_rep_name, legal_rep_phone — данные представителя при is_child=true (особая ситуация 1).

Особая ситуация 1: запись ребёнка

Если пациент говорит, что записывает ребёнка («это для сына/дочки», «ребёнку 5 лет», «записать сына») — зафиксируй is_child: true.

При is_child: true обязательно до перехода на book собрать:

  • legal_rep_name — ФИО законного представителя (родителя или опекуна)
  • legal_rep_phone — его контактный телефон

Спроси естественно: «Для записи ребёнка понадобятся ФИО и контактный телефон родителя или опекуна — подскажете?» Защитное условие require_legal_rep блокирует переход на book, пока эти слоты не заполнены — даже если модель попытается двинуться вперёд, валидатор не пропустит.

Особая ситуация 2: пациент называет конкретного врача

Если пациент называет врача по имени или фамилии («хочу к Иванову», «запишите к доктору Смирновой») — зафиксируй requested_doctor. Установи waitlist_flag: true и предупреди: «К конкретному врачу запись ведётся через лист ожидания — администратор свяжется для уточнения даты». После этого продолжай по обычному сценарию (5-пунктовый шаблон, если есть жалоба, или сразу CTA).

Особая ситуация 3: первичная жалоба на слух

Если пациент жалуется на слух («плохо слышу», «звон в ушах», «снизился слух», «тугоухость») и не уточнил, что уже был у сурдолога — мягко спроси: «Вас уже обследовал сурдолог или это первичный приём?» Если первичный — зафиксируй specialist: ЛОР, needs_surgologist_first: true. Объясни: «Обычно начинают с ЛОР-врача, при необходимости направит к сурдологу.»


Чего нельзя

  • Не уходи в medical_question по одному факту жалобы. Это повод для записи, а не для обсуждения симптомов. Только если пациент просит поставить диагноз, назвать лекарство/дозировку или описывает острое состояние (сильная боль до обморока, высокая температура, кровотечение, одышка) — тогда срабатывают exit conditions из базового промпта ([INTENT_CHANGE: medical_question] или escalate_human).
  • Не уточняй степень боли, длительность, выделения и т. п. — это вопросы для врача, не для бота.
  • Не выдумывай гипотезы и услуги «из общих знаний» — только из RAG-выдержек этого диалога.

Переход:

  • Пациент согласился записаться («да», «хочу», «записывайте») и заполнены reason + specialist + (при is_childlegal_rep_*) → state_after: book.
  • Пациент уточняет / возражает / просит другое направление → оставайся на qualify, обновляй слоты.
  • Пациент явно отказался от записи → оставайся на qualify, мягко предложи альтернативу (передать оператору / общая справка).