
2025
Plateforme d'évaluation de prompts - Société Pretto
Refactorisation de la plateforme d'évaluation Langfuse pour que les équipes métier puissent tester leurs prompts via une modale Slack, sans ticket Data et sans attente.
Avant cette refactorisation, chaque nouveau cas d'usage à évaluer nécessitait un ticket à l'équipe Data et deux jours d'attente. Les évaluations se lançaient depuis un Google Colab partagé, ce qui impliquait de modifier des cellules à la main pour changer de prompt ou de dataset. Après : les équipes métier évaluent leurs propres prompts via une modale Slack, sans intervention technique. J'ai unifié N fichiers Python (un par prompt) en un moteur générique pilotable par configuration : on sélectionne un prompt, un dataset annoté et les métriques adaptées au cas d'usage, et l'évaluation se lance sans toucher au code. L'interface Slack a remplacé le Colab car les options natives de Langfuse ne s'intégraient pas à notre API interne customisée. Sur le cas concret du chatbot SMS à tool calling (réservation de rendez-vous, consultation de créneaux courtiers), j'ai proposé une métrique cohérence x Jaccard sur les appels d'outils, adoptée par l'équipe pour sa robustesse et son interprétabilité. Résultat : -80% de régressions en production, +30% de projets IA initiés par les métiers, et une plateforme qui a directement servi de base au projet suivant : l'auto-amélioration automatique de prompts.
Étude de cas détaillée
Langfuse est une plateforme open source d'observabilité pour les applications LLM : elle permet de versionner des prompts, de constituer des datasets annotés (input / output attendu), et d'orchestrer des évaluations en trackant les scores au fil du temps. Chez Pretto, Langfuse était déjà en place pour gérer prompts et datasets. Le problème : l'évaluation elle-même s'exécutait via un Google Colab partagé à l'ensemble des employés. Chaque prompt avait son propre fichier Python, sa propre logique d'évaluation. Pour un nouveau cas d'usage, il fallait ouvrir un ticket à l'équipe Data, attendre qu'un développeur écrive le script, puis aller dans Colab pour lancer l'évaluation — un flux trop long et trop fragile.
J'ai unifié tout ça en un moteur générique piloté par configuration, et j'ai remplacé le Colab par une interface Slack (les options natives de Langfuse se connectaient mal à notre API interne, qui était customisée pour nos cas d'usage spécifiques). Résultat : les équipes métier évaluent leurs propres prompts en autonomie, sans ticket Data, et la plateforme a pu évoluer vers l'auto-amélioration de prompt dans la foulée.
Avant : une plateforme qui se sabotait elle-même
La plateforme existait, elle fonctionnait — mais son architecture décourageait son usage.
Un fichier Python par prompt. Pour chaque cas d'usage, l'équipe Data avait codé un script dédié : un pour le chatbot, un pour la classification, un pour l'extraction de données. Logique à trois cas d'usage, ingérable à quinze.
La friction du ticket + du Colab. Quand une équipe métier voulait tester un nouveau prompt, il fallait ouvrir un ticket, attendre qu'un développeur crée le script associé, puis aller dans un Google Colab partagé pour lancer l'évaluation. Deux à trois jours minimum pour quelque chose qui devrait prendre cinq minutes — et un Colab qui nécessitait quand même de modifier des cellules pour changer le prompt ou le dataset évalué.
L'absence d'adoption. Une plateforme d'évaluation qui coûte cher à utiliser, personne ne l'utilise vraiment. Les prompts partaient en production sans évaluation systématique, les régressions se découvraient tard, souvent après un incident.
L'objectif : zéro friction entre "nouveau prompt" et "évaluation lancée"
La refactorisation visait un objectif unique : qu'une équipe métier puisse créer un prompt et un dataset sur Langfuse, puis lancer l'évaluation sans jamais ouvrir un éditeur de code — et sans passer par un Colab.
Concrètement :
- Un seul script Python pilotable par configuration (prompt ID, dataset, métriques)
- Des métriques sélectionnables à la volée, pas câblées dans le code
- Une interface Slack pour déclencher les évaluations (les options natives de Langfuse ne s'intégraient pas à notre API interne customisée)
- Langfuse comme seul point d'entrée pour gérer prompts et datasets
La refactorisation : un moteur générique piloté par config
Le principe est simple : extraire tout ce qui variait d'un fichier à l'autre (le prompt, le dataset, les métriques) et en faire des paramètres d'une fonction unique.
def run_evaluation(
prompt_name: str,
dataset_name: str,
metrics: list[EvalMetric],
model: str = "gpt-4o",
) -> EvaluationReport:
prompt = langfuse.get_prompt(prompt_name)
dataset = langfuse.get_dataset(dataset_name)
results = []
for item in dataset.items:
output = run_prompt(prompt, item.input, model)
scores = {m.name: m.score(item.input, output, item.expected_output) for m in metrics}
results.append(EvaluationResult(item=item, output=output, scores=scores))
return EvaluationReport(results=results)Chaque EvalMetric implémente une interface commune : elle prend en entrée l'input, l'output produit et l'output attendu, et retourne un score entre 0 et 1. Cela permet de mélanger des métriques déterministes et des juges LLM dans la même évaluation, selon le besoin.
Cas concret : évaluer un chatbot SMS avec tool calling
Le cas le plus intéressant techniquement était le chatbot client. Il communique par SMS et peut appeler plusieurs outils métiers : réserver un rendez-vous, consulter les créneaux disponibles d'un courtier, récupérer des informations sur un dossier.
Le problème de mesure. Comment évaluer "le bot a appelé les bons outils au bon moment" de façon automatisée ? Un juge LLM est coûteux et difficilement reproductible. Une comparaison exacte est trop stricte (l'ordre des appels peut varier sans que ça soit une erreur).
La métrique retenue : cohérence × Jaccard. Après analyse des options, j'ai proposé une métrique en deux composantes :
def jaccard_tool_score(expected_tools: set[str], called_tools: set[str]) -> float:
if not expected_tools and not called_tools:
return 1.0
intersection = expected_tools & called_tools
union = expected_tools | called_tools
return len(intersection) / len(union)
def coherence_score(expected_sequence: list[str], called_sequence: list[str]) -> float:
# Sous-séquence commune la plus longue, normalisée
lcs_len = longest_common_subsequence(expected_sequence, called_sequence)
return lcs_len / max(len(expected_sequence), len(called_sequence), 1)
def tool_calling_score(item: DatasetItem, output: ChatOutput) -> float:
jaccard = jaccard_tool_score(set(item.expected_tools), set(output.called_tools))
coherence = coherence_score(item.expected_tools, output.called_tools)
return jaccard * coherence- Jaccard mesure la couverture : est-ce que les bons outils ont été appelés, même si l'ordre diffère ?
- Cohérence mesure la séquence : les outils sont-ils appelés dans un ordre logique ?
- Le produit pénalise doublement les erreurs graves (mauvais outil + mauvais ordre) sans sur-pénaliser une simple inversion.
Cette métrique a été adoptée après discussion d'équipe. Elle est calculable sans LLM, déterministe, et facile à interpréter : un score de 0,8 signifie quelque chose de concret.
Les résultats
Adoption côté métier. Avant la refactorisation, l'évaluation était l'affaire exclusive de l'équipe Data. Après, des profils non-développeurs ont commencé à évaluer leurs propres prompts en autonomie. Certains métiers se sont mis à l'évaluation d'eux-mêmes, sans qu'on le leur demande.
Moins de régressions en production. L'évaluation systématique avant déploiement a capturé des régressions silencieuses que les tests manuels laissaient passer. Les -80% observés sur la période sont directement corrélés à la généralisation de l'évaluation.
Une plateforme évolutive. Le moteur générique a rendu possible le projet suivant : un pipeline d'auto-amélioration de prompt qui utilise exactement la même infrastructure pour noter les versions améliorées.
Ce que ça apprend sur l'industrialisation de l'évaluation LLM
Quatre observations issues de ce projet, applicables à n'importe quelle équipe qui veut sérieusement évaluer ses prompts.
L'évaluation doit coûter moins cher que ne pas évaluer. Si lancer une évaluation demande un ticket et deux jours, les gens ne l'utilisent pas. L'investissement dans un moteur générique se justifie dès qu'on a plus de trois cas d'usage actifs.
Les métriques déterministes d'abord. Pour des tâches structurées (classification, tool calling, extraction JSON), une métrique calculable sans LLM est plus rapide, moins chère et plus reproductible qu'un juge LLM. Réserver le LLM-as-a-judge pour les cas vraiment qualitatifs.
Un dataset minimal vaut mieux qu'un dataset parfait inexistant. Commencer avec 20 cas annotés à la main. L'évaluation imparfaite sur un petit dataset est infiniment plus utile que l'absence d'évaluation en attendant un corpus de 1000 cas.
L'évaluation est un workflow, pas un one-shot. Elle a de la valeur uniquement si elle est répétée à chaque changement de prompt, avec des résultats historisés et comparables. C'est précisément ce que fournit Langfuse avec ses datasets versionnés et son historique de runs.
Pièges à éviter
Le fichier Python par cas d'usage. C'est la configuration de départ ici. Elle semble raisonnable à 3 cas d'usage, elle devient ingérable à 15. Partir d'un moteur générique dès le début, même imparfait.
La métrique unique universelle. Il n'existe pas de score qui mesure bien à la fois un chatbot conversationnel, un extracteur JSON et un classificateur. Mieux vaut trois métriques adaptées à leur contexte qu'une seule métrique médiocre sur tout.
LLM-as-a-judge avec le même modèle que le sujet évalué. GPT-4 tend à se favoriser lui-même dans les comparaisons. Si on évalue GPT-4o, utiliser un juge différent, ou une métrique déterministe.
Ne pas versionner les datasets. Un dataset qui évolue sans traçabilité rend les comparaisons historiques inutilisables. Langfuse gère ça nativement.
Conclusion : TL;DR
La refactorisation d'une plateforme d'évaluation n'est pas un projet pour faire du code propre. C'est un projet d'adoption : rendre l'évaluation accessible aux équipes qui en ont besoin, sans friction. Chez Pretto, ça s'est traduit par des équipes métier autonomes, moins de régressions, et une infrastructure qui a servi de base au projet suivant.
Les points-clés :
- Un moteur générique piloté par config élimine la friction entre "nouveau prompt" et "évaluation lancée"
- Les métriques déterministes (Jaccard, LCS) sont préférables aux juges LLM pour les tâches structurées
- L'évaluation n'a de valeur que si elle est systématique et historisée, pas ponctuelle
- La plateforme d'évaluation est le prérequis à l'auto-amélioration de prompt
Si vous voulez structurer l'évaluation de vos prompts ou outiller votre équipe IA pour l'autonomie, parlons-en.
Témoignage client
“A la suite de son stage nous avons continué à travailler avec Pierre en freelance alors qu'il continuait ses études en parallèle. Il est travailleur, efficace, précis et fiable. Merci encore Pierre pour tout le super boulot et à très vite :)”