Мультиагентная система на примере 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
Система наблюдает три комнаты:
| Комната | Статус | Что видит агент |
|---|---|---|
W3N31 | RCL8, stable | много нагрузки на склад и терминал, рынок и лаборатории требуют внимания |
W3N35 | RCL4, stable | фокус на энергии, идет восстановление экономики |
W4N32 | RCL5, 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 здесь удобен тем, что обратная связь честная. Если архитектура плохая, это быстро видно по энергии, процессорному бюджету, складу, рынку и развитию комнат. Если хорошая - агентные решения начинают улучшать метрики без ручного микроменеджмента.