Observability bezeichnet die Fähigkeit, den internen Zustand eines Systems aus seinen Ausgaben zu rekonstruieren. Bei klassischen Web-Anwendungen reichen Metriken (CPU, Latenz, Fehlerrate), strukturierte Logs und Distributed Tracing aus. Tools wie Datadog, New Relic oder Grafana decken das gut ab.
Bei LLM-Anwendungen entstehen jedoch fünf neue Probleme, die generische APM-Tools nicht lösen:
- Token-Kosten pro Anfrage — jede Modell-Antwort kostet Geld, abhängig von Modell, Input- und Output-Tokens. Ohne präzise Attribution wissen Sie schlicht nicht, welches Feature, welcher User oder welcher Tenant Ihre Cloud-Rechnung verursacht.
- Verschachtelte Tool- und Agent-Aufrufe — ein einziger User-Request kann zehn LLM-Calls, fünf Tool-Aufrufe und drei Vector-DB-Queries auslösen. Ein Span pro HTTP-Call reicht da nicht annähernd, um die kausale Kette zu rekonstruieren.
- Qualität als Metrik — HTTP-200 sagt nichts über die Qualität der Antwort. Sie brauchen Bewertungen für Halluzinationen, Antwort-Relevanz, Faithfulness und User-Feedback.
- Prompt-Versionierung — Prompts sind Code, ändern sich aber häufig außerhalb des Git-Workflows. Welche Prompt-Version war letzte Woche live, als die Beschwerden reinkamen?
- Datenschutz und Audit — Prompt- und Antwort-Daten enthalten häufig PII. Der EU AI Act und die DSGVO verlangen klare Audit-Trails und Datenresidenz.
LLM Observability adressiert genau diese Punkte. Im Zentrum steht das Tracing: jeder User-Request wird zu einem Trace, der alle LLM-Calls, Retrieval-Schritte, Tool-Ausführungen und Custom-Logik mit Timing, Inputs, Outputs und Metadaten festhält.
Warum Langfuse? Vergleich mit LangSmith, Helicone und Phoenix
Der Markt für LLM-Observability ist 2026 erwachsen geworden. Vier Plattformen dominieren, jede mit eigener Architektur:
| Plattform | Architektur | Open Source | Free Tier | Stärke |
| Langfuse | SDK + OpenTelemetry | Ja (MIT) | 50.000 Events/Monat | Self-Hosting, Prompt-Management, Framework-agnostisch |
| LangSmith | SDK (LangChain-nativ) | Nein | 5.000 Traces/Monat | Tiefste LangChain/LangGraph-Integration |
| Helicone | Proxy zwischen App und Provider | Ja | 10.000 Requests/Monat | Schnellster Setup, Cost-Tracking, Caching |
| Arize Phoenix | OpenTelemetry-nativ | Ja | Self-hostbar | ML-Monitoring-Heritage, RAG-Visualisierung |
Langfuse hat sich 2026 als pragmatischer Standard durchgesetzt — und das aus drei Gründen. Erstens ist die Open-Source-Lizenz (MIT) ohne Feature-Gating kompatibel mit produktivem Self-Hosting. Zweitens ist die SDK auf OpenTelemetry aufgebaut, was Vendor-Lock-in vermeidet. Drittens ist nach der ClickHouse-Akquisition im Januar 2026 (Teil einer Series-D-Runde von 400 Mio. USD) die Performance der Backend-Datenbank massiv gestiegen, ohne dass Lizenz oder Pricing-Modell geändert wurden. Das ist, ehrlich gesagt, in der LLM-Tooling-Welt eine Seltenheit.
Wann Sie eine Alternative wählen sollten:
- LangSmith, wenn Ihre gesamte Architektur auf LangChain/LangGraph basiert und Sie bereit sind, Vendor-Coupling für Zero-Config zu akzeptieren.
- Helicone, wenn Sie ausschließlich OpenAI verwenden und nur Cost-Tracking plus Caching brauchen — ohne Agent-Tracing.
- Phoenix, wenn Sie aus dem klassischen ML-Monitoring kommen und Embeddings visualisieren wollen.
Langfuse-Architektur: Trace, Span, Generation
Langfuse modelliert die Welt mit drei zentralen Konzepten, die direkt auf OpenTelemetry abgebildet sind:
- Trace — die komplette User-Interaktion, z. B. eine Chat-Antwort. Hat eine eindeutige ID, einen Namen, optional
userId, sessionId und Tags.
- Span — eine Arbeitseinheit innerhalb eines Trace, z. B. ein Retrieval-Schritt, ein Tool-Aufruf oder ein Sub-Agent-Run. Spans können verschachtelt werden.
- Generation — ein spezialisierter Span für LLM-Calls. Hält zusätzlich Modell-Name, Modell-Parameter, Input/Output-Tokens und berechnete Kosten fest.
An jeden Trace lassen sich später Scores heften — numerische oder kategoriale Bewertungen aus User-Feedback, manueller Annotation oder LLM-as-Judge-Evaluierung. Diese Scores sind die Brücke zwischen Observability und kontinuierlicher Verbesserung.
Setup: Langfuse in 5 Minuten zum Laufen bringen
Schritt 1 — Konto und API-Schlüssel
Registrieren Sie sich auf cloud.langfuse.com (für DSGVO-Konformität die EU-Region wählen) oder starten Sie ein lokales Self-Hosting per Docker:
git clone https://github.com/langfuse/langfuse.git
cd langfuse
docker compose up -d
# UI: http://localhost:3000
Erstellen Sie ein Projekt und kopieren Sie sich Public Key und Secret Key.
Schritt 2 — Python-SDK installieren
pip install langfuse openai langchain langchain-openai opentelemetry-sdk
Schritt 3 — Umgebungsvariablen setzen
export LANGFUSE_PUBLIC_KEY="pk-lf-..."
export LANGFUSE_SECRET_KEY="sk-lf-..."
export LANGFUSE_HOST="https://cloud.langfuse.com" # EU
# US: https://us.cloud.langfuse.com
# Self: http://localhost:3000
export OPENAI_API_KEY="sk-proj-..."
Schritt 4 — Verbindung prüfen
from langfuse import get_client
langfuse = get_client()
assert langfuse.auth_check(), "Langfuse-Authentifizierung fehlgeschlagen"
print("Langfuse bereit")
Wenn das durchläuft — gut, Sie sind drin. Falls nicht, ist es zu 90 % ein vergessenes export oder eine falsche Region-URL.
Tracing-Pattern 1: Der @observe-Decorator
Der schnellste Weg, eine bestehende Python-Funktion zu instrumentieren, ist der @observe()-Decorator. Er erzeugt automatisch einen Span pro Funktionsaufruf, erfasst Argumente und Rückgabewert und propagiert die Trace-ID über verschachtelte Aufrufe.
from langfuse import observe, get_client
from openai import OpenAI
client = OpenAI()
langfuse = get_client()
@observe(as_type="generation")
def chat_completion(prompt: str, model: str = "gpt-4o-mini") -> str:
response = client.chat.completions.create(
model=model,
messages=[{"role": "user", "content": prompt}],
)
langfuse.update_current_generation(
model=model,
input=prompt,
output=response.choices[0].message.content,
usage_details={
"input": response.usage.prompt_tokens,
"output": response.usage.completion_tokens,
},
)
return response.choices[0].message.content
@observe()
def answer_question(question: str, user_id: str) -> str:
langfuse.update_current_trace(user_id=user_id, tags=["faq", "production"])
context = retrieve_documents(question)
prompt = f"Kontext:\n{context}\n\nFrage: {question}"
return chat_completion(prompt)
answer_question("Wie funktioniert Prompt Caching?", user_id="user_42")
langfuse.flush()
Wichtig: Der äußere @observe()-Aufruf erzeugt den Trace, alle inneren Decorator-Aufrufe werden automatisch zu verschachtelten Spans bzw. Generations. Mehr Magie braucht's nicht.
Tracing-Pattern 2: OpenAI-Drop-in-Integration
Wenn Sie nur die OpenAI-SDK verwenden und keine Decorator-Änderungen wollen, ersetzen Sie einfach den Import:
from langfuse.openai import OpenAI # statt: from openai import OpenAI
client = OpenAI()
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": "Erkläre Vector Search in einem Satz."}],
metadata={"user_id": "user_42", "feature": "search"},
)
Jeder Call wird automatisch als Generation getraced — inklusive Modell, Tokens und Kosten. Die metadata-Keys user_id, session_id, tags und trace_id werden von Langfuse als First-Class-Felder erkannt. So einfach kann Tracing sein, wenn man's nicht überdenkt.
Tracing-Pattern 3: LangChain und LangGraph
Für LangChain-Pipelines registrieren Sie den Callback-Handler einmalig:
from langfuse.callback import CallbackHandler
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
handler = CallbackHandler(
user_id="user_42",
session_id="session_abc",
tags=["langchain", "qa"],
)
prompt = ChatPromptTemplate.from_template(
"Du bist ein hilfreicher Assistent. Beantworte: {question}"
)
chain = prompt | ChatOpenAI(model="gpt-4o-mini")
result = chain.invoke(
{"question": "Was ist OpenTelemetry?"},
config={"callbacks": [handler]},
)
Bei LangGraph-Workflows reichen Sie denselben Handler an graph.invoke(..., config={"callbacks": [handler]}) weiter. Jeder Knoten wird zu einem eigenen Span — und das State-Diagramm bleibt im Trace rekonstruierbar. Ziemlich praktisch, wenn ein Agent in einer Schleife hängenbleibt.
RAG-Pipelines tracen: Retrieval und Generation getrennt halten
Bei einer RAG-Pipeline ist die spannende Frage selten "Hat das LLM halluziniert?". Sondern: "Hat der Retriever die richtigen Dokumente gefunden?" Trennen Sie Retrieval und Generation deshalb in zwei Spans:
from langfuse import observe, get_client
langfuse = get_client()
@observe(name="retrieve")
def retrieve_documents(query: str, k: int = 5) -> list[dict]:
docs = vector_store.similarity_search(query, k=k)
langfuse.update_current_span(
input={"query": query, "k": k},
output=[{"id": d.metadata["id"], "score": d.metadata["score"]} for d in docs],
metadata={"index": "kb-2026-q2", "embedding_model": "text-embedding-3-large"},
)
return docs
@observe(name="rag-answer")
def rag_answer(question: str) -> str:
docs = retrieve_documents(question)
context = "\n\n".join(d.page_content for d in docs)
return chat_completion(f"Kontext:\n{context}\n\nFrage: {question}")
Im Langfuse-UI sehen Sie pro Trace nun: User-Frage, abgerufene Dokument-IDs mit Similarity-Scores, finalen Prompt und LLM-Antwort. Wenn ein User später meldet "die Antwort war falsch", können Sie sofort prüfen, ob der Retriever bereits versagt hat — bevor Sie das Modell oder den Prompt anfassen. Das spart in der Praxis Stunden, manchmal Tage.
Prompt-Management: Prompts versionieren ohne Redeploy
Hardcoded Prompts im Code sind in Produktion ein Problem. Jede Änderung verlangt einen Deploy, A/B-Tests sind aufwändig, und nicht-technische Stakeholder können nichts iterieren. Langfuse bietet ein Prompt-Repository mit Versionierung und Labels:
from langfuse import get_client
langfuse = get_client()
langfuse.create_prompt(
name="faq-system",
prompt="Du bist ein FAQ-Bot für {{product}}. Antworte präzise auf Deutsch.",
config={"model": "gpt-4o-mini", "temperature": 0.2},
labels=["production"],
)
prompt_obj = langfuse.get_prompt("faq-system", label="production")
compiled = prompt_obj.compile(product="AI Workflow Lab")
Verknüpfen Sie den geladenen Prompt mit der Generation — so wissen Sie später ganz genau, welche Prompt-Version welche Antwort produziert hat:
langfuse.update_current_generation(prompt=prompt_obj)
Ein Wechsel der Prompt-Version (z. B. label=production auf eine neue Version umhängen) erfordert dann keinen Deploy mehr. Product Manager freuen sich, Engineers haben Ruhe.
Evaluierung in Produktion: LLM-as-Judge in 30 Zeilen
Manuelle Bewertung skaliert einfach nicht. Das Pattern LLM-as-a-Judge nutzt ein zweites Modell, um Antworten automatisch zu bewerten — idealerweise ein stärkeres Modell als das Produktions-Modell, oder ein anderer Anbieter, um Bias zu vermeiden.
from langfuse import get_client
from openai import OpenAI
langfuse = get_client()
judge = OpenAI()
JUDGE_PROMPT = '''Bewerte die folgende Antwort auf einer Skala von 0.0 bis 1.0.
Frage: {question}
Antwort: {answer}
Kriterien:
- 1.0 = sachlich korrekt, vollständig, präzise
- 0.5 = teilweise korrekt oder unvollständig
- 0.0 = falsch oder irrelevant
Antworte nur mit der Zahl, nichts sonst.'''
def score_trace(trace_id: str, question: str, answer: str) -> float:
completion = judge.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": JUDGE_PROMPT.format(
question=question, answer=answer)}],
)
score = float(completion.choices[0].message.content.strip())
langfuse.create_score(
trace_id=trace_id,
name="answer-quality",
value=score,
comment="LLM-as-Judge mit gpt-4o",
)
return score
Lassen Sie diesen Job asynchron auf 5–10 % Ihrer Production-Traces laufen. Die Kosten bleiben überschaubar, und Sie erhalten einen kontinuierlichen Qualitäts-Trend im Langfuse-Dashboard. Traces mit Score < 0.7 lassen sich automatisch zur menschlichen Review-Queue eskalieren.
Datasets und Regression Testing
Bevor Sie einen neuen Prompt oder ein neues Modell live schalten, sollten Sie es gegen ein Golden Dataset testen. Langfuse Datasets erlauben genau das:
from langfuse import get_client
langfuse = get_client()
dataset = langfuse.create_dataset(name="faq-golden-set-v1")
langfuse.create_dataset_item(
dataset_name="faq-golden-set-v1",
input={"question": "Was ist Prompt Caching?"},
expected_output="Eine Anthropic-Funktion, die wiederverwendete Prompt-Präfixe...",
)
def run_experiment(experiment_name: str):
items = langfuse.get_dataset("faq-golden-set-v1").items
for item in items:
with item.run(run_name=experiment_name) as run:
answer = rag_answer(item.input["question"])
run.score(name="exact-match",
value=1.0 if answer == item.expected_output else 0.0)
Im UI vergleichen Sie zwei Experiment-Runs nebeneinander. Ideal für CI/CD: ein neuer PR, der den Prompt ändert, scheitert automatisch, wenn mehr als X % der Golden-Set-Items regredieren. So einfach wird Prompt-Engineering plötzlich diszipliniert.
Self-Hosting für DSGVO und EU AI Act
Für regulierte Branchen — Banking, Health, Public Sector — sind Prompt- und Antwort-Daten häufig nicht cloud-fähig. Langfuse Self-Hosted ist exakt dieselbe Codebasis wie Cloud, läuft aber auf eigener Infrastruktur. Die Architektur in Produktion:
- Web-Container nimmt Trace-Batches an und schreibt sie sofort in S3 (oder kompatibles Object-Storage wie MinIO).
- Redis hält nur Job-Referenzen für die Queue.
- Worker-Container liest aus S3 und schreibt nach ClickHouse.
- PostgreSQL für Metadaten (Projekte, User, Prompts).
Diese Trennung sorgt dafür, dass Lastspitzen am Eingang nicht die analytische Datenbank überlasten. Für das Deployment gibt es offizielle Helm-Charts — ein produktionsreifer Cluster läuft typischerweise in 2–4 Stunden, inklusive TLS und SSO via OIDC.
Konkrete Compliance-Effekte:
- Prompt- und Antwort-Daten verlassen nie Ihre VPC — relevant für DSGVO Art. 28 (Auftragsverarbeitung).
- Audit-Trail mit unveränderlicher Trace-Historie — relevant für EU AI Act Art. 12 (Logging).
- Datenresidenz wählbar pro Region — relevant für Schrems II.
Best Practices für Production
- userId und sessionId immer setzen — ohne diese Felder lässt sich später keine Funnel- oder Cohort-Analyse fahren. Die Felder akzeptieren beliebige Strings, also auch gehashte IDs für Datenschutz.
- Sampling für High-Traffic-Endpoints — ab ca. 1 Mio. Requests/Tag können Sie via
sample_rate=0.1 ein zehnprozentiges Sampling aktivieren, ohne die Aussagekraft zu verlieren.
- Asynchron flushen — Langfuse SDKs senden im Hintergrund in Batches. Bei kurzlebigen Skripten oder Serverless-Funktionen unbedingt
langfuse.flush() vor Beendigung aufrufen (vergessen Sie das einmal in einer Lambda, und Sie wundern sich tagelang über fehlende Traces).
- Filter für nicht-LLM-Spans — wenn Sie OpenTelemetry-Auto-Instrumentierung für HTTP, DB oder AWS-SDK einsetzen, verstopfen diese Spans Ihre Langfuse-Traces. Nutzen Sie
blocked_instrumentation_scopes, um sie auszufiltern.
- Cost-Alerts auf Tag- und User-Ebene — im Dashboard können Sie Schwellwerte konfigurieren (etwa > 50 USD/Tag für Tag enterprise), die per Slack/E-Mail benachrichtigen, bevor Ihre OpenAI-Rechnung explodiert.
- Trace-IDs an Endnutzer ausgeben — wenn ein User eine Beschwerde meldet, geben Sie ihm einen Support-Code, der die Trace-ID enthält. So springen Sie mit einem Klick auf den exakten Trace.
Häufige Stolperfallen
1. Spans erscheinen nicht im UI. Meistens fehlt ein flush(), oder die OTLP-Endpoint-URL ist falsch. Prüfen Sie mit OTEL_LOG_LEVEL=debug, ob Spans tatsächlich exportiert werden.
2. Doppelte Traces bei LangChain. Wenn Sie zusätzlich zur Callback-Handler-Variante OpenTelemetry-Auto-Instrumentierung für die OpenAI-SDK aktiviert haben, entstehen Duplikate. Eine der beiden Quellen deaktivieren — fertig.
3. PII in Logs. Langfuse loggt Inputs und Outputs by default. Für sensible Daten setzen Sie masked=True auf einzelnen Spans oder konfigurieren globale Redaction-Regex via mask_sensitive_data.
4. ClickHouse-Disk voll im Self-Hosting. Default-Retention ist unbegrenzt. Setzen Sie eine TTL-Policy auf der traces-Tabelle (z. B. 90 Tage), bevor das Volume überläuft. Klingt banal, aber ich hab's mehrfach in Reviews gesehen.
Fazit
LLM Observability ist 2026 keine Kür mehr. Es ist Voraussetzung dafür, KI-Anwendungen verantwortungsvoll in Produktion zu betreiben. Langfuse hat sich als pragmatischer Standard etabliert: Open Source, OpenTelemetry-nativ, mit Prompt-Management und Evaluierung in einer Plattform — und seit der ClickHouse-Akquisition mit deutlich verbesserter Backend-Performance.
Wer heute eine RAG-Pipeline, einen LangGraph-Agenten oder einen MCP-Server in Produktion bringt, sollte Tracing von Tag eins an mitdenken. Die Mehrarbeit beim Einrichten beträgt eine Stunde. Die Schmerzen, die Sie sich beim ersten Production-Bug ersparen, ein Vielfaches.
FAQ
Was ist der Unterschied zwischen LLM Observability und klassischem APM?
Klassisches APM (Datadog, New Relic) versteht HTTP-Calls, Datenbank-Queries und CPU-Metriken. LLM Observability versteht zusätzlich Token-Verbrauch, Modell-Parameter, verschachtelte Tool- und Agent-Aufrufe sowie Qualitäts-Scores. Ein generisches APM-Tool zeigt Ihnen "Request war 2,3 s schnell" — Langfuse zeigt "Request hat 12.000 Input-Tokens und 800 Output-Tokens verbraucht, kostete 0,047 USD, der LLM-as-Judge-Score lag bei 0,82, und der Retrieval-Schritt brauchte 1,4 s."
Ist Langfuse kostenlos?
Ja, in zwei Varianten. Die Cloud-Version bietet 50.000 Events pro Monat und 30 Tage Datenaufbewahrung kostenlos. Die Self-Hosted-Variante ist unter MIT-Lizenz vollständig kostenlos und ohne Feature-Limits — Sie zahlen nur Ihre Infrastruktur. Bezahlte Pläne (29–199 USD/Monat) sind nur für SSO, längere Retention und SLA relevant.
Welches Modell sollte ich als LLM-Judge verwenden?
Faustregel: Der Judge sollte mindestens so stark sein wie das Produktions-Modell, idealerweise von einem anderen Anbieter, um systematischen Bias zu vermeiden. Ein klassisches Setup ist gpt-4o als Judge für ein gpt-4o-mini-System — oder umgekehrt claude-sonnet als Judge für ein OpenAI-System. Wichtig: den Judge-Prompt selbst zu evaluieren. Mit einem manuell gelabelten Mini-Datenset prüfen Sie, ob der Judge mit menschlichen Bewertungen korreliert.
Funktioniert Langfuse auch mit Claude, Gemini oder lokalen Modellen?
Ja. Langfuse ist Modell-agnostisch. Die OpenAI-Drop-in-Integration funktioniert nur für OpenAI-kompatible APIs, aber mit dem @observe()-Decorator oder direkt über die OpenTelemetry-Schnittstelle tracen Sie jedes Modell — inklusive Anthropic Claude, Google Gemini, Cohere, Mistral oder Llama via Ollama bzw. vLLM. Für viele Anbieter gibt es bereits OpenLLMetry-Auto-Instrumentierungen, die Generations automatisch erkennen.
Wie geht Langfuse mit DSGVO und PII um?
In der Cloud-Version können Sie die EU-Region (cloud.langfuse.com) wählen — Daten verlassen die EU nicht. Für strenge Anforderungen (Banking, Health) ist Self-Hosting der sichere Weg, da Prompt- und Antwort-Daten Ihre VPC nie verlassen. Auf Span-Ebene unterstützt Langfuse Redaction (masked=True) und globale Maskierungsregeln, um PII vor dem Senden auszufiltern. Zusätzlich gibt es Audit-Logs für alle UI-Zugriffe — relevant für EU AI Act Art. 12.