Приключения в стране симуляции агентного ИИ

2025-03-11

(Или как мы научились не волноваться и полюбили облако)

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

Задача

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

  • Сколько запросов мы получаем всего?
  • Сколько мы разделяем по сравнению с отправкой напрямую?
  • Как часто мы отбрасываем запросы, если они превышают емкость нашего вычистельного кластера?
  • Как все это влияет на использование ресурсов и общую стоимость (в долларах)?

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

Наша структура симуляции

Для нашей модели исользуем SimPy - библиотеку для discrete event simulation, а также знакомые библиотеки Python, такие как NumPy, Pandas и Matplotlib для обработки данных и визуализации. Симуляция охватывает 30 дней работы (9 часов симулированного активного обслуживания в день), но учитывает, что узлы могут работать 24 часа (поэтому расчет стоимости ВМ использует 30 × 24 часа).

Ключевые моменты:

  • Генерация запросов: Мы генерируем запросы с использованием экспоненциального времени между прибытием (в среднем 2 запроса в минуту).
  • Управление ресурсами: Симуляция отслеживает использование ЦП и ОЗУ на узел. Если запрос требует больше ресурсов, чем доступно, система пытается масштабироваться — до определенного предела.
  • Режимы обработки: Запрос либо обрабатывается напрямую (вероятность 20%), либо разбивается на пять задач агентов (вероятность 80%). Каждая ветвь имеет свои собственные количество токенов и требования к ресурсам.
  • Расчет стоимости: Мы рассчитываем стоимость LLM на основе общего количества обработанных токенов и стоимость ВМ на основе среднего количества узлов, умноженного на количество часов (используя стоимость полного дня, т.е. 24 часа в сутки).

Предположения и числа

Вот некоторые из наших ключевых предположений:

  • Время и запросы: Симуляция длится 30 дней по 9 рабочих часов в день (16200 симулированных минут), со средним временем между запросами 0,5 минуты.
  • Узлы и емкость: Мы начинаем с 7 узлов и можем масштабироваться до 11. Каждый узел имеет 8 vCPU и 32 ГБ ОЗУ (32 × 1024 МБ).
  • Затраты:
    • LLM: $3 за миллион токенов.
    • ВМ: $0,397 за узел-час. Мы используем полный 24-часовой период (720 часов за 30 дней) для расчета стоимости ВМ.
  • Обработка запросов: Прямые запросы и разделенные запросы имеют разные диапазоны токенов и время обработки. Разделенные запросы имитируют участие 5 отдельных ИИ-агентов.

Эти цифры не являются “реальными”, но служат для иллюстрации компромиссов в масштабировании и управлении ресурсами.

Быстрый взгляд на код

Мы не будем перегружать вас всеми деталями, но вот общая структура нашего кода на Python:

import numpy as np
import pandas as pd
from tqdm import trange

NUM_RUNS = 100
results = []

for run in trange(NUM_RUNS):
    # 1. Генерация запросов
    user_queries = np.random.poisson(lam=5000, size=some_size)  # Просто пример

    # 2. Маршрутизация запросов
    direct_requests = 0
    split_requests = 0
    dropped_requests = 0
    total_tokens = 0
    
    # ... Некоторая логика для разделения или отбрасывания запросов ...
    
    # 3. Отслеживание стоимости (в долларах)
    llm_cost = ...
    aks_cost = ...
    total_cost = llm_cost + aks_cost

    # 4. Добавление результатов для каждого запуска
    results.append({
        'direct_requests': direct_requests,
        'split_requests': split_requests,
        'dropped_requests': dropped_requests,
        'total_requests': direct_requests + split_requests,
        'llm_cost': llm_cost,
        'aks_cost': aks_cost,
        'total_cost': total_cost,
        # ... другие статистические данные ...
    })

# Преобразование результатов в DataFrame и вычисление сводной статистики
df = pd.DataFrame(results)
summary = df.describe()
print(summary)

По сути:

  1. Мы генерируем пакет запросов с случайными размерами.
  2. Мы решаем, направлять их напрямую, разделять или отбрасывать.
  3. Мы рассчитываем, сколько токенов прошло и стоимость в долларах.
  4. Мы собираем все эти статистические данные в DataFrame и выводим сводную статистику.

Ноутбук здесь

Результаты: Великое раскрытие

После 100 запусков симуляции мы получили некоторые интересные сводные статистические данные:

StatisticMeanStd DevMinMax
direct_requests64797463326656
split_requests259211742548126307
dropped_requests59540498710
total_requests324001883201032794
percent_split8007980
user_query_tokens35635574704634648163683875
system_query_tokens950521925797929363181696394838
llm_response_tokens427689462622274214206143473226
total_llm_tokens141384694838885139355251143270004
llm_cost4243418430
aks_cost2290622722307
total_cost2714926902737
max_nodes1101111
avg_nodes8088

Что все это значит?

Конечно! Давайте разберем данные, представленные в таблице:

ПоказательСреднееСтандартное отклонениеМинимумМаксимум
direct_requests64797463326656
split_requests259211742548126307
dropped_requests59540498710
total_requests324001883201032794
percent_split8007980
user_query_tokens35635574704634648163683875
system_query_tokens950521925797929363181696394838
llm_response_tokens427689462622274214206143473226
total_llm_tokens141384694838885139355251143270004
llm_cost4243418430
aks_cost2290622722307
total_cost2714926902737
max_nodes1101111
avg_nodes8088

Интерпретация данных:

  • direct_requests (Прямые запросы): Среднее значение около 6479 означает, что за период симуляции система напрямую обработала примерно 6500 запросов, без дополнительного разделения. Диапазон от 6332 до 6656 указывает на небольшие колебания между запусками симуляции.
  • split_requests (Разделенные запросы): Среднее значение около 25921 показывает, что большая часть запросов (примерно 80% от общего числа) обрабатываются через разделение на несколько подзадач. Это подтверждается процентным соотношением (percent_split) – всегда около 80%.
  • dropped_requests (Отброшенные запросы): Среднее значение в районе 595 означает, что иногда система не справляется с нагрузкой и вынуждена отбросить примерно 600 запросов за период, что свидетельствует о том, что иногда ресурсы оказываются ограничены.
  • total_requests (Общее количество запросов): В среднем система получила около 32400 запросов за симуляционный период, что является суммой прямых и разделенных запросов.

Токены и стоимость:

  • user_query_tokens, system_query_tokens, llm_response_tokens: Эти показатели показывают, сколько токенов (единиц данных) прошло через систему на каждом этапе: от пользовательских запросов до ответов LLM. Это важно для понимания нагрузки на систему.
  • total_llm_tokens (Общее количество токенов LLM): Суммарное количество токенов, задействованных в обработке запроса, что позволяет оценить вычислительную нагрузку и, соответственно, стоимость обработки.
  • llm_cost (Стоимость LLM): Стоимость обработки токенов, которая в среднем составляет около $424. Это вычисляется исходя из тарифа $3 за миллион токенов.
  • aks_cost (Стоимость вычислительных узлов): Стоимость работы вычислительных ресурсов (узлов), которая составляет примерно $2290, что рассчитывается на основе среднего количества узлов и числа часов работы (с учетом работы 24 часа в сутки).
  • total_cost (Общая стоимость): Суммарные затраты, получающиеся как сумма затрат на LLM и вычислительные ресурсы – около $2714.

Масштабирование:

  • max_nodes (Максимальное количество узлов): Всегда достигается максимум в 11 узлов, что говорит о предельной возможности масштабирования системы в пиковых моментах нагрузки.
  • avg_nodes (Среднее количество узлов): В среднем система работает с 8 узлами, что указывает на то, что большую часть времени не требуется максимальное количество ресурсов, но система готова к пиковым нагрузкам.

Подведение итогов (и вопрос к вам!)

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

Вопрос к вам: Если вы управляете аналогичной системой ИИ-агентов, коррелируют ли ваши числа с нашими? Возможно, вы видите другое соотношение разделенных и прямых запросов, или, возможно, ваши затраты ведут себя иначе. Дайте нам знать, как наша модель сравнивается с вашими реальными опытами!

Мы надеемся, что это дало вам увлекательный взгляд на мир симуляции ИИ и планирования ресурсов. Если вам когда-нибудь будет интересно, не разорит ли ваша следующая большая идея банк (или ваш кластер), быстрая симуляция, подобная этой, может дать вам некоторое спокойствие — или, по крайней мере, направление для более детализированного моделирования!

Спасибо, что присоединились к нам в этом облачном серфинге, токеновом хрусте и управлении агентами. До следующего раза, удачных симуляций!