Это исходный отчёт фазы как есть — со всеми таблицами и методикой. Живая версия: 🏠 Голосовой ассистент.
Фаза 4: голосовой ассистент целиком (STT → LLM → TTS)
Прогон: 20 октября 2026
Хост: UGREEN DXP4800 Pro, i3-1315U, 32 GB, iGPU Intel RPL-U (Xe-LP, 64 EU)
Что меряли: как часто голосовая команда для Home Assistant превращается в правильный вызов, сколько секунд проходит от конца фразы до готового ответа и уживаются ли распознавание и LLM на одном iGPU. Кандидаты взяты из фаз 2, 3 и 5.
Коротко
- Лучшая связка по точности — Vosk (CPU) → Qwen3.5-4B (iGPU) → Silero (CPU). Она верно выполнила 93% команд со звука, а все ответы Qwen3.5-4B (100%) написаны словами и сразу годятся для Silero.
- По времени: распознавание 0.2 с, LLM ~8.4 с на вызов и ответ, синтез 0.1 с.
- Вместе ~8.7 с от конца фразы до ответа. Это оценка: в живом стеке стоял whisper, с ним вышло 10.6 с.
- Самое быстрое — Ling 3.0 Tiny: 6.3 с в живом стеке с whisper. Но команд верно на 6–7 п.п. меньше (83–87%), и Ling путает «погаси» и «включи».
- LLM на этом iGPU — главный тормоз. У Qwen3.5-4B вызов инструмента занимает 6.5 с, ответ ещё 1.9 с; whisper 2.3 с; Silero 0.1 с. Убрать второй шаг (для действий отвечать фиксированным «Готово») и взять Vosk — это ~6.8 с с Qwen3.5-4B и ~2.9 с с Ling (оценка).
- Распознавание коротких команд отличается от фазы 2.
- Vosk — лучший: 3.1% WER, 0.2 с.
- Parakeet: 6.2% и 0.6 с.
- whisper: 8.3% (если перевести его цифры в слова) и 2.3 с при любой длине фразы: он всегда кодирует 30 секунд.
- Parakeet на целых коротких командах ни разу не перешёл на украинский (0 из 240). Риск из фазы 2 касается только нарезки VAD.
- Почти все ошибки — от голоса Piper dmitri. Ударения у него неверные, поэтому распознавание выдаёт что-то вроде «Выключили устроф гостиной». На двух голосах Silero связка whisper + Qwen3.5-4B выполнила 79 из 80 команд. Живые голоса, скорее всего, где-то между этими крайностями.
- Найдены две опасные ошибки:
- Без вопросительного знака LLM выдумывает ответ. Распознавание теряет «?» в «На кухне что-нибудь включено?». Тогда Qwen3.5-4B вместо проверки состояния отвечает «На кухне включен чайник».
- Без запятой LLM отказывается. Фразу «потусклее процентов на тридцать» Qwen3.5-4B отклоняет: «не могу изменить яркость».
- STT и LLM на одном iGPU друг другу не мешают. whisper в стеке работает с той же скоростью, что и один (2.3 с). Память стека 7–9 GiB.
Как мерили
- Голосовые команды. 40 команд из фазы 5 (
../phase5_llm/make_ha.py) озвучены тремя голосами: Silero xenia, Silero aidar, Piper dmitri. Получилось 120 клипов, у каждого по 0.4 с тишины до и после, как после wake word (make_audio.py).- Зашумлённая копия: бубнёж трёх дикторов FLEURS плюс розовый шум при SNR 10 dB, как в фазе 2.
- Это синтетическая речь: живых записей с командами нет. Чище, чем микрофон в комнате, но голос Piper с неверными ударениями даёт трудный случай.
- STT — те же движки и настройки, что в фазе 2: whisper-large-v3-turbo int8 в OVMS на iGPU, Parakeet TDT 0.6B v3 и Vosk ru 0.42 в onnx-asr на CPU.
- LLM — llama.cpp
server-vulkanbuild 11718 с параметрами фазы 5 (--cache-ram 0,--reasoning off). Модели: Qwen3.5-4B, Qwen3-4B, Ling 3.0 Tiny.- Системный промпт — из фазы 5 плюс: «ответ будет озвучен синтезатором, одним коротким предложением, числа словами».
- Шаг 1 — команда и инструменты HA. Сверка вызова по правилам фазы 5.
- Шаг 2 — результат инструмента и ответ. Для вопросов о состоянии результат специально с цифрами: «21.5 °C», «38 %».
- Шаг 2 делался для эталонного текста и whisper на чистом звуке. Для остальных вариантов распознавания — только шаг 1.
- Живой стек (
assistant.py). OVMS и llama-server запущены одновременно. Конвейер по каждому клипу: WAV → расшифровка → шаг 1 → шаг 2 → Silero xenia → WAV ответа. Все 240 клипов по одному, для Qwen3.5-4B и для Ling. - Воспроизведение:
- на NAS:
run_phase4.sh audio | stt | llm <модель> | stack <модель>, вся цепочка —chain.sh; - сырые данные лежат в
raw/, таблицы генерируетpython3 make_report.py.
- на NAS:
Распознавание команд
40 команд × 3 голоса = 120 клипов (2–4 с речи + 0.4 с тишины с каждой стороны), «шум» — те же клипы с бубнежом и розовым шумом при SNR 10 dB. WER «как есть» — как в фазе 2; «числа словами» — цифры в расшифровке переведены в слова («22» → «двадцать два»), так whisper не штрафуется за запись чисел. «Без Piper» — только голоса Silero (у Piper dmitri ошибки в ударениях, см. фазу 3). «Укр.» — расшифровок с украинскими буквами (і, ї, є, ґ) из 240.
| Модель | Где | WER как есть, чисто / шум | WER числа словами, чисто / шум | Без Piper, чисто | Команда, с | Укр. |
|---|---|---|---|---|---|---|
| whisper-large-v3-turbo int8 | OVMS, iGPU | 14.5 / 17.0 | 8.3 / 10.6 | 2.3 | 2.3 | 0 |
| Parakeet TDT 0.6B v3 | onnx-asr, CPU | 7.5 / 6.9 | 6.2 / 6.9 | 3.2 | 0.6 | 0 |
| Vosk ru 0.42 | onnx-asr, CPU | 3.1 / 7.5 | 3.1 / 7.5 | 0.9 | 0.2 | 0 |
Команда выполнена верно: от звука до вызова инструмента
Доля команд, где LLM по расшифровке вызвала нужные инструменты с нужными параметрами (правила сверки — из фазы 5). «Текст» — сама команда без распознавания (40 штук), остальные — 120 клипов. «Silero» — только два голоса Silero (80 клипов). Системный промпт — из фазы 5 плюс просьба отвечать коротко и числа писать словами.
| LLM | текст | whisper | whisper, шум | Parakeet | Parakeet, шум | Vosk | whisper, Silero | LLM, с (медиана) |
|---|---|---|---|---|---|---|---|---|
| Qwen3.5-4B | 100.0 | 90.0 | 89.2 | 90.0 | 90.0 | 93.3 | 98.8 | 6.6 |
| Qwen3-4B | 90.0 | 86.7 | 85.8 | 89.2 | 86.7 | 87.5 | 88.8 | 4.6 |
| Ling 3.0 Tiny | 90.0 | 83.3 | 83.3 | 86.7 | 84.2 | 85.8 | 87.5 | 2.6 |
Ответ для озвучки
Второй шаг диалога: модель получает результат инструмента (для вопросов о состоянии — текст с цифрами: «21.5 °C», «38 %», «1.8 кВт») и формулирует ответ. «Без цифр» — доля ответов без цифр, латиницы и символов, то есть готовых для Silero без нормализатора; по команде (текст) и по 120 клипам whisper.
| LLM | Без цифр, все ответы | Без цифр, ответы о состоянии | Средняя длина, симв. | Пример ответа о состоянии |
|---|---|---|---|---|
| Qwen3.5-4B | 100.0 | 100.0 | 40 | Сейчас в спальне двадцать одна градус пять десятых по Цельсию. |
| Qwen3-4B | 80.6 | 42.9 | 36 | Температура в спальне: 21.5 °C. |
| Ling 3.0 Tiny | 80.6 | 50.0 | 47 | Температура в спальне сейчас составляет 21.5 градусов. |
Живой стек: от конца фразы до готового ответа
Одновременно запущены OVMS (whisper, iGPU) и llama-server (LLM, iGPU), Silero работает в процессе конвейера (CPU, 4 потока). 120 чистых и 120 зашумлённых клипов, по одному. Медиана и максимум, секунды. Ничего не стримится, поэтому «итого» — это и время до первого звука ответа.
| LLM | Звук | STT | LLM: вызов | LLM: ответ | TTS | Итого, медиана | Итого, макс. | Ответ звучит, с |
|---|---|---|---|---|---|---|---|---|
| Qwen3.5-4B | чисто | 2.3 | 6.5 | 1.9 | 0.1 | 10.6 | 17.5 | 2.0 |
| Qwen3.5-4B | шум | 2.3 | 6.5 | 1.9 | 0.1 | 10.6 | 17.6 | 2.1 |
| Ling 3.0 Tiny | чисто | 2.3 | 2.6 | 1.4 | 0.1 | 6.3 | 10.8 | 2.0 |
| Ling 3.0 Tiny | шум | 2.3 | 2.5 | 1.4 | 0.1 | 6.3 | 10.8 | 2.0 |
Память стека
Пик по docker stats за прогон (Silero — внутри контейнера конвейера, ~0.7 GiB по фазе 3, здесь не снимался).
| LLM | STT (OVMS), GiB | LLM, GiB | Вместе, GiB |
|---|---|---|---|
| Qwen3.5-4B | 2.4 | 4.7 | 7.1 |
| Ling 3.0 Tiny | 2.3 | 6.7 | 8.7 |
Выводы и рекомендации
Что ставить для голосового ассистента
| Вариант | Связка | Точность команд | Время ответа | Когда брать |
|---|---|---|---|---|
| Точный | Vosk → Qwen3.5-4B → Silero | 93% (со звука), 100% по тексту | ~8.7 с (оценка), 10.6 с с whisper | по умолчанию |
| Быстрый | Vosk → Ling 3.0 Tiny → Silero | 86% | ~4.3 с (оценка), 6.3 с с whisper | если 10 секунд — слишком долго и ошибки терпимы |
| Ещё быстрее | любой из двух без шага 2 (фиксированный ответ на действия) | та же | ~6.8 / ~2.9 с (оценка) | для команд управления; вопросы о состоянии всё равно через шаг 2 |
Отдельно стоит учесть:
- Нормализатор текста перед Silero для Qwen3.5-4B не нужен: все его ответы были без цифр и латиницы, хотя в результате инструмента цифры были. У Qwen3-4B и Ling так только 43–50% ответов о состоянии («Температура в спальне: 21.5 °C»), им нормализатор нужен.
- В Home Assistant эта связка собирается штатно, через Wyoming и OpenAI-совместимые API:
- Vosk и Silero нужно обернуть в Wyoming-сервер, готовые есть для Vosk;
- LLM подключается как OpenAI-совместимый сервер;
- с Piper вместо Silero всё есть из коробки, но звучит он хуже (фаза 3).
Что видно в цифрах
- Время ответа определяет LLM. На 4B-модели шаг с инструментами занимает 4.6–6.5 с, из них ~4 с — генерация ~40 токенов вызова при ~10 tok/s. Системный промпт с описанием дома (~2K токенов) лежит в кэше слота, его повторная обработка стоит ~0.7 с. Без кэша было бы +20 с.
- whisper для коротких команд не лучший выбор. Он тратит 2.3 с на любую фразу и пишет числа цифрами («22 градуса»). Для LLM это не страшно, но WER без перевода цифр — 14.5%. Vosk пишет числа словами, без пунктуации, и на командах оказался и точнее, и в 10 раз быстрее.
- Шум 10 dB почти не влияет. Точность команд падает на 0–3 п.п., у Vosk WER растёт с 3.1 до 7.5%.
- Распознавание — не единственный источник ошибок. Qwen3-4B даже по эталонному тексту выполнил 90% команд, а в фазе 5 без реплики про озвучку было 97.5%. Добавка про озвучку сбила его: в командах климата он перестал указывать устройство. Qwen3.5-4B к этому изменению оказался нечувствителен.
- Пунктуация влияет на поведение LLM. Пропавший «?» превращает вопрос в утверждение, и модель отвечает, не проверив состояние. Пропавшая запятая даёт отказ. Против этого:
- в системном промпте прямо требовать проверять состояние через GetLiveContext перед любым ответом о нём;
- или ставить STT, который пунктуацию не пишет вовсе (Vosk) — у такой модели она не меняется от фразы к фразе.
Ограничения
- Речь синтетическая. Живые записи (дикция, акцент, эхо, расстояние до микрофона) не проверялись. Голоса Silero — лёгкий случай, Piper dmitri — трудный.
- Шаг 2 проверялся только для эталонного текста и whisper. Инструменты не выполнялись по-настоящему: результат подставлялся.
- Оценки «с Vosk» и «без шага 2» сложены из отдельно измеренных этапов, вместе в стеке не запускались.
- Потоковый вывод не пробовали. Потоковые STT, LLM и TTS сократили бы время до первого звука.