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-created'abord — le suivi nécessite un tracker, qui est obtenu en appelantcreate_tracker()/createTracker()sur l'objet config retourné parcompletion_config()/completionConfig()/createModel(). - [ ] Sur l'API actuelle du SDK ? Si le site d'appel utilise
aiclient.config(...)/aiClient.config(...)ou construit un défautAIConfig(...)/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 ouaiclient.agent_config(...)pour le mode agent (reflète la signature d'appel). Node est identique avec camelCase.AIConfig(...)défaut →AICompletionConfigDefault(...)ouAIAgentConfigDefault(...)(Node :LDAICompletionConfigDefault/LDAIAgentConfigDefault).AIConfigest la classe de base que le SDK retourne ; ce n'est pas un constructeur de valeur par défaut valide — les variantes typées*Defaultle 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 viaconfig.create_tracker()/aiConfig.createTracker(). - Pour les réécritures plus profondes (sites d'appel avec modèle/prompt codé en dur également), délègue à
migrateau 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 :
- Vérifie toujours
config.enabledavant 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. - 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.
- Les erreurs sont gérées à l'intérieur de
trackMetricsOf. Le wrapper capture les exceptions, enregistretrackError()en interne, et relance — n'ajoute pasexcept: 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. - 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_tokenszé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
trackMetricsOfmais tu n'as pas ajouté l'appeltrackTimeToFirstTokenmanuel — 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 configcustom-metrics— métriques métier (conversion, résolution, rétention) superposées sur les métriques d'agent que cette skill captureonline-evals— notation de qualité automatique (LLM-as-judge) sur les requêtes en direct échantillonnées ; complémentaire aux métriques icimigrate— L'étape 4 de la migration hardcoded-to-AgentControl délègue à cette skill