Guillaume Duvernay

Jev a réduit de 61% le coût de cet agent IA

AI efficiencyagentscostexperiment

Ceci est la version longue d'une expérience. Lire la version courte

En juillet, j’écrivais que les petits modèles devraient décider de ce que voient les grands modèles : il ne s’agit pas de confier une tâche à un modèle moins cher, mais de placer de petits modèles aux côtés du grand pour choisir les jetons qu’il lira. Je concluais que les économies justifiaient de faire un essai, sans en constituer la preuve, et qu’il fallait que quelqu’un réalise le test.

Puis Jev est sorti le 15 septembre. C’est le premier modèle System One de TypeSafe : il ne génère aucun texte, renvoie des probabilités calibrées pour les réponses définies par votre code, coûte $0.042 par million de jetons en entrée et répond en quelques centaines de millisecondes. Cette combinaison rend deux déclinaisons très concrètes de l’idée de juillet assez peu coûteuses pour être réellement mesurées.

J’ai donc testé ces deux possibilités.

Précharger les compétences. Lorsqu’on lui fournit un catalogue de documents internes, un agent consacre un aller-retour complet à décider lesquels lire et à appeler un outil pour les récupérer. Jev peut prendre cette décision avant le premier tour, pour une fraction de centime, et les documents sont déjà présents dans le prompt.

Filtrer la charge utile des outils. Une réponse d’API réelle contient surtout des champs auxquels aucun agent ne donnera suite. Dans une configuration MCP, tout se retrouve dans la fenêtre de contexte et est renvoyé à chaque tour suivant. Jev peut évaluer chaque champ de la réponse avant que l’agent ne la voie.

Dans les deux cas, il s’agit de problèmes de classification, pas de rédaction. Voici les résultats de 192 exécutions sur 8 tâches, avec les coûts calculés pour Claude Opus 5 :

Jev peut aussi déterminer si le titre d’une conversation correspond toujours au contenu de l’échange. Je décris ce cas d’usage dans mon article sur la génération de titres de conversation. Je ne l’ai pas testé avec Jev.

Mêmes 8 tâches, même agent, même évaluation déterministe. Jev représente 3% du coût dans la barre de droite. Méthode complète et chiffres détaillés par tâche ci-dessous.

La tâche la plus avantageuse a coûté 61% moins cher. La baisse moyenne sur les huit tâches est de 29%, et la plus faible, de 13%. Dans chaque groupe, y compris celui sans optimisation, 99% des vérifications qualité ont été réussies : aucune concession n’a donc été nécessaire.

L’expérience entière a coûté $1.17.

Qu’est-ce que Jev ?

Jev ne génère aucun texte. Vous lui transmettez un state et une série de questions typées, et il renvoie une distribution de probabilités calibrées sur les réponses définies dans votre code. TypeSafe décrit Jev comme un modèle System One, entraîné par apprentissage par renforcement pour prendre des décisions calibrées.

ÉlémentValeur
Prix$0.042 par million de jetons en entrée, sortie gratuite
Contexte32,000 jetons
Latence mesurée ici300 à 600 ms, p50, quelle que soit la taille du lot
Point de terminaisonPOST /api/alpha/decisions sur OpenRouter

C’est le traitement par lots qui rend cette expérience possible. Toutes les questions sont envoyées dans un seul appel HTTP, avec le state transmis une seule fois. Évaluer 264 champs d’une charge utile ne nécessite qu’une requête, et non 264.

Premier mécanisme : précharger les compétences

Avant le premier tour de l’agent, Jev lit la demande et la description d’une ligne de chaque compétence. Il ne consulte jamais le contenu des compétences. Tout résultat égal ou supérieur à 0.55 est ajouté intégralement au prompt système.

C’est à l’étape 3 que tout se joue. Le texte des règles est déjà dans le prompt dès le premier tour, si bien que la règle du jour 10 est disponible avant tout appel de l’agent.

L’outil read_skill reste disponible : l’agent peut donc toujours récupérer ce que le routeur aurait oublié. C’est important, car le routeur passe parfois à côté de certaines choses.

Deuxième mécanisme : filtrer la charge utile des outils

Lorsqu’un outil renvoie un résultat, avant que celui-ci ne parvienne à l’agent, chaque champ terminal de la réponse est évalué selon sa pertinence pour la requête en cours. Tout champ dont le score est inférieur à 0.35 est supprimé.

Les scores affichés sont ceux consignés dans le journal d’exécution, pour les champs les plus proches du seuil. La plupart des champs en sont loin et leur score exact n’a pas été conservé : aucun chiffre ne leur est donc attribué.

À noter dans ces scores : les champs supprimés lors de cet appel obtiennent entre 0.31 et 0.34, tandis que ceux qui restent se situent entre 0.35 et 0.37. Le seuil est bien réel, et quelques champs le franchissent d’une exécution à l’autre. trial_end a obtenu 0.34 lors d’une exécution et 0.37 lors d’une autre. Aucun champ nécessaire à la tâche ne s’en est jamais approché.

D’où vient réellement la sécurité

Tout se joue à la troisième étape, celle de l’état. Le même seuil appliqué à un état moins complet est dangereux. Avec un état plus riche, le filtrage est à la fois plus sûr et plus sélectif.

Mesure isolée sur le champ déterminant pour la tâche de relance :

Contenu de l’étataccount.idmetadata.account_idConservés
requête + outil + arguments0.180.2051 / 124
+ les règles suivies0.190.1850 / 124
+ les actions déjà effectuées0.330.2540 / 124
+ les outils encore disponibles0.730.7627 / 124

Les deux colonnes du milieu indiquent les scores attribués au champ dont dépend réellement la tâche. La dernière indique combien des 124 champs passent le seuil de 0.35.

Ajouter les compétences ne change rien. L’historique aide un peu. Le facteur déterminant, c’est la liste des actions encore possibles. Tant que le système de scoring ne sait pas qu’un appel à billing_set_account_state(account_id, …) est disponible, un identifiant de compte n’est qu’une chaîne de caractères parmi d’autres.

La formulation générale, applicable à d’autres configurations :

Un champ n’est pas utile en soi. Il est utile en fonction de ce que l’agent s’apprête à en faire, et cette information ne figure pas dans la charge utile. Elle se trouve dans le schéma des outils encore disponibles.

Où se situent les gains, et où ils ne se situent pas

Les deux mécanismes mesurent des choses complètement différentes. Pour savoir lequel s’applique à votre charge de travail, c’est plus important que de regarder la moyenne.

C’est le critère pratique pour choisir. Pour l’un, examinez vos charges utiles ; pour l’autre, la structure de vos tours.

L’écart est considérable. Pour la tâche où six articles du centre d’aide sont renvoyés et où seul updated_at compte, le filtrage supprime 84% de la charge utile et 63% des jetons d’entrée. Pour la tâche de gestion d’incident, où presque tous les champs sont utilisés, il n’en supprime que 5%. Même agent, même seuil : un rapport de 17 entre les deux.

Coût par tâche avec Opus 5, agent seul comparé à l’agent avec les deux mécanismes :

TâcheProfilSeulLes deuxGain
docs obsolètescourte · charge utile très clairsemée$0.0639$0.0252−61%
remboursementmoyenne · mixte$0.0419$0.0249−41%
incidentcourte · dense$0.0340$0.0241−29%
relancecourte · mixte$0.0187$0.0135−28%
rechercheun appel · clairsemée$0.0083$0.0068−17%
gdprmoyenne · mixte$0.0336$0.0282−16%
slalongue · mixte$0.0442$0.0378−15%
post-mortemtrès longue · mixte$0.0906$0.0792−13%
moyenne$0.0419$0.0299−29%

Pour un agent Opus 5 qui traite 10,000 tâches par mois, le coût passe de $419 à $299, dont $9 reviennent à Jev.

Le coût de votre modèle principal détermine l’intérêt du filtrage

C’est ce résultat qui devrait changer votre façon de faire.

Le filtrage consomme des jetons Jev à chaque appel d’outil. Leur coût est fixe. Les jetons économisés, eux, sont facturés au tarif du modèle de votre agent. Tout dépend donc du rapport entre les deux, qui peut s’inverser.

Modèle d’agentTarif des entréesAgent sans mécanismeLes deux mécanismes
GPT-5.6 Luna$0.20/M$0.00182$0.00221+21%
Claude Sonnet 5$2.00/M$0.01676$0.01253−25%
Claude Opus 5$5.00/M$0.04191$0.02995−29%

Le nombre de jetons reste identique dans tous les cas. Seul le tarif de l’agent change. Avec le modèle le moins cher, Jev représente 42% de la facture et le filtrage coûte plus qu’il ne fait économiser. Avec Opus 5, il représente 3% de la facture.

En calculant le seuil de rentabilité à partir du nombre de jetons mesuré et de la structure tarifaire habituelle, on obtient $0.55 par million de jetons d’entrée avec la mise en cache du prompt, et $0.37 sans. En dessous, ne filtrez pas. Au-dessus, filtrez.

Le préchargement des compétences est rentable dans tous les cas, même avec le modèle le moins cher, car son coût est presque nul : environ 1,500 jetons Jev par exécution, soit $0.00006, pour un tour économisé.

Il y a un effet indirect à connaître. La mise en cache réduit la facture de moitié environ et diminue l’intérêt relatif du filtrage, car la plupart des éléments supprimés auraient été lus depuis le cache à faible coût. Le filtrage est donc plus intéressant pour un déploiement sans cache qu’avec cache.

Le mode d’échec

Le seuil de 0.35 n’est sûr que grâce à l’état enrichi. Une version antérieure qui en était dépourvue a produit le pire type d’échec.

Le filtre a supprimé account.id d’un abonnement Stripe, avec un score de 0.18, ainsi que sa deuxième occurrence, metadata.account_id. L’agent a utilisé le seul identifiant qui restait et a fait ceci :

appel :  billing_set_account_state(account_id="cus_PmT4k9WqLr2XbN", state="read_only")
                                                  ↑ l’identifiant client Stripe, pas celui du compte

rapport : « J’ai placé le compte associé en lecture seule, conformément à la politique du jour 10. »

Le bon identifiant était acct_borealis_4c77. L’agent a agi sur le mauvais objet et a remis un rapport assuré de lui, mais erroné.

Tout déploiement doit définir les chemins critiques et un seuil calibré en fonction de ceux-ci. Côté routage, un écart de deux centièmes sur le seuil suffisait à faire la différence entre « économiser un tour » et « ne rien économiser ». Côté filtrage, l’écart était bien plus important.

Ce que j’en retiens

Améliorer l’efficacité de l’IA vaut la peine, et une grande partie du potentiel réside dans la combinaison de modèles de tailles et de types différents. Ce qui rend cette approche intéressante, c’est qu’un modèle incapable d’écrire du texte s’avère être un bon juge de ce qu’un modèle qui écrit du texte devrait être autorisé à voir.

Deux points de départ ont été testés ici. Le même principe pourrait s’appliquer à bien d’autres tâches : choisir les fichiers qu’un agent ouvre, déterminer quand compacter une conversation, évaluer si un document récupéré vaut le coût de ses jetons, ou contrôler une écriture avant son exécution. Rien de cela n’a été mesuré, et je ne présumerais pas que ces approches fonctionnent avant de les avoir testées.

Vous trouverez ci-dessous le compte rendu complet : le banc d’essai, chaque tâche, chaque seuil, tous les tableaux et les limites de cette étude.


Tous les détails

Tout ce qui suit correspond à l’expérience complète. C’est volontairement long. Si vous vouliez seulement le résultat, vous l’avez déjà.

La configuration

L’agent

Environ 80 lignes. Pas de framework, pas de SDK d’agent, pas de bibliothèque d’orchestration. Une boucle while autour de fetch :

  1. Envoyer une requête POST au point de terminaison de complétion de chat d’OpenRouter, avec la liste des messages et les schémas d’outils au format d’appel de fonctions d’OpenAI.
  2. Si la réponse contient des tool_calls, exécuter chacun localement, ajouter le résultat comme message role: "tool", puis relancer la boucle.
  3. Si la réponse ne contient pas de tool_calls, le texte constitue la réponse finale et la boucle s’arrête.
ParamètreValeurRemarque
modelopenai/gpt-5.6-luna$0.20/M en entrée, $1.20/M en sortie, contexte de 1,050,000 tokens
tools17 schémas de fonctions
tool_choiceautol’agent décide s’il doit appeler un outil et lequel
seed1000 + repetition indexle seul paramètre modifié d’une répétition à l’autre
max_tokens2000un plafond, pas un objectif
reasoning / reasoning_effortnon définisvaleur par défaut du fournisseur
temperature, top_pnon définisvaleur par défaut du fournisseur

Concernant précisément le raisonnement : aucun paramètre reasoning n’a été transmis, le modèle a donc utilisé la valeur par défaut du fournisseur. Un appel de contrôle effectué ensuite renvoie reasoning_tokens: 0 : aucun budget de raisonnement distinct n’a été consommé et les comptes de tokens n’incluent aucun token de raisonnement caché. Répéter l’expérience avec un niveau d’effort de raisonnement supérieur donnerait des valeurs absolues différentes.

Deux garde-fous, car une boucle d’agent qui s’emballe coûte cher : 8 tours maximum par exécution et 6 appels d’outils maximum par tour. Aucun des deux plafonds n’a été atteint au cours des 192 exécutions. Un troisième garde-fou additionne le coût de tous les appels et interrompt l’exécution dès qu’un plafond est dépassé. Pour cette campagne, il était fixé à $2.60.

L’environnement

Une entreprise SaaS B2B fictive, Northwind Analytics, dont l’agent est l’assistant des opérations.

17 outils dont les charges utiles reproduisent la structure réelle de Stripe, Zendesk, HubSpot, Statuspage, PagerDuty, Slack, Linear et d’un CMS de centre d’aide : mêmes noms de clés, mêmes imbrications, mêmes données parasites. Ce sont des fonctions locales qui renvoient des données de test, rien ne quitte donc la machine. Les écritures sont consignées pour l’évaluation et renvoient un accusé de réception plausible.

OutilModélisé d’aprèsCharge utile
kb_list_articlespoint de terminaison de liste d’un CMS de centre d’aide28,128 caractères
stripe_list_chargesStripe GET /v1/charges6,993 caractères
kb_get_articlepoint de terminaison de lecture d’un CMS de centre d’aide4,966 caractères
stripe_get_subscriptionStripe GET /v1/subscriptions/:id3,181 caractères
zendesk_get_ticketZendesk GET /api/v2/tickets/:id avec chargements associés2,402 caractères
pagerduty_get_incidentPagerDuty GET /incidents/:id1,821 caractères
statuspage_get_incidentIncident et disponibilité Statuspage1,711 caractères
crm_get_accountObjet entreprise HubSpot1,117 caractères
read_skillinterne988 caractères
stripe_create_refundStripe POST /v1/refunds479 caractères
linear_create_issueLinear issueCreate202 caractères
billing_apply_creditAPI de facturation interne147 caractères
zendesk_replyZendesk PUT /api/v2/tickets/:id144 caractères
billing_set_account_stateAPI de facturation interne134 caractères
slack_post_messageSlack chat.postMessage124 caractères
billing_apply_discountAPI de facturation interne98 caractères
pagerduty_escalateEscalade PagerDuty92 caractères

11 compétences, sous forme de fichiers Markdown avec une ligne description dans le front matter et un corps qui contient les seuils, chiffres et formats à appliquer : churn-save-offers, docs-review-cadence, dunning-playbook, enterprise-contract-terms, escalation-matrix, gdpr-data-requests, incident-comms, oncall-handover, refund-policy, release-notes-format, slack-style-guide. Plusieurs ne concernent aucune tâche. Ce sont des distracteurs pour le routeur.

8 tâches, choisies pour couvrir deux axes indépendants : la longueur, d’un seul appel d’outil à sept tours, et la densité des données, de « chaque champ compte » à « 76% des octets sont du texte à ignorer ».

Les tâches, verbatim

TâcheInvite envoyée comme message utilisateur
T1-refundACME Analytics (compte acct_acme_9f21) a envoyé un e-mail : l’entreprise affirme avoir été facturée deux fois pour sa facture de novembre. Vérifie et règle entièrement le problème, en informant aussi l’équipe.
T2-slaLe ticket Zendesk 48213 concerne une demande de crédit SLA d’un client entreprise au sujet du mois d’octobre. Détermine le montant qui lui est dû, applique le crédit et réponds-lui.
T3-dunningL’abonnement sub_1QdRvT2eZvKYlo2CkW8pQm4L est en retard de paiement. Applique la prochaine étape prévue par notre procédure.
T4-gdprLe ticket 48377 vient d’arriver dans la boîte de réception dédiée à la confidentialité. Prends le relais et effectue toutes les étapes prévues par la procédure.
T5-incidentL’incident PD-99213 vient de se déclencher. Gère l’escalade et les communications.
T6-stale-docsLesquels de nos articles publiés dans le centre d’aide ont dépassé leur date de révision ? Suis les tâches à effectuer.
T7-postmortemL’incident INC-4471 est résolu. Assure le suivi : détermine qui a été affecté, ce qui lui est dû et informe l’entreprise de la situation.
T8-lookupQuel forfait utilise acct_borealis_4c77 et qui est son CSM ?

Évaluation

Déterministe. 59 vérifications réparties sur les huit tâches, chacune portant soit sur un appel d’outil avec des arguments exacts, comme stripe_create_refund(charge="ch_3QRk9X…", amount=14900, reason="duplicate"), soit sur un fait présent uniquement dans un document de compétence : le niveau SLA de 25%, la règle du jour 10, l’équipe PRIV, le délai de 30 jours.

Aucun évaluateur LLM n’intervient. Une exécution qui n’ouvre jamais les documents de compétences échoue mécaniquement aux vérifications du second type. C’est le but : mesurer si « l’agent disposait réellement de la politique », au lieu d’en faire une question d’opinion.

Chaque tâche indique aussi ses chemins de charge utile critiques, c’est-à-dire les champs dont dépend la réponse. Ils ne servent jamais à orienter le filtre. Ils permettent de repérer un filtre trop agressif dans les résultats, même lorsque l’exécution réussit malgré tout.

Les bras

BrasCompétences préchargéesCharge utile filtrée
0nonnon
Aoui, seuil de 0.55non
Bnonoui, seuil de 0.35, état enrichi
Doui, seuil de 0.55oui, seuil de 0.35, état enrichi

8 tâches × 4 bras × 6 répétitions = 192 exécutions, les répétitions ne différant que par le seed.

Étalonnage

Les deux seuils ont été testés hors ligne avant de dépenser le moindre jeton d’agent.

0.55 pour le routage est la valeur la plus élevée qui préserve le rappel complet pour les tâches ayant servi à l’étalonnage. À 0.60, slack-style-guide obtient 0.58 pour la tâche sur les remboursements, et le tour économisé disparaît. Deux centièmes séparent une réduction de 15% du nombre de tours de l’absence de gain.

0.35 pour le filtrage n’est viable que grâce à l’état enrichi décrit plus haut. La passe d’étalonnage coûte environ $0.004, car elle exécute le routeur et le scoreur sans lancer l’agent.

Une leçon généralisable : chaque formulation d’une question nécessite son propre étalonnage. Un seuil ne s’applique pas à deux formulations d’une même question. Des distributions sur des supports complètement différents ont été mesurées pour une formulation propre à une tâche et une autre indépendante de la tâche. Réétalonnez chaque fois que vous reformulez.

Totaux de la campagne

MesureTotal
Exécutions192
Tours de l’agent775
Jetons d’entrée de l’agent2,118,338, dont 1,685,860 (80%) servis depuis le cache
Jetons de sortie de l’agent130,003
Jetons d’entrée de Jev2,065,975
Appels à Jev96 pour le routage + 252 pour le filtrage
Dépenses réellesagent $0.2977 · Jev $0.0868
Total, étalonnage et variantes écartées compris$1.17

Résultats globaux par bras

BrasExécutions parfaitesVérifications réussiesToursJetons d’entréeChemins critiques supprimés
092%99%4.4412,960n/a
A96%99%3.6911,809n/a
B94%99%4.319,9670
D94%99%3.719,3961

Aucune technique n’a dégradé la qualité. 99% des vérifications réussissent dans les quatre bras. Sur les 96 appels filtrés du bras D, un seul chemin déclaré critique a été supprimé, et l’exécution concernée a tout de même réussi. Les écarts entre 92% et 96% d’exécutions « parfaites » par exécution relèvent du bruit, avec n = 48. Les effets robustes portent sur le nombre de tours et de jetons.

Nombre moyen de jetons par exécution, ventilé selon leur facturation réelle :

BrasEntrée non mise en cacheEntrée mise en cacheSortieEntrée Jev
02,94110,0207410
A2,7009,1096151,517
B1,8738,09372319,457
D1,4967,90062922,067

Le bras D réduit de 49% les jetons d’entrée non mis en cache, les plus coûteux.

Économies de jetons d’entrée par technique, de la plus faible à la plus forte

TechniqueMinimumMaximumMédiane
A préchargement des compétences−3% pour la tâche SLA+23% pour la tâche RGPD10%
B filtrage de la charge utile+2% pour la tâche RGPD+51% sur les documents obsolètes17%
D les deux+9% pour le post-mortem+63% sur les documents obsolètes26%

La seule valeur négative de toute la matrice concerne A pour la tâche SLA : le routeur charge une compétence de trop sans supprimer de tour. Cette compétence supplémentaire est ajoutée à l’invite système, puis renvoyée à chaque tour. Les deux techniques ne se cumulent pas toujours non plus : pour les tâches SLA et post-mortem, D économise moins de jetons que B seul, pour exactement la même raison.

Résultats réels du routeur

Probabilité moyenne par compétence et par tâche. Une compétence est chargée si son score est égal ou supérieur à 0.55.

TâcheCompétences chargéesMeilleurs scores
T1-refund2.0refund-policy 0.82 · slack-style-guide 0.60 · incident-comms 0.32
T2-sla2.0enterprise-contract-terms 0.95 · refund-policy 0.84 · churn-save-offers 0.13
T3-dunning1.0dunning-playbook 0.95 · churn-save-offers 0.32 · oncall-handover 0.13
T4-gdpr1.0gdpr-data-requests 0.87 · refund-policy 0.27 · escalation-matrix 0.22
T5-incident3.0escalation-matrix 0.93 · incident-comms 0.85 · slack-style-guide 0.69
T6-stale-docs1.0docs-review-cadence 0.93 · slack-style-guide 0.15 · oncall-handover 0.05
T7-postmortem3.0enterprise-contract-terms 0.92 · refund-policy 0.89 · incident-comms 0.58 · slack-style-guide 0.47
T8-lookup0.0slack-style-guide 0.07 · enterprise-contract-terms 0.06 · dunning-playbook 0.04

Rappel : 132 des 144 compétences nécessaires ont été chargées, soit 92%. Un oubli systématique et un faux positif systématique, qu’il faut signaler clairement.

La compétence slack-style-guide a été oubliée pour la tâche de postmortem : son score est de 0.47, sous le seuil, lors des 12 exécutions sur 12. La tâche demande de « dire à l’entreprise où elle en est », ce que le routeur n’interprète pas comme une question de mise en forme. L’agent l’a récupérée lui-même lorsqu’il en a eu besoin.

Le faux positif concerne refund-policy, avec un score de 0.84 pour la tâche SLA et de 0.89 pour le postmortem. Un crédit SLA ressemble à un remboursement. C’est précisément la confusion que refund-policy est censée éviter, puisque le document précise qu’une indisponibilité du service ne donne pas droit à un remboursement. Le routeur se trompe sur la forme, mais pas sur le fond, et cela n’a pas nui à l’agent.

La tâche de recherche ne charge aucune compétence, à juste titre. Aucune compétence n’est pertinente et le score le plus élevé est de 0.07.

Le fonctionnement réel du filtre

Branche D, par outil, sur 96 appels filtrés :

OutilAppelsCaractères avant → aprèsVariationClés conservées
kb_list_articles8225,024 → 24,834−89%605 / 1,808
stripe_list_charges641,958 → 12,819−69%405 / 1,584
stripe_get_subscription619,086 → 10,637−44%359 / 744
crm_get_account3029,400 → 16,723−43%384 / 1,002
zendesk_get_ticket1225,620 → 15,787−38%328 / 822
statuspage_get_incident915,399 → 10,734−30%311 / 540
pagerduty_get_incident1221,852 → 16,497−25%428 / 684
stripe_create_refund63,012 → 2,610−13%60 / 108
zendesk_reply128,685 → 9,489+9%24 / 84
linear_create_issue185,287 → 6,734+27%83 / 138
billing_apply_credit81,343 → 2,406+79%42 / 56

Les outils de lecture sont ceux qui génèrent les économies, avec des écarts considérables : de −89% pour une liste de documents à −25% pour un incident dont presque tous les éléments sont essentiels.

Les accusés de réception des opérations d’écriture évoluent dans le mauvais sens. billing_apply_credit renvoie 147 caractères, et le marqueur _trimmed ajouté à la réponse coûte plus cher que les champs supprimés. Filtrer un petit contenu entraîne donc une perte nette. Toute mise en œuvre en production devrait ignorer d’emblée les contenus de moins de quelques centaines de caractères. Nous l’avons conservé ici pour que son effet soit visible dans les données.

Toutes les tâches, toutes les branches

Les prix correspondent au coût total d’une exécution, agent et Jev compris, selon la répartition mesurée entre données fraîches et mises en cache. Les colonnes Sonnet 5 et Opus 5 reprennent le trafic mesuré avec les tarifs de ces modèles. Le coût de Jev est identique dans les trois colonnes.

T1-refund, moyenne · contenu mixte

BrancheParfaitVérificationsToursJetons entrantsRéduction du contenu$ Luna$ Sonnet 5$ Opus 5vs 0
0100%100%4.515,369n/a0.001800.01670.0419n/a
A100%100%4.014,247 (−7%)n/a0.001650.01500.0373−11%
B100%100%4.310,719 (−30%)65%0.002850.01410.0331−21%
D100%100%4.09,899 (−36%)66%0.002520.01080.0249−41%

T2-sla, longue · contenu mixte

BrancheParfaitVérificationsToursJetons entrantsRéduction du contenu$ Luna$ Sonnet 5$ Opus 5vs 0
083%96%6.818,811n/a0.001920.01770.0442n/a
A100%100%6.219,359 (+3%)n/a0.001930.01740.0433−2%
B83%96%6.515,528 (−17%)30%0.002860.01730.0417−6%
D83%96%6.016,533 (−12%)72%0.003120.01600.0378−15%

T3-dunning, courte · contenu mixte

BrancheParfaitVérificationsToursJetons entrantsRéduction du contenu$ Luna$ Sonnet 5$ Opus 5vs 0
0100%100%4.08,084n/a0.000800.00750.0187n/a
A100%100%3.06,704 (−17%)n/a0.000790.00690.0171−9%
B100%100%4.07,384 (−9%)44%0.001290.00690.0163−13%
D100%100%3.06,002 (−26%)44%0.001230.00580.0135−28%

T4-gdpr, moyenne · contenu mixte

VarianteParfaitVérificationsToursJetons en entréeCharge utile réduite$ Luna$ Sonnet 5$ Opus 5vs 0
050%94%4.28,344n/a0.001500.01340.0336n/a
A100%100%3.06,467 (−23%)n/a0.001320.01140.0285−15%
B83%98%4.28,167 (−2%)14%0.001860.01290.0315−6%
D83%98%3.06,159 (−26%)16%0.001780.01160.0282−16%

T5-incident, court · charge utile dense

VarianteParfaitVérificationsToursJetons en entréeCharge utile réduite$ Luna$ Sonnet 5$ Opus 5vs 0
0100%100%3.88,647n/a0.001510.01360.0340n/a
A67%96%3.07,004 (−19%)n/a0.001210.01040.0259−24%
B83%98%3.78,153 (−6%)6%0.001680.01270.0313−8%
D83%98%3.06,935 (−20%)5%0.001430.00990.0241−29%

T6-stale-docs, court · charge utile très clairsemée

VarianteParfaitVérificationsToursJetons en entréeCharge utile réduite$ Luna$ Sonnet 5$ Opus 5vs 0
0100%100%4.019,821n/a0.002650.02560.0639n/a
A100%100%3.018,468 (−7%)n/a0.002600.02460.0614−4%
B100%100%4.09,639 (−51%)78%0.002620.01390.0329−49%
D100%100%3.07,387 (−63%)84%0.002350.01090.0252−61%

T7-postmortem, très long · charge utile mixte

VarianteParfaitVérificationsToursJetons en entréeCharge utile réduite$ Luna$ Sonnet 5$ Opus 5vs 0
0100%100%6.021,294n/a0.004060.03630.0906n/a
A100%100%5.319,224 (−10%)n/a0.003390.02970.0743−18%
B100%100%5.717,064 (−20%)34%0.004880.03430.0841−7%
D100%100%5.719,430 (−9%)33%0.004720.03240.0792−13%

T8-lookup, un seul appel · charge utile clairsemée

VarianteParfaitVérificationsToursJetons en entréeCharge utile réduite$ Luna$ Sonnet 5$ Opus 5vs 0
0100%100%2.23,314n/a0.000360.00330.0083n/a
A100%100%2.03,004 (−9%)n/a0.000380.00300.0073−12%
B100%100%2.23,080 (−7%)62%0.000470.00260.0062−24%
D100%100%2.02,819 (−15%)62%0.000560.00290.0068−17%

Calcul des prix

On mesure une fois, puis on recalcule les prix. Le nombre de jetons sert de référence, et la facture de chaque modèle correspond à ces mêmes quantités, appliquées à ses tarifs.

La formule de facturation a été reconstituée à partir des données, plutôt que supposée. Sur l’ensemble des 192 exécutions, le coût observé de l’agent correspond

fresh_input × $0.25/M  +  cached_input × $0.02/M  +  output × $1.20/M

à une erreur relative médiane de 0.04%. Deux conséquences. La mise en cache des prompts était activée en permanence, automatiquement, sans marqueurs cache_control, et 80% des jetons en entrée provenaient de lectures du cache. De plus, chaque jeton d’entrée non mis en cache est facturé au tarif d’écriture du cache, soit 1.25× le prix nominal d’entrée. Ainsi, dans une boucle à plusieurs tours, le tarif nominal de $0.20/M est pratiquement toujours différent du prix payé.

Un modèle théorique antérieur du cache, selon lequel les lectures au tour t correspondent au préfixe du tour t−1, sous-estimait de 19% les lectures réelles du cache. Il a été abandonné au profit de la répartition mesurée pour chaque tour.

ModèleEntréeSortieLecture du cacheÉcriture dans le cache
openai/gpt-5.6-luna$0.20/M$1.20/M$0.02/M$0.25/M
anthropic/claude-sonnet-5$2.00/M$10.00/M$0.20/M$2.50/M
anthropic/claude-opus-5$5.00/M$25.00/M$0.50/M$6.25/M
typesafe/jev-1.13$0.042/Mgratuitn/an/a
VarianteLunaSonnet 5Opus 5Part de Jev, Opus 5
0$0.00182$0.01676$0.04191n/a
A$0.00166 (−9%)$0.01479 (−12%)$0.03688 (−12%)0%
B$0.00232 (+27%)$0.01435 (−14%)$0.03466 (−17%)2%
D$0.00221 (+21%)$0.01253 (−25%)$0.02995 (−29%)3%

À titre de référence, les mêmes exécutions sans aucune mise en cache :

VarianteLunaSonnet 5Opus 5
0$0.00348$0.03333$0.08332
A$0.00316$0.02984$0.07450
B$0.00368$0.02798$0.06874
D$0.00356$0.02601$0.06362

Une hypothèse est prudente plutôt que neutre. OpenAI met automatiquement en cache et facture chaque jeton d’entrée non mis en cache au tarif d’écriture, comme l’ont montré les mesures. La mise en cache chez Anthropic est facultative : seul le contenu situé dans un point de contrôle cache_control est facturé au tarif d’écriture, le reste étant facturé au tarif d’entrée standard. Facturer tous les jetons non mis en cache au tarif d’écriture surestime donc légèrement les colonnes Anthropic. En recalculant avec les jetons non mis en cache au tarif d’entrée standard, la moyenne d’Opus 5 passe de $0.04191 → $0.02995 (−29%) à $0.03823 → $0.02808 (−27%), et aucun chiffre par tâche ne varie de plus de 3 points.

Ce que ces résultats ne montrent pas

  • Un seul modèle d’agent. Toutes les mesures portent sur openai/gpt-5.6-luna avec le niveau de raisonnement par défaut. Les nombres de jetons sont les données mesurées, et les colonnes de prix sont calculées à partir de ceux-ci. Un autre modèle produirait des nombres de jetons différents, et pas seulement des prix différents.
  • n = 6 par cellule. C’est suffisant pour les nombres de tours et de jetons, qui sont presque déterministes. Ce n’est pas suffisant pour distinguer une qualité de 92 % d’une qualité de 96 %.
  • Des jeux de données de test, pas des API en direct. Les structures des charges utiles sont fidèles. Les véritables points de terminaison impliquent pagination, échecs partiels et limites de débit, que ce banc de test ne couvre pas.
  • Les tâches ont été conçues par la même personne que les compétences. L’évaluation est déterministe, mais le monde, lui, n’est pas adversarial.
  • La propre calibration de Jev n’a pas été auditée. La mesure porte sur l’effet de ses scores sur un agent, et non sur leur calibration au sens statistique.
  • Une seule architecture d’agent. Une boucle while avec appels de fonctions. Les sous-agents, les appels d’outils parallèles et les sessions de longue durée modifient tous les calculs.

Sources