Решения

Наблюдаемость сервинга LLM: метрики и трассировка

Задача страницы. Дать практический план по наблюдаемости LLM‑сервисов: какие SLI/SLO фиксировать, как мерить TTFT/TBT/TTLT, где смотреть TPS/QPS, как собирать GPU/KV‑кэш и стоимость за 1M токенов, как устроить трейсинг запросов (OpenTelemetry) и построить дашборды/алерты.

TL;DR

  • Разбейте запрос на этапы: queue → prefill → first_token → decode(stream) → post → done. На каждом этапе собирайте время/ошибки.
  • Ключевые метрики: TTFT, TBT, TTLT, QPS, TPS_decode/prefill_rate, KV‑occupancy/evictions, GPU‑util/HBM.
  • Для управления SLA держите пулы short/long, жёсткие лимиты max_tokens/context и стриминг; алертите по p95 и timeouts.
  • Логи — структурные события без PII. Трейсинг — сквозной trace_id от шлюза до сервера модели и инструментов.

Связанные разделы:
/solutions/monitoring-logging//solutions/llm-inference/streaming//solutions/llm-inference/guardrails//solutions/llm-inference/vllm//solutions/llm-inference/tgi//solutions/llm-inference/tensorrt-llm//solutions/llm-inference/sglang//solutions/llm-inference/llama-cpp//solutions/llm-inference/multi-model//solutions/llm-inference/costs//solutions/cost-planner//solutions/llm-inference/quantization/

SLI/SLO: что считаем «качеством сервиса»

SLI (показатели):

  • TTFT — время до первого токена.
  • TBT — средняя задержка между токенами (stream decode).
  • TTLT — время до последнего токена (время ответа).
  • QPS — запросов/с, TPS_decode/prefill_rate — токенов/с на декоде/префилле.
  • Error/Timeout rate, Queue wait (время ожидания планировщика).
  • GPU: utilization, HBM usage, power, SM occupancy; KV‑кэш: occupancy, evictions.

SLO (цели, пример):

  • TTFT p95 ≤ 300 мс (short‑pool), TBT p95 ≤ 50 мс/токен, TTLT p95 ≤ 2.5 с при L_out ≤ 200.
  • Ошибки ≤ 0.5%, timeouts ≤ 0.2%.
  • Цена за 1M токенов в short‑pool ≤ X ₽ (см. формулы ниже).

Таймлайн запроса и точки измерения

client → gateway

  → queue_in

  → prefill_start … prefill_end

  → first_token  (TTFT)

  → decode_tick (много раз; мерим TBT/TPS)

  → postprocess

  → done (TTLT)

События логируйте с общим trace_id и метаданными: модель, пул, лимиты, длины (L_in/L_out), параметры генерации, GPU‑узел, версия весов.

Метрики: полный базовый набор

API/транспорт

  • requests_total{route,model,pool,status} (counter)
  • request_duration_seconds p50/p95/p99 (histogram)
  • inflight_requests{pool} (gauge)
  • SSE/WS: активные соединения, обрывы, heartbeat‑timeouts

Латентность генерации

  • ttft_seconds (histogram)
  • tbt_seconds_per_token (histogram)
  • ttlt_seconds (histogram)
  • queue_wait_seconds (histogram)

Throughput

  • tokens_generated_total{phase=decode} (counter)
  • prefill_tokens_total (counter)
  • decode_batch_size (histogram)
  • scheduler_efficiency (gauge, 0–1)

KV‑кэш

  • kv_cache_bytes_used / kv_cache_evictions_total
  • prefix_cache_hit_ratio (где доступно)

GPU/система

  • gpu_utilization / gpu_memory_bytes / gpu_power_watts
  • nvlink_tx_rx_bytes_total / pcie_tx_rx_bytes_total
  • CPU токенизации, дисковый I/O (веса/логи), сеть на стриме

Модель/вызов

  • Распределения L_in/L_out, temperature, top_p, stop_reasons
  • Ошибки по классам: oom, timeout, over_limit, bad_json
  • Экономика
    tokens_totalTokens/hourCost_per_1M (см. §10)

Инструментирование по стеку

  • vLLM. Снимайте: prefill_rate, decode_tps, размер текущего батча, hit‑rate prefix‑кэша, paged‑KV занятость. См. /solutions/llm-inference/vllm/.
  • TGI. Очереди планировщика, max_input_length, max_total_tokens, фактический батч, p95 на short/long пулах. См. /solutions/llm-inference/tgi/.
  • TensorRT‑LLM. Время билда/прогрева движка, профиль ядёр, p95 при разных max seq len. См. /solutions/llm-inference/tensorrt-llm/.
  • SGLang/LightLLM. decode_tps, конкуренция, context-length распределения. См. /solutions/llm-inference/sglang/.
  • llama.cpp. tokens/s, -ngl, -c, CPU threads; p95 на hybrid CPU↔GPU. См. /solutions/llm-inference/llama-cpp/.

Пример метрик (Prometheus) и SSE‑хуки

Python (FastAPI + prometheus_client)

				
					from prometheus_client import Counter, Gauge, Histogram

REQS = Counter("requests_total","",["route","model","pool","status"])
INF  = Gauge("inflight_requests","",["pool"])
TTFT = Histogram("ttft_seconds","",buckets=[.05,.1,.2,.3,.5,1,2,5])
TBT  = Histogram("tbt_seconds_per_token","",buckets=[.005,.01,.02,.03,.05,.1])
TTLT = Histogram("ttlt_seconds","",buckets=[.5,1,2,3,5,8,13])
TOK  = Counter("tokens_generated_total","",["phase","model","pool"])
KV   = Gauge("kv_cache_bytes_used","",["model","pool"])

# Пример стрим‑обработчика (события start/first_token/token/done)
async def sse_stream(gen):
    import time, json
    t0, first = time.time(), None
    yield "event: start\ndata: {}\n\n"
    async for delta in gen:   # delta = {"content": "..."} от сервера модели
        NOW = time.time()
        if first is None:
            TTFT.observe(NOW - t0); first = NOW
        else:
            TBT.observe(NOW - prev)
        prev = NOW
        TOK.labels("decode","llama3-8b","short").inc(len(delta["content"])) # грубо: 1 символ = 1 токен? замените на реальный счетчик токенайзера
        yield f"data: {json.dumps({'choices':[{'delta':delta}]}, ensure_ascii=False)}\n\n"
    TTLT.observe(time.time() - t0)
    yield "event: done\ndata: [DONE]\n\n"

				
			

PromQL (примеры)

				
					# p95 TTFT по short-пулу
histogram_quantile(0.95, sum(rate(ttft_seconds_bucket{pool="short"}[5m])) by (le))

# QPS
sum(rate(requests_total[1m])) by (route, pool)

# TPS decode
sum(rate(tokens_generated_total{phase="decode"}[1m])) by (model,pool)

# Загруженность KV-кэша
avg(kv_cache_bytes_used) by (model,pool) / on(model,pool) avg(gpu_memory_bytes) by (model,pool)

				
			

Трейсинг (OpenTelemetry): сквозные спаны

Дерево спанов (минимум):

Serve.Chat (span)

 ├─ Pre.Filter

 ├─ Queue.Wait

 ├─ Prefill

 ├─ FirstToken

 ├─ Decode (stream, многократно)

 ├─ Postprocess

 └─ Store.Log/Audit

Добавляйте атрибуты: model, pool, L_in/L_out, kv_used, batch_size, gpu_id, node, tenant, quant (int4/int8/fp8), finish_reason.

Идентификаторы

  • Пробрасывайте trace_id/span_id с gateway до сервера модели (заголовок traceparent).
  • Для SSE/WS — передавайте trace_id в первом чанке и в конце (done) для корреляции.

Сэмплинг

  • 100% для ошибок/тайм‑аутов, 10% — для нормальных запросов; burst sampling для всплесков.

Дашборды: роли и панели

SRE‑дашборд

  • TTFT/TBT/TTLT p50/p95/p99 (short/long).

  • Ошибки/тайм‑ауты, queue_wait, inflight, распред. длин.

  • GPU util/HBM, KV‑occupancy/evictions, сеть/CPU/диск.

ML‑инженер

  • Prefill vs Decode доли, TPS, распределение параметров (temperature/top_p), контекст/выход, stop_reasons.
  • Влияние квантизации на TPS/латентность. См. /solutions/llm-inference/quantization/.

Продакт/стоимость

  • Tokens/hour, цена за 1M, доля short/long, пер‑тенантные графики. См. /solutions/llm-inference/costs/, /solutions/cost-planner/.

Логи: события вместо «сырого текста»

Событие (рекомендация)

{

  «ts»:»2025-08-22T12:34:56Z»,

  «trace_id»:»tr_abc123″,

  «tenant»:»acme»,

  «model»:»llama3-8b@int8″,

  «pool»:»short»,

  «len_in»:512, «len_out»:180,

  «ttft_ms»:180, «ttlt_ms»:1200,

  «kv_bytes»: 268435456,

  «finish_reason»:»stop»,

  «error»: null

}

Без PII/секретов; для PII — маски и хэши. См. /solutions/llm-inference/guardrails/ и /solutions/security/.

Стоимость: как вывести из метрик

Обозначим: TPS_decode — токены/с на декоде, Num_GPU, GPU_hour_price.

Tokens_per_hour ≈ TPS_decode × 3600

Cost_per_1M     ≈ (GPU_hour_price × Num_GPU) / (Tokens_per_hour / 1e6)Добавьте в экспортер счётчик tokens_generated_total и агрегируйте по модели/пулу/тенанту.
Сводные графики и планирование: /solutions/llm-inference/costs/, /solutions/cost-planner/.

Нагрузочное тестирование и ёмкость

Типы тестов: ступенчатая нагрузка, всплеск, длительное замачивание (soak), деградация.
Набор сценариев: short (L_in≤1K, L_out≤200), balanced, long (≥8K контекста).
Фиксируйте: p95 TTFT/TBT/TTLT, Timeouts/Errors, Queue wait, KV‑occupancy, GPU HBM/util, Tokens/hour.
Цель: найти «колено» — при каком QPS растут p95/тайм‑ауты; обновить лимиты и размеры пулов.

Интеграция со стримингом/агентами

  • Для SSE/WS измеряйте TTFT/TBT/TTLT в самих потоках; отправляйте trace_id и finish_reason. См. /solutions/llm-inference/streaming/.
  • Для агентов логируйте шаги инструментов: tool_start, tool_result, tool_error, длительность и объём контента. См. /solutions/llm-inference/agents/.

Чек‑лист перед продом

  • Зафиксированы SLO (TTFT/TBT/TTLT p95, ошибки/тайм‑ауты, цена/1M).
  • Включены метрики API/латентности/throughput/KV/GPU/стоимости.
  • Настроен трейсинг с trace_id от шлюза до сервера модели/инструментов.
  • Дашборды: SRE / ML / Стоимость; алерты по p95/тайм‑аутам/KV/GPU.
  • Логи — событийные, без PII; аудит и ретеншн.
  • План деградации: пулы short/long, лимиты max_tokens/context, квантизация/масштабирование.