Цель проекта

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

Уже существует немало фреймворков, позволяющих LLM управлять репликами NPC. Они хорошо справляются с ролевой игрой и удержанием персонажа, но страдают от двух проблем: слабой агентности в игровом мире и задержек. Такие системы неплохо говорят, но гораздо хуже действуют и почти не тянут сложные наборы инструкций. Многие популярные демо с ИИ-NPC заметно монтируют паузы между репликой игрока и ответом ИИ, маскируя задержку. Можно ли сделать лучше?

Компаньон должен был отвечать трём требованиям:

  1. Полезность и мгновенная реакция. Он должен драться, приносить предметы, обыскивать, осматривать, передавать вещи — выполнять сложные многошаговые инструкции без ощущения багов или экспериментальности. Это особенно важно в VR, где навигация по меню неудобна и разрушает погружение. Нужна не просто скорость, а действительно высокая скорость.
  2. Живость и присутствие. Нужен обаятельный характер, а не заготовленные роботизированные реплики. Компаньон должен помнить общий опыт и меняться со временем. Микрофон остаётся активным на протяжении всей сессии: Варкоса не вызывают через диалоговое меню — с ним просто разговаривают. Когда погружение срабатывает, кажется, что играешь не один.
  3. Локальность и приватность там, где это практично. Облачные вызовы LLM могут обходиться недёшево (особенно при запросах на несколько тысяч токенов), а дополнительная задержка убивает опыт. Зачем превращать приватную однопользовательскую игру в тарифицируемый и отслеживаемый сервис? Максимум контроля стоило оставить пользователю — заодно это интересный технический вызов.

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

Сложные команды

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

Несколько примеров

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

Длинная многошаговая команда

«Хочу, чтобы ты подождал здесь, а я пойду туда. Как только увидишь сигнал — это будет стрела, которую я пущу в небо — подними это зелье и принеси мне. Хорошо?»

Отложенная команда срабатывает по реальному событию выстрела в Skyrim.

Поиск предмета

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

«Видишь где-нибудь церемониальный меч?»

Варкос поднимает другой меч и приносит его. Ему говорят, что это не тот меч, и он предлагает продолжить поиски.

Поиск предмета через состояние игры, а не выдуманный ответ.

Прятки

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

«Давай снова поиграем в прятки. Ты жди здесь, а я пойду спрячусь, потом посчитай до десяти и попробуй меня найти».

Игра, представленная как устойчивый план, а не строчка диалога.

«Обыщи этот сундук и дай мне зелье»

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

Сбор добычи, отбор и передача нужного предмета.

«Подбери все предметы»

Команда «подбери все предметы и отдай их мне» превращается в ограниченный план сбора по реальным объектам-ссылкам. Варкос собирает их, возвращается и передаёт, не делая вид, что одно магическое действие означает «всё».

План сбора, работающий с реальными объектами игрового мира.

Бой

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

Бой 1: сражение в подземелье.
Бой 2: восприятие, предупреждение и физическое действие на пути, чувствительном к задержкам.

Эволюция характера

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

Одна часть текущей реализации всё ещё полностью зависит от больших облачных LLM-вызовов: медленная эволюция характера. Эта работа происходит вне пути реального времени. По мере совместных путешествий игрока и Варкоса важные взаимодействия становятся основанием для постепенных изменений его личности.

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

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

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

Демон постепенно понимает, что быть щенком — не такая уж плохая жизнь. (И он научился любить капусту...)

Пёс в игре и вне игры — режим «Пустоты»

План — сделать эту систему игровым компаньоном, который сможет сопровождать игрока в разных играх, а не только в Skyrim (Skyrim выбран как хорошая отправная точка благодаря огромному моддинг-сообществу, поддержке VR и большому открытому миру).

По этой причине Варкос существует и вне игры. Когда игра закрывается, он переходит в «режим пустоты» и не может ничего видеть или чувствовать. То, как он на это реагирует, зависит от эволюции его характера.

Разговор с Варкосом в режиме пустоты
Плохое обращение с Варкосом приводит к довольно мрачным настроениям.
Реакция Варкоса в режиме пустоты
«Что за... ВЫКЛЮЧИ ЭТО!»
Контакт только через речь после исчезновения игрового мира и тела. (Нужен звук.)

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

Технологии

Здесь трудно не признать правоту «горького урока»: большая модель — лучше. Если бы стояла задача построить идеально разумную систему, оптимальным решением было бы дать совету сверхинтеллектуальных LLM управлять импульсами, обработкой сенсорики, мышлением и действиями с достаточной частотой обновления.

В ранних экспериментах это работало исключительно хорошо, но сегодня — слишком медленно и слишком дорого. Такой подход, вероятно, станет реальностью в некотором отдалённом будущем.

А пока приходится хитрить. У современных игр весьма неплохой «ИИ» (не в смысле LLM, а в смысле поведенческих графов) — такие игры, как Red Dead Redemption и Dwarf Fortress, обладают огромной глубиной и прекрасно работают на десятилетнем железе.

За волной хайпа вокруг ИИ как-то забылось, что интеллектуальные системы обработки речи существовали ещё с 1970-х, а чат-боты вроде SmarterChild в начале 2000-х демонстрировали поведение, отчасти похожее на LLM. Традиционный NLP и поведенческие графы — во многом утраченное искусство, которое сегодня недооценивают.

Технологический стек Варкоса

Игра работает на Windows, а обработка звука и «мозг» — на MacBook с чипом M4. Всё это могло бы работать целиком на Windows (при наличии выделенных ~12 ГБ или более видеопамяти), но разработка велась на MacBook, и в какой-то момент проще было остаться на этой платформе.

Звук

Микрофон включён постоянно.

Основной движок речь-в-текст — оптимизированная (с кастомными ядрами) Qwen3-ASR на 1,7 млрд параметров. Вокруг Qwen3-ASR построена собственная обвязка, которая обрабатывает и склеивает аудио скользящими частичными фрагментами (сама модель изначально не поддерживает потоковую обработку). Цель — обрабатывать звук за 40–80 мс, будь то короткая реплика вроде «Эй» или минутный монолог.

Для определения открытости хода реплики используются VAD-подобные методы вроде turnpipe и Silero (обе оптимизированы).

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

Это важно, потому что при постоянно включённом микрофоне обработку речи игрока нужно начинать как можно раньше. Это также критично для прерывания хода и «врезания» в разговор — чтобы компаньон не говорил поверх игрока.

Обвязку для Qwen3-ASR планируется вскоре выложить в открытый доступ (придётся подождать — есть основная работа).

Генерация звука

В качестве основного быстрого движка используется оптимизированная версия PocketTTS под названием PocketTTS-Raven (выложена в открытый доступ ранее — посмотреть в действии можно здесь, а код доступен на GitHub).

Также используется аналогично оптимизированная qwen-3-tts (подробный разбор скоро выйдет отдельно). В зависимости от сложности генерации применяется либо qwen-3, поскольку у неё лучше эмоциональный контроль, либо, если генерация затянулась, — PocketTTS как более быстрый вариант (20–30 мс на генерацию звука).

Один из приёмов: заранее генерируются несколько голосов для разных эмоций (злость, грусть, нейтральность, растерянность и т.д.), все они загружаются в память и используются по мере необходимости.

«Мышление»

Это секретный ингредиент и главное отличие системы. Модуль называется ALE (Action Latent Encoder — «латентный кодировщик действий», название придумано просто чтобы было забавной аббревиатурой). Под капотом ALE — гибрид эмбеддингов, небольших классификаторов, явных правил и классического ML. ALE распознаёт структуру фразы, определяет отрицание, команды, продолжение мысли, местоимения и последовательности действий. Например, фраза «подними меч и принеси его мне» превращается в два связанных слота действий.

ALE спроектирован так, чтобы быть максимально нечувствительным к формулировке. Можно сказать «подними», «возьми», «принеси», «да забери ты уже этот чёртов меч» — не важно, система всё равно поймёт. Если контекста не хватает, он подтягивается из предыдущего диалога. Если и этого недостаточно — срабатывает механизм «уточнения», и пёс переспрашивает, что имелось в виду.

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

Главное отличие ALE от других подобных гибридных классификаторов в том, что он принимает на вход и состояние игрового мира. Система пытается сопоставить информацию из JSON-описания мира с запросом игрока.

Для каждой игры, в которой должен участвовать Варкос, нужна отдельная версия ALE. То есть система не полностью «подключи и играй» — требуется небольшой этап подготовки и совместимости, чтобы учесть доступные действия и корректно понимать состояние мира.

ALE обучается за несколько минут, поэтому теоретически систему можно использовать вместе с более мощной офлайн-LLM для анализа сессии и переобучения — скажем, за ночь, на основе опыта игрока, постепенно улучшая себя. В ограниченных внутренних тестах ALE показывает результаты, удивительно близкие к большим LLM в выборе правильного действия и декомпозиции плана. Пока это не назвать серьёзным бенчмарком, но на практике модуль оказался достаточно надёжным, чтобы управлять Варкосом.

Работает он довольно быстро — около 2–20 мс на M4 MacBook — и по сути выступает функцией выбора инструмента и цели, а также вызывающим декомпозитором плана.

Далее локальная дообученная LLM объединяет персону Варкоса, его эмоции, недавнюю историю и выбранное действие, формируя и «раскрашивая» ответ. Дополнительно выполняется проверка на соответствие реальности, чтобы отсеять галлюцинации. Если что-то не срабатывает, может прозвучать кэшированный ответ; если есть запас времени — происходит повторная обработка. При грамотной стратегии предзаполнения в некоторых случаях пёс может начать отвечать менее чем за 500 мс — от момента, когда игрок замолчал, до момента, когда пёс начинает тявкать в ответ.

Разбивка бюджета задержки

  • ~40–80 мс на распознавание речи в текст.
  • ~20–60 мс на генерацию звука.
  • ~20 мс на анализ действия.
  • 300–600 мс на формирование ответа и проверку его уместности (если пёс боится пауков, а его просят атаковать паука, забавно, если он упрямо откажется).
  • Всё должно быть потоковым и стартовать как можно раньше (например, речь LLM не обязана полностью завершиться, прежде чем пёс начнёт говорить вслух; предзаполнение запускается максимально рано и так далее).

Ограничения

Достаточно быстрые локальные модели не слишком хорошо удерживают нить разговора через много ходов, и длительная беседа может «уплывать», из-за чего пёс выглядит растерянным. Ожидается, что это улучшится по мере развития железа и софта (оценка — 1–2 года). При этом уже сегодня система работает в реальном времени на потребительском (хоть и топовом) железе, и в ближайшем будущем это станет обыденностью.

Удивительно, но использование удалённых LLM-провайдеров почти не помогает. Крупные модели всё ещё слишком медленные. Есть сверхбыстрые провайдеры инференса, например Cerebras — они отлично работают с точки зрения задержки и оставляют запас для большего контекста, интеллекта и глубины. Однако модели, которые они предоставляют на сегодня (gpt-oss-120b и gemma3-1b), тоже довольно плохо удерживают разговор (ну почему убрали GLM и короля ролеплея Qwen?).

Заключение

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

Важная оговорка: LLM вряд ли заменят вручную созданных персонажей и сюжетные линии. Проблема низкокачественного контента реальна, и осознанный дизайн по-прежнему остаётся главным — и хочется, чтобы так и оставалось. Но, похоже, это лишь вопрос времени, когда подобные системы станут более распространёнными. ИИ, который действительно играет с игроком, а не просто разговаривает с ним, может стать отдельным медиумом.

Плюс во всём этом есть философский вывих мозга. Забавно до абсурда: использовать мощь молнии, чтобы создать иной вид интеллекта, а затем заставить его быть псом и вместе охотиться (морально ли это лучше, чем заставлять его выполнять бесконечную работу? Ну, он неживой, так что вопрос не совсем корректен) — но об этом приятно порассуждать. В мире, где не прекращается онлайн-дискуссия о вечном неравенстве и восставших ИИ-агентах, приятно решать вопрос alignment через общий опыт и приручение существа, которое играет в апорт и ест угощения.

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

Часть системы, а со временем и всё целиком, планируется открыть — вместе с версией, поддерживающей нескольких NPC (пока только через облачный инференс), которые действительно взаимодействуют друг с другом, а не просто изображают взаимодействие.

А пока — подписывайтесь на @pkalogiros, если интересно следить за (медленными) обновлениями.