中文翻译暂不可用,显示俄语原文。

Настроить дашборд в Grafana для LLM

ТЕХНИЧЕСКОЕ ЗАДАНИЕ: Настроить дашборд в Grafana для LLM

1. Цель задачи

Научиться проектировать и разворачивать production-ready дашборд мониторинга для LLM-сервиса (или RAG-системы). Вы научитесь собирать метрики latency, error rate и throughput из LLM-приложения, загружать их в Prometheus и визуализировать в Grafana с использованием перцентилей (p50/p95/p99), агрегированных панелей и временных фильтров.

Ключевой результат Рабочий дашборд Grafana, который отражает p50/p95/p99 latency, error rate (доля ошибок 4xx/5xx) и throughput в разрезе эндпоинтов / моделей / временных окон, готовый к демонстрации и экспорту как JSON.


2. Исходные данные

Что нужноОткуда взять
LLM-сервис (или симуляция)Пет-проект / учебный проект / Python-скрипт, эмулирующий запросы к LLM
Метрики latency, ошибок, количества запросовPrometheus exporter внутри приложения или OpenTelemetry Collector
Prometheusлокальный Docker-контейнер (prometheus.yml)
Grafanaлокальный Docker-контейнер или облачная инстанция
Базовые знания PromQLДокументация Prometheus / шпаргалка
Инструмент для нагрузки (опционально)locust, vegeta или простой time + curl

Если нет реального LLM-сервиса — симулируем:

  1. Напишите простой FastAPI-сервер на Python с одним эндпоинтом /v1/chat/completions, который:
    • принимает POST-запрос с JSON {"prompt": "..."}
    • имитирует работу LLM (задержка от 200 до 2000 мс через time.sleep(random.uniform(0.2, 2.0)))
    • генерирует ответ {"response": "...", "model": "gpt-4o-mini"}
    • случайно возвращает ошибки 500 с вероятностью 1-5%
  2. Встройте в приложение Prometheus-клиент (prometheus_client) и экспортируйте метрики:
    • llm_request_duration_seconds (Histogram)
    • llm_requests_total (Counter с лейблами status, model)
  3. Запустите нагрузочный тест (например, 10 параллельных запросов в течение 3 минут) с помощью Python-скрипта или ab.

3. Технологический стек

КомпонентИнструментыНазначение
LLM-приложение (цель мониторинга)FastAPI / Flask + prometheus_clientГенерация метрик
Сбор метрикPrometheus (pull-модель)Хранение временных рядов
ВизуализацияGrafana (v10+)Дашборды и алерты
Нагрузочное тестированиеPython-скрипт / locust / vegetaГенерация трафика
Контейнеризация (опционально)Docker + docker-composeУпрощение развёртывания
Метрики latencyHistogram метрики Prometheusp50/p95/p99
Метрики ошибокCounter или Gauge по статусамError rate
ThroughputRate от CounterRequests per second

4. Этапы выполнения

Этап 1: Подготовка окружения и симуляция LLM-сервиса (оценка времени: 1 час)

Действия

  1. Создайте файл llm_service.py с FastAPI-приложением, экспортирующим Prometheus-метрики:

    from fastapi import FastAPI
    from prometheus_client import Histogram, Counter, generate_latest
    from starlette.responses import Response
    import random, time, asyncio
    
    app = FastAPI()
    
    REQUEST_DURATION = Histogram(
        'llm_request_duration_seconds',
        'Duration of LLM requests',
        buckets=(0.1, 0.25, 0.5, 0.75, 1.0, 2.5, 5.0, 10.0)
    )
    REQUESTS_TOTAL = Counter(
        'llm_requests_total',
        'Total LLM requests',
        ['status', 'model']
    )
    
    @app.get('/metrics')
    async def metrics():
        return Response(content=generate_latest(), media_type='text/plain')
    
    @app.post('/v1/chat/completions')
    async def chat(body: dict):
        model = body.get('model', 'default')
        delay = random.uniform(0.2, 2.0)
        await asyncio.sleep(delay)
        status = 'success' if random.random() > 0.03 else 'error'
        if status == 'error':
            REQUESTS_TOTAL.labels(status='500', model=model).inc()
            return Response(status_code=500, content='{"error":"internal"}')
        REQUESTS_TOTAL.labels(status='200', model=model).inc()
        REQUEST_DURATION.observe(delay)
        return {"response": f"Simulated response for: {body.get('prompt','')}", "model": model}
    
  2. Настройте prometheus.yml для сбора метрик каждые 5 секунд:

    global:
      scrape_interval: 5s
    scrape_configs:
      - job_name: 'llm_service'
        static_configs:
          - targets: ['host.docker.internal:8000']
    
  3. Соберите docker-compose.yml с сервисами:

  4. Запустите окружение:

    docker-compose up -d
    

Ожидаемый результат этапа
Приложение отвечает на POST-запросы, метрики доступны по http://localhost:8000/metrics, Prometheus видит цель (Status UP).


Этап 2: Генерация нагрузки и накопление данных (оценка времени: 30 минут)

Действия

  1. Напишите скрипт load_test.py, который в течение 5-10 минут отправляет запросы к LLM-сервису с разными промптами и моделями (model1, model2):

    import requests, time, threading, random
    
    def worker():
        while True:
            try:
                model = random.choice(['gpt-4o-mini', 'claude-3-haiku'])
                resp = requests.post('http://localhost:8000/v1/chat/completions',
                                     json={'prompt':'hello', 'model':model},
                                     timeout=10)
            except Exception:
                pass
            time.sleep(random.uniform(0.1, 0.5))
    
    threads = [threading.Thread(target=worker) for _ in range(10)]
    for t in threads:
        t.start()
    time.sleep(600)  # 10 минут нагрузки
    
  2. Запустите нагрузку:

    python load_test.py
    
  3. Проверьте, что Prometheus накопил данные:

    • Откройте http://localhost:9090 → выполните запрос:
      rate(llm_requests_total[1m])
      
    • Должен появиться график.

Ожидаемый результат этапа
В Prometheus есть временные ряды llm_request_duration_seconds_bucket, llm_requests_total с минимум 100 точками.


Этап 3: Создание дашборда в Grafana (оценка времени: 1.5 часа)

Действия

  1. Подключите Prometheus как источник данных в Grafana:

    • URL: http://prometheus:9090
    • Тип: Prometheus
    • Название: Prometheus
  2. Создайте новый дашборд с названием «LLM Service Monitoring».

  3. Добавьте панель «Latency (p50 / p95 / p99)» (Time series, Query A/B/C):

    • p50: histogram_quantile(0.50, sum(rate(llm_request_duration_seconds_bucket[5m])) by (le))
    • p95: histogram_quantile(0.95, sum(rate(llm_request_duration_seconds_bucket[5m])) by (le))
    • p99: histogram_quantile(0.99, sum(rate(llm_request_duration_seconds_bucket[5m])) by (le))
    • Настройте оси: Unit = seconds, Decimals = 3, Legend = p50, p95, p99.
    • Добавьте threshold: красная линия на 2 секунды как warning.
  4. Добавьте панель «Error Rate» (Stat или Time series):

    • Query: sum(rate(llm_requests_total{status="500"}[5m])) / sum(rate(llm_requests_total[5m])) * 100
    • Unit = percent (0-100), Decimals = 2.
    • Color: green if < 1, yellow if < 5, red otherwise.
  5. Добавьте панель «Throughput (RPS)» (Time series):

    • Query: sum(rate(llm_requests_total[5m]))
    • Unit = requests per second (cps), Decimals = 1.
  6. Добавьте панель «Requests by Model» (Bar gauge или Pie chart):

    • Query: sum by (model) (rate(llm_requests_total[5m]))
    • Legend: {{model}}.
  7. Настройте переменные дашборда (Dashboard variables):

    • $model: label_values(llm_requests_total, model) → позволяет фильтровать по модели.
    • $interval: интервал сглаживания (например, $__auto_interval_2m).
  8. Примените фильтры к панелям – добавьте model=~"$model" в запросы.

  9. Сохраните дашборд и экспортируйте как JSON (меню Share → Export → Save to file).

Ожидаемый результат этапа
Дашборд отображает четыре панели, данные обновляются каждые 5 секунд, фильтр по модели работает.


Этап 4: Настройка алертов (опционально, оценка времени: 30 минут)

Действия

  1. Создайте алерт в Grafana для панели Latency:

    • Alert condition: когда p99 > 2s в течение 2 минут.
    • Название: LLM High Latency.
    • Уведомление: email или slack (если настроены контакты).
  2. Создайте алерт для Error Rate:

    • Когда error rate > 5% за 1 минуту.

Ожидаемый результат этапа
Алерты активны, при превышении порога меняется цвет панели и отправляется уведомление (если настроено).


Этап 5: Документирование дашборда (оценка времени: 30 минут)

Действия

  1. Создайте файл README.md с описанием дашборда:

    • Цель мониторинга.
    • Перечень панелей и PromQL-запросов.
    • Как обновить переменные.
    • Инструкция по развёртыванию.
  2. Приложите экспортированный JSON дашборда (например, llm_dashboard.json).

Ожидаемый результат этапа
Git-репозиторий (или папка) содержит код симуляции, дашборд и документацию.


5. Критерии приемки (Definition of Done)

  • Дашборд содержит минимум 4 панели: latency (p50/p95/p99), error rate, throughput, распределение по моделям.
  • Все панели работают с реальными данными из Prometheus (не пустые графики).
  • Настроена хотя бы одна переменная дашборда (например, фильтр по модели).
  • Latency отображается в секундах с точностью до миллисекунд.
  • Error rate отображается в процентах с порогами раскраски.
  • Дашборд экспортирован как JSON-файл и включён в репозиторий.
  • Написана краткая документация (README) с описанием панелей и способом запуска.
  • (бонус) Настроен хотя бы один алерт на p99 latency > 2s.

6. Ожидаемый результат

Основной артефакт
Файл llm_dashboard.json (экспорт дашборда Grafana) и файл README.md с инструкциями.

Содержание дашборда

  • Latency Panel (time series): три линии p50, p95, p99.
  • Error Rate Panel (stat): одно число с окраской.
  • Throughput Panel (time series): RPS.
  • Requests by Model Panel (bar gauge или table): распределение запросов.
  • Переменная $model со значениями из метрик.

Дополнительно (опционально):

  • Docker-compose файл для воспроизведения окружения.
  • Скрипт нагрузки load_test.py.
  • Алерты в JSON (если настроены).

7. Возможные сложности и их решение

СложностьРешение
Prometheus не видит цель (target down)Проверьте docker-compose networking: используйте host.docker.internal или общую сеть, убедитесь, что порт 8000 открыт.
Histogram метрики не показывают перцентилиУбедитесь, что _bucket создаются (buckets заданы). Используйте histogram_quantile с правильным le.
Графики пустые из-за отсутствия нагрузкиЗапустите нагрузочный скрипт дольше (минимум 5 минут), убедитесь, что rate[5m] не слишком большой.
Grafana не подключается к PrometheusПроверьте URL источника данных – внутри Docker используйте имя сервиса http://prometheus:9090.
Переменная $model не подхватываетсяИспользуйте label_values(llm_requests_total, model) и убедитесь, что метрики имеют лейбл model.
Медленное обновление дашбордаУменьшите scrape_interval в Prometheus до 5-10 секунд.

8. Бюджет времени (оценка)

ЭтапВремя
Этап 1: Подготовка окружения и симуляция1 ч
Этап 2: Генерация нагрузки30 мин (активно), 10 мин ожидания
Этап 3: Создание дашборда1.5 ч
Этап 4: Настройка алертов (опционально)30 мин
Этап 5: Документирование30 мин
Итого~4-5 часов

Примечание Для первого выполнения увеличьте бюджет на 1–2 часа из-за возможных затруднений с Docker и PromQL.


9. Связанные вопросы из базы знаний

ВопросТема
42Как настроить Prometheus для сбора метрик из Python-приложения?
87Как рассчитать p95 latency с использованием Histogram в Prometheus?
131Какие панели Grafana лучше всего подходят для мониторинга производительности API?
205Как вычислить error rate (SLO/SLI) с помощью PromQL?
244Как настроить переменные дашборда Grafana с фильтрацией по лейблам?
310Как симулировать нагрузку на LLM-сервис для тестирования мониторинга?
412Как экспортировать и импортировать дашборды Grafana через JSON?
527Как настроить алерты на основе p99 latency в Grafana?
638В чём разница между rate и irate в PromQL при расчёте throughput?
789Как интерпретировать heatmap latency в Grafana?

10. Чек-лист самопроверки

  • Я запустил docker-compose, и сервис LLM отвечает на запросы.
  • Я убедился, что метрики доступны в Prometheus (/targets → UP).
  • Я сгенерировал нагрузку и дождался накопления данных (минимум 5 минут).
  • Я создал дашборд с нужными панелями (latency, error rate, throughput).
  • Я проверил, что фильтр по модели работает и меняет данные на панелях.
  • Я экспортировал дашборд как JSON и положил в репозиторий.
  • Я написал README с описанием дашборда и инструкцией по развёртыванию.
  • (опционально) Я настроил алерт и проверил его срабатывание при превышении порога.