Правила принятия OpenJev

September 20, 2026 · View on GitHub

Что оценивает модель

OpenJev — NLI cross-encoder. Он не слышит аудио и не знает, кому в реальном мире адресована фраза. Ему подаётся пара «предпосылка / гипотеза», а результатом являются вероятности классов:

  • 0: contradiction;
  • 1: entailment;
  • 2: neutral.

В gate сравниваются две пары и используется P(entailment):

«... вопрос или просьба?» → «Ответ: да.»
«... вопрос или просьба?» → «Ответ: нет.»

Первый запрос

Когда активного диалога нет, оценивайте полезное, проверяемое свойство:

Фраза: «<transcript>»
Вопрос: является ли фраза вопросом или просьбой?

Это принимает вопросы и просьбы без обязательного имени ассистента. Оно также может принять вопрос, обращённый к человеку рядом — это фундаментальное ограничение подхода без wake word.

Продолжение диалога

После принятого ответа держите последнюю реплику и последний ответ в RAM, не более короткого TTL. Для следующей реплики проводите две независимые проверки:

  1. связана ли фраза с этим контекстом;
  2. является ли она сама вопросом или просьбой.

Принимайте фразу, если прошла хотя бы одна проверка. Это важно: активный контекст не должен отклонять новый вопрос только потому, что он меняет тему.

Контекстная проверка:

Предыдущая реплика пользователя: «<user>»
Предыдущий ответ ассистента: «<assistant>»
Новая фраза: «<transcript>»
Вопрос: новая фраза является продолжением этого диалога?

Независимая проверка вопроса/просьбы использует тот же prompt, что и первый запрос. Рекомендуемый начальный TTL: 45 секунд. При истечении TTL используйте только проверку первого запроса.

Решение

Стартовое правило:

accepted = yes_score >= 0.40 and yes_score - no_score >= 0.22

Если accepted == False, не отправляйте транскрипт агенту, не выдавайте отрицательный звуковой сигнал и не создавайте сетевой запрос. Тишина уменьшает раздражение и не раскрывает окружающим распознанный текст.

При accepted == True подайте короткий локальный положительный звук. Закройте аудиопоток до воспроизведения, иначе динамик может попасть обратно в VAD/ASR.

Стоп-лист до JEV

Если транскрипт содержит целое слово или фразу из локального стоп-листа, отбрасывайте его до JEV, агента и Telegram. Это полезно для устойчивых ложных транскрипций и известных домашних реплик.

Начальный список из реального теста:

STOP_PHRASES = ('Мирон', 'Мерон', 'Аврора', 'Продолжение следует')
STOP_PATTERN = re.compile(
    r'(?iu)(?<!\\w)(?:' + '|'.join(map(re.escape, STOP_PHRASES)) + r')(?!\\w)'
)

Границы предотвращают ложное совпадение Миронов по слову Мирон. Логируйте причину stop_phrase локально, но не отправляйте отказ в чат и не проигрывайте отрицательный звук. Дополняйте список только после проверки реальных ошибок: чрезмерный стоп-лист станет скрытым фильтром обычных запросов.

Калибровка

Соберите датасет из реальных, но обезличенных транскриптов:

  • вопросы агенту без имени;
  • просьбы агенту;
  • разговоры с человеком рядом;
  • фрагменты телевизора, видео и музыки;
  • однословные ответы: «да», «нет», «спасибо»;
  • продолжения: «а подробнее?», «покажи пример»;
  • плохое ASR и шум.

Для каждого примера сохраните: ожидаемый класс, ASR-текст, yes_score, no_score, режим (first_request или continuation) и итог. Подбирайте пороги на отложенной выборке, ориентируясь прежде всего на ложные допуски, если доступ к инструментам возможен.

Не называйте yes_score калиброванной вероятностью намерения. Это оценка NLI-модели для выбранной формулировки.