Перейти к содержанию
вторник, 6 октября 2026 г.

ИИ Вестник

Главные новости о развитии искусственного интеллекта в России

Голосовой ИИ-агент спотыкается на числах: как 155 строк кода решают проблему русской нормализации

Источник: Все публикации в потоке Разработка
Developer at desk with code, Russian voice AI interface on screen, focused.
Generated by Sourceful Riverflow (RouterAI)

Разработчик голосового агента опубликовал разбор ключевой проблемы синтеза речи — некорректного чтения чисел, дат и телефонов. Решение заняло 155 строк кода с одной зависимостью и закрыло даты, суммы, проценты и номера заказов для русского языка. По словам автора, именно ошибки в числах мгновенно выдают робота в телефонном разговоре.

Практикующий разработчик голосовых интерфейсов представил подробный технический разбор одной из самых недооценённых проблем в создании ИИ-агентов — нормализации русских чисел перед синтезом речи. Публикация появилась в потоке «Разработка» и содержит полный исходный код библиотеки, умещающейся в 155 строк. Автор утверждает, что голосового агента выдаёт не качество синтеза, а то, как он произносит цифры: фраза «Привезём 15.07.2026» в устах робота легко превращается в бессмысленный набор звуков, от «пятнадцать точка ноль семь» до чтения даты как дроби. Каждый такой момент — это секунда, в которую собеседник окончательно понимает, что говорит с программой.

Ключевая идея решения состоит в том, что числа вообще не должны доходить до движка синтеза речи. Вся числовая информация разворачивается в слова заранее, на отдельном слое нормализации, и только после этого текст отправляется в TTS. Автор приводит два обоснования такого подхода. Первое — детерминизм: поведение конкретного движка при чтении «1 490 ₽» зависит от версии модели и её внутренних настроек, один синтезатор сносно читает суммы, но спотыкается на датах, другой — наоборот. Второе — переносимость: агент изначально работал на синтезе Яндекса, затем появился вариант с открытой моделью, и слой нормализации переехал без единой правки, тогда как настройки, вшитые в конкретный TTS, пришлось бы переделывать заново. Единственная внешняя зависимость библиотеки — пакет num2words, всё остальное построено на регулярных выражениях и работе с окончаниями.

Технически наиболее сложной частью оказалось склонение порядковых числительных. Библиотека num2words выдаёт формы только в мужском роде: для числа 15 возвращается «пятнадцатый», тогда как дате требуется средний род «пятнадцатое июля», а году — родительный падеж «две тысячи двадцать шестого года». Автор не считает это недостатком библиотеки, отмечая, что полное склонение порядковых числительных — отдельная большая задача. В решении нужные формы получаются заменой окончания у последнего слова: «-ий» превращается в «-ье», «-ый» и «-ой» — в «-ое». Отдельная ветка кода прописана для слова «третий» с его мягкой основой, иначе вместо «третье» получается «третьье». Меняется окончание только у последнего слова, поскольку в конструкции «две тысячи двадцать шестой» склоняется лишь «шестой».

Второй принципиальный момент — строгий порядок обработки числовых форматов. Регулярные выражения конкурируют за одни и те же цифры, поэтому последовательность зафиксирована в шапке файла: даты, затем телефоны, деньги, проценты, знак номера и только в конце голые числа. Если запустить обработку простых чисел первой, дата «15.07.2026» превращается в «пятнадцать.семь.две тысячи двадцать шесть», после чего регулярка дат уже не находит цифр и не может сработать. Правило сформулировано просто: от частного к общему, самые структурированные форматы разбираются первыми, пока их цифры целы. Телефоны требуют отдельной логики: читать их как одно большое число нельзя, но и побуквенное чтение неестественно, поскольку живой человек диктует номер группами. Группа с ведущим нулём читается по цифрам, чтобы «005» не превратилось в «пять» и абонент не записал неверный номер, остальные группы произносятся как числа. Дополнительно реализовано русское склонение существительных после числительных: один рубль, два рубля, пять рублей, с отдельным исключением для чисел от одиннадцати до четырнадцати.

Для российского рынка голосовых роботов эта публикация имеет практическое значение. Русский язык относится к языкам с развитой морфологией, и корректная генерация числительных в нужном роде, падеже и числе остаётся нетривиальной задачей для большинства зарубежных и даже отечественных TTS-движков. Компании, разворачивающие голосовых ассистентов в банках, логистике, телемедицине и службах поддержки, регулярно сталкиваются с тем, что клиенты неверно записывают номера заказов, суммы и даты доставки. Открытая публикация кода снижает порог входа для небольших команд, у которых нет ресурсов на собственную лингвистическую инфраструктуру. Показательно, что автор нашёл один из багов прямо в процессе подготовки текста статьи, что подчёркивает сложность тестирования подобных решений без покрытия краевыми случаями.

Альтернативные подходы к проблеме существуют, но каждый имеет ограничения. Крупные облачные провайдеры синтеза речи иногда предоставляют встроенную нормализацию текста, однако её поведение непрозрачно и меняется между версиями API. Лингвистические библиотеки вроде num2words покрывают базовые случаи, но не дают готовых форм для всех родов и падежей. Собственные решения на правилах, подобные описанному, требуют ручной поддержки исключений, зато предсказуемы и переносимы между движками. Автор фактически предлагает компромисс: минимальная зависимость плюс 155 строк кода, которые можно прочитать и проверить целиком, вместо чёрного ящика внутри TTS.

Открытыми остаются вопросы масштабирования подхода на другие языки и на более сложные числовые конструкции — диапазоны, дроби, отрицательные значения, валюты с копейками, адреса и артикулы. Перенос слоя нормализации на казахский, украинский или языки с иной морфологией потребует переписывания правил склонения. Кроме того, неясно, как решение поведёт себя при потоковой генерации текста языковой моделью, где числа появляются в произвольных форматах. Тем не менее публикация задаёт полезный ориентир: голосовой агент становится убедительным не за счёт более дорогого синтеза, а за счёт аккуратной предварительной обработки текста, и этот слой стоит выносить за пределы TTS-движка.

Читайте также