18.05.2026

Мультиагентная система на примере Screeps

Как я добавляю слой автономных агентов в игровой AI: наблюдение, предложения, безопасное выполнение и проверка результата.

screeps ai typescript automation

Мультиагентная система на примере Screeps

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

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

Зачем здесь агенты

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

Идея агентного слоя такая:

  • отделить диагностику от действий;
  • хранить объяснимые предложения с фактами, уровнем уверенности и историей наблюдений;
  • включать выполнение только через явные предохранители: режим работы, список разрешенных действий, ручные подтверждения, паузы между действиями и лимит действий за прогон;
  • не просто менять параметры, а проверять результат через несколько тиков;
  • оставить человеку понятную консоль: agentBrief(), agentDashboard(), agentProposals(), agentAssist().

Это важно: система не пытается быть магическим “AI, который все решит”. Она строит контролируемый контур принятия решений, где каждый шаг можно посмотреть, объяснить и отключить.

Архитектура

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

Контур выглядит так:

Game state
  -> RoomObserverAgent
  -> RoomHistory
  -> ProposalAgent + MarketAgent + LabAgent
  -> ProposalRegistry
  -> BalanceAgent / EconomyStrategyAgent
  -> RecommendationAgent
  -> WorkforceAgent / RemoteEconomyAgent / LogisticsAgent
  -> AssistAgent
  -> PolicyOutcomeAgent
  -> Memory.agentLayer + console dashboard

Наблюдение

RoomObserverAgent собирает нормализованный отчет по комнате: уровень контроллера, энергию, склад и терминал, заряд башен, удаленные источники, угрозы, строительные задачи, роли крипов, прогресс контроллера и заметки вроде “нет активных удаленных источников” или “энергия для спавна ниже 50%”.

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

Предложения

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

  • MarketAgent - анализирует запасы ресурсов и подсказывает, когда рынок может разгрузить склад или терминал;
  • LabAgent - цепочки boost-производства и недостающие ингредиенты;
  • ProposalRegistry - хранит историю предложений: как часто проблема повторялась, насколько агент в ней уверен, готова ли она к действию и не исчезла ли уже сама.

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

Рекомендации и политики

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

Здесь есть важная деталь: рекомендации не прыгают на каждом тике. Система удерживает выбранный фокус, пока новый сигнал не станет достаточно сильным, поддерживает ручные исключения и корректирует параметры по фактическому результату прошлых решений. Если прошлые политики ухудшали ситуацию, следующие параметры приглушаются; если помогали - усиливаются.

Специализированные агенты

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

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

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

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

Помощь и модель безопасности

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

Каждое действие проходит предварительную проверку:

  • правильный режим агентного слоя;
  • действие есть в списке разрешенных;
  • агент достаточно уверен в проблеме и видел ее несколько раз;
  • предложение готово к действию, а не только к наблюдению;
  • не превышен assistMaxActionsPerRun;
  • выдержана пауза после прошлого действия;
  • для опасных действий есть ручное подтверждение;
  • для выполнения включен assistExecute с TTL.

После выполнения создаются проверки и записи о результате. То есть система не только “нажала кнопку”, но и возвращается проверить, изменилось ли состояние в ожидаемую сторону.

Планирование комнат через внешнюю LLM

Отдельная часть проекта - планирование комнаты с помощью внешней LLM. В Screeps база строится на сетке 50x50, и хороший план должен учитывать стены, болота, источники энергии, минерал, контроллер, будущие дороги, склад, терминал, лаборатории, башни, защитные укрепления и маршруты к удаленным источникам.

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

Контур устроен так:

Screeps API
  -> набор данных по комнате и соседям
  -> внешняя LLM строит JSON-план
  -> validateAgentBasePlan()
  -> importAgentBasePlan()
  -> Memory.rooms[room]: план базы, укреплений и путей
  -> обычный строительный код Screeps

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

  • карту местности 50x50;
  • видимые объекты: источники энергии, минерал, контроллер, строения, крипы и строительные задачи;
  • текущую память комнаты и старый план, если он уже есть;
  • схему JSON, которую можно импортировать в игру;
  • жесткие ограничения и цели оптимизации.

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

Перед импортом план проверяется кодом:

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

Если проверка не проходит, импорт блокируется и возвращает список ошибок. Если проходит - importAgentBasePlan() пакует план в формат бота, сохраняет его в Memory.rooms, помечает как внешний и заблокированный от автоматической перезаписи, сбрасывает кэш старого планировщика. Дальше обычный игровой код строит комнату так, будто план был создан внутренним планировщиком.

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

Текущий live-статус

На live-сервере shard1 агентный слой сейчас включен:

tick=71034206
enabled=true
mode=assist
interval=25
minBucket=5000
lastRun=71034200
lastCPU=1.2
control=on

Система наблюдает три комнаты:

КомнатаСтатусЧто видит агент
W3N31RCL8, stableмного нагрузки на склад и терминал, рынок и лаборатории требуют внимания
W3N35RCL4, stableфокус на энергии, идет восстановление экономики
W4N32RCL5, watchнет активных удаленных источников, агент держит это как проблему развития добычи

Самые заметные предложения сейчас:

  • в W3N31 накопился большой избыток минерала U, и агент предлагает разгрузить склад и терминал через рынок;
  • там же не хватает H, чтобы продолжить цепочку лабораторного производства U -> UH -> UH2O -> XUH2O;
  • W4N32 уже достаточно зрелая, но у нее нет активных удаленных источников;
  • W3N35 и W4N32 - почти плоский прогресс контроллера, нужна ручная проверка причин.

По проверке результатов видно, что часть политик уже дает измеримый эффект: для W4N32 развитие контроллера получило положительную оценку 4.4, для W3N35 восстановление энергии - 3.2. При этом фокус на разгрузке склада в W3N31 пока дает отрицательную оценку, и агентный слой это не скрывает: результат остается в истории и влияет на следующие корректировки.

Почему это интересно

Для меня эта система ценна не тем, что “бот играет в Screeps”. Ценна инженерная форма:

  • TypeScript-код работает в жестком рантайме с ограниченным процессорным бюджетом;
  • агентный слой встроен в существующую большую систему, а не написан отдельной демкой;
  • внешняя LLM подключена через контракт, валидатор и импорт, а не через прямой доступ к состоянию игры;
  • решения объяснимы через краткое описание и набор фактов;
  • есть предохранители перед действиями, которые меняют состояние игры;
  • состояние, история, уровень уверенности, разрешения на действия и результаты проверок живут в постоянной памяти Screeps;
  • наблюдение, рекомендации, исполнение и проверка результата разделены по ответственности;
  • консольные команды дают операционный интерфейс, похожий на internal tooling.

Такой подход хорошо переносится на реальные продуктовые системы: автоматизация инфраструктуры, сервисы с автоматическим восстановлением, агенты для модерации и бизнес-процессов, финансовые или логистические backoffice-системы. Везде, где нельзя просто “дать агенту права администратора”, нужна именно такая архитектура: наблюдать, объяснять, предлагать, безопасно выполнять и измерять последствия.

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