Ce qui se passe
L'auteur du blog Entropic Thoughts devait ranger quelque 21 000 commits en
deux catégories, « maintenance » ou « nouveau développement ». Un modèle
récent et bon marché, gpt 5.6 Luna appelé via OpenRouter et l'outil llm de
Simon Willison, donnait exactement ses propres réponses sur un échantillon
vérifié à la main. Seul défaut : environ 1,5 seconde par appel.
Le principe : une cascade
Beaucoup de commits sont évidents. Un classifieur rapide passe donc en premier ; s'il est sûr de lui, sa réponse est gardée, sinon le LLM tranche, et son étiquette sert à entraîner le classifieur. Le modèle rapide apprend ainsi en continu, sur les réponses du modèle lent.
Le classifieur est une régression logistique sur un sac de mots, entraînée
exemple par exemple par descente de gradient. L'auteur l'a écrite en Perl, sans
bibliothèque. Esquisse en Python rédigée pour cette fiche d'après l'algorithme
décrit (bag_of_words et ask_llm sont à fournir) :
import math, random
class OnlineLogReg:
def __init__(self, lr=0.1):
self.w, self.lr, self.n = {}, lr, 0
def predict(self, feats):
z = sum(self.w.get(k, 0.0) * v for k, v in feats.items())
return 1 / (1 + math.exp(-z))
def refine(self, positive, feats):
err = (1.0 if positive else 0.0) - self.predict(feats)
for k, v in feats.items():
self.w[k] = self.w.get(k, 0.0) + self.lr * err * v
self.n += 1
def label(msg, fast, ask_llm):
feats = bag_of_words(msg)
# 5 % des cas vont au LLM quoi qu'il arrive
if fast.n > 50 and random.random() < 0.95:
p = fast.predict(feats)
if p < 0.08:
return "maintenance"
if p > 0.92:
return "nouveau développement"
result = ask_llm(msg)
fast.refine(result == "nouveau développement", feats)
return resultLes deux garde-fous comptent autant que le reste. Le seuil de 50 exemples évite de faire confiance à un modèle vide. Et le détour forcé vers le LLM, une fois sur vingt, empêche le classifieur de se convaincre qu'une probabilité vaut 0 ou 1 après une longue série d'étiquettes identiques.
Calibrer les probabilités
Les seuils 0,08 et 0,92 n'ont de sens que si les probabilités sont justes. La régularisation et le faible volume du début les faussent légèrement. L'auteur ajoute donc une calibration de Platt : une seconde régression logistique, posée sur la sortie de la première, entraînée sur 10 % des étiquettes du LLM détournées pour rester indépendantes. Mesurée par tranches de dix points, l'erreur restante reste dans la marge attendue.
Le résultat
- 46 % des étiquettes viennent du classifieur rapide : la vitesse double à peu près.
- Le gain serait bien plus grand sur une tâche plus tranchée ou avec un modèle plus cher, jusqu'à un ordre de grandeur selon l'auteur.
- Le classifieur retrouve seul le vocabulaire des développeurs : fix, bug, cleanup, refactor pour la maintenance ; add, implement, support, allow, option pour le nouveau développement. Les mêmes mots ressortent d'un dépôt à l'autre.
Le détail qui a le plus rapporté
Selon l'auteur, un autre choix a pesé plus lourd que le classifieur : le
hasard est tiré du hash de chaque commit. Le même commit reçoit toujours le
même tirage, l'échantillon est identique d'une exécution à l'autre, et un
simple fichier labels.csv (hash, étiquette) sert de cache aux réponses du
LLM.
Les limites
C'est un projet personnel, sans évaluation de variantes du prompt, et 46 % n'a rien de général : tout dépend de la part de cas évidents. Par construction, le petit modèle hérite aussi des erreurs du LLM dont il apprend. Pour qui travaille en Laravel, le SDK IA 1.0 sorti le même jour pousse la même idée par un autre chemin, avec des modèles de classification dédiés.
Source : Cheaper LLM labelling, Entropic Thoughts, 22 septembre 2026 (signalé sur Lobste.rs).