Почему облачные ассистенты бесят и как сделать своего
Алиса, Сири, Google Assistant. Произносишь команду, ждешь секунду-две, пока запрос улетит на сервер непонятно где, обработается, и только потом свет в коридоре загорается. А если интернет упал? Всё, ты в темноте, в прямом смысле. И вся твоя приватность — голос, привычки, распорядок дня — утекает корпорациям.
А что если процесс занимает не 2000 мс, а 500? И все данные остаются внутри твоей сети. Это не будущее, это реальность на 2026 год. Стек прост: Ollama для понимания команд, Whisper для перевода речи в текст и бэкенд умного дома вроде OpenClaw или Home Assistant. Собираем железного слугу, который не сливает данные и работает даже в полном офлайне.
Правда о ресурсах: Не верьте статьям 2023 года. Модели стали эффективнее. Для базового ассистента хватит системы с 8 ГБ оперативной памяти и видеокартой с 6 ГБ VRAM (например, NVIDIA RTX 2060). Для Raspberry Pi 5 есть оптимизированные сборки.
1 Выбор и установка ядра: Ollama 2026 года
Первая ошибка — качать первую попавшуюся модель. На 05.04.2026 флагман для задач понимания команд — это Qwen2.5-Coder-7B-Instruct или его облегченный брат Qwen2.5-Coder-3B-Instruct. Почему именно кодер? Он невероятно точен в разборе структурированных запросов. Скажите ему: "Включи свет в гостиной и поставь термостат на 22 градуса", и он не запутается, извлекая две четкие сущности: действие: включить, устройство: свет, локация: гостиная и действие: установить, устройство: термостат, значение: 22.
# Устанавливаем Ollama, если еще нет
curl -fsSL https://ollama.ai/install.sh | sh
# Загружаем актуальную модель (на 2026 год это Qwen2.5)
ollama pull qwen2.5:7b-instruct-q4_K_M
# Для слабого железа
ollama pull qwen2.5:3b-instruct-q4_K_M
q4_K_M — золотая середина. Сильно теряет в качестве? Нет. Жрет в 2 раза меньше памяти? Да. Для голосовых команд из 5-7 слов разницы с полной версией вы не заметите, а VRAM сэкономите гигабайты.Запускаем сервер с правильными переменными. Здесь многие спотыкаются, пытаясь подключаться к localhost из контейнеров.
# Экспортируем переменные, чтобы API был доступен не только с localhost
export OLLAMA_HOST=0.0.0.0:11434
# Для простой безопасности (если сервер в локальной сети)
export OLLAMA_API_KEY=your_simple_key_here
# Запускаем сервер в фоне
ollama serve &
# ИЛИ запускаем модель сразу для работы
ollama run qwen2.5:7b-instruct-q4_K_M
2 Уши системы: ставим Whisper, но не обычный
Официальный Whisper от OpenAI — не единственный игрок. Для реального времени с задержкой менее 500 мс смотрим на Whisper.cpp или faster-whisper. Первый — супероптимизированный на C++, второй использует CTranslate2 для ускорения inference. Разница в скорости в 4-5 раз. Выбираем второй, с ним проще в Python-экосистеме.
# Установка faster-whisper
pip install faster-whisper
С моделью тоже не все очевидно. whisper-large-v3 — отличная точность, но медленная и тяжелая. Для дома берем whisper-medium или даже whisper-small. Русский язык они понимают прекрасно. Если нужна сверхмалая задержка, смотрите в сторону Voxtral-Mini 4B Realtime, как описано в нашем отдельном разборе.
3 Пишем мост: Python-скрипт, который всё связывает
Вот где начинается магия. Сценарий должен: 1) Записывать аудио с микрофона, 2) Отправлять его в Whisper, 3) Полученный текст отправлять в Ollama с контекстом, 4) Разбирать ответ LLM и конвертировать в команду для умного дома.
Сначала как НЕ надо делать: пытаться в одном скрипте и аудио обрабатывать, и сложные цепочки LangChain строить. Получится монстр, который падает от любой ошибки.
# core_bridge.py - упрощенная основа
import requests
import json
from faster_whisper import WhisperModel
import sounddevice as sd
import numpy as np
import wave
# Конфигурация
OLLAMA_URL = "http://localhost:11434/api/generate"
WHISPER_MODEL_SIZE = "small"
DEVICE_INDEX = 0 # индекс вашего микрофона
# Загружаем модель Whisper (один раз при старте)
print("Загрузка модели Whisper...")
whisper_model = WhisperModel(WHISPER_MODEL_SIZE, device="cuda", compute_type="float16")
def listen_and_transcribe():
"""Записывает аудио с микрофона и возвращает текст."""
duration = 3 # секунды записи
sample_rate = 16000
print("Говорите...")
audio = sd.rec(int(duration * sample_rate), samplerate=sample_rate, channels=1, dtype='float32')
sd.wait()
# Конвертируем в байты для Whisper
audio_int16 = (audio * 32767).astype(np.int16)
segments, info = whisper_model.transcribe(audio_int16.flatten(), beam_size=5, language="ru")
text = " ".join([segment.text for segment in segments])
return text.strip()
def ask_ollama(prompt):
"""Отправляет промпт в Ollama и возвращает ответ."""
payload = {
"model": "qwen2.5:7b-instruct-q4_K_M",
"prompt": prompt,
"stream": False,
"options": {"num_predict": 50, "temperature": 0.1} # Температура низкая для стабильности команд
}
try:
response = requests.post(OLLAMA_URL, json=payload, timeout=10)
response.raise_for_status()
return response.json()['response']
except requests.exceptions.ConnectionError:
return "Ошибка: Не могу подключиться к Ollama. Запущен ли сервер?"
def parse_home_command(llm_response):
"""Извлекает из ответа LLM команду для умного дома."""
# Здесь должна быть ваша логика парсинга.
# Пример: LLM отвечает в JSON: {"device": "light", "action": "turn_on", "room": "living_room"}
# Конвертируем это в команду для OpenClaw/Home Assistant API.
pass
if __name__ == "__main__":
while True:
user_text = listen_and_transcribe()
if user_text:
print(f"Вы сказали: {user_text}")
# Формируем системный промпт для LLM
system_prompt = f"""Ты — контроллер умного дома. Пользователь сказал: '{user_text}'.
Извлеки команду в строгом JSON формате: {{\"device\": \"тип_устройства\", \"action\": \"действие\", \"room\": \"комната\", \"value\": \"значение\"}}.
Доступные устройства: light, thermostat, socket, curtain.
Действия: turn_on, turn_off, set.
Если команда неясна, верни JSON с полем \"error\"."""
ollama_answer = ask_ollama(system_prompt)
print(f"Ollama ответил: {ollama_answer}")
# Далее parse_home_command и вызов API умного дома
Секрет промптинга: Заставьте LLM возвращать строгий JSON. Так вы избежите хаоса в ответах типа "Конечно, я включу свет в гостиной!" которые потом невозможно распарсить. Температуру (temperature) ставьте 0.1-0.3, чтобы модель была более детерминированной.
Типичные грабли, на которые все наступают
Ошибка 1: "Error: model 'qwen2.5:7b' not found"
Вы скачали модель, но скрипт ее не видит. Причина: Ollama хранит модели по полному тегу. Вы скачали qwen2.5:7b-instruct-q4_K_M, а в запросе указываете просто qwen2.5:7b. Всегда проверяйте точное имя через ollama list.
Ошибка 2: Таймауты и долгий ответ
Если от команды до действия проходит 10 секунд — это не система, это мучение. Разбиваем задержки:
- Whisper медленный: Переходите на faster-whisper или tiny-модель. Или используйте VAD (Voice Activity Detection) чтобы записывать только когда говорите, а не фиксированные интервалы.
- Ollama тупит: Уменьшайте контекстное окно в запросе (
"num_ctx": 512) и используйте квантованные модели. 7B модель на 4-битном квантовании отвечает за секунду. - Сеть: Если компоненты в разных Docker-контейнерах, используйте
--network=hostили корректные имена сервисов, а не localhost.
Ошибка 3: Нехватка VRAM (CUDA out of memory)
Классика. Запускаете и Whisper, и Ollama на одной видеокарте с 8 ГБ — и всё падает. Решения:
- Загружайте Whisper на CPU:
WhisperModel(..., device="cpu"). Для small-модели это нормально. - Ограничьте память для Ollama:
OLLAMA_NUM_GPU=1иOLLAMA_GPU_MEMORY_LIMIT=4000(4 ГБ). - Рассмотрите запуск на двух разных устройствах. Например, Whisper на встроенной графике Intel, а Ollama на дискретной NVIDIA. Подробнее о распределении моделей по устройствам смотрите в гайде про построение AI-монстра.
Интеграция с умным домом: от слов к действию
Получили JSON {"device": "light", "action": "turn_on", "room": "kitchen"}. Что дальше? Самый гибкий вариант — OpenClaw (открытый аналог Home Assistant с фокусом на производительность) или MQTT-брокер.
# Пример отправки команды в OpenClaw API
import requests
def execute_openclaw_command(parsed_json):
openclaw_url = "http://localhost:8123/api/services/switch/turn_on"
headers = {"Authorization": "Bearer YOUR_LONG_LIVED_TOKEN", "Content-Type": "application/json"}
# Entity ID в Home Assistant/OpenClaw формируется как switch.kitchen_light
entity_id = f"switch.{parsed_json['room']}_{parsed_json['device']}"
data = {"entity_id": entity_id}
response = requests.post(openclaw_url, json=data, headers=headers)
return response.status_code == 200
Для Raspberry Pi есть свой путь оптимизации. Смотрите наш материал про сборку умной колонки, где мы запускали похожий стек на маломощном железе.
Финальный совет: не зацикливайтесь на одной модели
Экосистема локального AI на 2026 год развивается бешено. Появилась новая, более эффективная модель? Склонируйте репозиторий, соберите образ для Ollama с помощью Modelfile и протестируйте. Сегодня Qwen2.5 лидер, завтра может быть что-то от Cohere или новая разработка русской команды. Система, которую мы собрали, позволяет менять "мозги" за 10 минут — главное сохранить контракт API (текст на вход, JSON на выход).
И последнее: заведите второй микрофон. Самый дешевый USB-микрофон за 1000 рублей дает качество записи в разы лучше встроенного в ноутбук, что снижает количество ошибок транскрибации на 30%. Это самое простое и эффективное апгрейд-решение.