中文翻译暂不可用,显示俄语原文。
Настроить cost tracking в production
ТЕХНИЧЕСКОЕ ЗАДАНИЕ: Настроить cost tracking в production
1. Цель задачи
Научиться внедрять мониторинг стоимости AI‑сервиса в production. Вы настроите сбор метрик cost_per_request, cost_per_user и cost_per_session, реализуете эмиссию этих метрик в Prometheus и построите дашборд в Grafana с детализацией по пользователям, сессиям и временным срезам.
Ключевой результат Дашборд Grafana, на котором за последние 7 дней виден breakdown затрат: общая стоимость, стоимость на пользователя (top‑N), стоимость на сессию, стоимость на запрос с возможностью фильтрации по типу модели и временному окну.
2. Исходные данные
| Что нужно | Откуда взять |
|---|---|
| Тестовое окружение (docker‑compose или облачный инстанс) | Личная машина / арендованный сервер / Gitpod |
| Запросы к LLM (логи с информацией о модели, токенах, пользователе, сессии) | Собранный pet‑project или CSV‑экспорт из production (обезличенный) |
| Prometheus + Grafana | docker‑compose или установка вручную |
Python 3.10+ с библиотеками prometheus_client, fastapi (или любой HTTP‑фреймворк) | Установить через pip |
| Данные о стоимости токенов (стоимость input/output токенов для каждой модели) | API документация провайдера (OpenAI, Anthropic, Mistral и т.п.) |
Если нет реального инструмента — симулируем:
- Запустите эмулятор LLM‑сервиса на FastAPI, который принимает запросы вида
POST /chatс полями user_id, session_id, model и возвращает сгенерированный ответ (можно фиктивный). - Внутри эмулятора вычисляйте количество входных/выходных токенов (например, случайное число от 50 до 500 для input и от 20 до 1000 для output).
- Используйте таблицу стоимости (в центах/тыс. токенов) для каждой модели (например, GPT‑4o: input 5 $ / 1M tokens, output 15 $ / 1M).
- На каждом запросе вычисляйте стоимость и обновляйте метрики Prometheus.
3. Технологический стек
| Компонент | Инструменты | Назначение |
|---|---|---|
| Эмиссия метрик | Python + prometheus_client | Формирование и экспорт метрик cost |
| Хранилище метрик | Prometheus (pull‑модель) | Сбор, агрегация, хранение временных рядов |
| Визуализация | Grafana | Построение дашбордов с breakdown |
| Имитация сервиса | FastAPI / Flask | Приём запросов, расчёт стоимости, вызов метрик |
| Контейнеризация (опционально) | Docker, docker‑compose | Упрощение развёртывания тестового стенда |
| Генератор нагрузки | locust или python-requests | Имитация потока запросов для отладки дашборда |
4. Этапы выполнения
Этап 1: Развёртывание тестового стенда и эмулятора (1.5 часа)
Действия
- Запустите Prometheus и Grafana через docker‑compose:
version: '3.8' services: prometheus: image: prom/prometheus:latest ports: ["9090:9090"] volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml grafana: image: grafana/grafana:latest ports: ["3000:3000"] environment: - GF_SECURITY_ADMIN_PASSWORD=admin - Создайте конфигурацию Prometheus (prometheus.yml), добавив target
localhost:8000(наш эмулятор). - Напишите эмулятор LLM‑сервиса на FastAPI:
from fastapi import FastAPI, Request from prometheus_client import Histogram, Counter, Gauge, generate_latest, REGISTRY import random, time app = FastAPI() # Метрики cost_counter = Counter('llm_total_cost_usd', 'Total cost in USD', ['model', 'user_id']) cost_per_request = Histogram('llm_cost_per_request_usd', 'Cost per request in USD', buckets=(0.0001, 0.001, 0.01, 0.1, 1.0)) # Добавить cost_per_user и cost_per_session — через Gauge или Summary COST_TABLE = { 'gpt-4o': {'input_per_1k': 0.005, 'output_per_1k': 0.015}, 'gpt-4o-mini': {'input_per_1k': 0.00015, 'output_per_1k': 0.0006} } @app.post("/chat") async def chat(user_id: str, session_id: str, model: str, input_text: str): input_tokens = len(input_text.split()) + random.randint(20, 100) output_tokens = random.randint(20, 1000) price = COST_TABLE.get(model, COST_TABLE['gpt-4o']) cost = (input_tokens * price['input_per_1k'] + output_tokens * price['output_per_1k']) / 1000.0 # Обновляем метрики cost_counter.labels(model=model, user_id=user_id).inc(cost) cost_per_request.observe(cost) # Для cost_per_user и cost_per_session используем gauge с уникальными лейблами # (подробнее в следующем этапе) return {"cost": cost, "text": "Simulated response"} - Проверьте, что метрики доступны: откройте http://localhost:8000/metrics.
- Отправьте несколько тестовых запросов через curl или Python.
Ожидаемый результат этапа Prometheus забирает метрики с эндпоинта /metrics; есть базовый llm_total_cost_usd с лейблами model и user_id.
Этап 2: Разработка метрик cost per user, cost per session и cost per request (2 часа)
Действия
-
Добавьте метрику
llm_cost_per_user_usdкак Gauge с лейблом user_id. Идея: суммарная стоимость пользователя за последние N минут (скользящее окно). Поскольку в Prometheus сложно хранить скользящие суммы без записи всех событий, используем агрегацию на стороне эмитента: в памяти храним словарь стоимости на пользователя за последние 5 минут, обновляем при каждом запросе. Для простоты можно просто использовать Gauge, который устанавливается в полную стоимость, посчитанную через counter. Но лучше сделать отдельный Gauge, который обновляем из накопленного словаря раз в 30 секунд.from collections import defaultdict import threading, time user_costs = defaultdict(float) session_costs = defaultdict(float) lock = threading.Lock() # Добавить в /chat: with lock: user_costs[user_id] += cost session_costs[user_id + ":" + session_id] += costЗапустить фоновый поток:
def update_gauges(): while True: time.sleep(30) with lock: for uid, total in user_costs.items(): gauge_user.labels(user_id=uid).set(total) for sess_id, total in session_costs.items(): gauge_session.labels(session_id=sess_id).set(total) -
Создайте метрику
llm_cost_per_session_usdс лейблом session_id. Аналогично. -
Для cost_per_request уже есть Histogram из Этапа 1. Дополнительно создайте Summary с квантилями (p50, p90, p99) для отчётности.
-
Добавьте метрику
llm_cost_per_user_histogram— распределение стоимости на пользователя (для анализа выбросов). -
Настройте очистку старых данных: в фоновом потоке каждые 5 минут удаляйте из словарей записи, которые не обновлялись > 10 минут (чтобы не текла память).
Ожидаемый результат этапа На /metrics появляются все три ключевые метрики: llm_cost_per_user_usd, llm_cost_per_session_usd, llm_cost_per_request_usd (Histogram).
Этап 3: Создание дашборда в Grafana (2.5 часа)
Действия
-
Подключите Prometheus datasource в Grafana.
-
Создайте dashboard с названием "Cost Tracking — LLM Production".
-
Добавьте панели
Панель Метрика / запрос Тип визуализации Total cost (last 24h) sum(rate(llm_total_cost_usd[24h]))илиincreaseStat / Big number Cost breakdown by model sum(increase(llm_total_cost_usd[24h])) by (model)Bar chart Top‑N users by cost topk(10, llm_cost_per_user_usd)Table / Bar gauge Cost per session — top 10 topk(10, llm_cost_per_session_usd)Table Cost per request distribution (p50,p90,p99) histogram_quantile(0.5, sum(rate(llm_cost_per_request_usd_bucket[5m])) by (le))etc.Stat / Graph Cost per user over time avg(llm_cost_per_user_usd) by (user_id)— select few usersTime series -
Настройте переменные для удобства: $model (list from label_values),
$user(list from label_values(llm_cost_per_user_usd, user_id)). -
Добавьте аннотации о деплоях (если есть).
-
Проверьте визуализацию: сгенерируйте нагрузку (скрипт на Python, шлёт 100–500 запросов с разными user_id и session_id).
Ожидаемый результат этапа Дашборд показывает все ключевые метрики, фильтры работают, данные обновляются в реальном времени.
Этап 4: Тестирование и валидация корректности (1 час)
Действия
- Напишите юнит-тесты для эмиттера метрик (pytest + prometheus_client test utilities):
- Проведите нагрузочное тестирование (Locust): 50 concurrent users, 10 минут. Убедитесь, что метрики не теряются, нет ошибок в эмиттере.
- Перекрёстно проверьте стоимость: вручную посчитайте стоимость нескольких запросов и сравните с данными в Prometheus (
/api/v1/query). - Проверьте, что сессии корректно закрываются: отправьте несколько запросов с одной сессией, затем закончите сессию — в дашборде стоимость за сессию должна остаться неизменной.
Ожидаемый результат этапа Все метрики корректны, тесты проходят, нет утечек памяти.
Этап 5: Документирование и подготовка к production (0.5 часа)
Действия
- Напишите README со структурой репозитория, инструкцией по запуску, описанием метрик и дашборда.
- Экспортируйте дашборд в JSON (встроенная функция Grafana) — сохраните в
dashboards/cost_tracking.json. - Добавьте примеры PromQL для типовых запросов (cost per user per day, cost per model per hour).
- Задокументируйте, как добавить новую модель (добавить строчку в
COST_TABLEи обновить дашборд).
Ожидаемый результат этапа Репозиторий содержит код, конфигурацию, дашборд и инструкции; любой инженер может развернуть и подключить свой сервис.
5. Критерии приемки (Definition of Done)
- В Prometheus появляются метрики
llm_total_cost_usd,llm_cost_per_user_usd,llm_cost_per_session_usd,llm_cost_per_request_usd. - Дашборд Grafana отображает breakdown затрат по моделям, пользователям (top‑10) и сессиям (top‑10).
- Метрика
llm_cost_per_request_usdявляется гистограммой, по которой можно вычислить p50, p90, p99. - Все метрики имеют лейблы
model,user_id(кроме per_session — тамsession_id). - При нагрузке 100 запросов/сек не возникает ошибок в эмиттере и Prometheus не теряет данные (check on
prometheus_tsdb_head_series). - Есть юнит-тесты для расчёта стоимости и обновления gauges.
- Дашборд экспортирован в JSON и включён в репозиторий.
- README содержит инструкцию по запуску и список метрик.
6. Ожидаемый результат
- Код эмулятора/эмиттера (
emulator.pyилиcost_tracker.py) с FastAPI-сервером. - Конфигурация Prometheus (
prometheus.yml). - Дашборд Grafana (
dashboards/cost_tracking.json). - README с описанием архитектуры и инструкцией.
- Юнит-тесты (опционально, но желательно).
- Скрипт генерации нагрузки (например
load_test.py).
Дополнительно: документация по добавлению новых моделей и интерпретации метрик.
7. Возможные сложности и их решение
| Сложность | Решение |
|---|---|
| Высокая кардинальность лейблов (user_id может быть миллионы) — Prometheus начнёт тормозить | Использовать summary и histogram без уникальных лейблов, а для per_user/per_session — агрегировать в batch и записывать как Gauge с ограниченным числом лейблов (только активные пользователи за последние N минут). |
| Несоответствие стоимости во времени (цены меняются) | Хранить версию таблицы стоимости в отдельном gauge метрике llm_cost_table_version и при изменении инвалидировать старые данные. В дашборде можно добавить аннотации о смене цен. |
| Переполнение памяти при хранении словарей сессий | Использовать TTL-словарь (например, cachetools.TTLCache) или периодически очищать по последнему обновлению. |
| Гистограмма cost_per_request создаёт много временных рядов | Использовать buckets, адекватные распределению стоимости (например, экспоненциально до 1$). |
| Prometheus не забирает метрики, если сервис перезагружается | Добавить job_name: 'cost-emitter' и настроить scrape_interval на 5–10 секунд. |
8. Бюджет времени (оценка)
| Этап | Время (часы) |
|---|---|
| Этап 1: Развёртывание стенда и эмулятора | 1.5 |
| Этап 2: Разработка метрик cost per user/session | 2.0 |
| Этап 3: Создание дашборда Grafana | 2.5 |
| Этап 4: Тестирование и валидация | 1.0 |
| Этап 5: Документирование | 0.5 |
| Итого | 7.5 часов |
Примечание При первом выполнении может потребоваться до 10 часов с учётом изучения инструментов.
9. Связанные вопросы из базы знаний
| Вопрос | Тема |
|---|---|
| 12 | Как организовать мониторинг в ML‑системе? |
| 45 | Основные метрики для LLM‑сервиса |
| 78 | PromQL: агрегация с группировкой |
| 123 | Настройка Grafana для production |
| 200 | Управление кардинальностью лейблов |
| 345 | Оценка стоимости токенов разных моделей |
| 456 | Сквозное логирование и трассировка запросов |
| 567 | A/B тестирование моделей и cost analysis |
| 678 | Best practices по дашбордам для инженеров |
| 789 | Alerting на основе cost (аномальные расходы) |
10. Чек-лист самопроверки
- Я запустил docker‑compose с Prometheus и Grafana, убедился, что метрики собираются.
- Я реализовал эмитлер с метриками
llm_total_cost_usd,llm_cost_per_user_usd,llm_cost_per_session_usdиllm_cost_per_request_usd. - Я проверил, что в дашборде корректно отображаются top‑N пользователей и сессий по стоимости.
- Я написал хотя бы один тест, проверяющий расчёт стоимости.
- Я экспортировал дашборд в JSON и добавил в репозиторий.
- Я прочитал логи и убедился, что нет ошибок при высокой нагрузке (100+ rps).
- Я задокументировал, как добавить новую модель и как интерпретировать метрики.