1 points par jhs6312 6 시간 전 | Aucun commentaire pour le moment. | Partager sur WhatsApp

Bonjour. Je développe Spanlens, une plateforme open source d’observabilité qui permet de voir en un seul endroit les logs d’appels LLM, le suivi des coûts et les traces d’agents.

Pourquoi je l’ai créé

En utilisant des LLM pour des projets perso, deux problèmes revenaient sans arrêt.

Le premier, c’était le suivi des coûts.
Tout a commencé quand j’ai créé une extension de navigateur basée sur GPT et que j’ai eu la surprise de recevoir ma facture OpenAI à la fin du mois. En tant qu’étudiant, ce n’était pas une somme énorme, mais même si le total était visible, il n’y avait pas de détail sur quelle fonctionnalité avait coûté combien, ni sur quel modèle consommait en moyenne combien de tokens. Je me suis donc retrouvé à ajouter des console.log partout dans le code, à exporter en CSV, à faire les sommes dans Excel, puis à multiplier par les tarifs selon les modèles pour estimer les coûts — encore et encore.

Le second, c’était le débogage des agents.
Je m’en suis rendu compte directement en intégrant LangGraph à Spanlens : lorsqu’une seule trace mêlant plusieurs appels LLM mettait 30 secondes, il fallait dérouler les logs et les suivre à la main pour comprendre

  • sur quel nœud le temps était parti
  • pourquoi le même outil avait été appelé deux fois
  • à quel moment l’état LangGraph avait changé

J’ai créé Spanlens pour réduire ces deux frictions.

Fonctionnalités principales

  1. Intégration en une ligne via baseURL

Il suffit de remplacer le baseURL du SDK OpenAI/Anthropic/Gemini par quelque chose comme https://api.spanlens.io/proxy/openai/v1 pour que les requêtes, réponses, tokens et coûts soient enregistrés automatiquement. Les réponses sont transmises en passthrough, donc le streaming, le tool calling et le mode JSON fonctionnent exactement comme à l’origine.

Dans les cas où un agent nécessite une approche par wrap, j’ai aussi permis d’injecter trace_id et span_id via le SDK afin d’enregistrer en même temps les relations parent-enfant.

  1. Trace d’agent + vue topologique LangGraph

Les traces sont visibles non seulement sous forme de timeline chronologique, mais aussi directement superposées aux vrais nœuds du graphe. Pour un agent construit avec LangGraph, on peut voir sur un seul écran quels nœuds ont pris du temps et quelles arêtes sont parcourues le plus souvent.

  1. Analyse automatique du Critical Path

La chaîne d’appels qui consomme le plus de latence dans une trace est mise en évidence automatiquement. L’objectif était de réduire le nombre de clics nécessaires pour répondre à la question : « pourquoi cette trace est-elle lente ? »

  1. Comparaison statistique A/B des prompts

Deux versions d’un même prompt peuvent être comparées selon la latence, le coût et l’usage des tokens. Au lieu de se limiter à une simple différence de moyenne, Spanlens applique un test t de Welch afin de montrer des écarts qui tiennent aussi compte de la variance des échantillons. Je l’ai ajouté pour pouvoir dire non pas seulement « la moyenne est un peu plus basse », mais « la différence est significative ».

  1. Self-hosting

Le projet peut être déployé sur son propre serveur via une image Docker. Le même code que la version SaaS est disponible tel quel dans le dépôt public. L’ensemble du code est sous licence MIT.

Comment c’est implémenté

Le pipeline actuel ressemble globalement à ceci.

  • Les requêtes proxy sont reçues par Hono, qui sépare l’en-tête Authorization et les métadonnées X-Spanlens-*, puis déchiffre la clé provider en AES-256-GCM afin de ne l’utiliser qu’en mémoire juste avant l’appel.
  • Pour les réponses en streaming, body.tee() renvoie immédiatement le flux d’origine au client, tandis qu’une copie est analysée en arrière-plan pour calculer les tokens et le coût.
  • Les logs sont insérés de façon asynchrone dans ClickHouse. En cas d’échec d’INSERT, ils sont conservés dans une file de secours Supabase puis réessayés par un cron ; l’idée était de garder un fonctionnement fire-and-forget tout en évitant la perte de données.
  • Les tarifs des modèles sont stockés dans une table en base et mis en cache avec une stratégie stale-while-revalidate et un TTL de 5 minutes. Des tarifs de fallback servent de filet de sécurité au cold start.

Au début, ce n’était qu’un simple proxy, mais à l’usage j’ai constaté que le plus important n’était pas le log brut, mais la trace normalisée. Pour répondre à la question « pourquoi cette trace est-elle lente ? », il faut plus que l’ordre des appels : il faut aussi les relations parent-enfant, les appels parallèles et le Critical Path. C’est de là que sont venues des fonctionnalités comme la vue topologique LangGraph ou l’analyse automatique du Critical Path.

La stack repose sur Next.js 14, Hono, Supabase Postgres et ClickHouse, le tout dans un monorepo pnpm en TypeScript.

Points sur lesquels j’hésite encore

  • J’aimerais proposer le self-hosting avec un simple docker run, mais cela impliquerait aussi d’embarquer Supabase Postgres. Pour l’instant, le docker-compose part du principe d’un Supabase managé et comprend trois conteneurs : web, server et ClickHouse. Je me demande s’il vaut mieux ajouter une option de self-hosting pour Supabase aussi, ou conserver l’hypothèse d’un service managé.

  • Le calcul du test t de Welch est déjà présent dans la comparaison A/B des prompts, mais je n’ai pas encore décidé s’il vaut mieux afficher directement la p-value ou seulement un badge de conclusion (significatif / non significatif). Je réfléchis aussi à la meilleure façon d’afficher un avertissement lorsque l’échantillon est petit (n<30).

  • Dans la vue topologique LangGraph, les nœuds, les arêtes et le Critical Path sont visualisés, mais j’ai volontairement exclu les changements de state channel parce que cela introduisait trop de bruit. J’aimerais savoir si, en pratique, le suivi des changements d’état est plus utile pour le débogage, ou si le niveau actuel vous semble suffisant.

C’est un projet que j’améliore régulièrement, parti d’un inconfort vécu directement.

[ Spanlens ]
Web : https://www.spanlens.io
GitHub : https://github.com/spanlens/Spanlens
Guide de self-hosting : https://www.spanlens.io/docs/self-host

Je serais vraiment reconnaissant pour tout retour, que ce soit sur l’UX du dashboard, la visualisation des traces, la méthode d’intégration du proxy, l’expérience de self-hosting ou tout autre angle. En particulier, s’il y a d’autres providers que vous aimeriez voir pris en charge en plus d’OpenAI/Anthropic/Gemini, dites-le-moi en commentaire.

Une démo est disponible sur le site, n’hésitez pas à y jeter un œil.
L’interface est actuellement en anglais, et la prise en charge du coréen sera ajoutée prochainement.

Aucun commentaire pour le moment.

Aucun commentaire pour le moment.