Voici une fonction de cinq lignes. Il appelle un LLM, enregistre la réponse, la renvoie.
fonction asynchrone demander (question : chaîne) { const res = attendre openai.responses.create ({ modèle : "o4-mini", entrée : question }); console.log("réponse:", res.output_text); renvoyer res.output_text ; }Cela compile. Il passe les tests. Il est expédié. Et cela vous coûtera discrètement quatre chiffres par mois avant que quiconque ne le remarque, car rien dans ce journal ne vous indique que le modèle a brûlé 8 000 jetons de raisonnement cachés pour produire une réponse de 40 jetons.
C’est la lacune sur laquelle porte cet article. Les appels AI ne sont pas des appels HTTP classiques. L'état intéressant n'est pas le corps de réponse - ce sont les messages que vous avez envoyés, les outils choisis par le modèle, les jetons qu'il a consommés (visibles et autres) et les dollars qui ont été retirés du budget. Si votre histoire d'observabilité est « nous enregistrons la réponse », vous pilotez un avion avec une seule jauge et cette jauge est l'altimètre.
Parlons de ce qu'il faut réellement capturer.
Chaque système d’IA a les mêmes quatre dimensions qui méritent d’être instrumentées, et la plupart des équipes n’en suivent qu’une ou deux :
Si vous perdez l'un de ces éléments, vous travaillerez à l'aveugle sur un axe différent du problème. Perdez le signal de coût et vous vous réveillez avec un message Slack de la finance. Perdez le signal d'appel de l'outil et vous ne pouvez pas savoir pourquoi votre agent a continué à réserver le mauvais vol. Perdez le signal d'invite et une régression de prod devient un jeu de devinettes. Perdez les journaux simples et vous ne savez même pas que l'appel a eu lieu.
La bonne nouvelle : en 2026, il existera enfin une norme pour capturer les quatre. La mauvaise nouvelle : la plupart des équipes roulent toujours les leurs et manquent la moitié du terrain.
Commencez par la couche ennuyeuse. Chaque appel LLM mérite une ligne de journal structurée avec au minimum :
ouvert,anthropique,base, votre propre passerelle), nom du modèle, version du modèle si vous l'avez.chat.achèvements,réponses,messages).arrêt,longueur,appels_outils,contenu_filter).Ce dernier est le piège. Un 200 de l'API ne signifie pas "le modèle a répondu à la question". UNfinish_reasondelongueursignifie que la réponse a été tronquée au milieu de la phrase.contenu_filtersignifie que le système de sécurité a bloqué la sortie.appels_outilssignifie que le modèle vous demande de faire un travail et que la conversation n'est pas terminée. Si votre suivi compte les 200 comme succès, vous comptez les troncatures et les refus comme des victoires.
Le cas du streaming est une affaire à part entière. Une réponse diffusée en continu peut renvoyer un HTTP 200, émettre une demi-phrase, puis mourir avec une interruption de connexion. La vérification « cet appel a-t-il réussi » doit avoir lieu à la fin du flux, et non au niveau des en-têtes. Capturez également le nombre d'octets et le nombre de morceaux - une réponse partielle arrivée en trois morceaux au lieu de quarante vous indique que le modèle est mort prématurément, et la latence jusqu'au premier jeton aura fière allure même si l'utilisateur n'a rien d'utile.
Le délai d'obtention du premier jeton est le nombre de latence qui est en corrélation avec la vitesse perçue par l'utilisateur. La durée totale est importante pour la facturation et la planification de la capacité, mais un utilisateur qui voit le premier jeton en 600 ms et le dernier jeton en 8 s ressent une application rapide. Un utilisateur qui attend 4 secondes avant que quelque chose n'apparaisse n'apparaît pas, même si la durée totale est plus courte.