LLM observability is a trace-shaped problem with three axes your APM doesn't chart natively: latency that splits into time-to-first-token and tokens-per-second, cost that varies per request with token counts, and quality that regresses without any error code.
Tier: Advanced · Workflow area: Platform-for-AI: observability & cost
This playbook instruments the pb-45 gateway stack with self-hosted Langfuse, defines the metric vocabulary, load-tests to find your real TTFT/TPS envelope, and sets the alerts that catch cost and quality regressions.
Skip standalone tooling only if your existing observability vendor's LLM module already gives you trace-level tokens/cost/TTFT — then apply this playbook's metrics and alerts there instead.
LANGFUSE_PUBLIC_KEY / LANGFUSE_SECRET_KEY created, and your instance URL (SDK env var LANGFUSE_BASE_URL; older SDK versions called it LANGFUSE_HOST).Instrument at the gateway first. One config change covers every consumer — in litellm-config.yaml:
litellm_settings:
success_callback: ["langfuse"]
failure_callback: ["langfuse"]
with the Langfuse keys and base URL in the proxy's environment. Every request now lands in Langfuse as a generation with model, tokens, computed cost, latency, and your key/team metadata. Verify field names against your pinned LiteLLM version.
Add app-level traces where the workflow is multi-step. Gateway traces show calls; they can't show that three calls belong to one user action. In services with RAG/agent pipelines, use the Langfuse SDK (OpenTelemetry-based; @observe decorator or spans as context managers in Python) to wrap the workflow so retrieval, tool calls, and generations nest under one trace. Propagate user_id, session_id, and a prompt_version tag — these make regressions attributable.
Load-test to find the envelope. Use an LLM-aware load generator (vLLM's vllm bench serve, genai-perf, or a k6 script that timestamps first-chunk arrival on streaming responses — plain HTTP timing misses TTFT). Sweep concurrency (1, 8, 16, 32...) with a realistic prompt/output length mix and record P50/P95 TTFT and per-request TPS at each step. The knee of the TTFT curve is your capacity number; publish it next to the SLO.
Define SLOs on the right measurements. Interactive chat: P95 TTFT (e.g. < 1.5s) and minimum streaming TPS (reads-like-typing threshold, ~10+ tok/s). Batch: throughput and cost-per-request, not latency. Alert on burn rate like any other SLO.
Set the regression alerts that errors won't catch.
Close the attribution loop. Build the two dashboards people actually use: (a) FinOps view — spend by team/feature/model, trend and forecast; (b) SRE view — TTFT/TPS/error taxonomies by model and route. Both derive from the same traces; check dashboard definitions into git.
Tokens, not requests, are the unit of both cost and latency — every dashboard that charts request counts without token counts is hiding the thing that pages you.
An observability store full of prompts is a shadow copy of your most sensitive data flows — scope its access and retention like the production datastore it is.