built-in-metrics

Par launchdarkly · agent-skills

Instrumentez une base de code existante avec le suivi de configuration LaunchDarkly. Parcourt l'échelle à quatre niveaux (runner géré → package provider → extracteur personnalisé + `trackMetricsOf` → manuel brut) et choisit l'option la moins contraignante qui capture tout de même la durée, les tokens et le succès/l'erreur.

npx skills add https://github.com/launchdarkly/agent-skills --skill built-in-metrics

Instrumentation des métriques d'agent

Tu utilises une skill qui encapsule les métriques d'agent LaunchDarkly autour d'un appel à un fournisseur existant. Ton travail consiste à auditer ce qui est déjà en place, choisir le bon niveau dans l'échelle ci-dessous, et l'implémenter avec le minimum de cérémonie nécessaire pour capturer les métriques dont l'onglet Monitoring a besoin (durée, jetons d'entrée/sortie, succès/erreur, plus TTFT en streaming).

La chose la plus importante à bien faire : préfère le niveau le plus élevé qui correspond à la forme de l'appel. Descendre plus bas (« juste écrire les appels de tracker manuels ») semble flexible mais te coûte de la dérive, des métriques manquées, et des patterns obsolètes que les SDK ont abandonnés.

L'échelle à quatre niveaux

Voici l'ordre que les README officiels du SDK (Python core, Node core, et tous les packages de fournisseur) recommandent. Descends depuis le haut et arrête-toi au premier niveau qui convient :

Niveau Pattern À utiliser quand Assure automatiquement le suivi de
1 — Runner géré Python : ai_client.create_model(...) retournant un ManagedModel, puis await model.run(...). <br>Node : aiClient.createModel(...) retournant un ManagedModel, puis await model.run(...). L'appel est conversationnel (historique de chat, tour par tour). C'est ce que les README du fournisseur mettent en avant. Durée, jetons, succès/erreur — tout, zéro appel de tracker.
2 — Package fournisseur + trackMetricsOf tracker.trackMetricsOf(Provider.getAIMetricsFromResponse, () => providerCall()). Packages fournisseur actuels : @launchdarkly/server-sdk-ai-openai, -langchain, -vercel (Node) et launchdarkly-server-sdk-ai-openai, -langchain (Python). La forme n'est pas une boucle de chat (complément unique, sortie structurée, étape d'agent) mais le framework ou le fournisseur a un package. Durée + succès/erreur depuis le wrapper ; jetons depuis l'extracteur getAIMetricsFromResponse intégré du package.
3 — Extracteur personnalisé + trackMetricsOf Même wrapper trackMetricsOf, mais tu écris une petite fonction qui mappe la réponse du fournisseur vers LDAIMetrics (jetons + succès). Aucun package fournisseur n'existe (Anthropic direct, Gemini, Cohere, HTTP personnalisé). Durée + succès/erreur depuis le wrapper ; jetons depuis ton extracteur.
4 — Manuel brut Appels séparés à trackDuration, trackTokens, trackSuccess / trackError, plus trackTimeToFirstToken pour les streams. Streaming avec TTFT, formes de réponse inhabituelles, suivi partiel, tout ce que les niveaux 2–3 ne peuvent pas envelopper proprement. Seulement ce que tu appelles explicitement — c'est à toi de ne rien oublier.

Chaque fournisseur — OpenAI, LangChain, Vercel, Bedrock, Anthropic, Gemini, HTTP personnalisé — utilise la même forme générique : tracker.trackMetricsOf(getAIMetricsFromResponse, () => providerCall()) en Node, tracker.track_metrics_of(get_ai_metrics_from_response, provider_call) en Python. L'extracteur est la seule chose qui change par fournisseur : importe getAIMetricsFromResponse depuis le package correspondant @launchdarkly/server-sdk-ai-<provider> (ou ldai_<provider>), ou écris une petite fonction personnalisée qui retourne LDAIMetrics. Il n'y a pas de méthodes de tracker spécifiques au fournisseur.

Flux de travail

1. Explorer le site d'appel existant

Avant de choisir un niveau, trouve l'appel au fournisseur et réponds à ces questions :

  • [ ] Forme ? Est-ce une boucle de chat (historique + tour par tour), un complément unique, une étape d'agent, ou autre chose ? → détermine le niveau 1 vs 2.
  • [ ] Framework ? SDK fournisseur brut ? LangChain / LangGraph ? Vercel AI SDK ? CrewAI ? Strands ? → détermine quel package de fournisseur au niveau 2 (le cas échéant) s'applique.
  • [ ] Fournisseur ? OpenAI, Anthropic, Bedrock, Gemini, Azure, HTTP personnalisé ? → référence croisée avec la matrice de disponibilité du package ci-dessous.
  • [ ] Streaming ? Si oui, tu auras besoin du suivi TTFT, ce qui signifie le niveau 4 pour la partie TTFT même si le reste est au niveau 2.
  • [ ] Langue ? Python ou Node ? La couverture du package fournisseur diffère entre les deux.
  • [ ] Déjà utilise une config ? Si non, route vers configs-create d'abord — le suivi nécessite un tracker, qui est obtenu en appelant create_tracker() / createTracker() sur l'objet config retourné par completion_config() / completionConfig() / createModel().
  • [ ] Sur l'API actuelle du SDK ? Si le site d'appel utilise aiclient.config(...) / aiClient.config(...) ou construit un défaut AIConfig(...) / LDAIConfig, il est sur la surface pré-0.20. Migre-le dans le cadre de ce travail avant d'ajouter le suivi :
    • aiclient.config(...)aiclient.completion_config(...) pour one-shot/chat ou aiclient.agent_config(...) pour le mode agent (reflète la signature d'appel). Node est identique avec camelCase.
    • AIConfig(...) défaut → AICompletionConfigDefault(...) ou AIAgentConfigDefault(...) (Node : LDAICompletionConfigDefault / LDAIAgentConfigDefault). AIConfig est la classe de base que le SDK retourne ; ce n'est pas un constructeur de valeur par défaut valide — les variantes typées *Default le sont.
    • Si le résultat était en cours de déballage de tuple (config, tracker = aiclient.config(...)), supprime le déballage — les nouvelles méthodes retournent un seul objet config. Obtiens le tracker via config.create_tracker() / aiConfig.createTracker().
    • Pour les réécritures plus profondes (sites d'appel avec modèle/prompt codé en dur également), délègue à migrate au lieu de faire la migration complète ici.

2. Consulter ton option au niveau 2

Utilise cette matrice pour décider si le niveau 2 (package fournisseur) est disponible pour ta situation. Si ce n'est pas le cas, descends au niveau 3 (extracteur personnalisé). Si la forme est une boucle de chat, va au niveau 1 en premier lieu indépendamment de ce qui est dans cette matrice.

Framework / fournisseur Package fournisseur Python Package fournisseur Node Référence
OpenAI (SDK direct) launchdarkly-server-sdk-ai-openai @launchdarkly/server-sdk-ai-openai openai-tracking.md
LangChain / LangGraph launchdarkly-server-sdk-ai-langchain @launchdarkly/server-sdk-ai-langchain langchain-tracking.md
Vercel AI SDK @launchdarkly/server-sdk-ai-vercel (utilise les docs du fournisseur Vercel)
AWS Bedrock (Converse ou InvokeModel) — (utilise LangChain-aws ou extracteur personnalisé) — (utilise LangChain-aws ou extracteur personnalisé) bedrock-tracking.md
Anthropic SDK direct anthropic-tracking.md
Gemini / Google GenAI gemini-tracking.md
Strands Agents — (Niveau 3 extracteur personnalisé) — (Niveau 3 extracteur personnalisé) strands-tracking.md
Cohere, Mistral, HTTP personnalisé Niveau 3 extracteur personnalisé
N'importe quel fournisseur, streaming + TTFT — (Niveau 4 uniquement) trackStreamMetricsOf (pas de TTFT) + TTFT manuel streaming-tracking.md

3. Implémenter à partir de la référence correspondante

Une fois que tu connais le niveau et le fournisseur, ouvre le fichier de référence et suis le pattern. Les références sont écrites pour que le niveau 1 soit toujours le premier exemple, les niveaux 2/3 ensuite, et le niveau 4 en dernier. Arrête-toi au premier niveau qui correspond à la forme de l'app.

Les garde-fous qui s'appliquent à tous les niveaux :

  1. Vérifie toujours config.enabled avant de faire l'appel suivi. Une config désactivée signifie que l'utilisateur a désactivé la fonctionnalité — tu dois revenir à court-circuit à ce que l'app utilise comme fallback (réponse en cache, erreur, chemin dégradé) plutôt que de faire l'appel au fournisseur du tout.
  2. Enveloppe l'appel existant, ne le réécris pas. Les niveaux 2 et 3 sont conçus pour s'insérer autour d'un appel fournisseur non modifié. Si tu te retrouves à réécrire l'appel pour l'adapter au tracker, tu es au mauvais niveau — descends d'un.
  3. Les erreurs sont gérées à l'intérieur de trackMetricsOf. Le wrapper capture les exceptions, enregistre trackError() en interne, et relance — n'ajoute pas except: tracker.trackError() par-dessus, c'est un noop qui déclenche aussi la garde at-most-once. Le niveau 1 gère les deux chemins automatiquement. Au niveau 4 (manuel, streaming, track_duration_of) l'appelant gère sa propre cible l'appel error-tracking.
  4. Vide toujours avant fermeture. Appelle ldClient.flush() (Python : ldclient.get().flush() ; Node : await ldClient.flush()) avant de fermer le client. Les événements de fin risquent d'être perdus sinon — dans les scripts de courte durée et les services de longue durée. En Node, ldClient.close() retourne une Promise ; attend-la.

4. Vérifier

Confirme que l'onglet Monitoring s'affiche :

  • [ ] Exécute une vraie requête à travers le chemin instrumenté.
  • [ ] Ouvre la config dans LaunchDarkly → onglet Monitoring. La durée, les comptages de jetons, et les comptages de génération doivent apparaître dans 1–2 minutes.
  • [ ] Force une erreur (clé API mauvaise, max_tokens zéro, ce que tu veux) et confirme que le comptage d'erreur s'incrémente.
  • [ ] Si streaming : vérifie que TTFT apparaît. Si ce n'est pas le cas, tu as probablement enveloppé la création de stream avec trackMetricsOf mais tu n'as pas ajouté l'appel trackTimeToFirstToken manuel — vois streaming-tracking.md.

Référence rapide : méthodes de tracker

Obtiens un tracker via la factory sur l'objet config : tracker = config.create_tracker() (Python) ou const tracker = aiConfig.createTracker() (Node). Appelle la factory une fois par exécution et réutilise le tracker retourné pour chaque appel — chaque invocation de factory crée un nouveau runId qui marque chaque événement de suivi émis par ce tracker pour que les événements d'une seule exécution puissent être corrélés ensemble (via événements exportés / systèmes en aval). L'onglet Monitoring agrège les événements plutôt que de les grouper par run actuellement — le runId est utile quand les événements sont exportés ou interrogés en dehors de l'UI, et est l'identifiant sur lequel les gardes at-most-once du SDK sont clés. Les méthodes ci-dessous sont la surface API brute — la plupart du temps tu ne dois pas les appeler individuellement ; utilise trackMetricsOf ou un runner géré au niveau 1. La liste est ici pour que tu puisses reconnaître les méthodes dans le code existant et attraper la bonne quand tu as vraiment besoin du niveau 4.

Méthode (Python ↔ Node) Niveau Ce qu'elle fait
track_metrics_of(extractor, fn) / trackMetricsOf(extractor, fn) 2 / 3 Enveloppe un appel fournisseur, capture durée + succès/erreur, appelle ton extracteur pour les jetons. C'est le tracker générique par défaut.
track_metrics_of_async(extractor, fn) (Python) 2 / 3 Variante async de ce qui précède.
trackStreamMetricsOf(extractor, streamFn) (Node uniquement) 2 / 3 Variante streaming. Capture l'utilisation par chunk quand l'extracteur traite les chunks. N'auto-capture pas TTFT.
track_duration(ms) / trackDuration(ms) 4 Enregistre la latence en millisecondes.
track_duration_of(fn) / trackDurationOf(fn) 4 Enveloppe un callable et enregistre la durée automatiquement. N'enregistre pas les jetons ou le succès — apparie avec des appels explicites.
track_tokens(TokenUsage) / trackTokens({input, output, total}) 4 Enregistre l'utilisation de jetons.
track_time_to_first_token(ms) / trackTimeToFirstToken(ms) 4 Enregistre TTFT pour les réponses streaming.
track_success() / trackSuccess() 4 Marque la génération comme réussie. Requis pour que l'onglet Monitoring la compte.
track_error() / trackError() 4 Marque la génération comme échouée. N'appelle pas aussi trackSuccess() dans la même requête.
track_feedback({kind}) / trackFeedback({kind}) quelconque Enregistre un pouce levé / pouce baissé depuis une UI de feedback. Indépendant du chemin succès/erreur.
track_tool_call(name) / trackToolCall(name) quelconque Enregistre une invocation d'outil unique par nom. Disponible sur les deux SDK.
track_tool_calls([names]) / trackToolCalls([names]) quelconque Variante batch — enregistre une liste d'invocations d'outil en un appel.
track_judge_result(result) / trackJudgeResult(result) quelconque Enregistre une évaluation de judge programmatique. result.sampled indique si l'évaluation a fonctionné.

Skills associées

  • configs-create — prérequis si l'app n'a pas encore de config
  • custom-metrics — métriques métier (conversion, résolution, rétention) superposées sur les métriques d'agent que cette skill capture
  • online-evals — notation de qualité automatique (LLM-as-judge) sur les requêtes en direct échantillonnées ; complémentaire aux métriques ici
  • migrate — L'étape 4 de la migration hardcoded-to-AgentControl délègue à cette skill

Skills similaires