Langfuse für KI-Agenten selbst hosten: VPS-Setup
Betreiben Sie Langfuse auf dem eigenen VPS: mit realer Ressourcenuntergrenze, festen Image-Tags, TLS, ClickHouse-Aufbewahrung und funktionierenden Backups.
Warum einen KI-Agenten überhaupt nachverfolgen?
Sie hosten Langfuse selbst, um zu sehen, was Ihr Agent bei einer Ausführung tatsächlich getan hat. Langfuse ist ein Open-Source-Tool zur Beobachtung von LLMs (Large Language Models). Es zeichnet jeden Prompt, jede Modellantwort, jeden Tool-Aufruf und jedes Token auf und fasst sie anschließend unter einem Trace zusammen, den Sie öffnen und auswerten können. Wenn Sie Langfuse auf Ihrem eigenen VPS betreiben, verlassen diese Prompts niemals einen Server, den Sie kontrollieren.
Der Grund dafür ist einfach. Ein Kosten- oder Qualitätsproblem lässt sich nicht beheben, wenn es nicht sichtbar ist. Eine Anbieterrechnung zeigt Ihnen, dass Dienstag viermal so viel gekostet hat wie Montag. Ein Trace zeigt, welcher Agent-Lauf dafür verantwortlich war, welcher Prompt auf 40,000 Tokens angewachsen ist und welche Retry-Schleife neunmal ausgeführt wurde, bevor sie abgebrochen hat. Die Rechnung liefert die Zahl. Der Trace zeigt den Code, der sie verursacht hat.
In diesem Leitfaden werden drei Begriffe verwendet. Ein Trace ist ein vollständiger Lauf Ihres Agenten von Anfang bis Ende. Eine Observation ist ein einzelner Schritt innerhalb dieses Laufs: ein Span für gewöhnlichen Code oder eine Generation für den Aufruf eines Modells. Ein Score ist eine Zahl, die einem Trace zugeordnet wird und aus einer menschlichen Bewertung oder einer automatisierten Evaluierung stammt. Langfuse verwendet OpenTelemetry (OTel), den herstellerunabhängigen Standard für Distributed Tracing. Daher kann eine bereits vorhandene Instrumentierung auf Langfuse verweisen.
Was beim Self-Hosting von Langfuse tatsächlich läuft
Langfuse v4 besteht nicht aus einem Container. Es sind zwei Anwendungscontainer und vier Speicherdienste. Auf einem einzelnen VPS laufen alle sechs auf Ihrem Server.
langfuse-webstellt die Weboberfläche und die Ingestion-API bereit.langfuse-workerleert die Warteschlange im Hintergrund. Der Worker verarbeitet Ingestion-Batches, berechnet Kosten und führt den nächtlichen Aufbewahrungsjob aus.- Postgres speichert transaktionale Daten wie Benutzer, Organisationen, Projekte, API-Schlüssel und Prompts.
- ClickHouse speichert die eigentlichen Trace-Daten, also Observations und Scores. Es ist ein für analytische Abfragen entwickelter Spaltenspeicher. Deshalb antwortet ein Dashboard auch bei mehr als hundert Millionen Zeilen noch schnell.
- Redis ist die Warteschlange und der Cache zwischen Webcontainer und Worker.
- MinIO stellt S3-kompatiblen Objektspeicher auf dem Server bereit. Dort werden jedes eingehende Rohereignis sowie alle von Ihnen angehängten Medien gespeichert.
Langfuse veröffentlicht Mindestressourcen für die drei Komponenten, die die eigentliche Arbeit ausführen.
The data behind this chart
[
{
"label": "ClickHouse",
"cpu_cores": 2,
"memory_gib": 8
},
{
"label": "Langfuse web",
"cpu_cores": 2,
"memory_gib": 4
},
{
"label": "Langfuse worker",
"cpu_cores": 2,
"memory_gib": 4
}
]ClickHouse benötigt allein 8 GiB Arbeitsspeicher. Der Webcontainer und der Worker benötigen jeweils 4 GiB. Das sind die veröffentlichten Mindestwerte für die 3 von Langfuse dimensionierten Komponenten. Postgres, Redis und MinIO benötigen zusätzlich Arbeitsspeicher. Die Docker-Compose-Anleitung des Projekts empfiehlt einen Server mit 4 Kernen, 16 GiB Arbeitsspeicher und etwa 100 GiB Speicherplatz. Das entspricht dieser Rechnung und enthält keinen zusätzlichen Puffer.
Versuchen Sie das nicht auf einem Tarif mit 2 GiB. ClickHouse startet und nimmt eine Zeit lang Schreibvorgänge an. Anschließend beendet sich der Dienst während eines Hintergrund-Merges, weil dabei große Tabellenteile in den Arbeitsspeicher geladen werden. Sie sehen dann docker compose ps, das den clickhouse-Container als restarting meldet, sowie dmesg mit einer Zeile wie Out of memory: Killed process 1234 (clickhouse-serv). Danach liefern alle Langfuse-Dashboards den Statuscode 500. Bei geringerer Auslastung verweigert ClickHouse stattdessen die Abfrage und protokolliert DB::Exception: Memory limit (total) exceeded. Acht GiB sind für einen einzelnen Entwickler mit einigen tausend Traces pro Tag ausreichend. Planen Sie mit 16 GiB. Wenn auf demselben VPS noch andere Dienste laufen sollen, müssen Sie deren Ressourcen separat einplanen. Selbst ein vergleichsweise schlanker Stack wie ein selbst gehosteter AFFiNE-Arbeitsbereich benötigt eigene GiB, und ClickHouse gibt keinen Arbeitsspeicher davon zurück.
Langfuse mit Docker Compose bereitstellen
Klonen Sie das Repository. Der Stack, die Verbindungen und die Standardumgebung befinden sich in docker-compose.yml.
git clone https://github.com/langfuse/langfuse.git
cd langfuseJeder Wert, den Sie ändern müssen, ist in dieser Datei mit # CHANGEME markiert. Generieren Sie zuerst die drei Anwendungsgeheimnisse.
openssl rand -base64 32 # NEXTAUTH_SECRET
openssl rand -base64 32 # SALT
openssl rand -hex 32 # ENCRYPTION_KEYENCRYPTION_KEY muss 256 Bit umfassen und als 64 Hexadezimalzeichen geschrieben sein. Genau das gibt openssl rand -hex 32 aus. Der Wert verschlüsselt vertrauliche Werte im Ruhezustand, einschließlich aller LLM-Provider-Schlüssel, die Sie in der Instanz speichern. Wenn Sie ihn ändern, nachdem bereits Daten vorhanden sind, können diese Datensätze nicht mehr entschlüsselt werden. Behandeln Sie ihn daher ab dem ersten Start als dauerhaft. SALT wird zum Hashen Ihrer Langfuse-API-Schlüssel verwendet. Eine Änderung macht jeden Schlüssel ungültig, den Ihre Agents bereits verwenden.
Setzen Sie anschließend POSTGRES_PASSWORD, CLICKHOUSE_PASSWORD, REDIS_AUTH und MINIO_ROOT_PASSWORD. Das MinIO-Passwort erscheint an vier Stellen: einmal als MINIO_ROOT_PASSWORD und anschließend als LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY, LANGFUSE_S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY und LANGFUSE_S3_BATCH_EXPORT_SECRET_ACCESS_KEY. Wenn eine Stelle fehlt, weist MinIO den betreffenden Client mit SignatureDoesNotMatch zurück. Diese Meldung landet im Worker-Log, während die Weboberfläche weiterhin fehlerfrei aussieht. Wenn Sie diese Werte in einer Env-Datei statt in der versionierten Compose-Datei speichern, entspricht das dem Muster aus Env-Dateien und Secrets in Docker Compose.
Image-Tags vor dem Start festlegen
Die mitgelieferte Datei verwendet langfuse/langfuse:4 und langfuse/langfuse-worker:4. Diese Tags ändern sich. Langfuse führt seine Postgres- und ClickHouse-Migrationen beim Start automatisch aus. Dadurch wird ein routinemäßiger docker compose pull Monate später zu einer ungeplanten Schema-Migration auf einer Datenbank, die Sie an diesem Morgen nicht gesichert haben. Fixieren Sie beide Images in einem docker-compose.override.yml auf dieselbe Version. Compose führt diese Datei zusätzlich zur mitgelieferten Datei zusammen. Ein späteres git pull überschreibt Ihre Anpassungen dadurch nicht.
services:
langfuse-web:
image: docker.io/langfuse/langfuse:4.3.1
langfuse-worker:
image: docker.io/langfuse/langfuse-worker:4.3.1Version 4.3.1 war im August 2026 die aktuelle Version der 4.3-Reihe. Inzwischen wurde 4.4.0 veröffentlicht. Prüfen Sie die GitHub-Releases-Seite des Projekts, fixieren Sie am Tag der Bereitstellung die aktuelle Version und ändern Sie diese Nummer später bewusst. Die Storage-Images in der mitgelieferten Datei sind bereits auf Major-Versionen, postgres:17, clickhouse-server:25.12 und redis:7, fixiert und sollten genauso behandelt werden. Diese Regel gilt nicht nur für Langfuse: ein selbst gehosteter openGym-Workout-Tracker verwendet nur einen Teil dieses Stacks und benötigt trotzdem einen benannten Git-Tag, weil jede Anwendung, die ihre eigene Datenbank beim Start migriert, einen routinemäßigen Pull in eine Schemaänderung verwandeln kann.
Starten Sie den Stack.
docker compose up -d
docker compose ps
docker compose logs -f langfuse-workerBeim ersten Start werden die Migrationen ausgeführt. Warten Sie daher ein bis zwei Minuten, bevor Sie eine Antwort erwarten. docker compose ps sollte sechs Services im Zustand running auflisten. Wenn der Worker in einer Schleife neu startet, finden Sie den Grund in seinem Log: CLICKHOUSE_MIGRATION_URL verwendet das native ClickHouse-Protokoll auf Port 9000, nicht den HTTP-Port 8123. Eine Konfiguration mit Port 8123 schlägt dort fehl, während der Webcontainer weiterhin fehlerfrei aussieht.
Prüfen Sie den Zustand direkt auf dem Server.
curl -s "http://localhost:3000/api/public/health?failIfDatabaseUnavailable=true"
curl -s -o /dev/null -w '%{http_code}\n' http://localhost:3000/api/public/readyEin einfacher Aufruf von /api/public/health bestätigt nur, dass der API-Prozess aktiv ist. Die Datenbank wird dabei absichtlich nicht geprüft, damit der Service bei kurzen Ausfällen von Postgres weiterhin Anfragen verarbeitet. Die Variante failIfDatabaseUnavailable=true eignet sich für die Überwachung. Sie gibt 503 zurück, wenn die Datenbank nicht erreichbar ist. /api/public/ready gibt nach Abschluss der Migrationen 200 zurück, sobald der Container Datenverkehr akzeptiert. Beides sind gewöhnliche HTTP-Prüfungen. Eine Statusseite in Uptime Kuma kann sie daher überwachen und Ihnen melden, dass der Stack ausgefallen ist, bevor Ihre Agents dies bemerken.
TLS vorschalten und die zusätzlichen Ports schließen
Die mitgelieferte Compose-Datei veröffentlicht 3000:3000 für den Webcontainer und 9090:9000 für MinIO. Beide Dienste binden an alle Schnittstellen. Bei einer öffentlichen IP-Adresse bedeutet das: Jeder, der Port 3000 scannt, erreicht Ihre Registrierungsseite. Jeder, der Port 9090 scannt, greift auf den Bucket mit Ihren unverarbeiteten Prompts zu.
Eine einzelne Firewall-Regel schließt diese Ports nicht. Docker schreibt eigene DNAT-Regeln in die Tabelle nat. Diese werden ausgewertet, bevor die Filterregeln von ufw das Paket sehen. Daher lässt ufw deny 3000 den veröffentlichten Port weiterhin offen. Dieses Problem tritt so häufig auf, dass es dafür eine eigene Anleitung gibt: warum veröffentlichte Docker-Ports ufw umgehen. Binden Sie die Ports stattdessen in Ihrer Override-Datei an die Loopback-Schnittstelle.
services:
langfuse-web:
ports:
- "127.0.0.1:3000:3000"
environment:
NEXTAUTH_URL: https://langfuse.example.com
minio:
ports:
- "127.0.0.1:9090:9000"
- "127.0.0.1:9091:9001"NEXTAUTH_URL muss die exakte öffentliche Adresse einschließlich Schema enthalten, weil der Anmeldevorgang daraus die Callback-URL erstellt. Lassen Sie den Wert hinter einem HTTPS-Proxy auf http://localhost:3000 stehen, leitet der Anmeldevorgang den Browser an eine nicht erreichbare Adresse weiter.
Leiten Sie nun einen Reverse Proxy an 127.0.0.1:3000 weiter und lassen Sie ihn das Zertifikat verwalten. Traefik im selben Compose-Projekt ist dafür die übliche Wahl. Die Routing-Labels werden in mehrere Anwendungen hinter einem Traefik-Reverse-Proxy betreiben beschrieben. Caddy erledigt dieselbe Aufgabe mit zwei Zeilen, wenn Langfuse die einzige Anwendung auf dem Server ist. Prüfen Sie mit curl -sI https://langfuse.example.com/api/public/ready. Bestätigen Sie anschließend von einem zweiten Rechner aus, dass curl http://YOUR_IP:3000 nun mit einem Timeout endet.
Bei MinIO gibt es eine Einschränkung. Langfuse stellt angehängte Medien über vorsignierte URLs bereit, die auf diesen S3-Endpunkt verweisen. Wenn Sie multimodale Traces mit Bildern oder Audiodateien verwenden, werden die Anhänge bei einem ausschließlich an Loopback gebundenen MinIO daher nicht geladen. Lesen Sie vor dem Proxying die Konfigurationsseite für Blob Storage. Der in der vorsignierten URL eingetragene Endpunkt muss mit der veröffentlichten Adresse übereinstimmen. Reine Text-Traces sind davon nicht betroffen.
Erstellen Sie Ihr Konto beim ersten Aufruf und behalten Sie anschließend die Kontrolle über die Instanz. Setzen Sie LANGFUSE_ALLOWED_ORGANIZATION_CREATORS auf Ihre eigene E-Mail-Adresse. Dadurch kann eine fremde Person, die die Seite erreicht, keine Organisation auf Ihrem Server erstellen. Wenn Sie bereits Authentik als eigenen Identity Provider betreiben, unterstützt Langfuse eine standardmäßige OIDC-Verbindung. Konten werden dann gemeinsam mit den Konten Ihrer übrigen Anwendungen verwaltet, statt in einer ausschließlich diesem Server bekannten Passwortliste zu liegen.
Ersten Trace senden
Erstellen Sie in der Weboberfläche ein Projekt und kopieren Sie die öffentlichen und geheimen Schlüssel aus den Projekteinstellungen. Das Python SDK liest drei Umgebungsvariablen.
export LANGFUSE_PUBLIC_KEY="pk-lf-..."
export LANGFUSE_SECRET_KEY="sk-lf-..."
export LANGFUSE_BASE_URL="https://langfuse.example.com"LANGFUSE_BASE_URL ist der Variablenname im SDK v4, das im März 2026 veröffentlicht wurde. Älterer Code und ältere Anleitungen verwenden LANGFUSE_HOST. Wenn Ihre Traces statt auf Ihrem Server in Langfuse Cloud ankommen, ist eine nicht gesetzte Base-URL die Ursache, weil der Standardwert auf die gehostete Instanz verweist.
pip install langfuse opentelemetry-instrumentation-anthropic anthropicimport os
from anthropic import Anthropic
from langfuse import get_client, observe
from opentelemetry.instrumentation.anthropic import AnthropicInstrumentor
AnthropicInstrumentor().instrument()
langfuse = get_client()
client = Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
@observe(as_type="tool")
def lookup_order(order_id: str) -> str:
return f"order {order_id}: shipped"
@observe()
def handle_request(question: str) -> str:
context = lookup_order("A-1042")
message = client.messages.create(
model="claude-haiku-4-5",
max_tokens=512,
messages=[{"role": "user", "content": f"{context}\n\n{question}"}],
)
return message.content[0].text
if __name__ == "__main__":
assert langfuse.auth_check()
print(handle_request("Where is my order?"))
langfuse.flush()Der Decorator @observe öffnet eine Observation um die Funktion, erfasst deren Argumente und Rückgabewert und ordnet sie unter der bereits aktiven Observation ein. AnthropicInstrumentor ist die OpenTelemetry-Instrumentierung für den Anthropic-Client. Sie wandelt jeden messages.create-Aufruf in eine Generation mit Modellnamen, Tokenverbrauch und Latenz um, ohne dass die Aufrufstelle geändert werden muss.
Zwei Aufrufe übernehmen die Prüfung für Sie. langfuse.auth_check() gibt bei ungültigen Schlüsseln oder einer falschen Basis-URL False zurück. Das ist schneller, als nach der Ursache für ein leeres Dashboard zu suchen. langfuse.flush() wartet, bis die in der Warteschlange befindlichen Spans gesendet wurden. Kurzlebige Prozesse benötigen diesen Aufruf, weil das SDK die Daten im Hintergrund bündelt und ein Skript, das sofort beendet wird, seinen noch nicht gesendeten Batch mit beendet. Wenn ein ganzes Team statt eines einzelnen Skripts Traces sendet, setzen Sie diese drei Variablen einmal im Gateway, über das die Agents ohnehin laufen, statt in der Shell jeder Person. So sorgt ein selbst gehostetes OneCLI-Harness dafür, dass die Ausführungen aller Kollegen instrumentiert werden, während die Schlüssel an einer Stelle verbleiben.
Warum wächst ClickHouse ständig?
Traces sind bei den meisten selbst betriebenen Systemen die am schnellsten wachsenden Daten. Jeder Agent-Lauf schreibt pro Schritt eine Zeile. Eingaben und Ausgaben werden vollständig gespeichert. Ein gesprächiger Agent mit langen Prompts erzeugt deshalb pro Tag deutlich mehr Daten als die Anwendung, die er überwacht. Wenn Sie nichts unternehmen, füllt ClickHouse den Datenträger. Ein voller Datenträger stoppt die Aufnahme von Daten, statt sie nur zu verlangsamen.
Hier wachsen zwei getrennte Datenbestände. Dafür sind zwei getrennte Maßnahmen erforderlich.
Der erste Datenbestand sind Ihre eigenen Trace-Daten. Die passende Maßnahme ist die Aufbewahrungseinstellung. Öffnen Sie die Projekteinstellungen in der Weboberfläche und legen Sie die Aufbewahrungsdauer in Tagen fest. Langfuse akzeptiert mindestens 3 Tage. Ein nächtlicher Job sucht dann Traces, Observations, Scores und Medien-Assets, die älter als dieser Zeitraum sind, und löscht sie aus ClickHouse und aus dem Blob Storage. Der Job benötigt die Berechtigung DeleteObject für den Bucket. Die Root-Zugangsdaten von MinIO in der Standard-Compose-Datei haben diese Berechtigung bereits. Die Löschung ist dauerhaft. Konfigurieren Sie daher zuerst einen Export in den Blob Storage, wenn Sie den langfristigen Verlauf benötigen. Schreiben Sie keine eigenen TTL-Klauseln für die Tabellen von Langfuse. Der Aufbewahrungsjob hält ClickHouse und den Bucket synchron. Eine manuelle TTL löscht nur eine Seite.
Wählen Sie den Zeitraum danach aus, wofür Sie die Daten tatsächlich verwenden. Kosten- und Qualitätsprüfungen beziehen sich auf Daten von vor einigen Tagen, nicht auf Daten von vor mehreren Monaten. Dreißig Tage sind für ein kleines Team ein sinnvoller Ausgangspunkt. 14 Tage reichen aus, wenn Sie einen Trace nur öffnen, sobald etwas fehlschlägt.
Der zweite Datenbestand sind die systemeigenen Logtabellen von ClickHouse. Das überrascht viele, weil der Datenträger auch nach der Konfiguration der Aufbewahrung weiter wächst. ClickHouse schreibt trace_log, text_log, opentelemetry_span_log, metric_log und asynchronous_metric_log für die eigene Diagnose. Diese Tabellen werden ohne TTL ausgeliefert. Langfuse liest sie nie. Ermitteln Sie zuerst, wohin der Speicher tatsächlich gegangen ist.
SELECT table, formatReadableSize(size) AS size, rows FROM (
SELECT table, database, sum(bytes) AS size, sum(rows) AS rows
FROM system.parts
WHERE active
GROUP BY table, database
ORDER BY size DESC
)Führen Sie den Befehl mit docker compose exec clickhouse clickhouse-client --password "$CLICKHOUSE_PASSWORD" aus. Wenn sich Systemtabellen weit oben in der Liste befinden, deaktivieren Sie sie mit einem Konfigurations-Overlay. ClickHouse führt beim Start jede Datei in /etc/clickhouse-server/config.d/ über der Hauptkonfiguration zusammen.
<clickhouse>
<trace_log remove="1"/>
<text_log remove="1"/>
<opentelemetry_span_log remove="1"/>
<asynchronous_metric_log remove="1"/>
<metric_log remove="1"/>
</clickhouse>Binden Sie das Overlay ein und starten Sie ClickHouse neu.
services:
clickhouse:
volumes:
- ./clickhouse-config.d/system-logs.xml:/etc/clickhouse-server/config.d/system-logs.xml:roDamit werden neue Schreibvorgänge verhindert. Bereits auf dem Datenträger vorhandene Zeilen bleiben jedoch erhalten. Geben Sie den Speicher daher mit DROP TABLE IF EXISTS system.trace_log ausdrücklich frei. Gehen Sie für jede entfernte Tabelle genauso vor. Wenn Sie die Diagnosedaten behalten möchten, können Sie stattdessen für jede Tabelle eine aggressive TTL konfigurieren. Die Langfuse-Dokumentation zur Skalierung beschreibt diese Alternative anstelle von remove="1".
Eine weitere Tabelle sollten Sie kennen. blob_storage_file_log erfasst die in Ihren Bucket hochgeladenen Ereignisdateien. Wenn Sie zusätzlich eine Lifecycle-Richtlinie für den Bucket konfigurieren, geben Sie der Tabelle eine passende TTL. Andernfalls können beide Datenbestände auseinanderlaufen.
ALTER TABLE blob_storage_file_log MODIFY TTL created_at + INTERVAL 30 DAY DELETE;Richten Sie außerdem einen einfachen df -h-Alarm für den Datenträger ein, auf dem die Daten liegen. Traces wachsen nicht gleichmäßig. Sie wachsen an dem Tag stark an, an dem Sie einen neuen Agent ausrollen. Das erste Anzeichen dafür sollte nicht ein Ausfall der Datenaufnahme sein.
Postgres und ClickHouse sichern
Ein Langfuse-Backup besteht aus drei Teilen. Postgres enthält Ihre Benutzer, Organisationen, Projekte und API-Schlüssel. ClickHouse enthält die Traces. MinIO enthält die Rohereignisse. Wenn Sie nur Postgres wiederherstellen, erhalten Sie eine funktionierende Anmeldung ohne Verlauf. Wenn Sie nur ClickHouse wiederherstellen, erhalten Sie einen Verlauf, den niemand ohne Anmeldung anzeigen kann. Diese Aufteilung ist nicht spezifisch für Langfuse. Auch ein selbst gehosteter Chatwoot-Supportdesk hat dieselbe Struktur: Wird ein Postgres-Dump ohne das Uploads-Verzeichnis erstellt, lassen sich die Unterhaltungen wiederherstellen, aber alle Anhänge fehlen.
Postgres ist ein einfaches pg_dump. Das empfehlen auch die Langfuse-Backup-Dokumente.
docker compose exec -T postgres pg_dump -U postgres postgres \
| gzip > langfuse-pg-$(date +%F).sql.gzBei ClickHouse ist mehr Sorgfalt erforderlich, weil ein während laufender Merges kopiertes Datenverzeichnis kein konsistentes Backup darstellt. Auf einem einzelnen Server besteht der einfache Ansatz darin, den Container zu stoppen und das Volume zu archivieren.
docker compose stop clickhouse
docker volume ls | grep clickhouse
docker run --rm -v langfuse_langfuse_clickhouse_data:/data -v "$PWD":/backup alpine \
tar czf /backup/langfuse-ch-$(date +%F).tar.gz -C /data .
docker compose start clickhouseVerwenden Sie den von docker volume ls ausgegebenen Volume-Namen, nicht den im YAML eingetragenen Namen. Die Datei definiert langfuse_clickhouse_data, und Compose versieht ihn mit dem Projektnamen. Ein Klon in einem Verzeichnis namens langfuse erzeugt daher langfuse_langfuse_clickhouse_data. Wenn Sie das verwechseln, erstellt docker run kommentarlos ein neues leeres Volume, und Ihr Archiv enthält keine Daten.
Der Webcontainer schreibt jedes eingehende Ereignis in den Bucket, bevor der Worker es verarbeitet. Ein kurzer ClickHouse-Stopp bedeutet daher meist nur, dass der Worker die Verarbeitung anschließend wiederholt. Führen Sie dies in einer ruhigen Stunde durch und halten Sie den Stopp kurz. Bei einer stärker ausgelasteten Instanz schreibt die eigene BACKUP DATABASE default TO S3(...)-Anweisung von ClickHouse ein konsistentes Backup, ohne den Server zu stoppen. MinIO ist der dritte Teil. mc mirror oder eine MinIO-Replikation in einen externen Bucket deckt diesen Teil ab. Unabhängig davon, welches Backup Sie erstellen, übertragen Sie es vom Server. Dafür sind verschlüsselte restic-Backups auf einem VPS vorgesehen.
Für Redis ist kein Backup erforderlich. Redis enthält die Warteschlange und den Cache. Bei einem Verlust gehen daher die aktuell verarbeiteten Ereignisse verloren, ältere Daten jedoch nicht.
Der Hinweis zur Konsistenz ist relevant und sollte klar formuliert werden. Postgres und ClickHouse werden zu unterschiedlichen Zeitpunkten gesichert. Nach einer Wiederherstellung kann daher eine Projektzeile ohne Traces vorhanden sein oder Traces zu einem nicht mehr existierenden Projekt enthalten. Langfuse toleriert diesen Zustand. Erstellen Sie beide Dumps dennoch zeitnah nacheinander und in einem Zeitfenster mit wenig Datenverkehr. Der Ereignis-Bucket ist die eigentliche Sicherheitsreserve, weil Langfuse jedes eingehende Ereignis vor der Verarbeitung dort speichert.
Stellen Sie die Daten mindestens einmal in einem Test-Stack wieder her. So erkennen Sie einen falschen Volume-Namen jetzt und nicht erst während eines Ausfalls.
Was Sie zuerst prüfen sollten
Vier Punkte sind in der ersten Woche besonders wichtig.
- Kosten pro Trace. Langfuse berechnet die Kosten aus dem Modellnamen und dem Tokenverbrauch. Sortieren Sie die Traces daher nach Kosten und lesen Sie den teuersten Trace vollständig. Meist ist der Prompt zu groß geworden: Ein vollständiges Dokument wurde in den Kontext eingefügt oder ein Gesprächsverlauf wird nicht gekürzt. Sobald Sie das sehen, wird die Kontrolle der Kosten eines AI-Agenten zu einer Engineering-Aufgabe statt zu einer Schätzung.
- Tokenverbrauch getrennt nach Input und Output. Input-Tokens sind zahlreich und günstig. Output-Tokens sind weniger zahlreich und teuer. Gecachter Input ist noch günstiger. Die gleiche Abrechnung wird in der Berechnung des Tokenverbrauchs von Claude Code erläutert. Sie gilt für jeden Agenten, den Sie selbst schreiben.
- Latenz-Perzentile. Der Median verdeckt das Problem. Bei p95 und p99 treten die Timeouts auf. Innerhalb einer Agentenschleife wird ein langsamer Tool-Aufruf bei p95 mit der Anzahl der Iterationen multipliziert.
- Fehlgeschlagene Tool-Aufrufe. Filtern Sie Beobachtungen nach der Stufe
ERROR. Ein Tool, das in 5% der Fälle fehlschlägt, bleibt in einer aggregierten Erfolgsrate unsichtbar. In den Traces ist das Problem dagegen deutlich sichtbar, wenn Sie beobachten, wie das Modell den Aufruf wiederholt und anschließend Tokens für eine Umgehung verbraucht.
Legen Sie das Aufbewahrungsfenster fest und wählen Sie das Dashboard aus, das Sie wöchentlich am selben Tag prüfen. Tun Sie das am besten an dem Tag, an dem Sie den Dienst bereitstellen. Ein Observability-Tool, das niemand öffnet, ist eine Datenbank, die eine Festplatte füllt.
FAQ
Wie viel Arbeitsspeicher benötigt ein selbst gehostetes Langfuse?
Planen Sie 4 CPU-Kerne und 16 GiB Arbeitsspeicher ein. Das entspricht der Empfehlung des Langfuse-Docker-Compose-Leitfadens für eine einzelne virtuelle Maschine. Zusätzlich sollten Sie etwa 100 GiB Speicherplatz vorsehen. Die veröffentlichten Mindestanforderungen der Komponenten liegen bei 8 GiB für ClickHouse und jeweils 4 GiB für die Web- und Worker-Container. Postgres, Redis und MinIO benötigen darüber hinaus ebenfalls Arbeitsspeicher. Acht GiB reichen für die Instanz eines einzelnen Entwicklers. Zwei GiB reichen nicht aus: Der Kernel beendet ClickHouse während Hintergrundzusammenführungen, und dmesg zeigt Out of memory: Killed process.
Warum läuft mein ClickHouse-Speicherplatz weiter voll, nachdem ich die Datenaufbewahrung festgelegt habe?
Die Einstellung zur Datenaufbewahrung gilt nur für die eigenen Daten von Langfuse. ClickHouse schreibt außerdem separat in die Diagnosetabellen trace_log, text_log, opentelemetry_span_log, metric_log und asynchronous_metric_log. Diese Tabellen werden ohne TTL ausgeliefert. Führen Sie die Abfrage system.parts, nach Tabelle gruppiert, aus, um die größte Tabelle zu ermitteln. Deaktivieren Sie anschließend die nicht verwendeten Tabellen mit einem Eintrag remove="1" in einer Datei unter /etc/clickhouse-server/config.d/, starten Sie ClickHouse neu und löschen Sie die vorhandenen Tabellen, um den bereits belegten Speicherplatz freizugeben.
Wie lang ist die kürzeste Datenaufbewahrungsfrist in Langfuse?
Drei Tage. Die Aufbewahrung wird pro Projekt in den Projekteinstellungen oder über die Projects API festgelegt. Ein nächtlicher Job löscht Traces, Beobachtungen, Scores und Medienobjekte, die älter als dieser Zeitraum sind, aus ClickHouse und dem Blob-Speicher. Gelöschte Daten können nicht wiederhergestellt werden. Richten Sie daher zuerst einen Export in den Blob-Speicher ein, wenn Sie den Verlauf länger aufbewahren müssen.
Muss ich sowohl Postgres als auch ClickHouse sichern?
Ja, da beide unterschiedliche Daten enthalten. Postgres speichert Benutzer, Organisationen, Projekte und API-Schlüssel. ClickHouse speichert die Trace-Daten selbst. Eine Wiederherstellung nur aus Postgres ergibt eine Instanz, bei der Sie sich anmelden können, die jedoch keine Trace-Daten enthält. Sichern Sie außerdem den MinIO-Bucket. Er enthält die Rohereignisse, die Langfuse beim Eingang speichert, und ist damit der Quelle der Wahrheit im Stack am nächsten.
Kann ich eine vorhandene OpenTelemetry-Konfiguration an selbst gehostetes Langfuse anbinden?
Ja. Langfuse v4 und seine v4 SDKs basieren auf OpenTelemetry. Die OTel-Instrumentierungen für Anthropic und OpenAI exportieren direkt dorthin. Führen Sie in Python pip install langfuse opentelemetry-instrumentation-anthropic aus, rufen Sie beim Start einmal AnthropicInstrumentor().instrument() auf und setzen Sie LANGFUSE_PUBLIC_KEY, LANGFUSE_SECRET_KEY und LANGFUSE_BASE_URL auf Ihren eigenen Host. Überprüfen Sie die Konfiguration mit langfuse.auth_check(), bevor Sie nach einem fehlenden Dashboard suchen.