Сборка голосового ассистента на KoboldCpp, TTS и веб-поиске: полный гайд | AiManual
AiManual Logo Ai / Manual.
12 Янв 2026 Гайд

Полное руководство: Как собрать голосового ассистента на локальных LLM (KoboldCpp, TTS, Web Search)

Пошаговое руководство по созданию локального голосового ассистента с KoboldCpp, TTS синтезом речи и веб-поиском. Приватная альтернатива HeyAmica и Jarvis.

Зачем собирать ещё одного ассистента, если есть ChatGPT?

Потому что этот будет твоим. Настоящим. Без ежемесячных платежей, без ограничений API, без отправки твоих личных разговоров в облако. Ты спросишь - "Какая погода?", а он не просто ответит, а полезет в интернет за свежими данными. Ты забудешь, кто такой Альберт Эйнштейн - он найдёт биографию и перескажет своими словами. И всё это будет происходить на твоём компьютере, в твоей комнате, без единого байта, улетевшего к OpenAI или Google.

Если ты уже пробовал сборку на LangChain и Ollama, этот гайд покажет другой подход - более гибкий, с ручным контролем над каждым компонентом. Здесь нет магии фреймворков, только чистый Python и понимание, как всё работает на самом деле.

Архитектура: что мы строим и почему именно так

Схема простая, но в этой простоте скрывается мощь:

Компонент Что делает Почему этот выбор
KoboldCpp Запускает LLM локально через API Поддерживает GGUF, работает на CPU/GPU, стабильный
TTS (Coqui или Piper) Преобразует текст в речь Локальный, качественный, с поддержкой русского
Web Search (DuckDuckGo) Ищет свежую информацию Не требует API ключей, приватный
STT (Whisper или Vosk) Распознаёт речь Точность 95%+, работает оффлайн

Главное отличие от решения на одной видеокарте - мы разделяем компоненты. KoboldCpp может работать на сервере в другой комнате, TTS - на твоём ноутбуке, а поиск - вообще в отдельном процессе. Это не монолит, а распределённая система, которую можно масштабировать.

1 Готовим фундамент: KoboldCpp и выбор модели

Начнём с мозга системы. KoboldCpp - это не просто запускалка моделей, это полноценный сервер с API, который понимает OpenAI-совместимые запросы. Скачиваешь один файл, запускаешь - и получаешь локальный ChatGPT.

# Скачиваем KoboldCpp (Linux/Windows/Mac)
wget https://github.com/LostRuins/koboldcpp/releases/download/v1.70/koboldcpp-linux-x64-cuda1150
chmod +x koboldcpp-linux-x64-cuda1150

# Запускаем с моделью
./koboldcpp-linux-x64-cuda1150 --model mistral-7b-instruct-v0.2.Q4_K_M.gguf --port 5001 --threads 8
💡
Не бери самые большие модели. Для голосового ассистента важна скорость отклика. Mistral 7B, Qwen 7B, или даже Phi-3 Mini (3.8B) отлично справятся. Если нужна русская речь - ищи модели, дообученные на русских данных, например, Saiga или Russian-LLaMA.

Проверяем, что сервер работает:

curl -X POST http://localhost:5001/api/v1/generate \
-H "Content-Type: application/json" \
-d '{
  "prompt": "Привет, как дела?",
  "max_length": 50
}'

Если видишь JSON с ответом - всё готово. Если нет - проверь, что модель загрузилась (в терминале KoboldCpp будет прогресс-бар).

2 Голос: выбираем TTS, который не звучит как робот из 90-х

Вот где большинство спотыкается. Берут первый попавшийся pyttsx3 - и получают механического монстра. Не делай так. Современные локальные TTS звучат почти как люди.

Вариант A - Coqui TTS (качество как у ElevenLabs, но бесплатно):

pip install TTS
# Загружаем русскую модель
python -c "from TTS.api import TTS; tts = TTS('tts_models/multilingual/multi-dataset/xtts_v2', gpu=True)"

Вариант B - Piper (легче, быстрее, но чуть хуже качество):

# Скачиваем бинарник и голос
# Пример для русского: https://github.com/rhasspy/piper/blob/master/VOICES.md
# Используем через subprocess

Вариант C - если совсем мало ресурсов, посмотри статью про SAPI5 и Балаболку для Windows.

Не пытайся запустить XTTS v2 на слабой видеокарте. Модель требует 4-6 ГБ VRAM. Если у тебя только CPU или мало памяти - выбирай Piper или даже RHVoice.

3 Уши системы: ставим распознавание речи

Здесь два пути: точный, но тяжёлый (Whisper) или быстрый, но менее точный (Vosk).

Для Whisper:

pip install openai-whisper
# Модель tiny, base, small, medium, large - выбирай по возможностям
# tiny работает даже на Raspberry Pi

Для Vosk (оффлайн, очень быстро):

pip install vosk
# Скачиваем русскую модель с https://alphacephei.com/vosk/models

Я предпочитаю Whisper small - баланс скорости и точности. Но если нужна мгновенная реакция на команды типа "стоп" или "пауза" - Vosk справится лучше.

4 Мозги с доступом в интернет: добавляем веб-поиск

Вот секретный соус, который превращает твоего ассистента из энциклопедии в эксперта по текущим событиям. Мы не будем использовать Google API (платно, лимиты), а возьмём DuckDuckGo через beautifulsoup.

import requests
from bs4 import BeautifulSoup

def web_search(query, num_results=3):
    """Ищет в DuckDuckGo и возвращает сниппеты"""
    url = f"https://duckduckgo.com/html/?q={query}"
    headers = {'User-Agent': 'Mozilla/5.0'}
    
    response = requests.get(url, headers=headers)
    soup = BeautifulSoup(response.text, 'html.parser')
    
    results = []
    for result in soup.find_all('a', class_='result__url', limit=num_results):
        title = result.find_next('h2').text
        snippet = result.find_next('a', class_='result__snippet').text
        results.append(f"{title}: {snippet}")
    
    return " ".join(results)

Но есть проблема - DuckDuckGo иногда блокирует запросы. Альтернатива - Searxng (самостоятельный поисковой агрегатор), который можно запустить локально. Или использовать n8n для сложных сценариев поиска.

5 Собираем всё вместе: главный скрипт

Теперь самый интересный момент - склеиваем компоненты в работающую систему. Вот каркас:

import whisper
import sounddevice as sd
import soundfile as sf
import numpy as np
import requests
import json
from TTS.api import TTS
import threading
import queue

class VoiceAssistant:
    def __init__(self):
        # STT
        self.stt_model = whisper.load_model("small")
        
        # TTS
        self.tts = TTS("tts_models/multilingual/multi-dataset/xtts_v2", gpu=True)
        
        # Очередь для обработки
        self.input_queue = queue.Queue()
        self.output_queue = queue.Queue()
        
        # Контекст диалога
        self.conversation_history = []
        
    def listen_loop(self):
        """Фоновая запись и распознавание"""
        print("Слушаю...")
        while True:
            # Запись с микрофона
            duration = 5  # секунд
            recording = sd.rec(int(duration * 16000), samplerate=16000, channels=1)
            sd.wait()
            
            # Сохраняем во временный файл
            sf.write('temp.wav', recording, 16000)
            
            # Распознаём
            result = self.stt_model.transcribe('temp.wav', language='ru')
            text = result['text'].strip()
            
            if text and len(text) > 2:  # Игнорируем случайные звуки
                print(f"Распознано: {text}")
                self.input_queue.put(text)
                
    def process_query(self, query):
        """Обработка запроса с веб-поиском при необходимости"""
        
        # Определяем, нужен ли поиск
        search_keywords = ['погода', 'новости', 'курс', 'кто такой', 'что такое', 'сколько стоит']
        needs_search = any(keyword in query.lower() for keyword in search_keywords)
        
        context = "\n".join(self.conversation_history[-5:])  # Последние 5 реплик
        
        if needs_search:
            # Ищем в интернете
            search_results = web_search(query)
            prompt = f"""Контекст разговора:
{context}

Пользователь спрашивает: {query}

Вот что найдено в интернете по этому вопросу:
{search_results}

Ответь на вопрос пользователя, используя информацию из поиска. Если информации недостаточно, скажи об этом.
Ответ:"""
        else:
            prompt = f"""Контекст разговора:
{context}

Пользователь: {query}

Ассистент:"""
        
        # Запрос к KoboldCpp
        response = requests.post(
            'http://localhost:5001/api/v1/generate',
            json={
                'prompt': prompt,
                'max_length': 300,
                'temperature': 0.7,
                'stop': ['\nПользователь:', '\n\n']
            }
        )
        
        if response.status_code == 200:
            result = response.json()
            answer = result['results'][0]['text'].strip()
            
            # Обновляем историю
            self.conversation_history.append(f"Пользователь: {query}")
            self.conversation_history.append(f"Ассистент: {answer}")
            
            return answer
        else:
            return "Извините, произошла ошибка."
    
    def speak(self, text):
        """Озвучивание ответа"""
        # Сохраняем в файл
        self.tts.tts_to_file(
            text=text,
            file_path="output.wav",
            speaker="Александра",  # Выбери голос
            language="ru"
        )
        
        # Воспроизводим
        data, fs = sf.read('output.wav')
        sd.play(data, fs)
        sd.wait()
        
    def main_loop(self):
        """Главный цикл"""
        # Запускаем поток прослушки
        listen_thread = threading.Thread(target=self.listen_loop, daemon=True)
        listen_thread.start()
        
        print("Ассистент запущен. Говорите...")
        
        while True:
            try:
                # Ждём запрос
                query = self.input_queue.get(timeout=1)
                
                # Обрабатываем
                answer = self.process_query(query)
                print(f"Ответ: {answer}")
                
                # Озвучиваем
                self.speak(answer)
                
            except queue.Empty:
                continue
            except KeyboardInterrupt:
                print("\nЗавершение работы...")
                break

if __name__ == "__main__":
    assistant = VoiceAssistant()
    assistant.main_loop()

Это базовая версия. В реальности добавь обработку ошибок, кэширование поисковых запросов, горячие клавиши для активации (чтобы не слушал постоянно), и проверку фактов для критически важной информации.

Где всё ломается: частые ошибки и как их избежать

1. KoboldCpp молчит или возвращает ошибки
Проверь порт (5001 по умолчанию). Убедись, что модель загрузилась полностью. Попробуй простой запрос через curl перед запуском основного скрипта.

2. TTS не находит модель или падает с ошибкой CUDA
У Coqui TTS есть проблемы с зависимостями. Если не работает с GPU, перейди на CPU: tts = TTS(..., gpu=False). Или используй Piper - он проще.

3. Whisper не распознаёт русскую речь
Укажи язык явно: transcribe(..., language='ru'). Используй модель не меньше 'small' для русского. 'tiny' плохо справляется с русской речью.

4. Поиск возвращает капчу или блокируется
DuckDuckGo борется с ботами. Добавь реалистичные заголовки User-Agent, делай паузы между запросами. Или перейди на Searxng.

5. Задержка между вопросом и ответом больше 10 секунд
Оптимизируй конвейер:
- Используй более лёгкую LLM (Phi-3 Mini вместо Mistral)
- Включи streaming в KoboldCpp (флаг --stream)
- Запускай TTS параллельно с генерацией текста
- Кэшируй частые ответы

Что дальше? Куда развивать своего ассистента

Базовая версия работает. Теперь сделай её полезной:

  • Добавь память - сохраняй историю разговоров в SQLite, чтобы ассистент помнил, о чём вы говорили вчера.
  • Подключи календарь и почту - через IMAP для почты, CalDAV для календаря. Пусть напоминает о встречах.
  • Сделай плагины - система, где каждый скрипт на Python может добавить новую команду. "Включи свет" → вызывает скрипт home_automation.py.
  • Настрой голос - если используешь XTTS, обучи LoRA на своём голосе или голосе любимого актёра.
  • Добавь визуальный интерфейс - простой UI на PyQt или веб-интерфейс на Flask.

Самый интересный путь - дать ассистенту доступ к твоим данным. Научи его анализировать твои заметки, искать файлы на компьютере, читать RSS-ленты. Через месяц он будет знать о тебе больше, чем ты сам.

Не пытайся сделать всё сразу. Сначала добейся стабильной работы базовой версии. Потом добавляй по одной функции в неделю. Через два месяца у тебя будет система, которой нет аналогов - потому что она создана под твои конкретные нужды.

Вопросы, которые ты хотел задать, но стеснялся

Насколько мощный компьютер нужен?
Минимум: 4 ядра CPU, 8 ГБ ОЗУ, любая видеокарта с 4 ГБ VRAM (или без неё, но тогда медленнее). Идеально: 6+ ядер, 16 ГБ ОЗУ, RTX 3060 12GB или лучше.

Можно ли запустить на Raspberry Pi?
Да, но с ограничениями. Используй tiny-модель Whisper, Phi-1.5 или 2B-модель для LLM, и Piper для TTS. Будет работать, но с задержками 10-20 секунд.

Как сделать, чтобы ассистент просыпался по ключевой фразе?
Добавь Vosk с маленькой моделью для постоянного прослушивания "привет" или "окей". Как только срабатывает - включаешь Whisper для полного распознавания.

А если я не знаю Python?
Тогда тебе будет сложно. Но можно начать с готовых решений вроде Offloom, а потом постепенно разбираться в коде.

Почему не использовать готовые решения вроде HeyAmica?
Потому что они чёрные ящики. Ты не знаешь, что там внутри, не можешь поменять модель, добавить свою логику. Наш подход - полный контроль над каждым компонентом.

Самый важный совет: первый запуск будет кривым. TTS заикается, LLM генерирует ерунду, поиск возвращает мусор. Это нормально. Каждый компонент нужно отдельно настроить и отладить. Потом собрать - и заработает.

Через неделю ты привыкнешь разговаривать с компьютером. Через месяц - будешь удивляться, как жил без этого. А через год твой ассистент будет знать твои привычки лучше, чем ты сам. Главное - начать.