Vera возвращается: как голосовой ассистент превратился в локального AI-агента для Windows

от автора

Полгода назад Vera была консольным голосовым ассистентом, который умел открывать приложения, управлять громкостью и искать информацию в интернете. Я собирался просто добавить графический интерфейс. В итоге переписал значительную часть архитектуры, сменил движки распознавания и синтеза речи, добавил память, зрение, Skills, работу с документами и полноценную агентную систему инструментов.
Фактически от старой Vera осталось название, общая идея и часть системных команд.

При этом Vera изначально проектировалась под небольшие локальные модели до 10B параметров. Все основные сценарии — обычный диалог, работа с инструментами, анализ документов и генерация презентаций — выполняются одной и той же локальной моделью, без отдельной большой модели для «сложных» задач.

Было

Было
Стало

Стало

Консольная версия Vera была хорошим способом проверить саму идею: может ли небольшая локальная модель управлять компьютером, пользоваться инструментами и при этом нормально работать на обычном пользовательском железе.

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

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

На что я ориентировался при создании интерфейса

При проектировании новой версии я во многом ориентировался на Hermes Agent Desktop. Мне понравился общий подход к интерфейсу: разные цветовые схемы, боковая навигация, отдельные рабочие разделы и ощущение не обычного чат-бота, а полноценной среды для взаимодействия с агентом.

При этом я не ставил перед собой задачу скопировать интерфейс один в один. Hermes скорее стал визуальным и функциональным ориентиром, от которого я отталкивался при разработке собственной структуры приложения.

В итоге Vera получила:

отдельное окно чата;

плавающий виджет поверх остальных окон; (в дальнейшем будет «персонажем» по типу питомца в Claude Code, Codex)

управление сессиями;

раздел заметок;

раздел созданных проектов;

настройки локальной модели;

просмотр системных логов;

работу с файлами через drag-and-drop;

встроенную рабочую панель с деревом файлов и терминалом.

Настройки

Настройки
Боковые меню

Боковые меню

Но новый интерфейс оказался только началом

Изначально я думал, что просто добавлю к существующему Python-приложению графическую оболочку. На практике это быстро превратилось в переделку значительной части проекта.

Старая архитектура была рассчитана в первую очередь на последовательную работу из консоли:

Голосовая команда        ↓Распознавание речи        ↓Определение намерения        ↓Выполнение команды или запрос к LLM        ↓Голосовой ответ

Для новой версии этого уже было недостаточно. Теперь агенту нужно было одновременно обслуживать графический интерфейс, голосовой ввод, текстовые сообщения, фоновые задачи, несколько диалоговых сессий и вызовы инструментов.

Поэтому приложение пришлось разделить на две основные части:

Electron + ReactИнтерфейс, сессии, настройки, файлы                ↓          локальный API                ↓Python backendLLM, голос, память, инструменты и задачи

GUI отвечает за взаимодействие с пользователем, а Python backend — за основную агентную логику. Electron также запускает backend вместе с приложением, следит за его состоянием и при необходимости пытается перезапустить его.

Сначала нужно было исправить распознавание речи

Для первого прототипа vosk-model-small-ru хватало: она работала локально, быстро запускалась и почти не нагружала компьютер. Но в обычной разговорной речи модель регулярно искажала короткие команды и названия приложений. Для диктовки такая ошибка не всегда критична, а для агента фраза «открой Telegram», распознанная как «открой теле гра», уже означает неправильное действие или его отсутствие.

Поэтому первым делом я решил полностью заменить движок распознавания речи.

Переход с Vosk на Sherpa-ONNX

В новой версии Vera использует Sherpa-ONNX и потоковую модель:

sherpa-onnx-streaming-zipformer-small-ru-vosk-2025-08-16

Несмотря на довольно длинное название, с точки зрения пользователя всё работает просто: микрофон постоянно передаёт небольшие участки аудио в распознаватель, а тот обрабатывает речь по мере её поступления, не дожидаясь окончания всей записи.

В коде для этого создаётся OnlineRecognizer, состоящий из трёх ONNX-компонентов:

  • encoder.onnx;

  • decoder.onnx;

  • joiner.onnx.

Encoder обрабатывает входные аудиопризнаки, decoder учитывает уже распознанную последовательность, а joiner объединяет их результаты и предсказывает следующие токены.

Распознавание работает с частотой 16 кГц, может выполняться на CPU и по умолчанию использует всего один вычислительный поток. Поэтому новая система по-прежнему нормально работает на обычных компьютерах без дискретной видеокарты.

stt_recognizer = sherpa_onnx.OnlineRecognizer.from_transducer(    tokens=tokens_path,    encoder=encoder_path,    decoder=decoder_path,    joiner=joiner_path,    num_threads=1,    sample_rate=16000,    feature_dim=80,    decoding_method="greedy_search",    provider="cpu",    enable_endpoint_detection=True,)

В моих тестах новая модель заметно реже ошибалась на коротких командах и названиях приложений. Формальный WER-бенчмарк я не проводил — сравнивал на собственном микрофоне и реальных сценариях Vera.

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

Потоковое распознавание вместо записи целой фразы

Ещё одно важное изменение — Vera теперь использует именно потоковое распознавание.

Старая логика голосового ассистента часто выглядит так:

Пользователь начал говорить        ↓Запись всей фразы        ↓Остановка записи        ↓Распознавание        ↓Обработка команды

В новой версии аудио передаётся в Sherpa-ONNX постоянно:

Микрофон   ↓Небольшие фрагменты аудио   ↓OnlineRecognizer   ↓Частичный результат   ↓Определение конца фразы   ↓Готовая команда

Sherpa-ONNX самостоятельно определяет конец реплики по продолжительности тишины. В Vera параметры endpoint detection вынесены в конфигурацию: можно настроить, сколько агент должен ждать после короткой или длинной фразы.

Это позволило избавиться от жёстко заданной продолжительности записи. Пользователь может произнести как короткое:

Вера, погода

так и более длинную команду:

Вера, найди последние новости про локальные языковые модели и коротко перескажи главное.

Агент сам понимает, когда пользователь закончил говорить.

Затем я занялся голосом

С синтезом речи история получилась случайно.

Предыдущая Vera использовала системные голоса Windows через pyttsx3. Для прототипа это почти идеальный вариант: ничего не нужно скачивать, генерация начинается быстро, а интеграция занимает несколько строк.

Но звучит такой голос всё равно как системный диктор. Для утилиты это нормально, а для агента, с которым пользователь регулярно разговаривает, голос является полноценной частью интерфейса.

Мне требовался локальный TTS с поддержкой русского языка, достаточно естественной речью, небольшими требованиями к железу и без зависимости от платных API.

Supertonic я нашёл практически случайно

Я просто листал GitHub в поисках интересных проектов и идей для дальнейшего развития Vera и наткнулся на Supertonic. Скачал его скорее из любопытства, сгенерировал несколько русских фраз и почти сразу понял, что это именно то, что нужно.

Supertonic работает локально через ONNX Runtime, поддерживает разные голосовые стили и позволяет управлять скоростью речи и количеством шагов генерации. При этом ему не нужен отдельный сервер или облачный API.

После системных голосов Windows разница оказалась особенно заметной. Vera перестала звучать как экранный диктор и стала больше напоминать отдельного голосового персонажа.

В текущей версии Vera используется голос Lily, которому внутри Supertonic соответствует стиль F2. Перед синтезом агент получает голосовой стиль, передаёт русский текст модели, а затем воспроизводит готовый аудиомассив через sounddevice.

voice_style = tts.get_voice_style("F2")wav, duration = tts.synthesize(    text=text,    voice_style=voice_style,    lang="ru",    total_steps=4,    speed=1.15,)sd.play(wav.T, samplerate=tts.sample_rate)

Настройки голоса без повторной загрузки модели

Параметры синтеза читаются перед каждой новой репликой, поэтому пользователь может изменить их в настройках приложения без перезапуска Vera:

используемый голос;

громкость;

скорость речи;

количество шагов генерации.

Количество шагов влияет на компромисс между скоростью и качеством синтеза. Для Vera я оставил достаточно небольшое значение, по умолчанию — 4, поскольку для голосового агента время ответа не менее важно, чем идеальная детализация голоса.

Сам Supertonic инициализируется один раз в отдельном фоновом потоке. После этого текстовые ответы складываются в очередь и последовательно озвучиваются. Благодаря этому загрузка TTS не блокирует основной цикл агента и не мешает обработке команд.

Схематично это выглядит так:

Ответ LLM или системной команды              ↓       Очистка текста              ↓          TTS-очередь              ↓     Фоновый поток Supertonic              ↓       Генерация аудио              ↓          sounddevice

Что получилось в итоге

После замены обеих частей голосового конвейера схема стала выглядеть так:

Микрофон   ↓Sherpa-ONNX Streaming   ↓Распознанная команда   ↓Маршрутизатор / LLM / инструмент   ↓Текстовый ответ   ↓Supertonic   ↓Голос

Обе системы работают локально, запись с микрофона не отправляется во внешние сервисы.

При этом переход на более современные модели не превратил Vera в приложение, которому обязательно нужна мощная видеокарта. Sherpa-ONNX настроен на CPU, а Supertonic достаточно лёгкий, чтобы использовать его как основной голосовой движок, а не как отдельный медленный режим «повышенного качества».

Однако после решения проблем со слухом и голосом проявилось другое ограничение: возможностей становилось всё больше, а небольшая локальная модель должна была выбирать инструменты из постоянно растущего списка.

Почему нельзя просто отдать модели все инструменты

После добавления новых возможностей появилась другая проблема: чем больше инструментов получает небольшая локальная модель, тем чаще она начинает путаться.

Если передать ей одновременно веб-поиск, Telegram, чтение документов, создание файлов, Python-интерпретатор и системные команды, увеличивается системный промпт, а модель чаще выбирает неподходящий инструмент.

Поэтому в Vera используется многоуровневая маршрутизация.

Сначала запрос проверяют обычные обработчики. Команды вроде:

Вера, громкость 50

Вера, открой Telegram

Вера, поставь таймер на 10 минут

выполняются напрямую, без обращения к LLM. Для предсказуемых системных действий нейросеть просто не нужна.

Если готового обработчика нет, запрос передаётся в центральный маршрутизатор route_intent. Он определяет, какие инструменты могут понадобиться модели. Сейчас маршрутизатор умеет выделять запросы к веб-поиску, Telegram, документам и Python-интерпретатору, а также отдельно определяет создание презентаций и текстовых документов.

Схема выглядит примерно так:

Запрос пользователя        ↓Проверка системных команд        ↓Определение намерения        ↓Выбор подходящих инструментов        ↓LLM или отдельный skill        ↓Результат

При этом модель получает не весь список инструментов, а максимум два, выбранных для конкретного запроса. Это ограничение явно задано в route_intent и повторно применяется перед вызовом LLM.

Например:

«Найди последние новости про Python»→ web_search«Прочитай документ report.pdf»→ read_document«Посчитай медиану этого списка»→ code_interpreter«Отправь сообщение в Telegram»→ telegram

Обычный разговор инструментов вообще не получает. Это снижает вероятность того, что Vera внезапно запустит поиск или попытается создать файл в ответ на простое сообщение.

Для запросов, где нужен только веб-поиск, есть ещё более короткий путь: Vera вызывает поиск напрямую и возвращает результат, не запуская полный цикл tool calling.

Простые команды по-прежнему работают без LLM

Этот принцип сохранился ещё с первой версии Vera.

Перед вызовом модели route_command_simple сначала запускает детерминированные обработчики. Только если ни один из них не подошёл, запрос отправляется в LLM.

То есть команда:

Вера, яркость 70

не превращается в prompt и не ждёт генерации ответа. Она сразу попадает в соответствующий системный обработчик.

Это даёт три преимущества:

  1. команда выполняется быстрее;

  2. результат не зависит от поведения модели;

  3. LLM не получает лишние полномочия.

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

Skills для составных задач

Некоторые запросы нельзя свести к одному вызову инструмента. Например, создание презентации включает несколько этапов: исследование темы, подготовку структуры, генерацию содержимого и сохранение готового файла.

Для таких сценариев в Vera появились Skills.

Сейчас встроены два основных skill-конвейера:

presentations — создание презентаций;

Оповещение о создании презентации

Оповещение о создании презентации
Вкладка "проекты"

Вкладка «проекты»
Презентация

Презентация

documents — создание текстовых документов, докладов и отчётов.

Маршрутизатор определяет такой запрос до обычного вызова LLM и запускает специализированный pipeline. Например, запрос «сделай презентацию про искусственный интеллект» направляется в presentations, а «подготовь доклад про локальные модели» — в documents.

В коде эти конвейеры выполняются отдельно:

if skill_name == "presentations":    return execute_presentation_creation(...)if skill_name == "documents":    return execute_text_document_creation(...)

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

Главное отличие от обычного tool calling в том, что модель не должна самостоятельно придумывать весь порядок действий. Последовательность уже определена внутри конкретного skill, а LLM используется только на тех этапах, где действительно нужна генерация или анализ.

В итоге Vera не пытается решать любую задачу одним огромным промптом:

Системная команда → прямой обработчикПростой вопрос → LLM без инструментовПоиск или вычисление → LLM с 1-2 инструментамиПрезентация или документ → отдельный skill-конвейер

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

Память между запусками

В первой версии Vera фактически жила в пределах текущего диалога. После перезапуска агент уже не помнил имя пользователя, его город, предпочтения или проекты.

Теперь долгосрочная память хранится локально в data/memory.json, а история диалогов и сессий в SQLite-базе data/vera.db.

Факты автоматически распределяются по категориям:

  • личная информация;

  • контакты;

  • предпочтения;

  • проекты;

  • остальные факты.

Для поиска подходящих воспоминаний я не стал подключать векторную базу и отдельную embedding-модель. Вместо этого используется BM25 с учётом давности, категории и закреплённых фактов.

В system prompt попадает не вся память сразу, а только профиль пользователя, закреплённые данные и несколько наиболее подходящих фактов. Контекст памяти дополнительно ограничен по размеру, чтобы не занимать значительную часть контекстного окна небольшой локальной модели.

Память можно контролировать обычными командами:

Вера, запомни, что меня зовут Тимур

Вера, что ты знаешь обо мне

Вера, забудь про мой проект

Кроме явных команд, Vera умеет извлекать некоторые факты из обычного разговора и сохранять их автоматически.

Работа с файлами и изображениями

В чат теперь можно перетаскивать документы и изображения или вставлять их из буфера обмена.

Vera поддерживает чтение PDF, DOCX, XLSX, PPTX, TXT, Markdown, исходного кода и других текстовых форматов. Извлечённое содержимое передаётся модели вместе с вопросом пользователя.

Например, можно загрузить отчёт и попросить: Коротко перескажи документ и выдели основные проблемы

Для изображений используется локальная мультимодальная модель с соответствующим mmproj. Текст и изображение передаются в одном запросе, поэтому Vera может анализировать скриншоты, фотографии и элементы интерфейса.

При этом мультимодальность зависит от выбранной пользователем модели: обычная текстовая GGUF-модель изображения обрабатывать не сможет.

Периодические и фоновые задачи

Ещё одно заметное изменение — Vera теперь умеет выполнять задачи по расписанию.

Можно создать обычное напоминание:

Вера, напомни через полчаса позвонить другу

или повторяющуюся задачу:

Вера, рассказывай мне новости каждое утро в 9:00

Простые напоминания не отправляются в LLM: в нужное время Vera просто показывает и озвучивает сохранённый текст. Если задача требует поиска или обработки информации, она проходит через обычный маршрутизатор и получает необходимые инструменты.

Все задачи хранятся локально. Для каждой сохраняются время запуска, интервал, статус последнего выполнения и текст ошибки. Управлять расписанием можно как голосом, так и через отдельный раздел интерфейса.

Таймер с обратным отсчетом в маленьком виджете

Таймер с обратным отсчетом в маленьком виджете

Локальная модель

Vera изначально разрабатывалась с расчётом на небольшие модели до 10B параметров, которые можно запускать локально на обычном пользовательском компьютере.

Во время разработки я в основном использовал Qwen3.5 2B. Эта же модель обрабатывает диалоги, выбирает инструменты, анализирует документы, работает с памятью и участвует в генерации презентаций и текстовых файлов.

То есть для создания презентации Vera не переключается на отдельную облачную или более крупную модель. Один локальный LLM последовательно выполняет все этапы: помогает собрать материал, сформировать структуру, подготовить содержимое и передать его генератору файла.

На маленькой модели это работает только потому, что я не заставляю её решать всё самой. Простые команды обрабатывает код, инструментов она видит максимум два, а сложные сценарии вынесены в отдельные pipeline. .

Также можно подключить уже запущенный OpenAI-совместимый сервер, например Ollama или LM Studio.

Адрес сервера задаётся в настройках.

Там же можно изменить размер контекста, включить или отключить режим размышления и задать его токенный бюджет.

Установка без Python и Node.js

В прошлой версии для запуска Vera пользователю приходилось скачивать исходники, устанавливать Python, зависимости и отдельно разбираться с моделями.

Теперь я собрал полноценный установщик для Windows в формате .exe.

Пользователю достаточно скачать установщик, запустить его и дождаться завершения установки. Не нужно отдельно устанавливать Python, Node.js и зависимости проекта, приложение устанавливается как обычная программа для Windows.

После запуска Vera остаётся работать в системном трее. Основное окно можно закрыть, не завершая работу агента, а полностью выйти через контекстное меню иконки в трее.

При этом проект остаётся открытым. Те, кто хочет изменить архитектуру, добавить собственные команды, Skills или инструменты, по-прежнему могут клонировать репозиторий и запустить Vera из исходного кода. Инструкция для разработки и список необходимых зависимостей находятся в README проекта.

Итоги

За почти год Vera прошла путь от консольного голосового ассистента до локального приложения, в котором появились:

  • графический интерфейс и отдельные сессии;

  • Sherpa-ONNX и потоковое распознавание речи;

  • локальный нейросетевой голос Supertonic;

  • долгосрочная память;

  • работа с документами и изображениями;

  • маршрутизация инструментов;

  • Skills для составных задач;

  • фоновые и периодические задачи;

  • поддержка локальных и внешних LLM-серверов;

  • готовый установщик для Windows.

При этом главный принцип проекта не изменился: пользовательские данные, голос, история диалогов и модель могут оставаться на компьютере пользователя.

Все команды в статье я намеренно перечислять не стал, их уже стало слишком много. Полный справочник, инструкция по установке и описание конфигурации находятся в README проекта.

Проект всё ещё активно развивается, поэтому буду рад сообщениям об ошибках, предложениям и pull request.

Если Vera показалась вам интересной, можно поддержать проект звездой на GitHub — это действительно помогает open-source-проекту становиться заметнее.

Новости разработки, новые сборки и планы я публикую в Telegram-канале: @agent_vera_ai.

P.S. Качество ответов и вызова инструментов сильно зависит от выбранной модели, а небольшие локальные LLM всё ещё могут ошибаться. Для комфортной работы рекомендую 16 ГБ оперативной памяти, хотя базовые функции запускаются и на менее мощных компьютерах. Мультимодальность доступна только при использовании совместимой vision-модели.

ссылка на оригинал статьи https://habr.com/ru/articles/1058810/