🧠NAS как ИИ-сервер
🏠
Фаза 4 · STT → LLM → TTSС оговорками

Голосовой ассистент

Собрали всё вместе. Говоришь «погаси свет в коридоре», NAS распознаёт речь, LLM решает, что нажать в Home Assistant, и голосом отвечает «Свет в коридоре погашен». Работает, и довольно точно. Но думает он 9–10 секунд.

Берём Vosk → Qwen3.5-4B → Silero: 93% команд со звука, ~9 секунд на ответ
Сухие цифры и методика →

Как это устроено: распознавание речи (фаза 2) → языковая модель с инструментами Home Assistant (фаза 5) → синтез речи (фаза 3). Мы взяли 40 типичных команд — свет, шторы, климат, таймеры, вопросы «что включено?» — и озвучили их тремя синтетическими голосами. Получилось 120 голосовых команд плюс их зашумлённые копии. Весь конвейер честно работал на NAS: распознавание и LLM одновременно на одном iGPU.

93%команд выполнено верно (Vosk → Qwen3.5-4B)
10.6 сот конца фразы до ответа (замер)
6.3 сс быстрым Ling, но 83–87% команд
7–9 ГБпамяти на весь стек

Живые диалоги

Вот как это выглядело в живом стеке: whisper → LLM → Silero. Слева Qwen3.5-4B, справа Ling 3.0 Tiny. Можно послушать саму команду, она синтетическая.

сказано «Поставь кондиционер на двадцать два градуса.»
whisper услышал Поставь кондиционер на 22 градуса.
Qwen3.5-4B✅ 11.7 с
HassClimateSetTemperature(temperature=22, name="Кондиционер", area="Гостиная")
🔊 «Кондиционер в гостиной установлен на двадцать две градуса.»
Ling 3.0 Tiny⚠️ 6.7 с
HassClimateSetTemperature(temperature=22, name="Кондиционер", area="Гостиная")
🔊 «Кондиционер в гостиной установлен на 22 градуса.»

Оба поняли. Но Ling ответил цифрами, и Silero без нормализатора сказал бы «Кондиционер в гостиной установлен на градуса». Qwen ответил словами, правда, с «двадцать две градуса».

сказано «Погаси свет в коридоре.»
whisper услышал Погаси свет в коридоре.
Qwen3.5-4B✅ 11.5 с
HassTurnOff(name="Свет в коридоре", area="Коридор")
🔊 «Свет в коридоре погашен.»
Ling 3.0 Tiny❌ 6.2 с
HassTurnOn(name="Свет в коридоре", area="Коридор")
🔊 «Свет в коридоре включен.»

«Погаси» для Ling оказалось незнакомым словом, и свет он включил. Зато бодро отчитался.

сказано «Засеки полчаса для пирога.»
whisper услышал Засейки полчаса для пирога.
Qwen3.5-4B✅ 11.9 с
HassStartTimer(hours=0, minutes=30, seconds=0, name="Пирог")
🔊 «Таймер на полчаса запущен.»
Ling 3.0 Tiny❌ 5.6 с
ничего не вызвал
🔊 «Я не вижу устройства "засейки" в списке. Пожалуйста, уточните, какое именно устройство вы хотите управлять, или я могу помочь с другим устройством из списка.»

Whisper услышал «засейки». Qwen догадался, что это таймер, Ling ищет устройство «засейки».

сказано «На кухне что-нибудь включено?»
whisper услышал На кухне что-нибудь включено.
Qwen3.5-4B❌ 4.0 с
ничего не вызвал
🔊 «На кухне включен чайник.»
Ling 3.0 Tiny✅ 5.0 с
GetLiveContext()
🔊 «На кухне включён чайник.»

Распознавание потеряло «?», и Qwen принял вопрос за утверждение: ответил, ничего не проверив. Чайник он выдумал (угадал, но всё же).

сказано «Выключи люстру в гостиной.»
whisper услышал Выключили устроф гостиной.
Qwen3.5-4B❌ 4.2 с
ничего не вызвал
🔊 «Устройства в гостиной выключены.»
Ling 3.0 Tiny❌ 6.3 с
HassTurnOff(name="Телевизор", area="Гостиная")
🔊 «Телевизор в гостиной выключен.»

Голос Piper с неверными ударениями: распознавание выдало абракадабру. Qwen сказал, что всё выключил, но ничего не вызвал, а Ling выключил телевизор вместо люстры.

Где тратится время

«Замер» — живой стек на NAS, медиана по 120 командам. «Оценка» — сложено из отдельно измеренных этапов. «Готово» — вместо второго обращения к LLM на действия отвечать фиксированной фразой.

Главный тормоз — языковая модель. Распознавание и синтез вместе укладываются в 2.5 секунды с whisper или в 0.3 секунды с Vosk. А Qwen3.5-4B думает 6.5 секунды, чтобы выбрать действие, и ещё почти 2 секунды, чтобы сформулировать ответ. Из этого времени около 4 секунд уходит на генерацию ~40 токенов вызова: на этом iGPU 4B-модель выдаёт около 10 токенов в секунду.

Как ускорить

  • Vosk вместо whisper: на коротких командах он и точнее, и в 10 раз быстрее (0.2 с против 2.3 с).
  • На действия отвечать «Готово» без второго обращения к LLM. Для вопросов о состоянии второй шаг всё равно нужен.
  • Вместе с Qwen3.5-4B это около 7 секунд, с Ling — около 3. Но Ling ошибается заметно чаще.

Точность

40 команд × 3 голоса. «По тексту» — LLM получает команду без распознавания (идеальный слух).

Qwen3.5-4B по тексту выполнил все 40 команд, а со звука — 90–93%. Почти все ошибки распознавания — от голоса Piper с кривыми ударениями: на двух голосах Silero связка whisper + Qwen3.5-4B выполнила 79 команд из 80. Живой голос, скорее всего, где-то посередине.

Шум почти не мешает: точность падает на 0–3 пункта.

Две опасные ошибки

Потерянный «?» — выдуманный ответ

Если распознавание теряет вопросительный знак, «На кухне что-нибудь включено?» превращается в утверждение. Тогда Qwen3.5-4B не проверяет дом, а сразу отвечает «На кухне включён чайник». Лечится строгим требованием в системном промпте: про состояние дома — только через проверку. Ещё можно взять STT, который пунктуацию не ставит вовсе (Vosk), — тогда её не потеряешь.

Потерянная запятая — отказ

«Сделай свет потусклее процентов на тридцать» без запятой Qwen3.5-4B отклоняет: «не могу изменить яркость».

Приятная мелочь: Qwen3.5-4B отвечает словами

Мы попросили модели отвечать так, чтобы ответ можно было сразу озвучить: коротко, числа словами. Qwen3.5-4B сделал так в 100% случаев, даже когда Home Assistant вернул ему «21.5 °C». Qwen3-4B и Ling так делают только в половине ответов о состоянии. Значит, с Qwen3.5-4B нормализатор текста перед Silero не нужен.

Qwen3.5-4B: «Сейчас в спальне двадцать одна градус пять десятых по Цельсию.»

Qwen3-4B: «Температура в спальне: 21.5 °C.» ← Silero скажет «Температура в спальне», и всё.

Что в итоге

Чего мы не проверили

Живые голоса: дикцию, эхо, расстояние до микрофона. Потоковый режим, где ассистент начинает говорить, ещё не додумав, сильно сократил бы ожидание. Его тоже не пробовали.