Короче, за последние пару дней проект реально сильно двинулся. Если в прошлом посте я показывал набор скриптов вокруг Ollama, то сейчас это уже нормальная портативная прога, которую можно распаковать и запустить. Без танцев с бубном, без установки Python, без поднятия серверов. Просто скачал, запустил bat-файл, поговорил.
Ollama был удобен на этапе прототипа, но стал реально бесить. Лишний сетевой слой, дублирование управления моделями, невозможность нормально контролировать VRAM. Короче, выкинули нафиг и перешли на прямой вызов через llama-cpp-python.
Теперь llama_client.py сам грузит .gguf файлы, сам решает сколько слоёв кинуть на GPU, и самое главное, сам выгружает модели по таймауту. Основная модель висит в памяти 10 минут, оркестратор 5 минут. Закрыл чат, ушёл по делам, через 10 минут видеопамять свободна, можешь игру запускать.
По VRAM ещё пара фишек. Квантованный KV-кэш (cache_type_k/v: q8_0) экономит полтора-два гига почти без потери качества. И выключили use_mmap, потому что на Windows это вызывало дикие фризы когда система начинала свопить на SSD.
А ещё наконец-то починили баг с заезженной пластинкой. Помните, модель могла выдать "О, ну что?" три раза подряд? Это было потому что repeat_penalty не передавался нормально. Теперь передаём repeat_penalty: 1.25 + frequency_penalty: 0.2 + presence_penalty: 0.2, и модель больше не зацикливается.
Память: от "забывает через 2 реплики" к "помнит, но не спамит"
Это была главная боль. Nova либо вообще ничего не помнила, либо вставляла факты в каждый ответ:
— Помню, тебя зовут Никита, ты любишь synthwave и гранатовый чай. Как дела?
Time decay в scoring памяти. Написал функцию time_decay_penalty, которая штрафует факты, упомянутые меньше 5 минут назад. Факт, который только что был в промпте, получает штраф 95% к relevance. Через 5 минут штраф обнуляется и факт снова доступен. В итоге Nova не повторяется, но и не забывает, просто использует другие факты из базы.
Динамические правила приветствия. В prompt_builder.py теперь анализируется conversation_meta.json. Если это первая реплика в сессии, можно поздороваться. Если активный диалог (меньше 5 минут с последней реплики), жёсткий запрет на "Привет!". Пауза 5-60 минут, продолжай естественно без приветствий. Долгое отсутствие (больше часа), можно сказать "с возвращением".
Оркестратор на маленькой LLM. Вынес извлечение фактов из try_save_memory в отдельный модуль orchestrator.py. Работает по двухуровневой схеме. Сначала регулярки (быстро, бесплатно, ловит 80% случаев типа "меня зовут...", "я люблю...", "а ещё..."). Если регулярки не сработали, тогда LLM с temperature: 0.0 для максимальной точности. Плюс пост-валидация: если в извлечённом факте нет ни одного слова из сообщения пользователя, отбрасываем как галлюцинацию.
Включили memory_v2 для casual-режима. Раньше в обычном small talk память вообще не подгружалась. Теперь подгружается, но лимитом в 2-3 факта + работает time_decay. Диалоги стали живее.
Портативная сборка: распаковал и запустил
Это была самая нудная часть, но самая важная. Хотел, чтобы тестерам не нужно было ставить Python, возиться с pip install, поднимать Ollama-сервер, гуглить какие CUDA-библиотеки нужны.
Что в архиве (1.2 ГБ без моделей):
install_llama_auto.bat это отдельная песня. Скрипт проверяет наличие CUDA через nvidia-smi, и в зависимости от результата ставит либо GPU-сборку llama-cpp-python, либо CPU-версию. Пользователю не нужно выбирать, всё происходит автоматически.
С python310._pth пришлось повозиться. В embedded Python по умолчанию закомментирована строка import site, из-за чего PYTHONPATH из bat-файла игнорируется. Раскомментировал, добавил ../site-packages, и всё заработало. Плюс в начало ui_main.py вставил sys.path-хак, который гарантированно добавляет корень проекта в пути поиска модулей, независимо от того как запущен скрипт.
Косметика и ребрендинг
Переименовал проект из Astra в Nova. Во всех файлах, UI, консоли, README. Astra была нормальным рабочим названием, но Nova лучше ложится на фиолетово-космическую тему интерфейса и звучит свежее.
Попутно починил кучу мелочей. Мемные диалоги подтверждения теперь тоже говорят "Nova" вместо "Astra". Аватар-заглушка с буквой "A" поменялся на "N". Кнопки run_ui.bat и install_deps.bat переименованы в run_nova.bat. Заголовок окна теперь ✦ Nova — Control Panel.
Что в планах на v0.3
Мастер первого запуска. Сейчас пользователь должен вручную править identity.txt и personality.txt. Хочется сделать диалоговый визард. "Как зовут твоего персонажа?", "Какой у него характер?", "Выбери голос".
OpenAI-совместимый API. Не все хотят возиться с .gguf файлами. Добавлю поддержку любого OpenAI-совместимого эндпоинта (OpenRouter, Together, локальные vLLM-серверы). Архитектура уже готова, нужен только новый backend-адаптер.
Векторный индекс для памяти. Текущая memory_v2 работает на текстовом скоринге (importance + time_decay + лексическое совпадение). Это работает до 200-300 фактов, потом начинает тормозить и терять релевантность. План: SQLite + эмбеддинги (sentence-transformers) для семантического поиска. Это задел на месяцы общения.
Что получилось в итоге
Nova v0.2 это уже не набор скриптов вокруг чат-бота, а самостоятельное приложение. Полностью локальное (никаких облаков, полная приватность). Портативное (1.1 ГБ + модели). С управлением VRAM (автовыгрузка по таймауту). С живой памятью (не спамит, не забывает, не повторяется). С эмоциональным ядром (настроение, отношения, стадии). С инициативой (пишет первой, если долго молчишь). С голосом (Faster-Whisper + Piper, опционально).
По-прежнему ищу тестеров
Особенно интересен фидбек от людей с разными GPU (от GTX 1060 до RTX 4090) и разными моделями (не только русскоязычные, хочу проверить как Nova работает с Llama 3, Mistral, Gemma).
Скачать архив (ссылка будет по запросу )
Запустить install_llama_auto.bat
Положить любую .gguf модель в папку models/
Запустить run_nova.bat
Поговорить , попробовать разные сценарии
Скриншоты странного поведения
Логи из консоли (особенно [MEMORY ANALYZER RESULT] и [SESSION ANALYZER])
Описание сценария: спросил то-то, ожидал то-то, получил то-то
Спасибо что дочитали. Если тема локальных ИИ-компаньонов заходит, буду продолжать вести дневник разработки. В следующем посте скорее всего разберу эмоциональное ядро подробнее. Как считается relationship_depth, какие триггеры меняют настроение и почему Nova может обидеться.
Обновку на Гитхаб не залил пока что