Langfuse : la fiche technique
à quoi ça sert (le pitch en 30 secondes)
Langfuse est l'APM des applications LLM (open-source, auto-hébergeable). Pour chaque interaction il capture la hiérarchie complÚte :
Trace « extract.{request_id} » â une requĂȘte de bout en bout
ââ Span « node.matcher_fast » 240 ms â une Ă©tape (node LangGraph)
ââ Generation « structurer.extract » â UN appel LLM :
â prompt EXACT envoyĂ©, rĂ©ponse, modĂšle, tokens in/out, coĂ»t, latence
ââ Event « COPILOT_TURN_TRUNCATED » â un fait notable
Ce que ça débloque concrÚtement : relire le prompt exact qui a produit une mauvaise réponse (le « stack trace » du LLM), suivre coûts et tokens par feature/tenant/modÚle, voir la latence par node du pipeline, et rejouer une conversation entiÚre via les sessions. Sans ça, débugger un agent = archéologie dans les logs.
Les concepts, mappés sur le projet
- Session = un thread de conversation copilot (
session_id = thread_id, avecuser_id) : toute la conversation regroupée dans l'UI ; - Generation = une itération de la boucle ReAct, avec
usage_details(tokens + lecture cache â on vĂ©rifie que le prompt caching du module 4 fonctionne vraiment !) ; - Span = un node LangGraph ou l'exĂ©cution d'un tool ;
- l'API v3+ :
client.start_observation(as_type="agent"|"span"|"generation"|"tool"|"event")â le projet passe par une classeLangfuseObservermaison plutĂŽt que les dĂ©corateurs@observe, pour garder le contrĂŽle.
Les trois patterns d'intégration à retenir
- Best-effort, toujours : Langfuse down â un observer Noop prend la place ; les
flushpartent viaasyncio.to_thread. L'observabilitĂ© ne casse jamais la prod ni ne bloque l'event loop ; - Redactor + Sampler : les inputs sont scrubĂ©s (PII, prix) avant envoi â les traces vivent hors de la base RLS, elles n'ont pas le droit d'ĂȘtre plus bavardes qu'elle ; et on n'Ă©chantillonne pas forcĂ©ment 100 % du trafic ;
- Le piĂšge async (ADR-0013) : la propagation de contexte OTel (
start_as_current_span) se perd aux points de suspension de LangGraph (chaqueawaitpeut changer de contexte). Solution du projet : porter la trace courante dans desContextVarexplicites (_CURRENT_PIPELINE_TRACE,_CURRENT_NODE_SPAN) â la propagation manuelle, fiable par construction.
Les évolutions récentes (l'outil vit)
Deux progrÚs depuis le premier état des lieux :
- les datasets d'Ă©val sont maintenant utilisĂ©s : le harness d'Ă©val (module 3, Ă©tude de cas) pousse chaque run comme dataset run comparable dans l'UI â les scores d'un fix se lisent cĂŽte Ă cĂŽte avec la baseline ;
- les coĂ»ts sont devenus rĂ©els : le suivi de coĂ»ts couvre dĂ©sormais le cache de prompt (lu â facturĂ© plein tarif), l'OCR et le rerank â pas seulement les tokens du LLM principal. Une trace qui ignore 30 % de la facture ment ; le multi-provider (LLM + OCR + rerank) exige une comptabilitĂ© par fournisseur.
Restent inutilisĂ©s : le prompt management (versionner/itĂ©rer les prompts sans redĂ©ploiement â la porte d'entrĂ©e naturelle quand les consignes par tenant arriveront) et les scores automatiques.
La différence entre un Span et une Generation :