Auto-héberger Langfuse pour tracer vos agents IA
Déployez Langfuse sur votre VPS avec le minimum de ressources, des images versionnées, TLS, une rétention ClickHouse maîtrisée et des sauvegardes testées.
Pourquoi tracer un agent IA
Vous auto-hébergez Langfuse pour voir ce que votre agent a réellement fait lors d’une exécution. Langfuse est un outil open source d’observabilité des LLM (large language models). Il enregistre chaque prompt, chaque réponse du modèle, chaque appel d’outil et chaque token, puis les regroupe dans une trace que vous pouvez ouvrir et consulter. En l’exécutant sur votre propre VPS, ces prompts ne quittent jamais un serveur que vous contrôlez.
La raison est simple. Vous ne pouvez pas corriger un problème de coût ou de qualité que vous ne voyez pas. Une facture fournisseur vous indique que mardi a coûté quatre fois plus cher que lundi. Une trace vous indique quelle exécution de l’agent en est responsable, quel prompt est passé à 40,000 tokens et quelle boucle de retry a été exécutée neuf fois avant d’abandonner. La facture donne le chiffre. La trace montre le code qui l’a produit.
Trois termes sont utilisés dans ce guide. Une trace est une exécution complète de votre agent, du début à la fin. Une observation est une étape de cette exécution : un span pour du code ordinaire, une generation pour un appel à un modèle. Un score est un nombre associé à une trace, provenant d’une évaluation humaine ou automatisée. Langfuse utilise OpenTelemetry (OTel), le standard indépendant des fournisseurs pour le distributed tracing. L’instrumentation dont vous disposez déjà peut donc pointer vers Langfuse.
Ce que l’auto-hébergement de Langfuse exécute réellement
Langfuse v4 ne se limite pas à un conteneur. Il comprend deux conteneurs applicatifs et quatre services de stockage. Sur un VPS unique, les six s’exécutent sur votre serveur.
langfuse-websert l’interface web et l’API d’ingestion.langfuse-workertraite la file d’attente en arrière-plan. Il analyse les lots d’ingestion, calcule les coûts et exécute la tâche de rétention nocturne.- Postgres stocke les données transactionnelles telles que les utilisateurs, les organisations, les projets, les clés d’API et les prompts.
- ClickHouse stocke les données des traces elles-mêmes, c’est-à-dire les observations et les scores. Il s’agit d’un column store conçu pour les requêtes analytiques. C’est pourquoi un dashboard portant sur plus de cent millions de lignes répond encore rapidement.
- Redis est la file d’attente et le cache situés entre le service web et le worker.
- MinIO fournit un stockage objet compatible S3 sur le serveur. Il conserve chaque événement brut reçu ainsi que tous les médias que vous joignez.
Langfuse publie les ressources minimales de chaque composant qu’il exécute. Le graphique présente les trois composants qui effectuent le traitement.
Les données de ce graphique
[
{
"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 nécessite à lui seul 8 Gio de mémoire. Le conteneur web et le worker nécessitent chacun 4 Gio. Il s’agit des seuils minimaux publiés pour les 3 composants du graphique. La même page indique 4 Gio pour Postgres, 1.5 Gio pour Redis ou Valkey et 4 Gio pour MinIO. Le minimum pour les six composants atteint donc 25.5 Gio. Le guide Docker Compose du projet recommande au moins 4 cœurs, 16 Gio de mémoire et environ 100 Gio de stockage pour une machine unique. Cette valeur est inférieure à la somme des seuils minimaux des composants. Considérez donc 16 Gio comme le minimum nécessaire pour un serveur Compose partagé, et non comme une marge disponible.
N’essayez pas d’exécuter cette configuration sur une offre de 2 Gio. ClickHouse démarre et accepte les écritures pendant un certain temps, puis s’arrête pendant une fusion en arrière-plan, car une fusion charge de grandes parties d’une table en mémoire. Vous verrez docker compose ps signaler le conteneur clickhouse comme restarting, dmesg contenant une ligne telle que Out of memory: Killed process 1234 (clickhouse-serv), et tous les dashboards Langfuse renvoyer une erreur 500. Avec une charge moindre, ClickHouse refuse plutôt la requête et journalise DB::Exception: Memory limit (total) exceeded. Prévoyez 16 Gio. Si le même VPS doit héberger d’autres services, prévoyez leurs ressources séparément. Même une stack relativement légère comme un espace de travail AFFiNE auto-hébergé nécessite ses propres gigaoctets, et ClickHouse ne libérera aucune mémoire pour vous.
Déployer Langfuse avec Docker Compose
Clonez le dépôt. La stack, sa configuration et l’environnement par défaut se trouvent dans son docker-compose.yml.
git clone https://github.com/langfuse/langfuse.git
cd langfuseChaque valeur à modifier est marquée # CHANGEME dans ce fichier. Commencez par générer les trois secrets de l’application.
openssl rand -base64 32 # NEXTAUTH_SECRET
openssl rand -base64 32 # SALT
openssl rand -hex 32 # ENCRYPTION_KEYENCRYPTION_KEY doit contenir 256 bits, écrits sous la forme de 64 caractères hexadécimaux. C’est exactement ce que openssl rand -hex 32 affiche. Il chiffre les valeurs sensibles au repos, notamment les clés des fournisseurs LLM que vous stockez dans l’instance. Si vous le modifiez après la création des données, ces lignes ne pourront plus être déchiffrées. Considérez-le donc comme définitif dès le premier démarrage. SALT sert à hacher vos clés API Langfuse. Le modifier invalide toutes les clés déjà utilisées par vos agents.
Définissez ensuite POSTGRES_PASSWORD, CLICKHOUSE_PASSWORD, REDIS_AUTH et MINIO_ROOT_PASSWORD. Le mot de passe MinIO apparaît à quatre endroits : une première fois comme MINIO_ROOT_PASSWORD, puis de nouveau comme LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY, LANGFUSE_S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY et LANGFUSE_S3_BATCH_EXPORT_SECRET_ACCESS_KEY. Si vous en oubliez un, MinIO rejette le client avec SignatureDoesNotMatch. Le message apparaît dans le journal du worker, alors que l’interface web peut sembler fonctionner normalement. Conserver ces valeurs dans un fichier env plutôt que dans le fichier Compose versionné est la méthode présentée dans Fichiers env et secrets Docker Compose.
Épinglez les tags des images avant de commencer
Le fichier fourni utilise docker.langfuse.com/langfuse/langfuse:4 et docker.langfuse.com/langfuse/langfuse-worker:4. Ces tags évoluent. Langfuse exécute automatiquement les migrations Postgres et ClickHouse au démarrage. Ainsi, un simple docker compose pull plusieurs mois plus tard devient une migration de schéma imprévue sur une base de données qui n’a pas été sauvegardée ce matin-là. Épinglez les deux images sur une même release dans un docker-compose.override.yml. Compose le fusionne par-dessus le fichier fourni. Un git pull ultérieur n’écrasera donc pas vos modifications. Les mêmes images sont publiées sur Docker Hub, d’où l’override ci-dessous les récupère.
services:
langfuse-web:
image: docker.io/langfuse/langfuse:4.72.0
langfuse-worker:
image: docker.io/langfuse/langfuse-worker:4.72.0La version 4.3.1 était la release 4.3 actuelle en août 2026. Depuis, les releases se sont succédé rapidement. v4.56.0 était la dernière version publiée sur GitHub au 11 octobre 2026. L’override ci-dessus utilise v4.72.0, la dernière version publiée sur GitHub au 31 octobre 2026. Consultez la page des releases du projet sur GitHub. Épinglez la version actuelle le jour du déploiement, puis faites évoluer ce numéro volontairement. Certaines images de stockage du fichier fourni méritent le même traitement, car leurs tags évoluent également. postgres:17 (la valeur par défaut d’une variable POSTGRES_VERSION) et redis:7 suivent une version majeure. Le fichier fourni utilise désormais un tag de version exact pour docker.io/clickhouse/clickhouse-server, ce qui épingle une version précise de ClickHouse. Cette règle ne concerne pas uniquement Langfuse : un gestionnaire de séances de sport openGym auto-hébergé utilise une partie de cette stack et nécessite malgré tout un tag git nommé, car tout logiciel qui migre sa propre base de données au démarrage peut transformer un simple pull en modification de schéma.
Démarrez la stack.
docker compose up -d
docker compose ps
docker compose logs -f langfuse-workerLe premier démarrage exécute les migrations. Attendez donc deux ou trois minutes avant de tester les services. Le conteneur web journalise Ready lorsqu’il est prêt. docker compose ps doit afficher six services dans l’état running. Si un conteneur redémarre en boucle, son journal contient la cause. Les migrations ClickHouse sont appliquées au démarrage du conteneur web. Une valeur CLICKHOUSE_MIGRATION_URL incorrecte apparaît donc dans docker compose logs langfuse-web, et non dans le journal du worker que vous suivez. Cette variable utilise le protocole natif ClickHouse sur le port 9000, et non le port HTTP 8123. La définir sur 8123 empêche les migrations de démarrage du conteneur web. Le worker exécute les migrations d’arrière-plan plus lentes. C’est donc dans son journal que ces migrations sont signalées.
Vérifiez l’état depuis le serveur lui-même.
curl -s "http://localhost:3000/api/public/health?failIfDatabaseUnavailable=true"
curl -s -o /dev/null -w '%{http_code}\n' http://localhost:3000/api/public/readyUn appel /api/public/health simple prouve seulement que le processus API fonctionne. Par défaut, il ne vérifie pas la base de données. La forme failIfDatabaseUnavailable=true est celle qu’il faut utiliser pour la supervision. Elle renvoie 503 lorsque la base de données est inaccessible. /api/public/ready renvoie 200 lorsque le conteneur web est prêt à recevoir du trafic, puis 500 lorsqu’il a reçu l’ordre de s’arrêter. Ce sont de simples vérifications HTTP. Vous pouvez donc utiliser une page de statut Uptime Kuma pour les surveiller et savoir que la stack est indisponible avant vos agents.
Placez TLS devant le service et fermez les ports supplémentaires
Le fichier compose fourni publie 3000:3000 pour le conteneur web et 9090:9000 pour MinIO. Les deux services écoutent sur toutes les interfaces. Avec une IP publique, toute personne qui scanne le port 3000 atteint votre page d’inscription, et toute personne qui scanne le port 9090 accède au bucket qui contient vos prompts bruts.
Une règle de pare-feu ne suffit pas à les fermer. Docker écrit ses propres règles DNAT dans la table nat. Ces règles sont évaluées avant que les règles de filtrage d’ufw ne voient le paquet. Ainsi, ufw deny 3000 laisse le port publié ouvert. Le problème est suffisamment fréquent pour faire l’objet d’un guide dédié : pourquoi les ports publiés par Docker contournent ufw. Liez plutôt les ports à loopback dans votre fichier override. Utilisez !override avec Docker Compose 2.24.4 ou une version ultérieure pour remplacer les ports publiés. Une simple liste fusionne avec les bindings d’origine.
services:
langfuse-web:
ports: !override
- "127.0.0.1:3000:3000"
environment:
NEXTAUTH_URL: https://langfuse.example.com
minio:
ports: !override
- "127.0.0.1:9090:9000"
- "127.0.0.1:9091:9001"NEXTAUTH_URL doit être l’adresse publique exacte, schéma inclus, car le flux de connexion construit son URL de callback à partir de cette valeur. Laissez-la à http://localhost:3000 derrière un proxy HTTPS et l’aller-retour de connexion redirigera le navigateur vers une adresse qu’il ne peut pas atteindre.
Configurez maintenant un reverse proxy vers 127.0.0.1:3000 et laissez-le gérer le certificat. Pour Traefik dans le même projet Compose, acheminez les requêtes vers langfuse-web:3000 via le réseau Compose, en utilisant les labels présentés dans exécuter plusieurs applications derrière un reverse proxy Traefik. Caddy effectue la même opération en deux lignes si Langfuse est le seul service sur la machine. Vérifiez avec curl -sI https://langfuse.example.com/api/public/ready, puis confirmez depuis une seconde machine que curl http://YOUR_IP:3000 ne peut pas se connecter.
Une précision concernant MinIO. Langfuse fournit des URL presigned qui pointent vers cet endpoint S3, à la fois aux SDK qui téléversent les médias et à votre navigateur lorsqu’il les charge. Si vous utilisez des traces multimodales contenant des images ou de l’audio, un MinIO limité à loopback empêchera le téléversement de ces pièces jointes depuis d’autres machines et leur chargement dans votre navigateur. Consultez la page de configuration du blob storage avant de le placer derrière un proxy, car l’endpoint inscrit dans l’URL presigned, LANGFUSE_S3_MEDIA_UPLOAD_ENDPOINT, doit correspondre à l’adresse que vous publiez. Les traces en texte brut ne sont pas concernées.
Créez votre compte lors de la première visite, puis gardez le contrôle de l’instance. Définissez AUTH_DISABLE_SIGNUP=true une fois votre compte créé, afin qu’un inconnu qui atteint la page ne puisse plus s’inscrire. Langfuse propose également LANGFUSE_ALLOWED_ORGANIZATION_CREATORS, qui limite les personnes autorisées à créer des organisations, mais cette option est réservée à l’Enterprise Edition et ne prend effet qu’avec une clé de licence. Si vous utilisez déjà Authentik comme votre propre fournisseur d’identité, Langfuse accepte une connexion OIDC standard. Les comptes suivent ainsi les autres applications, au lieu de rester dans une liste de mots de passe connue uniquement de cette machine.
Envoyez votre première trace
Créez un projet dans l’interface web, puis copiez ses clés publique et secrète depuis les paramètres du projet. Le SDK Python lit trois variables d’environnement.
export LANGFUSE_PUBLIC_KEY="pk-lf-..."
export LANGFUSE_SECRET_KEY="sk-lf-..."
export LANGFUSE_BASE_URL="https://langfuse.example.com"LANGFUSE_BASE_URL est le nom de variable utilisé par le SDK v4, sorti en mars 2026. Les anciens codes et les anciennes documentations utilisent LANGFUSE_HOST. Si vos traces arrivent sur Langfuse Cloud au lieu de votre serveur, c’est parce que l’URL de base n’est pas définie : la valeur par défaut pointe vers l’instance hébergée.
Le SDK Python v5 actuel nécessite Python 3.11 ou une version ultérieure, ainsi que Langfuse v4.59.0 ou une version ultérieure en auto-hébergement. Le serveur installé plus haut respecte cette contrainte.
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()Le décorateur @observe ouvre une observation autour de la fonction, capture ses arguments et sa valeur de retour, puis l’imbrique sous l’observation déjà active, le cas échéant. AnthropicInstrumentor assure l’instrumentation OpenTelemetry du client Anthropic. Il transforme chaque appel messages.create en génération contenant le nom du modèle, l’utilisation des tokens et la latence, sans modification du code d’appel.
Deux appels effectuent les vérifications nécessaires. langfuse.auth_check() renvoie False si les clés sont incorrectes ou si l’URL de base est erronée. Vous identifiez ainsi plus rapidement le problème au lieu de chercher pourquoi le dashboard est vide. langfuse.flush() bloque jusqu’à l’envoi des spans en attente. Les processus de courte durée en ont besoin, car le SDK regroupe les données en arrière-plan et un script qui se termine immédiatement emporte avec lui son lot non envoyé. Si toute une équipe envoie des traces plutôt qu’un seul script, définissez ces trois variables une seule fois dans la gateway par laquelle les agents passent déjà, au lieu de les définir dans le shell de chaque utilisateur. C’est ainsi qu’un harness OneCLI auto-hébergé instrumente les exécutions de tous les collègues tout en conservant les clés au même endroit.
Pourquoi la taille de ClickHouse continue-t-elle d’augmenter ?
Les traces sont généralement les données qui grossissent le plus vite dans un environnement auto-hébergé. Chaque exécution d’agent écrit une ligne par étape. Les entrées et les sorties sont conservées intégralement. Un agent verbeux avec de longs prompts produit donc beaucoup plus d’octets par jour que l’application qu’il surveille. Si vous ne faites rien, ClickHouse remplit le disque. Un disque plein bloque l’ingestion au lieu de seulement la ralentir.
Deux éléments distincts grossissent ici. Ils nécessitent donc deux corrections différentes.
Le premier est constitué de vos propres données de trace. La correction consiste à configurer la rétention. Sur une instance auto-hébergée, la rétention des données est une fonctionnalité d’Enterprise Edition qui nécessite une clé de licence. Sans licence, Langfuse conserve indéfiniment les traces, les observations, les scores et les médias. Dimensionnez donc le disque en conséquence et utilisez l’alerte de disque présentée à la fin de cette section. Avec une licence, les propriétaires de projet et les administrateurs ouvrent les paramètres du projet et définissent une durée de rétention en jours. Langfuse accepte une durée minimale de 3 jours. Une tâche nocturne sélectionne ensuite les traces, les observations, les scores et les ressources multimédias plus anciennes que cette durée, puis les supprime de ClickHouse et du blob storage, à l’exception des médias associés aux éléments de dataset enregistrés. La tâche nécessite l’autorisation DeleteObject sur le bucket. Les identifiants root de MinIO présents dans le fichier compose par défaut disposent déjà de cette autorisation. La suppression est définitive. Configurez donc d’abord un export vers le blob storage si vous avez besoin de conserver un historique à long terme. N’écrivez pas manuellement de clauses TTL sur les propres tables de Langfuse : c’est la tâche de rétention qui maintient ClickHouse et le bucket synchronisés, tandis qu’un TTL manuel ne supprimerait les données que d’un seul côté.
Choisissez cette durée en fonction de votre usage réel. Les analyses de coûts et de qualité portent sur des données vieilles de quelques jours, pas de plusieurs mois. Trente jours constituent un bon point de départ pour une petite équipe. 14 jours suffisent si vous n’ouvrez une trace que lorsqu’un problème survient.
Le second élément est constitué des propres tables de journaux système de ClickHouse. Ce point surprend souvent, car le disque continue de se remplir après la configuration de la rétention. ClickHouse écrit trace_log, text_log, opentelemetry_span_log, metric_log, asynchronous_metric_log et latency_log pour ses propres diagnostics. Ces tables sont livrées sans TTL, et Langfuse ne les lit jamais. Commencez par déterminer où l’espace disque est réellement utilisé.
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
)Exécutez cette commande avec docker compose exec clickhouse clickhouse-client --password "$CLICKHOUSE_PASSWORD". Si les tables système figurent parmi les premières utilisatrices d’espace, désactivez-les au moyen d’un config overlay, car ClickHouse fusionne au démarrage chaque fichier de /etc/clickhouse-server/config.d/ avec sa configuration principale.
<clickhouse>
<trace_log remove="1"/>
<text_log remove="1"/>
<opentelemetry_span_log remove="1"/>
<asynchronous_metric_log remove="1"/>
<metric_log remove="1"/>
<latency_log remove="1"/>
</clickhouse>Montez-le, puis redémarrez ClickHouse.
services:
clickhouse:
volumes:
- ./clickhouse-config.d/system-logs.xml:/etc/clickhouse-server/config.d/system-logs.xml:roCela arrête les nouvelles écritures. Les lignes déjà présentes sur le disque y restent. Récupérez donc explicitement l’espace avec DROP TABLE IF EXISTS system.trace_log, et faites de même pour chaque table supprimée. Si vous préférez conserver les diagnostics, vous pouvez appliquer à la place un TTL agressif à chaque table, plutôt que remove="1". La documentation de scaling de Langfuse décrit cette méthode. Ces directives TTL ne s’appliquent que lors de la création initiale d’une table système. Sur une installation existante, cette même documentation explique donc aussi comment les appliquer aux tables déjà présentes.
Une autre table mérite votre attention. blob_storage_file_log suit les fichiers d’événements envoyés vers votre bucket. Si vous configurez également une lifecycle policy sur le bucket, définissez un TTL correspondant pour la table afin d’éviter que les deux ne divergent.
ALTER TABLE blob_storage_file_log MODIFY TTL created_at + INTERVAL 30 DAY DELETE;Ajoutez également une alerte simple df -h sur le disque qui contient les données. Les traces n’augmentent pas de manière régulière. Leur volume augmente le jour où vous déployez un nouvel agent. Le premier signe de ce changement ne devrait pas être un échec de l’ingestion.
Sauvegarder Postgres et ClickHouse
Une sauvegarde de Langfuse comporte trois parties. Postgres contient vos utilisateurs, organisations, projets et clés API. ClickHouse contient les traces. MinIO contient les événements bruts. Si vous restaurez uniquement Postgres, vous obtenez une connexion fonctionnelle, mais aucun historique. Si vous restaurez uniquement ClickHouse, vous obtenez un historique auquel personne ne peut accéder. Cette séparation n’est pas propre à Langfuse : un helpdesk Chatwoot auto-hébergé suit la même logique. Un dump Postgres effectué sans le répertoire des uploads restaure les conversations, mais toutes leurs pièces jointes ont disparu.
Postgres utilise un pg_dump standard, comme l’indique la documentation de sauvegarde de Langfuse pour une installation Docker.
docker compose exec -T postgres pg_dump -U postgres postgres \
| gzip > langfuse-pg-$(date +%F).sql.gzClickHouse demande davantage de précautions, car la copie d’un répertoire de données actif pendant l’exécution de merges ne constitue pas une sauvegarde cohérente. Sur une machine unique, l’approche la plus simple consiste à arrêter le conteneur et à archiver le volume.
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 clickhouseUtilisez le nom du volume affiché par docker volume ls, et non celui écrit dans le fichier YAML. Le fichier déclare langfuse_clickhouse_data, puis Compose ajoute le nom du projet comme préfixe. Ainsi, un clone dans un répertoire appelé langfuse produit langfuse_langfuse_clickhouse_data. Si vous vous trompez, docker run crée un nouveau volume vide sans afficher d’erreur, et votre archive ne contient rien.
Langfuse envoie les données d’événements brutes vers le bucket lors de chaque requête d’ingestion, puis les relit pour réessayer les tâches d’ingestion échouées. Un court arrêt de ClickHouse signifie donc principalement que le worker réessaiera ensuite. Effectuez cette opération pendant une période calme et limitez sa durée. Pour une instance plus chargée, la commande BACKUP DATABASE default TO S3(...) de ClickHouse écrit une sauvegarde cohérente sans arrêter le serveur. MinIO constitue le troisième élément. mc mirror ou la réplication MinIO vers un bucket externe permet de le sauvegarder. Quel que soit le format produit, transférez-le hors du serveur. C’est le rôle des sauvegardes restic chiffrées sur un VPS.
Redis contient la file d’attente et le cache. Sa perte supprime les tâches en attente, même si leurs fichiers d’événements bruts sont toujours présents dans le bucket.
La limite liée à la cohérence est réelle et doit être formulée clairement. Postgres et ClickHouse sont sauvegardés à des moments différents. Une restauration peut donc laisser une ligne de projet sans traces, ou des traces associées à un projet qui n’existe plus. Langfuse tolère cette situation, mais effectuez les deux dumps à peu d’intervalle, pendant une période de faible trafic. Le bucket d’événements constitue la véritable protection, car Langfuse y envoie les données d’événements brutes lors de chaque requête d’ingestion.
Restaurez au moins une fois dans une stack de test. Vous découvrirez ainsi un nom de volume incorrect maintenant, plutôt que pendant une panne.
Ce qu’il faut examiner en premier
Quatre éléments méritent votre attention dès la première semaine.
- Coût par trace. Langfuse calcule le coût à partir du nom du modèle et de l’utilisation des tokens. Triez donc les traces par coût, puis lisez entièrement la plus chère. Il s’agit généralement d’un prompt qui a grandi : un document entier collé dans le contexte ou un historique de conversation que personne ne tronque. Une fois ce phénomène visible, maîtriser le coût d’un agent IA devient une tâche d’ingénierie plutôt qu’une estimation.
- Répartition des tokens entre l’entrée et la sortie. Les tokens d’entrée sont nombreux et peu coûteux. Les tokens de sortie sont moins nombreux et plus coûteux. Les tokens d’entrée mis en cache coûtent encore moins cher. Le même calcul est détaillé dans le décompte des tokens utilisés par Claude Code, et il s’applique à tout agent que vous écrivez vous-même.
- Percentiles de latence. La médiane masque le problème. Les p95 et p99 concentrent les timeouts. Dans une boucle d’agent, un appel d’outil lent au p95 voit son impact multiplié par le nombre d’itérations.
- Appels d’outils en échec. Filtrez les observations par niveau
ERROR. Un outil qui échoue 5% du temps ne se voit pas dans un taux de réussite global. En revanche, il est très visible dans les traces, où vous pouvez observer le modèle réessayer, puis consommer des tokens pour contourner le problème.
Définissez la durée de rétention et choisissez le dashboard que vous consulterez chaque semaine, le même jour que votre déploiement. Un outil d’observabilité que personne n’ouvre est une base de données qui finit par remplir un disque.
FAQ
De quelle quantité de mémoire Langfuse auto-hébergé a-t-il besoin ?
Prévoyez 4 cœurs CPU et 16 GiB de mémoire. C’est ce que recommande le guide Docker Compose de Langfuse pour une seule machine virtuelle. Prévoyez également environ 100 GiB de stockage. Les minimums publiés pour les composants sont de 8 GiB pour ClickHouse et de 4 GiB chacun pour les conteneurs web et worker. La même page indique 4 GiB pour Postgres, 1.5 GiB pour Redis et 4 GiB pour MinIO. Les six composants totalisent donc 25.5 GiB, soit davantage que les 16 GiB recommandés pour Compose.
Pourquoi le disque de ClickHouse continue-t-il à se remplir après la configuration de la rétention des données ?
Le paramètre de rétention ne couvre que les propres données de Langfuse. ClickHouse écrit séparément ses tables de diagnostic trace_log, text_log, opentelemetry_span_log, metric_log, asynchronous_metric_log et latency_log. Ces tables sont créées sans TTL. Exécutez system.parts avec un regroupement par table pour identifier la plus volumineuse. Désactivez ensuite les tables inutilisées avec une entrée remove="1" dans un fichier situé sous /etc/clickhouse-server/config.d/, redémarrez ClickHouse, puis supprimez les tables existantes pour récupérer l’espace déjà utilisé.
Quelle est la période minimale de rétention des données dans Langfuse ?
Trois jours. La rétention se configure par projet dans les paramètres du projet ou via l’Organization Management API. Une tâche nocturne supprime de ClickHouse et du blob storage les traces, observations, scores et ressources multimédias plus anciennes que cette période. Les ressources multimédias associées à des éléments de dataset enregistrés font exception. Sur une instance auto-hébergée, cette fonctionnalité appartient à l’Enterprise Edition et nécessite une clé de licence. Sans clé de licence, les données sont conservées indéfiniment. La suppression est irréversible. Configurez donc d’abord un export vers un blob storage si vous devez conserver un historique au-delà de cette période.
Dois-je sauvegarder à la fois Postgres et ClickHouse ?
Oui, car ils contiennent des données différentes. Postgres contient les utilisateurs, les organisations, les projets et les clés API. ClickHouse contient les données des traces elles-mêmes. Une restauration de Postgres uniquement vous donne une instance à laquelle vous pouvez vous connecter, mais qui ne contient aucune donnée. Sauvegardez également le bucket MinIO. Il contient les événements bruts que Langfuse conserve à leur réception et constitue ce qui se rapproche le plus d’une source de vérité dans cette stack.
Puis-je connecter une configuration OpenTelemetry existante à Langfuse auto-hébergé ?
Oui. Langfuse v4 et ses SDK actuels reposent sur OpenTelemetry. Les instrumentations OTel pour Anthropic et OpenAI exportent directement vers celui-ci. En Python, exécutez pip install langfuse opentelemetry-instrumentation-anthropic, appelez AnthropicInstrumentor().instrument() une fois au démarrage, puis définissez LANGFUSE_PUBLIC_KEY, LANGFUSE_SECRET_KEY et LANGFUSE_BASE_URL avec votre propre hôte. Vérifiez le résultat avec langfuse.auth_check() avant de rechercher un dashboard manquant.