Aller au contenu

Plafonner la dépense d'un client

Les plans, le plafond mensuel, et les deux refus que reçoit un appelant qui ne passe pas.

Une équipe consomme des modèles à vos frais, et vous voulez borner ce qu’elle peut dépenser dans le mois. Cette page décrit le plan, son plafond, et ce que reçoit l’appelant qui le dépasse.

Un plan est l’arrangement de facturation sous lequel la passerelle revend l’accès. plans.max_cost_euro est le plafond mensuel du client, en euros.

État du compteCe que répond la passerelle
users.plan_id vide (aucun plan)403 {"error": "No plan assigned. Ask your administrator to assign one."}
plan dont le plafond est videservi, quelle que soit la dépense : le plan est illimité
plan avec un plafondservi tant que la dépense du mois est sous le plafond, 402 {"error": "Plan limit reached"} au-delà

Les deux codes sont différents parce que ce ne sont pas les mêmes personnes qui les lèvent.

402 dit « le titulaire a dépensé son plan » : un paiement, ou le mois suivant, le lève, et c’est le titulaire du compte qui agit.

403 dit « il n’y a pas de plan à dépenser » : aucun paiement ne peut y être imputé, le mois suivant n’y change rien, et seul l’exploitant le lève, en affectant un plan depuis la console.

Un troisième 403 existe, de sens différent, {"error": "Endpoint \"<nom>\" is disabled."}, quand l’endpoint visé existe mais a été désactivé. Il est rendu avant le contrôle de quota : un endpoint éteint ne consomme rien.

Onglet Plans, formulaire Add plan : un nom, et un plafond mensuel en euros. Le nom est unique ; la console refuse en 409 un nom déjà pris.

Laisser le champ de plafond vide crée un plan illimité. C’est une valeur distincte de zéro, et une situation distincte de « ce compte n’a pas de plan » : le plan illimité passe toujours, le compte sans plan ne passe jamais. La migration 011-plans-plafond-illimite distingue les deux en base : un plafond vide y est une valeur nulle, et non zéro.

Le plan administrator, semé par cette même migration, est illimité. La passerelle l’affecte au compte admin au démarrage si ce compte n’a pas déjà un plan : un plan que vous lui avez donné, plafonné par exemple, n’est pas repris par un redémarrage.

Onglet Users, sélecteur de la colonne Plan sur la ligne du compte. Le changement prend effet à la requête suivante.

La valeur No plan du même sélecteur retire son plan au compte : c’est le geste de blocage immédiat. Un badge Blocked apparaît sur la ligne.

Onglet Plans, édition en ligne. La modification porte sur le plan, donc sur tous les comptes qui le portent.

La suppression d’un plan est refusée en 409 tant que des comptes le portent ; le message demande de les réaffecter d’abord. Supprimer un plan porté bloquerait en masse les comptes qui en dépendent.

Onglet Caps. Il liste tous les comptes avec ce que chacun a dépensé ce mois calendaire, le plafond de son plan, et la part de ce plafond déjà consommée. Les comptes plafonnés viennent d’abord, du plus proche de son plafond au plus loin ; puis les comptes au plan illimité ; puis les comptes sans plan.

C’est le seul écran qui met les deux nombres côte à côte. Chaque compte y porte un état écrit en toutes lettres :

ÉtatCe que fait la passerelle
Under capsert
Near capsert ; quatre cinquièmes du plafond au moins sont consommés
Blocked: cap reachedrefuse en 402
Blocked: no planrefuse en 403
Unlimitedsert, quelle que soit la dépense

Deux choses à savoir avant de présenter cet écran :

  • les montants sont un plancher, pas un total. Un appel que rien n’a pu chiffrer entre dans la somme pour zéro euro ; l’écran affiche un bandeau qui dit combien il y en a eu ce mois-ci. Les causes sont détaillées plus bas ;
  • le seuil de Near cap est fixé à quatre cinquièmes du plafond. Il n’est pas réglable.

L’onglet Usage ne connaît pas les plafonds : il répond à « qu’est-ce qui a été consommé, par qui, sur quels modèles », sur une période que vous choisissez. Voir Lire la consommation dans la console.

Le plafond n’est pas une estimation périodique : la dépense du mois est recalculée à chaque requête relayée, par agrégat sur request_logs joint aux prix par token de la table models.

  • La fenêtre est le mois calendaire en cours : timestamp >= date_trunc('month', NOW()). Elle repart à zéro au premier du mois, pas trente jours après la première requête.
  • La comparaison est >= : à plafond exactement atteint, le refus commence.
  • Le prix vient des modèles, en nano-euros par token entrant et par token sortant. Ces colonnes, et elles seules, alimentent le coût.

La requête n’est pas exécutée pour un compte sans plan : il n’y a pas de plafond à comparer, donc pas de total à calculer.

À vérifier avant de promettre un plafond à un client. Chaque point ci-dessous fait qu’une consommation réelle ne compte pas, ou pas encore, dans le total.

Un modèle sans prix compte pour zéro. Les prix par token valent 0 par défaut à la création d’un modèle. Un modèle servi et laissé à zéro ne fait monter aucun compteur, donc ne déclenche aucun plafond. Renseignez les prix en même temps que le modèle.

Un flux en cours n’est pas encore compté. Sur une réponse en streaming, la ligne de request_logs n’est écrite qu’à la fin du flux. Entre-temps, la consommation existe et n’est pas visible du contrôle de quota.

Un flux sans compteurs de tokens compte pour zéro. Sur les chemins de complétion au format OpenAI, la passerelle demande elle-même au fournisseur le récapitulatif de consommation (stream_options.include_usage). Si le fournisseur ne le sert pas, la ligne est écrite sans compteurs et pèse zéro sur le plafond ; le bandeau de l’onglet Caps compte ces appels.

Une ligne de facturation refusée par la base laisse une trace. Sur une réponse non diffusée, la réponse est retenue et l’appelant reçoit un refus : rien n’est servi sans être compté. Sur une réponse diffusée, l’appelant a déjà reçu son flux ; la ligne est gardée en mémoire dans une file de reprise et réécrite quand la base répond (500 lignes au plus, 20 tentatives par ligne). Un redémarrage de la passerelle perd ce qui attend dans cette file. Chaque ligne différée laisse une trace [BILLING] sur la sortie d’erreur de la passerelle.

La requête qui franchit le plafond est servie en entier. Le contrôle compare la dépense déjà enregistrée avant de relayer ; il ne devine pas le coût de la requête en cours. Le dépassement se constate après coup, d’au moins un appel.

Les plafonds saisis avant la migration 007 ont pu être arrondis. La colonne était un entier : 12,50 € était enregistré 13 €, sans erreur. La migration corrige le type mais ne restaure pas les décimales perdues. Sur une base ancienne, relisez les plafonds à centimes et ressaisissez-les.

L’onglet Caps met la dépense du mois de chaque compte face au plafond qui le bloquera (voir plus haut). L’onglet Usage donne les coûts par période, filtrables par compte et par modèle ; l’onglet Plans donne les plafonds.

Le journal de la passerelle imprime aussi le rapprochement à chaque requête relayée, sous la forme [COST] <compte>: €<dépensé> used / €<plafond> limit, ou [COST] <compte>: €<dépensé> used (plan has no cap) pour un plan illimité.