SIM: Событийная модель симулятора (Event-Driven Simulation Model)

Published

June 11, 2026

WarningОграничение публичной документации

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

  • Полная спецификация метода: Будет доступна только во внутреннем контуре разработки (Confluence / Swagger Enterprise).

Основа цифрового симулятора процессов. Сам этот термин описывает математический или логический подход, алгоритм и принцип работы симулятора. Он указывает на то, что симуляция двигается не по фиксированному времени (таймеру), а реагирует на конкретные события (Discrete Event Simulation). Генерируются случайные величины, выстроена причинно-следственная связь событий и бизнес-правила.Каждое изменение состояния системы генерирует событие, которое мы и публикуем.

1. Архитектура Цифрового Двойника (Digital Twin Persona)

В основе алгоритмов вычисления лежит концепция Событийного моделирования (Discrete Event Simulation). Симулятор двигается по временной шкале фиксированными шагами, но внутри каждого шага поведение цифрового двойника или агента полностью стохастично и определяется его персональными характеристиками.

Примечание: Для примеров оспользовали приложение FoodTracker.

Каждый агент описывается двумя изолированными слоями данных:

  1. Статический профиль (StaticProfile): Неизменяемая анкета, определяющая социально-экономический класс двойника, его характер, диету и базовые привычки (класс дохода, чувствительность к ценам, склонность к накопительству).
  2. Динамическое состояние (DynamicState / TwinFoodState): Постоянно меняющиеся физиологические и психологические метрики (текущий уровень голода, стресса, время без покупок и моментальный снимок содержимого холодильника).

2. Механика эволюции шкал и марковские цепи

На каждом тике времени (равном 1 часу) движок производит расчет поведения агента, состоящий из трех последовательных фаз: Линейный рост шкал -> Оценка марковских вероятностей -> Расчет задержки.

graph LR
    Tick[Новый час симуляции] --> Advance[1. AdvanceState: Линейный рост голода и стресса]
    Advance --> Eval[2. EvaluateBehavior: Модификация базовых весов]
    Eval --> Markov[3. MarkovEngine: Выбор действия рулеткой]
    Markov --> Weibull[4. WeibullEngine: Расчет длительности действия]

2.1 Линейное приращение (AdvanceState)

Модель симулирует непрерывную жизнедеятельность. За каждый час пассивного времени показатели агента детерминированно увеличиваются:

  • Голод (current_hunger): Увеличивается на +0.05 за шаг (Clamped до 1.0).
  • Стресс (current_stress): Увеличивается на +0.01 за шаг (Clamped до 1.0).
  • Время без закупок (time_since_last_shop): Инкрементируется на +1.

2.2 Динамическая модификация весов Маркова

В системе определена базовая матрица вероятностей для пяти состояний:

  • IDLE (0.45),
  • COOKING (0.20),
  • CONSUMPTION (0.20),
  • PURCHASE (0.10),
  • WASTE (0.05).

Перед выбором действия модель накладывает на базовую матрицу динамические модификаторы, отражающие текущее состояние шкал твина и контекст времени:

  • Фактор критического голода (hunger > 0.75): Подавляет бездействие (IDLE -0.40), стимулирует готовку (COOKING +0.25) и еду (CONSUMPTION +0.15).
  • Фактор компульсивного шоппинга (stress > 0.80): Увеличивает вероятность закупки, масштабируя её на личную склонность к накопительству (PURCHASE +0.25 * hoarding_tendency).
  • Фактор ночного времени (с 1 до 5 утра): Базово усыпляет твина (IDLE +0.50), но если зафиксирован высокий стресс (>0.75) и низкая чувствительность к ценам (<0.40), активируется паттерн ночного стресс-шоппинга: PURCHASE получает +0.35, а IDLE штрафуется на -0.45.

2.3 Математическая нормализация и Алгоритм Рулетки

Для защиты математической модели от ухода в отрицательные вероятности после применения отрицательных значений или штрафов, MarkovEngine выполняет нормализацию:

  • Если итоговый вес действия < 0, он принудительно заменяется на минимальный порог безопасности: w = 0.01.
  • Выбор действия происходит по алгоритму рулетки (Roulette Wheel Selection): генерируется случайное число roll = rand.Float64() * totalWeight, итеративно накапливается сумма весов, и выбирается сектор, в который попало число. При полном обнулении весов возвращается дефолтное значение (IDLE).

3. Распределение Вейбулла: Генерация задержек времени

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

Плотность вероятности рассчитывается на основе параметров формы (shape, α) и масштаба (scale, β). Метод GenerateNextEventDelay преобразует случайное число методом обратной функции:

\[ \text{hours} = \beta \cdot (-\ln(1 - u))^{\frac{1}{\alpha}} \]

  • Стабилизация наносекундного смещенеия: Для предотвращения рассинхронизации часов между предположим 50 000+ параллельных воркеров, вычисленное дробное время в часах сразу переводится в минуты и округляется до минутных границ:

    totalMinutes := hours * 60.0
    return time.Duration(totalMinutes) * time.Minute

4. Генеративный AI-в-контуре (LLM Semantic Synthesis)

Если марковский процесс выбирает активное действие, в контур симуляции включается генеративный модуль PromptBuilder. Он переводит сухие математические параметры агента в семантический контекст (Промпт) для Large Language Model, заставляя ИИ-сервис генерировать приближенные к реальности, контекстные JSON-данные.

4.1 Трансляция параметров в промпт

  • Параметр HoardingTendency > 0.8 транслируется для LLM как: “Ты склонен закупаться впрок огромными объемами (опт, мешки, коробки, килограммы)”.
  • Параметр PriceSensitivity > 0.7 транслируется как: “Ты крайне чувствителен к ценам, выбираешь только дешевые базовые товары”.

4.2 Схемы данных генеративного слоя (Примеры выходных JSON)

В зависимости от ActionType, LLM обязана вернуть строго валидный JSON-объект без markdown-разметки. Разработчикам ИИ-модуля необходимо настроить парсинг под следующие структуры:

Пример для действия PURCHASE (Чек покупки)

Учитывает диету, доход и склонность к опту.

{
  "receipt_no": "BILL-2026-X901",
  "total_price": 600.0,
  "items": [
    {
      "item_id": "a1b2-c3d4-e5f6",
      "name": "Хлеб Бородинский",
      "category": "Выпечка",
      "units": 2.0,
      "weight_grams": 800.0,
      "price": 100.0
    },
    {
      "item_id": "f8e7-d6c5-b4a3",
      "name": "Масло сливочное 82%",
      "category": "Молочные продукты",
      "units": 1.0,
      "weight_grams": 200.0,
      "price": 400.0
    }
  ]
}

Пример для действия COOKING (Приготовление блюда)

Утилизирует ингредиенты из холодильника, создавая новое виртуальное блюдо.

{
  "dish_item_id": "dish-992-uuid",
  "dish_name": "Суп домашний",
  "yield_portions": 4.0,
  "yield_weight_grams": 1500.0,
  "ingredients": [
    {
      "source_item_id": "a1b2-c3d4-e5f6",
      "used_units": 0.5,
      "used_weight_grams": 200.0
    },
    {
      "source_item_id": "8b5c4112-9c3a-4a6c-b26a-123456789abc",
      "used_portions": 2.0,
      "used_weight_grams": 200.0
    },
    {
      "source_item_id": "1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
      "used_portions": 1.0,
      "used_weight_grams": 250.0
    }
  ]
}

Пример для действия CONSUMPTION (Поедание порции)

Уменьшает количество порций готового блюда.

{
  "item_id": "dish-992-uuid",
  "portions": 1.0,
  "weight_grams": 350.0
}

Пример для действия WASTE (Утилизация испорченной еды)

{
  "item_id": "1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
  "portions": 0.5,
  "weight_grams": 125.0,
  "reason": 1
}

Что модель дает проекту? (Аналитика данных)

Выстроенная по бизнес-процессам модель помогает набирать датасет синтетических данных, когда естественно собираемых данных еще нет. В зависимости от точности и сложности модели, мы заранее можем увидеть как сравнительно большие данные будут работать на репортинг, процесс майнинг и построенние гипотез. В анализе данных например тоже есть бутстрап, который по сути тоже явялется синтетическким. Также модель используется симулятором при нагрузочном тестировании и тестирует user story use cases, а еще сбор ошибок так называемый слой observability. В примерах мы показали одно српаниельно небольшое приложение, а в документации приложений два для демонстрации применния симуляттора для разных моделей или универсатльности.