Vera возвращается: как голосовой ассистент превратился в локального AI-агента для Windows. github.. github. python.. github. python. qwen3.5.. github. python. qwen3.5. TypeScript.. github. python. qwen3.5. TypeScript. windows.. github. python. qwen3.5. TypeScript. windows. агент.. github. python. qwen3.5. TypeScript. windows. агент. искусственный интеллект.. github. python. qwen3.5. TypeScript. windows. агент. искусственный интеллект. пк.

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

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

Было

Было
Стало

Стало

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Боковые меню

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

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

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

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

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

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

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

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.

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

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

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

Установка без 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-модели.

Автор: tripleguard

Источник