- BrainTools - https://www.braintools.ru -
«Все модели неправильны. Некоторые из них полезны.» — Джордж Бокс
Прежде чем начать эту часть, хочется извиниться перед теми, кто пробирался через первую. Зоопарк аббревиатур (S&OP, IBP, DDAE, MRP, DDMRP, MES, WMS, TMS и далее по списку) местами утомлял меня самого, не говоря уже о читателе. Во второй части зоопарка меньше, но появляются новые странные звери: ECS, DoD, Actor Model, barrier sync, archetype-based. Зато тут больше истории, чем теории.
Структура примерно такая. Сначала кратко напомню, что было в первой и какие мысли я тащу дальше. Потом как из работы с чужим кастомным симулятором у меня выросла идея «хочу тоже что-нибудь собрать». Дальше история про акторную модель (actor model): почему она показалась подходящей, и на чём я споткнулся. Потом про ECS как часть DoD, с признанием что подсказку нашел в чате с ИИ. И в конце три варианта архитектуры, которые из этого получились и почему гибридная кажется наиболее из них интересной.
Финальная третья часть истории будет про прикладные кейсы и пересечения с играми. Но обо всем по порядку.
Если совсем коротко, то четыре мысли.
Мир усложняется быстрее, чем мы успеваем под него подстраивать планы. SPOD сменился на VUCA, VUCA на BANI, BANI на SHIVA. На практике это означает, что динамические перепланирования нужны не «иногда», а постоянно. План, написанный утром, к обеду уже может быть неактуален.
Иерархия уровней управления исторически сложилась правильно. Стратегический, тактический, операционный. Попытка их выкинуть или склеить в один обычно заканчивается тем, что либо нет долгосрочной картины, либо ежечасно никто не управляет. Лучше всего эту иерархию я увидел в DDAE: стратегия задаёт цели и горизонт, тактика настраивает параметры (буферы, приоритеты), операционка их исполняет.
Мультидоменность и мультимодельность. Мультидоменность – это возможность собирать модель как из изолированных доменов (логистика отдельно, производство отдельно, склады отдельно), так и из их объединения. Мультимодельность – это возможность к одному и тому же домену цеплять разные модели на разных свойствах. Условно, склад можно моделировать как поток ящиков по конвейерам или как взаимодействие пятидесяти ричтраков с диспетчером это два разных взгляда на одно и то же.
И самое неудобное, а что же делать с существующими ERP, MES, WMS, TMS? Они уже работают, в них десятки тысяч человеко-часов настройки. Варианты:
сохранить как есть для совместимости;
превратить их в tool-calling инструменты, которые агенты вызывают по требованию;
свернуть до итоговых экранов «подтверди, что всё верно».
Сюда же относится открытый вопрос про солверы и оптимизаторы. Их явно тоже хочется иметь как инструменты, которые агент дёргает, когда надо посчитать маршруты или расписания. Но как это всё связать в единое – в первой части ответа не было. Эта часть про попытку к нему подойти.
Обычно с имитационным моделированием знакомятся в вузе. За семестр студенты узнают всю базу: терминологию, виды симуляций (DES, ABM, system dynamics), пробуют что-нибудь сделать в GPSS или AnyLogic, читают пару книг, сдают курсовик. Дальше большинство забывает [1], кто-то идёт в исследования.
У меня было иначе. На работе я столкнулся с одним кастомным симулятором. Не буду подробно рассказывать каким, но скажу что начал в нём копаться, чтобы понять, как он устроен. Увлёкся. Вспомнил про X-Tension из первой части и про то, как сильно мне когда-то нравились симуляторы. Загорелся идеей попробовать сделать что-нибудь похожее. Потом понял, что хочу архитектуру принципиально другую. Затем, что хочу прототип.
То есть по-хорошему я должен был сначала пройти базу: SimPy, AnyLogic, пара книг по DES и ABM, теория синхронизации, может быть курс по теории очередей. И только потом думать про «новое решение». А я пошёл с обратного конца: придумал требования и начал искать инструменты под них.
Требование звучало так: «Автономный симулятор Grande», почти как «Grand Sim Auto». В качестве иронического оммажа.
Спросить было не у кого, поэтому я двинулся ковырять разные кирпичи, на которых это всё в принципе можно собирать. Дальше про то, что из этого получилось.
В первой части я упоминал, что отдельно по дороге попал на статьи и книгу Петра Олеговича Скобелева «Как создавать сложные системы». Это книга про MAS – мультиагентные системы. В ней мне особенно понравились мысли про эмерджентный интеллект [2], “равновесие неравновесий или неравновесное равновесие”, поиск оптимума через переговоры агентоы. И когда я её прочёл, я поймал себя на странной мысли: MAS-агент – это же по сути то же самое, что классический агент в ABM. Тогда зачем эти две дисциплины существуют отдельно и почему MAS-платформы типа JADE и JACAMO давно перестали обновляться, а ABM-инструменты типа Mesa и NetLogo живут?
Полез разбираться. Выяснилось, что:
MAS вырос из distributed AI 80-х. Главная задача – сделать так, чтобы автономные программные агенты могли координироваться, договариваться, торговаться. Contract Net Protocol, BDI-архитектуры, holonic manufacturing.
ABM вырос из социальных и биологических наук. Главная задача – смоделировать, как из поведения [3] многих индивидов возникает динамика всей системы. Школа Wolfram, потом Schelling, потом сотни моделей в социологии и экономике.
На уровне кода эти миры почти не отличаются. На уровне сообществ и инструментов – отличаются сильно. И именно классические MAS-платформы как-то застряли в академии. JADE последний крупный релиз делал в 2017, JACAMO живёт, но как исследовательский проект.
Хочется задать вопрос: если идея MAS сама по себе правильная (а она правильная – агент это изолированный программный контейнер со своим состоянием и поведением [4], общающийся с другими через сообщения), то что из живых технологий ближе всего к этой идее?
Ответ оказался прямо под носом – actor model.
Идею акторной модели в 1973 году опубликовал Карл Хьюитт со своими аспирантами в MIT. Они пытались осмыслить параллельные вычисления и пришли к простой формулировке: пусть базовая единица – «актор», у него есть свой почтовый ящик, и он умеет три вещи: получать сообщения, обрабатывать их, создавать новые акторы. Никакой разделяемой памяти [5]. Никаких блокировок. Только сообщения.
Идея долго оставалась академической. Реально в индустрию её затащили шведы из Ericsson. В середине 80-х им нужно было программировать телефонные станции с очень высокой надёжностью (девять девяток uptime, то есть простой меньше секунды в год). Классические языки не справлялись с двумя вещами одновременно: параллельностью и отказоустойчивостью. Так в 1986 году появился Erlang, в котором акторная модель встроена прямо в язык. На Erlang потом написали WhatsApp, RabbitMQ, ejabberd и кучу другой инфраструктуры телекома.
Джо Армстронг, один из создателей Erlang, хорошо сформулировал, чем подкупает эта модель: реальный мир сам по себе concurrent, у вещей нет общей памяти, они взаимодействуют через сообщения. Так что код, который пытается это моделировать на классическом ООП с потоками и блокировками, заведомо упирается в чужую парадигму.
В 2009 году Йонас Бонер портировал идею в JVM-мир под названием Akka. Scala-разработчики получили инструмент для распределённых систем без боли [6] с потоками. Через несколько лет Microsoft Research выпустила Orleans – вариант с «виртуальными акторами», которые активируются автоматически и не требуют явного жизненного цикла. На Orleans, например, в своё время держался бэкенд Halo.
Я перечитал эти истории несколько раз и подумал: если столько серьёзных систем на акторах работает, и идея концептуально совпадает с MAS-агентами – значит, для симулятора это тоже должно подойти.
Сначала фавориты были такие:
Akka.NET – порт оригинальной Akka JVM. Зрелый, кластеризация из коробки, supervision (если ребёнок упал, родитель решает что делать), persistence.
Orleans – тоже C#, но с виртуальными акторами и более ленивым lifecycle.
Erlang/Elixir – идея на уровне runtime. Миллионы лёгких процессов на одной машине, hot code reload, preemptive scheduling.
Proto.Actor, ractor – попадались по касательной, как примеры реализаций в Go и Rust соответственно.
Перешерстил статьи. Действительно, симуляторы на акторах делают, особенно научные. Логика [7] красивая: создаёшь инстанс модели через инициализацию набора акторов, загружаешь в них переменные (входящие, исходящие, состояние), формулы поведения, и они начинают общаться. Каждый актор – изолированная коробочка. Можно собирать симуляцию из тысяч таких коробочек, они будут крутиться параллельно, на разных ядрах или машинах.
Тогда я ещё сильно недооценивал момент с детерминизмом и синхронизацией. И это меня в итоге и подкосило.
Когда симулятор работает в DTS-режиме (discrete time simulation, симуляция с фиксированным шагом по времени), на каждом шаге все акторы должны:
Прочитать своё текущее состояние и сообщения от соседей.
Посчитать новое состояние.
Отправить результаты соседям.
Дождаться, пока все остальные тоже это сделают, и только потом перейти на следующий шаг.
Этот «дождаться» и есть барьерная синхронизация. Реализуется обычно через главного актора-диспетчера, к которому все остальные шлют сообщения «я готов». Когда у него собралось N таких сообщений, он рассылает «поехали дальше».
И вот когда я начал считать, сколько сообщений будет лететь в этом диспетчере при, скажем, 10 000 акторов и 1 000 шагов в секунду — стало нехорошо. Десять миллионов сообщений в секунду только на синхронизацию. Само быстродействие симуляции это бы похоронило.
Альтернатива — оптимистичная синхронизация с откатами (это когда акторы шагают вперёд оптимистично, и если приходит «запоздалое» сообщение из прошлого, состояние откатывается). Звучит красиво, на практике сложно реализовать без багов. Особенно когда внутри агента есть тяжёлая логика, состояние которой откатить – отдельный квест.
Я тогда не знал ещё про каналы (channels) и про то, что барьер можно реализовать дешевле, не через миллион «я готов» сообщений. Это я узнал уже позже, когда копал ECS. А тогда казалось, что чистая акторная архитектура для большого симулятора – заведомо проигрышный путь.
И я снова пошёл читать книги и статьи по теории. И расспрашивать ИИ.
ИИ, которому я задал вопрос «что подходит для DTS-симуляции с десятками тысяч сущностей лучше акторов», без колебаний ответила: используйте ECS, гейм-разработчики всё уже придумали. (Эту особенность ИИ – всегда иметь готовое решение – можно воспринимать как радость или как разочарование, в зависимости от задачи. Сегодня я скорее радуюсь, потому что подсказка оказалась правильной.)
И вот тут пришлось разворачиваться в новую сторону.
ECS (Entity Component System) — архитектурный паттерн в гейм-разработке. Если упростить: вместо классической ООП-иерархии «у меня есть класс Enemy, у него есть атрибуты hp, position, velocity и методы attack, move» – всё это разбирается на три части.
Entity – это просто id (число). «Корабль номер 47», «снаряд номер 12345».
Component – таблицы атрибутов. Таблица Position, таблица Velocity, таблица HP. Каждая строка принадлежит какому-то entity по id.
System – функции, которые проходят по таблицам и обновляют данные. Система Movement каждый кадр пробегает таблицу Position, добавляет к ней Velocity. Система Damage пробегает таблицу HP и уменьшает где надо.
Никакого ООП с методами на объектах. Никаких виртуальных вызовов. Только таблицы данных и функции над ними.
Корни идеи уходят в 90-е, в движки игр вроде Thief и Dungeon Siege. Но как осознанная философия она оформилась благодаря докладу Майка Эктона «Data-Oriented Design and C++» на CppCon 2014. Эктон тогда был главным инженером по движкам Insomniac Games (это они делали Ratchet & Clank и Spider-Man для PlayStation). Его главный тезис, который я перескажу своими словами: программисты слишком долго пытались моделировать реальный мир в коде через классы и иерархии. На самом деле компьютер ничего не знает о реальном мире. Он знает про память, кэши и инструкции. Если ты организуешь данные так, как удобно процессору, а не так, как удобно твоей ментальной модели, то получаешь на порядок более быстрый код. На том же железе.
У самого Эктона есть жёсткая формулировка, которая встречается во всех его выступлениях и которой он любит дразнить ООП-программистов: задача всех программ – преобразовывать данные из одной формы в другую. Не моделировать реальность, не выражать концепции, а преобразовывать данные. Если ты этого не понял, то ты не понял задачу.
Этот доклад очень многих в индустрии встряхнул. Через несколько лет Unity объявил DOTS (Data-Oriented Technology Stack) – попытку добавить ECS в движок, который десять лет жил на классических GameObject. Параллельно в Rust-мире появился Bevy – движок где ECS лежит в основе, а не добавлен сбоку. Если кто не видел этот доклад на YouTube – то рекомендую посмотреть хотя бы пару минут, ругань Эктона на ООП-программистов сама по себе бодрит.
Главный выигрыш ECS – кеш-локальность (cache friendly). Когда все Position лежат в памяти подряд (плотным массивом, а не как объекты разбросанные по куче памяти (heap)), процессор может загрузить их в L1 уровень кэша одной операцией и пробежать в N раз быстрее, чем по разбросанным указателям. В современных системах разница между: в кэше процессора и в оперативной памяти – различается на порядки. Поэтому пара тысяч простых сущностей на ECS работает быстрее ста сложных объектов на ООП.
Делится на два основных подхода: Archetype (используется в Unity DOTS, Bevy, Flecs) и Sparse-set (EnTT, Bevy исторически archetype, но недавно добавили sparse-set как опцию). Они управляют тем, как компоненты лежат в памяти, определяя скорость обработки и гибкость.
Archetype (Архетипы). Сущности группируются в «архетипы» на основе точного набора компонентов, которыми они владеют (например, сущность с позицией и скоростью попадает в один архетип). Все данные компонентов хранятся плотными, последовательными блоками в памяти, что обеспечивает максимальную скорость итерации и кэш-дружественность. Однако добавление или удаление компонента требует полного копирования всех данных сущности в другой архетип, что создает высокие накладные расходы на частые изменения.
Sparse-set (Разряженное множество). Компоненты каждого типа хранятся в отдельных плотных массивах (для быстрых циклов), а связь сущности с ними осуществляется через вспомогательную структуру из двух списков. Этот подход позволяет добавлять и удалять компоненты мгновенно, не перемещая сущность в памяти целиком. При этом обход (итерация) по нескольким компонентам может быть медленнее из-за большего количества промахов по кэшу процессора по сравнению с архетипами.
Некоторые ECS строго ориентированные на один из типов, Некоторые например Bevy позволяют комбинировать разные типы и предстоит еще понять и разобраться, а какие объекты с какими типами – лучше работают.
Когда я начал примерять ECS к симуляции, что-то начало складываться.
Симуляторы – это зачастую про много однородных сущностей. Десятки тысяч ящиков на конвейерах, тысячи курьеров, сотни тысяч заказов. Все они в массе своей делают примерно одно и то же. На ООП каждая такая сущность – отдельный объект, с указателями, виртуальными вызовами, дисциплиной памяти. На ECS – это строки в таблице, и тысяча таких строк это аккуратно лежащий массив в памяти.
В играх давно поняли, что нужно отталкиваться от возможностей среднестатистического игрового ПК. Пока учёные борются за оптимальность алгоритмов, гейм-разработчики борются за то, чтобы 60 кадров в секунду на условном RTX 3060 крутилось. И они таки делают игры с десятками тысяч активных юнитов на одной машине. RimWorld, Factorio, Dwarf Fortress — это всё та же задача, что и в симуляторе склада: много активных сущностей, простые правила, эмерджентное поведение.
Bevy ECS – Rust, archetype-based, можно использовать отдельно от движка как библиотеку. Активно развивается и также активно ломающие изменения в API раз в три месяца.
Flecs – C, один из самых feature-полных ECS. Уникальная фича — relationships между сущностями (объект A «принадлежит» объекту B), что в большинстве ECS приходится реализовывать самому.
Arch – C#, archetype-based, молодой, но один из лучших по перфомансу в C# сегодня.
EnTT – C++, header-only, используется в AAA-играх.
Unity DOTS – коммерческий, как внутренняя часть Unity. Лучший пример для некоторых из кейсов использования, если бы не плохая история с лицензированием. Burst-компилятор даёт C-уровень производительности из C#.
Самым удобным выглядит расклад «Bevy ECS на Rust» или «Arch на C#», в зависимости от того, на каком стеке хочется собирать прототип и какие итоговые цели проекта. Bevy дешевле во всём, кроме экосистемы (которой просто меньше). Если говорить про vibe-coding, то C# ИИ знает лучше, ну и скомпилировать что-то работающие получится быстрее чем на Rust из-за borrow checker.
Не буду снова делать полный каталог инструментов. Во-первых, такие каталоги быстро устаревают. Во-вторых, нет смысла перечислять то, с чем даже при изучении теории не сталкивался. Расскажу про несколько инструментов, которые попадались, пока ковырял разные варианты – иногда напрямую через статьи, иногда через очередной разговор с ИИ, иногда просто потому что их упоминают рядом.
In-process аналитическая база. По сути SQLite, только для OLAP, а не для транзакций. Работает прямо внутри процесса, без сервера. Читает Parquet, CSV, Arrow на лету и быстро делает аналитические запросы поверх них.
Зачем она в симуляторе? Когда симулятор работает, он генерирует трейс – историю того, что происходило. До тысяч событий в секунду, миллионов за прогон. Этот трейс хочется хранить и анализировать. Классический подход – писать в CSV или Postgres, потом грузить в pandas. Но если симулятор хочет на лету спрашивать у своей же истории «а сколько у меня в среднем простоев за последний час по третьему цеху», то нужна аналитическая база прямо внутри симулятора, в том же процессе.
DuckDB в этом кажется очень интересно. Запрос к миллиону строк – десятки миллисекунд. Никакого ETL, никакого сервера, никакой инфраструктуры, просто библиотека.
Отдельный бонус: DuckDB это естественный слой знаний и аналитики для “Сложных” или вовсе LLM-агентов, которые сидят на стратегическом уровне. Агент может задавать ей произвольные вопросы на SQL («покажи распределение задержек поставок за последние семь дней по поставщикам») и получать ответы. Без специальных интеграций.
В большом масштабе DuckDB не годится – она in-process, не распределённая. Когда симуляций много, и трейсы со всех нужно складывать в одно место для последующего анализа – тут уже может помочь ClickHouse. Колоночная база, миллиарды событий, отличная аналитика. Довольно часто применяется в крупных компаниях.
В пайплайне это выглядело бы примерно так: каждый прогон симулятора пишет локально в DuckDB или Parquet, потом по расписанию данные собираются в ClickHouse-кластер для сравнения прогонов между собой.
Apache Arrow и Parquet – стандарт для колоночных данных. Все современные аналитические инструменты их понимают. Arrow в контексте zero-copy, а Parquet для скидывания итоговых трейсов в файл.
Polars – быстрее pandas в разы (потому что на Rust), API приятный.
Google OR-Tools – инструментарий с VRP-солвером (vehicle routing — прямо для логистики) и CP-SAT. CP-SAT — топ в своей нише constraint programming.
Gymnasium и PettingZoo – почти стандартные инструменты для RL-environments, single-agent и multi-agent. Если когда-нибудь захочется обучать политики через симулятор – то вероятнее всего выбор будет между ними.
ONNX Runtime – чтобы иметь возможность обученную где-нибудь модель запускать прямо из Rust или C# без таскания PyTorch или конструирования отдельного сервиса с API.
deck.gl и H3 – Uber-овский стек для визуализации геоданных. Если в симуляторе будет логистика на реальных картах – обойти их будет сложно.
Чем рисовать
Если выкинуть из обсуждения вопросы визуализации, симулятор остаётся чёрным ящиком: считает что-то у себя внутри, а посмотреть нельзя. Для MVP это нерабочая ситуация. Поэтому пара слов про UI-стек.
Bevy сам по себе. Раз внизу уже Bevy ECS, дёшево использовать его же и для рендера. Bevy умеет 2D и 3D, ECS-сущности рисуются буквально из тех же таблиц, с которыми работает симуляция. Минус – рендер у Bevy пока не индустриального уровня, до Unity или Unreal по визуальному качеству далеко. Но для технического симулятора, где главное увидеть, что происходит, этого хватает.
egui. Immediate-mode UI для Rust. «Immediate mode» означает, что UI перерисовывается каждый кадр, без долгоживущих виджетов – просто и быстро для дев-тулов и дашбордов. egui отлично прикручивается к Bevy: получаешь панели управления, графики через egui_plot, табличные отображения метрик. Не Figma, но для прототипа симулятора – вполне. Тот же подход в C++ мире называется Dear ImGui, его используют как внутренний инструмент почти все крупные игровые студии.
WASM. Главная фишка Bevy и Rust-стека в целом – компиляция в WebAssembly. Это означает, что готовый симулятор открывается прямо в браузере, без установки. Для демонстраций это огромный плюс: отправил ссылку, по ней кликнули и крутится симуляция. Никакого «давайте я подключусь по zoom и покажу». Особенно ценно для MVP, который надо показывать многим людям. Справедливости ради на C# тоже есть возможности WASM – но тяжелее и сложнее.
Godot 4. Если хочется уже не просто схематичный 2D, а нормальный 3D с зданиями, машинами, людьми – Godot хороший выбор. Open source с MIT-лицензией, без репутационных скандалов как у Unity. Интересный подход – Godot можно использовать только как слой визуализации, а логику симуляции держать на стороне Rust или C# через GDExtension. То есть архитектура такая: Bevy ECS считает, Godot рисует, между ними gRPC или прямые биндинги.
rerun. Отдельная штука для визуализации лог-данных симуляции. Не движок, а специальный инструмент для записи всего, что происходит, с временной осью. Удобно для отладки: гоняешь симуляцию, потом проигрываешь шаг за шагом, смотришь, что пошло не так. Растёт из мира робототехники, где такая отладка нужна постоянно.
В сухом остатке для MVP я бы держал в голове такой расклад: Bevy + egui для 2D-схематичного представления, скомпилированного в WASM, чтобы открывать в браузере. Для следующего шага – Godot можно использовать как 3D-витрину поверх того же вычислительного ядра. Rerun для дев-инструментов и отладки.
Список не претендует на полноту. Это скорее то, что я бы выбрал при сборке прототипа. Из этого списка, если выкинуть совсем уж специализированное, вырисовывается следующая примерная картинка: Bevy ECS снизу + лёгкая акторная абстракция поверх + DuckDB для аналитики + ONNX для inference моделей + опционально LLM-агент с tool calling в самом верху. Об этом ниже.
После всех этих копаний у меня сложились три варианта. Они не взаимоисключающие — скорее это спектр от чистой архитектуры к гибридной.
Каждый объект – это актор. Доставщик, склад, диспетчер. Они общаются сообщениями, синхронизируются барьером через отдельного системного актора или через каналы.
Уточнение: В какой-то момент изучения я наткнулся на информацию, что в теории для синхронизации шагов симуляции на чистых акторах – можно использовать channels, которые являются менее overhead, чем мое предыдущее понимание – делать синхронизацию через классические сообщения.
Что хорошо. Естественная изоляция: упал один актор – остальные живут, упавшего подняли. Распределённость почти даром: акторы можно разнести по машинам, и они продолжат общаться ничего не зная про это (пример с Akka.Net). Возможна гибкая агрегация: один актор может быть один-к-одному к объекту, быть агрегацией нескольких однотипных объектов, регионом для одиночных или множественных акторов. Отдельные акторы как среды (environments).
Что плохо. На больших масштабах синхронизация становится бутылочным горлышком (моя предыдущая боль). Cache friendly плохая – каждый актор это отдельный объект в куче (heap). Численные расчёты медленнее.
Где подходит. Сценарии, где важнее изоляция и распределённость, чем максимальный перформанс. Например, если симулятор должен моделировать сотни автономных компаний, каждая со своей политикой или каждый объект настолько уникальный, что ни о какой группировке их в однотипные объекты – не может идти и речи. Если же в симуляции необходимо крутить миллионы ящиков на конвейерах – то синхронизация станет узким местом.
Все объекты – это сущности (entity) отдельно плюс данные (components) также отдельно. Системы (systems) последовательно/параллельно применяют пользовательские вводы, события, вмешательства агентов, вычисляют изменения в компонентах объектов (сущностей) и тем самым меняют состояние мира. Это то, чем живут современные AAA-игры.
Что хорошо. Быстродействие специально ориентированное на быструю работу с большим количеством объектов. Простота MVP – на чистом ECS можно собрать рабочий прототип симулятора в одиночку за обозримое время и вероятно с меньшей вероятностью утонуть в классических проблемах ООП разработки игр с “наследованием от наследования”. Естественная пакетная обработка: система обрабатывает все Position за один проход.
Что плохо. ООП разработчикам сложнее перестроиться на новый подход. Проблемы иного рода – как те или иные действия над объектами – выразить через системы. Также сложно прикрутить какой-то интеллект. Если хочется, чтобы курьер «подумал» над маршрутом, придётся это либо ставить в систему (что неуклюже), либо переплетать с чем-то ещё. Проще всего в виде систем реализовывать расчет каких то быстрых и простых метрик и триггеров о том что что-то пошло не так.
Где подходит. Один домен. Простые эвристики на операционном уровне. Например, сортировочный центр с робо-перемещениями стеллажей на Bevy ECS, скомпилированный в WASM и работающий прямо в браузере. Или прототип Яндекс-логистики с тысячами курьеров на том же стеке.
Этот вариант показался наиболее интересным и перспективным. ECS-миры лежат внутри акторов снизу как операционный движок. Поверх них – иерархия из акторов разных уровней, которые занимаются всеми «мыслительными» функциями.
Это удивительно переплетается с уровнями из DDAE первой части.
Операционный уровень. ECS-миры внутри акторов. Множество однотипных сущностей, простые tight-loop системы. Например, цех это ECS-мир. Сущности: единицы продукции, инструменты, рабочие места. Системы: движение по конвейерам, обработка, контроль. Этот слой работает быстро и часто, тысячи раз в секунду. Сами акторы с ECS-мирами максимально простые и только они требует жёсткой синхронизации между шагами. Если акторы-мыслители не успели поставить задачи, то объекты просто стоят и ждут.
Тактический уровень. Акторы-руководители. Каждый ECS-мир принадлежит актору-менеджеру. Он смотрит на агрегированные метрики своего мира (как сообщения от акторов ECS-миров, а также возможности сделать запрос в DuckDB) и принимает тактические решения: «конвейер три перегружен, надо снизить подачу», «у курьера 47 пробка впереди, надо пересчитать маршрут». Этот слой работает с частотой «раз в N тиков» и может использовать правила или лёгкую оптимизацию.
Стратегический уровень. Акторы более высокого уровня с доступом к большой картине. Они работают редко – раз в N минут симуляционного времени – но мыслят глубже. Могут спросить у DuckDB исторические тренды, прогнать ML-модель для прогноза спроса, дёрнуть ИИ-агента с tool calling, чтобы разобрать сложную ситуацию. Они меняют правила игры: переключают режимы, переназначают ресурсы.
Реактивная среда. Отдельный модуль, который наблюдает за всем и подкручивает параметры, как иммунная система [8]. На неё ложатся события: поломки, скачки спроса, погода, кризисы. Может работать по жёстким сценариям или адаптивно – подобно AI Director из Left 4 Dead, который следит, не слишком ли скучно или сложно, и подстраивает. Также реализация различных сред отлично подходит сюда.
Этот расклад мне понравился ещё и тем, что разные слои работают на разных частотах и с разной «ценой решения». Операционщики ECS считает до тысячи раз в секунду. Тактики – раз в секунду или реже. Стратеги – раз в минуту или реже, но с тяжёлым интеллектуально вычислительным процессом. Это совпадает с тем, как реально устроено управление в больших организациях, и это же напрямую похоже на DDAE-иерархию из первой части.
Вторая часть получилась предпоследней, хоть я и надеялся уложиться в 2 части. Сейчас я сам примерно на стадии «архитектура сложилась в голове, начинаю выбирать инструменты, домен и границы MVP».
В заключительной части планирую рассказать про прикладные кейсы – где такая архитектура в теории должна хорошо ложиться на реальные задачи. Поделиться мыслями про MVP-симулятора сортировочного центра, как он может лечь в основу более амбициозного MVP “автономной фабрики будущего” (например мебельный завод), где работают десять айтишников и десять экспертов валидаторов – следящих как human-in-the-loop за работой систем. А также про типы и примеры возможных игр. Потому что граница между серьёзным инженерным симулятором и реалистичной игрой – сегодня тоньше, чем казалось ранее. Примеры из Unity, Unreal, Omniverse – тому яркое подтверждение.
Если коротко эту границу можно проиллюстрировать следующим рисунком:
Симуляторы можно представить в виде следующей шкалы:
Слева – чисто аркадные игра. Правила условны, физика сильно упрощена, экономика существует по большей части для развлечения. Civilization, Anno, Tropico.
Посередине – educational simulator. Не претендует на большую точность, но даёт почувствовать, как работают реальные процессы. RollerCoaster Tycoon, Kerbal Space Program, SimCity, Factorio. С одной стороны это игра, с другой – после неё человек что-то да понимает. Часто такие игры рекомендуют в ВУЗах и крупных компаниях, для развития мышления [9]. Сложно выделить совсем подходящие игры для этого уровня, порой сюда хорошо подходят всякого рода специфичные бизнес-симуляторы.
Справа – непосредственно инженерные симуляторы или тренажёры. Высокая точность, реальные данные, валидируется специалистами. AnyLogic-модель цеха, симулятор полётов для пилотов, цифровой двойник линии метро, тренажеры опасных производственных объектов.
Двигаться по этой шкале значит увеличивать достоверность за счёт развлекательности и наоборот. Любопытно, что архитектура, к которой я пришёл, подходит ко всему диапазону с допущением что в совсем инженерные и сложные вещи все же лезть не стоит, хотя бы причине потенциального скепсиса “где игры, а где инженерная точность”.
В третьей части я постараюсь финализировать историю. Где гибридная архитектура действительно работает, где она избыточна, и почему игровые домены кажутся хорошей площадкой для опробывания этих идей.
Спасибо, что снова дочитали до конца!
Автор: Elpiti
Источник [10]
Сайт-источник BrainTools: https://www.braintools.ru
Путь до страницы источника: https://www.braintools.ru/article/30361
URLs in this post:
[1] забывает: http://www.braintools.ru/article/333
[2] интеллект: http://www.braintools.ru/article/7605
[3] поведения: http://www.braintools.ru/article/9372
[4] поведением: http://www.braintools.ru/article/5593
[5] памяти: http://www.braintools.ru/article/4140
[6] боли: http://www.braintools.ru/article/9901
[7] Логика: http://www.braintools.ru/article/7640
[8] иммунная система: http://www.braintools.ru/nervous-system/immune-system
[9] мышления: http://www.braintools.ru/thinking
[10] Источник: https://habr.com/ru/articles/1035768/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1035768
Нажмите здесь для печати.