Observabilitet för LLM-system: Mått, spår, loggar och testning i produktion

Slutpunkt-till-slutpunkt-övervakningsstrategi för LLM-inferens och LLM-program

Sidinnehåll

LLM-system kan misslyckas på sätt som traditionell API-övervakning inte kan upptäcka – köer fylls tyst, GPU-minne fylls långt innan CPU verkar sysselsatt, och latens exploderar i batchningslageret snarare än i applikationslageret. Den här guiden täcker en fullständig övervakningsstrategi för LLM-inferens och LLM-applikationer: vad du bör mäta, hur du instrumenterar det med Prometheus, OpenTelemetry och Grafana, och hur du distribuerar telemetri-pipelinen i stora skala.

övervakningsdashboard för LLM-system lyckad användare

TL;DR (Executive summary)

LLM-system försämras på sätt som klassiska “HTTP-latens + felfrekvens”-övervakning inte kan förklara. Övervakning för LLM-system på produktionsnivå måste snabbt och försvarligt besvara:

  • Om användarupplevelsen försämras (svans-latens, tid till första token, inter-token-latens, fel och avbrott).
  • Var tiden spenderas (köning vs batchning vs modellutförande; hämtning/verktyg/säkerhetsfilter vs inferens).
  • Vad som fylls först (GPU-användning och minnespress, KV-cache/köpress, CPU-tokenisering).
  • Hur kostnad och kapacitet driftar (token per begäran, token/sec per GPU, cache-hittfrekvens, förlorade genereringar).
  • Om telemetrin är säker att lagra (prompter kan innehålla PII; förhindra känslig läckage till loggar/attribut).

Den mest hållbara designen är en flersignalspipeline:

  • Mått för snabb detektering och kapacitetsplanering (Prometheus + PromQL; valfri långsiktig lagring via Thanos/Cortex/Mimir/VictoriaMetrics).
  • Spår för begärandenivås kausalitet (OpenTelemetry med OTLP; backend som Tempo/Jaeger/Zipkin/Elastic APM).
  • Loggar för kontext, korrelerade till spår (Loki/Elastic/OpenSearch), designade för låg-kardinalitet metadata.
  • Profiling för CPU/minneshotspots och svans-latens (Grafana Pyroscope).
  • Synthetiska + belastningstester för att upptäcka regressioner innan användare gör det (Grafana k6; blackbox-stil provning).
  • SLO för att mäta användarresultat och driva handlingsbara varningar (felbudgeter; brinntidstil).

Vad som gör observabilitet för LLM-system olika

Områdesnotering: målet LLM-ramverket är ospecifierat. Exemplen i denna artikel täcker vanliga servrar/ramverk (Triton, vLLM, TGI, LangChain/LangSmith) och gäller andra stackar genom att ersätta motsvarande mått och spans.

LLM:er introducerar driftbeteenden som skiljer sig från konventionella webbtjänster:

  • Variabel arbete per begäran: tokenantal (inmatning/utmatning) varierar mycket, så “begäran per sekund” kan verka stabilt medan token-throughput kollapsar. TGI och vLLM exporterar explicit token- och token-latensrelaterad telemetri för att stödja detta typ av övervakning.
  • Köning + kontinuerlig batchning: throughputs beroende av batchning/ködiscipliner; köstorlek och batchstorlek blir första klassindikatorer (TGI exponerar båda).
  • Strömmande UX: användare bryr sig om TTFT och inter-token-latens minst lika mycket som full svars tid; OpenTelemetry standardiserar till och med server TTFT/time-per-token mått under GenAI semantiska konventioner.
  • GPU-press dominerar misslyckandemönster: GPU-användning och GPU-minne (inklusive minne som används) är centrala för tillförlitlighet; NVIDIA:s DCGM exporter finns specifikt för att exponera GPU-telemetri vid en Prometheus /metrics-slutpunkt.
  • Multi-stegspipelines: hämtning, verktygskall, säkerhetsfilter och efterbearbetning innebär att slutna latens är en sammansättning av flera spans/köer – vilket gör att distribuerad spårning och noggrann måttdesign är avgörande.

Konkreta exempel från populära inferensservrar illustrerar detta:

  • NVIDIA Triton Inference Server exponerar mått som ren text via /metrics (vanligtvis :8002/metrics) och tillhandahåller flaggor för att aktivera/avaktivera mått och välja en måttport.
  • vLLM exponerar ett omfattande Prometheus /metrics-slutpunkt med en vllm: prefix; dess dokumentation innehåller räknare för genererade token och histogram som time to first token.
  • Hugging Face TGI dokumenterar en /metrics-slutpunkt med köstorlek, batchstorlek, slutna begärandetid, genererade token och kötid.

Kärnobservabilitetsuppgifter och krävda LLM-telemetri

Observabilitet för LLM-system är enklast att implementera när du mappar uppgifter → signaler → verktyg, och sedan begränsar kardinalitet och sampling från första dagen.

Mått: För online-serverande system, Prometheus egen instruktionsguidning betonar frågefördelning, fel och latens som nyckelmått; LLM:er utökar detta med TTFT, per-token-throughput/latens, kölängd, batchstorlek och GPU-användning.

Spår: Spår är hur du tilldelar latens och fel över hämtning/verktyg/säkerhet/inferenssteg; OpenTelemetry formulerar spår/exporterare som en leverantörsnötrisk metod att skicka telemetri till samlingare eller backendar.

Loggar: Loggar ger mänskligt läsbara kontext och “varför”, men förblir endast användbara i stora skala om du undviker indexering av obegränsade värden (exempel: Loki indexar etiketter endast och lagrar komprimerade loggnunkor i objektlagring).

Profiling: Kontinuerligt profiling fängslar produktions CPU/minnesbeteende med lågöverhöjd sampling; Grafana Pyroscope är explicit positionerad för detta.

Synthetiska tester och belastningstester: Grafana k6 är en öppen källkod belastningstestverktyg, och Grafana noterar att Synthetisk Övervakning drivs av k6 och utgår från enkla protokollkontroller.

SLO: Googles SRE-guidlines definierar en SLO som ett målvärde/intervall för en tjänstnivå mätt av en SLI, och ger riktlinjer för varningar om SLO:er (precision/recall/detekterings tid kompromisser).

Nyckelmått för LLM:er

Kategori Exempelmått (verkliga exempel) Typ Varför det är viktigt Exempelkällor
Sluttillgänglighet tgi_request_duration Histogram Svans-latens är användarupplevelsen TGI exponerar detta explicit
Tid till första token vllm:time_to_first_token_seconds ; gen_ai.server.time_to_first_token Histogram Strömmande/dela första token är ofta första tecknet av mättning vLLM och OTel semconv GenAI
Tid per utgående token tgi_request_mean_time_per_token_duration ; gen_ai.server.time_per_output_token Histogram Inter-token-latens; “känns långsam” även om begäran slutförs TGI och OTel semconv GenAI
Tokenanvändning/volym tgi_request_generated_tokens ; gen_ai.client.token.usage Histogram / Räknare Kostnad + kapacitet är tokenbaserade TGI och OTel semconv GenAI
Begäran tgi_request_count ; vllm:request_success_total Räknare Trafikgrunden och resultat TGI och vLLM
Kölängd tgi_queue_size Gauge Köning förutsäger latensexplosioner TGI
Batchstorlek och batchgränser tgi_batch_current_size ; tgi_batch_current_max_tokens Gauge Throughput–latens kompromisser TGI
GPU-användning/minne DCGM_* (exporterare tillhandahålls) Gauge Mättning, OOM risk, skalningstrigg DCGM exporter exponerar GPU-mått vid /metrics
Inferensserverns telemetri-slutpunkt :8002/metrics (Triton standard i dokumentation/arkiv) Standard skrapningsmål för Prometheus Triton dokumentation

OpenTelemetry GenAI semantiska konventioner för standardisering

OpenTelemetry tillhandahåller GenAI semantiska konventioner (status: “Utveckling”) med standardnämnd för GenAI-mått som:

  • gen_ai.client.token.usage och gen_ai.client.operation.duration
  • gen_ai.server.request.duration, gen_ai.server.time_per_output_token, och gen_ai.server.time_to_first_token

Denna standardisering är en praktisk hävstång för portabela “övervaka LLM-modeller med OpenTelemetry”-strategier: skicka en gång och skicka samma telemetri till OSS eller leverantörsbackendar senare.

Designa telemetri-pipelinen

llm observabilitetsflödesschema

Pull vs push

Prometheus är pull-först. Processer exponerar mått i en stödd exponeringsformat, och Prometheus skrapar dem enligt konfigurerade skrapningsjobb.

Push är för undantag. Prometheus “När du ska använda Pushgateway”-guiden rekommenderar explicit Pushgateway endast i begränsade fall (inte som allmän push-ersättning), och Pushgateway README betonar att den inte kan “göra Prometheus till en pushbaserad övervakningssystem”.

LLM-specifika praktiska mönster:

  • Använd pull för inferensservrar/exportare (Triton/vLLM/TGI måttslutpunkter; DCGM exporter; nodmått).
  • Använd OTLP push för spår/loggar/OTel mått (OpenTelemetry Protocol definierar transport/kodning/leverans mellan källor, samlingare och backendar).
  • Använd remote write när du skalar utöver en enda Prometheus (Prometheus tillhandahåller riktlinjer för remote write-tuning; Mimir/Thanos/Cortex tillhandahåller långsiktig och/eller HA-lagringsalternativ).

Agent vs sidecar vs gateway samlingare

OpenTelemetry dokumenterar en agent distributionsmönster, där telemetri skickas till en samlingare som körs tillsammans med applikationen eller på samma värd (sidecar/DaemonSet), sedan exporteras den.

För Kubernetes stöds sidecar-injektion via OpenTelemetry Operator (annotation-baserad injektion).

Praktisk regel för LLM-stackar:

  • Använd en DaemonSet-agent för värdnivås förbättring och delade pipelines över många poddar.
  • Använd en sidecar när du behöver strikt per-arbetsbelastning isolering eller dedikerad lokal filtrering (vanligt när prompts kan innehålla känslig data).
  • Använd en gateway samlingare för centraliserad svanssamplings, batchning, omprovtagningar och exportfanout.

Sampling och kardinalitetkontroll

OpenTelemetry förtydligar att svanssamplings tillåter samplingbeslut med kriterier härledda från en spår (inte möjligt med huvudsamplings endast).

Prometheus instruktionsguiden varnar mot etikettnötsbruk, ger en regel för att hålla kardinalitet låg och råder om omplanering av mått om potentiell kardinalitet överskrider ~100.

LLM-specifika “kardinalitetsfällor” att förbjuda tidigt:

  • Prompttext, svars text, konversation ID:er, begärande ID:er som etiketter/attribut.
  • Verktygsargumentblobbar som spanattribut.
  • Ogränsade “user_id”-etiketter.

Föredra begränsade dimensioner: model, model_family, endpoint, region, status_code, deployment, tenant (endast om begränsade).

Jämförelse av LLM-observabilitetsverktyg

Verktyg mappade till observabilitetsuppgifter

Verktyg Mått Spår Loggar Profiling Synthetiska tester SLO / varningar LLM-relevans
Prometheus ◻️ ◻️ ◻️ ◻️ Instruktionsguidance + varningsmodell; pull-baserad skrapning
Grafana ✅ (visualisering) ✅ (visualisering) ✅ (visualisering) Dashboards är paneler över datakällor; stöder breda datakällor
OpenTelemetry ✅ (profiler utvecklas) ◻️ ◻️ OTLP-spec + GenAI semantiska konventioner; leverantörsneutral instruktering
Jaeger ◻️ ◻️ ◻️ ◻️ ◻️ Accepterar OTLP (gRPC/HTTP) och är en vanlig spårningsserver
Grafana Tempo ◻️ ◻️ ◻️ ◻️ ◻️ Högskalig spårning; kan generera mått från spans via metrics-generator
Grafana Loki ◻️ ◻️ ◻️ ◻️ ◻️ Indexerar endast etiketter; lagrar komprimerade chunkar; minskar logkostnader i stora skala
Elastic Stack (ELK) ◻️ ◻️ Elastic Stack listar Elasticsearch + Kibana grundläggande; Elastic APM stöder OTel-integration
DCGM exporter ◻️ ◻️ ◻️ ◻️ ◻️ GPU-måttsexporterare exponerar /metrics skrapningslutpunkt
Mimir / Thanos / Cortex ◻️ ◻️ ◻️ ◻️ ◻️ Långsiktig/HA Prometheus-kompatibel måttslagring
Datadog Accepterar OTel-spår/mått/loggar; innehåller känslig data skanning funktioner
New Relic Dokumenterar OTLP-slutpunktskonfiguration och stödda OTLP/HTTP-praktiker
Honeycomb ◻️ ◻️ Stöder mottagande av OTLP över gRPC/HTTP; OTel-första inläsning
LangSmith ◻️ ◻️ ◻️ ◻️ ◻️ Stöder OpenTelemetry-baserad spårning för LLM-applikationer

Grafana vs alternativ för visualisering

  • Grafana-dashboards består av paneler som frågar datakällor (inklusive Loki och Mimir) för att producera diagram och visualiseringar.
  • Kibana tillhandahåller dashboards/visualiseringar som UI-lager inom Elastic Stack.
  • OpenSearch Dashboards tillhandahåller verktyg för datavisualisering för OpenSearch.
  • InfluxData:s dokumentation positionerar Chronograf som visualiseringskomponent inom Influx-ekosystemet.

Prometheus vs alternativ för måttbackendar

  • Prometheus lokala lagringsstandardvärden: om behållningsflaggor inte är inställda, är behållning standard 15d (planera behållning/kostnad tidigt).
  • Grafana Mimir beskrivs som horisontellt skalerbar, HA, flerbrukare långsiktig lagring för Prometheus och OpenTelemetry mått.
  • Thanos beskrivs som en mycket tillgänglig Prometheus-konfiguration med långsiktig lagringsförmåga.
  • Cortex beskriver sig själva som en horisontellt skalerbar, HA, flerbrukare långsiktig lagringssystem för Prometheus och OpenTelemetry mått.
  • VictoriaMetrics Cloud dokumenterar Prometheus remote write-integration för långsiktig lagring.
  • Amazon Managed Service for Prometheus beskriver en hanterad lösning som skalar med inmatning/fråga behov och stöder PromQL och remote write.

Praktisk implementeringskockbok

Måtnamn och typer att implementera idag

OpenTelemetry GenAI semantiska konventioner (status: Utveckling) definierar måtnamn du kan standardisera på omedelbart:

  • gen_ai.client.token.usage
  • gen_ai.client.operation.duration
  • gen_ai.server.request.duration
  • gen_ai.server.time_per_output_token
  • gen_ai.server.time_to_first_token

Serverexempel du kan skrapa direkt:

  • vLLM:s Prometheus-slutpunkt innehåller räknare (t.ex. totala genererade token) och histogram (TTFT) och dokumenterar en model_name etikettkonvention.
  • TGI dokumenterar mått inklusive köstorlek, begärandetid, genererade token och genomsnittlig tid per token.
  • Triton dokumenterar /metrics exponering och måttswitchar.

PromQL-exempel för LLM-latens och throughputsdashboards

# p95 sluttillgänglighet för en applikationshistogram
histogram_quantile(
  0.95,
  sum(rate(llm_request_latency_seconds_bucket[5m])) by (le, model)
)

# Felprocent (5xx)
100 *
(
  sum(rate(llm_requests_total{status_code=~"5.."}[5m]))
  /
  sum(rate(llm_requests_total[5m]))
)

# Token/sec (utgående) över alla modeller
sum(rate(llm_tokens_total{direction="out"}[5m]))

# TGI köstorlek (gauge)
max(tgi_queue_size) by (instance)

# vLLM TTFT p95
histogram_quantile(
  0.95,
  sum(rate(vllm:time_to_first_token_seconds_bucket[5线m])) by (le, model_name)
)

Prometheus histogramguiden förklarar att histogramkvantiler beräknas server-sidan från bucketar med histogram_quantile().

OpenTelemetry instruktioner för LLM-system

  • OTLP är OpenTelemetry Protocol som definierar hur telemetri kodas/överförs mellan källor, samlingare och backendar.
  • OpenTelemetry SDK-konfiguration dokumenterar miljövariabler som OTEL_EXPORTER_OTLP_ENDPOINT (och protokollalternativ) för att exportera telemetri.
  • OpenTelemetry Python contrib dokumenterar stöd för automatisk och manuell instruktering för FastAPI.
  • GenAI semantiska konventioner inkluderar en opt-in stabilitetsmekanism via OTEL_SEMCONV_STABILITY_OPT_IN för GenAI konventioner migration.

Kort Python-exempel: mått + spår + loggar

Det nedanför visar:

  • Prometheus-måttsexponering (/metrics) för “övervaka LLM-inferens med Prometheus”
  • OpenTelemetry-spår exporteras via OTLP (leverantörsneutral)
  • Strukturerade loggar korrelerade med spårkontext, med en privat säker standard (logga inte rå prompts)
import logging
import time

from fastapi import FastAPI, Request
from pydantic import BaseModel

# Prometheus (pull-baserade mått)
from prometheus_client import Counter, Histogram, generate_latest, CONTENT_TYPE_LATEST
from starlette.responses import Response

# OpenTelemetry (OTLP-spår)
from opentelemetry import trace
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter

app = FastAPI(title="LLM Inferens API", version="1.0.0")
FastAPIInstrumentor.instrument_app(app)

# --- Loggning (privatsäker standard) ---
logger = logging.getLogger("llm")
logging.basicConfig(level=logging.INFO, format="%(message)s")

def trace_id_hex() -> str:
    span = trace.get_current_span()
    ctx = span.get_span_context()
    return format(ctx.trace_id, "032x") if ctx.is_valid else ""

# --- Prometheus mått ---
LLM_REQUESTS = Counter(
    "llm_requests_total",
    "LLM-begäran totalt",
    ["route", "status_code", "model"],
)
LLM_LATENCY = Histogram(
    "llm_request_latency_seconds",
    "Sluttillgänglighet för LLM-begäran (sekunder)",
    ["route", "model"],
    buckets=(0.1, 0.2, 0.35, 0.5, 0.75, 1, 1.5, 2, 3, 5, 8, 13),
)

# --- OpenTelemetry tracer provider ---
resource = Resource.create({"service.name": "llm-inference-api"})
trace.set_tracer_provider(TracerProvider(resource=resource))
trace.get_tracer_provider().add_span_processor(
    BatchSpanProcessor(OTLPSpanExporter())  # konfigurera via OTEL_EXPORTER_OTLP_* miljövariabler
)
tracer = trace.get_tracer(__name__)

class GenerateRequest(BaseModel):
    prompt: str
    model: str = "ospecificerad"
    max_tokens: int = 256

class GenerateResponse(BaseModel):
    model: str
    output: str
    latency_ms: int

@app.post("/v1/generera", response_model=GenerateResponse)
async def generera(req: GenerateRequest, request: Request):
    route = "/v1/generera"
    start = time.perf_counter()

    with tracer.start_as_current_span("llm.generera") as span:
        # Undvik att logga hela prompten; skicka säker metadata
        span.set_attribute("gen_ai.request.model", req.model)
        span.set_attribute("gen_ai.request.max_tokens", req.max_tokens)

        # Ersätt med faktisk LLM-kall (Triton/vLLM/TGI-klient)
        time.sleep(0.15)
        output = "Hej från modellen."

        latency_s = time.perf_counter() - start
        LLM_LATENCY.labels(route=route, model=req.model).observe(latency_s)
        LLM_REQUESTS.labels(route=route, status_code="200", model=req.model).inc()

        logger.info(
            {
                "msg": "llm_request_complete",
                "trace_id": trace_id_hex(),
                "model": req.model,
                "latency_ms": int(latency_s * 1000),
                # Inga rå prompt/output om policy inte tillåter det.
            }
        )

        return GenerateResponse(model=req.model, output=output, latency_ms=int(latency_s * 1000))

@app.get("/metrics")
def metrics():
    return Response(generate_latest(), media_type=CONTENT_TYPE_LATEST)

Distribution, skalning, säkerhet och felsökning

llm dashboard distribution

Distributionsoptioner

Distributionsoption Bäst för Kompromisser
Kubernetes + kube-prometheus-stack (Helm) Standardiserad klusterövervakningspaket (Prometheus Operator, dashboards, regler) CRDs/operator livscykelhantering
Kubernetes + OpenTelemetry Collector (DaemonSet/sidecar) Standardiserad OTLP-pipelines; lokal känslig filtrering Kräver sampling/limit-tuning
Docker Compose Snabb prototyper på en enda värd Inte HA; lagring är manuell
systemd / VM installationer Nätverksfria GPU-flockar och traditionella operatörer Manuell upptäckning och konfiguration
Hanterade tjänster (Grafana Cloud / Datadog / New Relic / AMP) Snabb tid till värde; hanterad skalning Kostnad och styre; leverantörsspärr kompromisser

Skalning och behållning: praktiska begränsningar

  • Prometheus lokala lagring: utan explicit storlek/tidflaggor, är behållningstiden standard 15d.
  • Prometheus remote write: Prometheus dokumenterar remote write-tuning för skalning bortom “sanna standarder”.
  • Grafana Tempo: positionerad som en högskalig spårningsserver och kan generera mått från spans med hjälp av metrics-generator (remote writes till en Prometheus datakälla).
  • Loki-lagring: Loki:s dokumentation betonar etikettnära indexering och komprimerade chunklagring (objektlagring), vilket gör att etikettkonvention är central till skalning och kostnad.

Säkerhet och integritet: prompter kan innehålla PII

OpenTelemetry:s säkerhetsguidlines betonar att telemetriinsamling kan oavsiktligt fånga känslig/personlig information; du är ansvarig för att hantera den korrekt.

Prometheus:s säkerhetsmodell varnar att Prometheus-slutpunkter inte bör exponeras till offentligt tillgängliga nätverk (som internet) eftersom de serverar information om övervakade system.

Operativa integritetskontroller som håller “observabilitet för LLM-system” säker:

  • Standard till inte logga rå prompter/svar; logga tokenantal, modellnamn, latens och trace ID:er istället.
  • Rensa/droppa känsliga attribut i samlingare/pipelines (samlingarnivå filtrering är vanligt förekommande inom ekosystemen).
  • Förbli RBAC och behållningspolicyer för loggar/spår; överväg känsligdata-scanners där lämpligt (t.ex. leverantörer dokumenterar scannare för telemetri).

Felsökningschecklista

Om din Grafana-dashboard för LLM-latens ser fel ut, felsök i den här ordningen:

  • Ingestion hälsa
    • Prometheus: validera skrapningssuccess och konfigurationssemantik (Prometheus-konfiguration definierar skrapningsjobb/instanser).
    • OTLP: bekräfta exporterarens slutpunkt konfiguration (SDK:er använder OTEL_EXPORTER_OTLP_ENDPOINT, protokollinställningar).
  • Schema mismatch
    • Dashboard förväntar sig model, men din server emitterar model_name (vLLM dokumenterar explicit model_name etiketter).
  • Kardinalitetsexplosion
    • Någon etiketterade efter begärande ID:er/prompt-hashar; Prometheus varnar om etikettuppsättningar ökar RAM/CPU/disk/network kostnader och ger kardinalitetsriktlinjer.
  • Histogram misbruk
    • Se till att du beräknar kvantiler från _bucket serier med rate() och le; Prometheus förklarar histogramkvantilberäkning kompromisser.
  • Spår sampling gaps
    • Om du head-samples för aggressivt, försvinner sällsynt långsam/fel spår; tail sampling behåller “viktiga” spår baserat på fulla spårkriterier.
  • Tempo span-mått problem
    • Om du använder Tempo metrics-generator och span-mått, bekräfta att den är aktiverad och inställd (Tempo dokumenterar metrics-generator och span-mått processorer; felsökning finns för generatorproblematik).
  • GPU-mått frånvarande
    • Bekräfta att DCGM exporter är distribuerad och /metrics är tillgänglig (DCGM exporter exponerar GPU-mått över HTTP för Prometheus).

Några användbara länkar