Jev a réduit de 61% le coût de cet agent IA
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.
Coût moyen d’une exécution d’agent avec Opus 5
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ément | Valeur |
|---|---|
| Prix | $0.042 par million de jetons en entrée, sortie gratuite |
| Contexte | 32,000 jetons |
| Latence mesurée ici | 300 à 600 ms, p50, quelle que soit la taille du lot |
| Point de terminaison | POST /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.
Étape 1 · demande de l’utilisateur
Étape 2 · Jev évalue les 11 compétences à la fois, en ne lisant que leur description d’une ligne
Un appel HTTP, 11 questions, environ 1,500 jetons, $0.00006. Avec un seuil de 0.55, une compétence est sélectionnée.
Étape 3 · le prompt reçu par l’agent dès son tout premier tour
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é.
Étape 1 · l’agent appelle un outil et l’API renvoie toute la réponse
Étape 2 · ce que Jev sait de la situation, au-delà de la seule charge utile
Étape 3 · un appel, un score par champ. En dessous de 0.35, le champ est barré
Sur les six exécutions de cette tâche, 58 à 62 des 124 champs ont été conservés. Les trois champs nécessaires à la tâche (status, dunning.days_past_due, account.id) l’ont été lors des six exécutions.
Étape 4 · ce qui entre dans la fenêtre de contexte de l’agent
De 3,181 caractères à environ 1,780, soit une réduction de 44 %. Et aucun des champs supprimés ne revient non plus aux tours 3, 4 et 5.
À 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’état | account.id | metadata.account_id | Conservés |
|---|---|---|---|
| requête + outil + arguments | 0.18 | 0.20 | 51 / 124 |
| + les règles suivies | 0.19 | 0.18 | 50 / 124 |
| + les actions déjà effectuées | 0.33 | 0.25 | 40 / 124 |
| + les outils encore disponibles | 0.73 | 0.76 | 27 / 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.
Le préchargement cible les tours qu’on peut supprimerPas la taille de la charge utile
- Idéal pour une tâche qui nécessite une règle et consacrerait un tour à aller la chercher
- Aucun intérêt pour une tâche qui n’a besoin d’aucune compétence
- Peut avoir un effet négatif : une compétence chargée à tort est renvoyée à chaque tour
Le filtrage cible la densité de la charge utilePas la durée de la tâche
- Idéal lorsque la plupart des octets correspondent à du texte que personne ne lit
- Presque aucun gain lorsque chaque champ est indispensable
- L’effet s’accumule : un champ supprimé n’est pas renvoyé au tour suivant
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âche | Profil | Seul | Les deux | Gain |
|---|---|---|---|---|
| docs obsolètes | courte · charge utile très clairsemée | $0.0639 | $0.0252 | −61% |
| remboursement | moyenne · mixte | $0.0419 | $0.0249 | −41% |
| incident | courte · dense | $0.0340 | $0.0241 | −29% |
| relance | courte · mixte | $0.0187 | $0.0135 | −28% |
| recherche | un appel · clairsemée | $0.0083 | $0.0068 | −17% |
| gdpr | moyenne · mixte | $0.0336 | $0.0282 | −16% |
| sla | longue · mixte | $0.0442 | $0.0378 | −15% |
| post-mortem | trè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’agent | Tarif des entrées | Agent sans mécanisme | Les 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 :
- 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.
- Si la réponse contient des
tool_calls, exécuter chacun localement, ajouter le résultat comme messagerole: "tool", puis relancer la boucle. - Si la réponse ne contient pas de
tool_calls, le texte constitue la réponse finale et la boucle s’arrête.
| Paramètre | Valeur | Remarque |
|---|---|---|
model | openai/gpt-5.6-luna | $0.20/M en entrée, $1.20/M en sortie, contexte de 1,050,000 tokens |
tools | 17 schémas de fonctions | |
tool_choice | auto | l’agent décide s’il doit appeler un outil et lequel |
seed | 1000 + repetition index | le seul paramètre modifié d’une répétition à l’autre |
max_tokens | 2000 | un plafond, pas un objectif |
reasoning / reasoning_effort | non définis | valeur par défaut du fournisseur |
temperature, top_p | non définis | valeur 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.
| Outil | Modélisé d’après | Charge utile |
|---|---|---|
kb_list_articles | point de terminaison de liste d’un CMS de centre d’aide | 28,128 caractères |
stripe_list_charges | Stripe GET /v1/charges | 6,993 caractères |
kb_get_article | point de terminaison de lecture d’un CMS de centre d’aide | 4,966 caractères |
stripe_get_subscription | Stripe GET /v1/subscriptions/:id | 3,181 caractères |
zendesk_get_ticket | Zendesk GET /api/v2/tickets/:id avec chargements associés | 2,402 caractères |
pagerduty_get_incident | PagerDuty GET /incidents/:id | 1,821 caractères |
statuspage_get_incident | Incident et disponibilité Statuspage | 1,711 caractères |
crm_get_account | Objet entreprise HubSpot | 1,117 caractères |
read_skill | interne | 988 caractères |
stripe_create_refund | Stripe POST /v1/refunds | 479 caractères |
linear_create_issue | Linear issueCreate | 202 caractères |
billing_apply_credit | API de facturation interne | 147 caractères |
zendesk_reply | Zendesk PUT /api/v2/tickets/:id | 144 caractères |
billing_set_account_state | API de facturation interne | 134 caractères |
slack_post_message | Slack chat.postMessage | 124 caractères |
billing_apply_discount | API de facturation interne | 98 caractères |
pagerduty_escalate | Escalade PagerDuty | 92 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âche | Invite envoyée comme message utilisateur |
|---|---|
T1-refund | ACME 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-sla | Le 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-dunning | L’abonnement sub_1QdRvT2eZvKYlo2CkW8pQm4L est en retard de paiement. Applique la prochaine étape prévue par notre procédure. |
T4-gdpr | Le 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-incident | L’incident PD-99213 vient de se déclencher. Gère l’escalade et les communications. |
T6-stale-docs | Lesquels de nos articles publiés dans le centre d’aide ont dépassé leur date de révision ? Suis les tâches à effectuer. |
T7-postmortem | L’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-lookup | Quel 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
| Bras | Compétences préchargées | Charge utile filtrée |
|---|---|---|
0 | non | non |
A | oui, seuil de 0.55 | non |
B | non | oui, seuil de 0.35, état enrichi |
D | oui, seuil de 0.55 | oui, 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
| Mesure | Total |
|---|---|
| Exécutions | 192 |
| Tours de l’agent | 775 |
| Jetons d’entrée de l’agent | 2,118,338, dont 1,685,860 (80%) servis depuis le cache |
| Jetons de sortie de l’agent | 130,003 |
| Jetons d’entrée de Jev | 2,065,975 |
| Appels à Jev | 96 pour le routage + 252 pour le filtrage |
| Dépenses réelles | agent $0.2977 · Jev $0.0868 |
| Total, étalonnage et variantes écartées compris | $1.17 |
Résultats globaux par bras
| Bras | Exécutions parfaites | Vérifications réussies | Tours | Jetons d’entrée | Chemins critiques supprimés |
|---|---|---|---|---|---|
0 | 92% | 99% | 4.44 | 12,960 | n/a |
A | 96% | 99% | 3.69 | 11,809 | n/a |
B | 94% | 99% | 4.31 | 9,967 | 0 |
D | 94% | 99% | 3.71 | 9,396 | 1 |
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 :
| Bras | Entrée non mise en cache | Entrée mise en cache | Sortie | Entrée Jev |
|---|---|---|---|---|
0 | 2,941 | 10,020 | 741 | 0 |
A | 2,700 | 9,109 | 615 | 1,517 |
B | 1,873 | 8,093 | 723 | 19,457 |
D | 1,496 | 7,900 | 629 | 22,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
| Technique | Minimum | Maximum | Médiane |
|---|---|---|---|
A préchargement des compétences | −3% pour la tâche SLA | +23% pour la tâche RGPD | 10% |
B filtrage de la charge utile | +2% pour la tâche RGPD | +51% sur les documents obsolètes | 17% |
D les deux | +9% pour le post-mortem | +63% sur les documents obsolètes | 26% |
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âche | Compétences chargées | Meilleurs scores |
|---|---|---|
T1-refund | 2.0 | refund-policy 0.82 · slack-style-guide 0.60 · incident-comms 0.32 |
T2-sla | 2.0 | enterprise-contract-terms 0.95 · refund-policy 0.84 · churn-save-offers 0.13 |
T3-dunning | 1.0 | dunning-playbook 0.95 · churn-save-offers 0.32 · oncall-handover 0.13 |
T4-gdpr | 1.0 | gdpr-data-requests 0.87 · refund-policy 0.27 · escalation-matrix 0.22 |
T5-incident | 3.0 | escalation-matrix 0.93 · incident-comms 0.85 · slack-style-guide 0.69 |
T6-stale-docs | 1.0 | docs-review-cadence 0.93 · slack-style-guide 0.15 · oncall-handover 0.05 |
T7-postmortem | 3.0 | enterprise-contract-terms 0.92 · refund-policy 0.89 · incident-comms 0.58 · slack-style-guide 0.47 |
T8-lookup | 0.0 | slack-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 :
| Outil | Appels | Caractères avant → après | Variation | Clés conservées |
|---|---|---|---|---|
kb_list_articles | 8 | 225,024 → 24,834 | −89% | 605 / 1,808 |
stripe_list_charges | 6 | 41,958 → 12,819 | −69% | 405 / 1,584 |
stripe_get_subscription | 6 | 19,086 → 10,637 | −44% | 359 / 744 |
crm_get_account | 30 | 29,400 → 16,723 | −43% | 384 / 1,002 |
zendesk_get_ticket | 12 | 25,620 → 15,787 | −38% | 328 / 822 |
statuspage_get_incident | 9 | 15,399 → 10,734 | −30% | 311 / 540 |
pagerduty_get_incident | 12 | 21,852 → 16,497 | −25% | 428 / 684 |
stripe_create_refund | 6 | 3,012 → 2,610 | −13% | 60 / 108 |
zendesk_reply | 12 | 8,685 → 9,489 | +9% | 24 / 84 |
linear_create_issue | 18 | 5,287 → 6,734 | +27% | 83 / 138 |
billing_apply_credit | 8 | 1,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
| Branche | Parfait | Vérifications | Tours | Jetons entrants | Réduction du contenu | $ Luna | $ Sonnet 5 | $ Opus 5 | vs 0 |
|---|---|---|---|---|---|---|---|---|---|
0 | 100% | 100% | 4.5 | 15,369 | n/a | 0.00180 | 0.0167 | 0.0419 | n/a |
A | 100% | 100% | 4.0 | 14,247 (−7%) | n/a | 0.00165 | 0.0150 | 0.0373 | −11% |
B | 100% | 100% | 4.3 | 10,719 (−30%) | 65% | 0.00285 | 0.0141 | 0.0331 | −21% |
D | 100% | 100% | 4.0 | 9,899 (−36%) | 66% | 0.00252 | 0.0108 | 0.0249 | −41% |
T2-sla, longue · contenu mixte
| Branche | Parfait | Vérifications | Tours | Jetons entrants | Réduction du contenu | $ Luna | $ Sonnet 5 | $ Opus 5 | vs 0 |
|---|---|---|---|---|---|---|---|---|---|
0 | 83% | 96% | 6.8 | 18,811 | n/a | 0.00192 | 0.0177 | 0.0442 | n/a |
A | 100% | 100% | 6.2 | 19,359 (+3%) | n/a | 0.00193 | 0.0174 | 0.0433 | −2% |
B | 83% | 96% | 6.5 | 15,528 (−17%) | 30% | 0.00286 | 0.0173 | 0.0417 | −6% |
D | 83% | 96% | 6.0 | 16,533 (−12%) | 72% | 0.00312 | 0.0160 | 0.0378 | −15% |
T3-dunning, courte · contenu mixte
| Branche | Parfait | Vérifications | Tours | Jetons entrants | Réduction du contenu | $ Luna | $ Sonnet 5 | $ Opus 5 | vs 0 |
|---|---|---|---|---|---|---|---|---|---|
0 | 100% | 100% | 4.0 | 8,084 | n/a | 0.00080 | 0.0075 | 0.0187 | n/a |
A | 100% | 100% | 3.0 | 6,704 (−17%) | n/a | 0.00079 | 0.0069 | 0.0171 | −9% |
B | 100% | 100% | 4.0 | 7,384 (−9%) | 44% | 0.00129 | 0.0069 | 0.0163 | −13% |
D | 100% | 100% | 3.0 | 6,002 (−26%) | 44% | 0.00123 | 0.0058 | 0.0135 | −28% |
T4-gdpr, moyenne · contenu mixte
| Variante | Parfait | Vérifications | Tours | Jetons en entrée | Charge utile réduite | $ Luna | $ Sonnet 5 | $ Opus 5 | vs 0 |
|---|---|---|---|---|---|---|---|---|---|
0 | 50% | 94% | 4.2 | 8,344 | n/a | 0.00150 | 0.0134 | 0.0336 | n/a |
A | 100% | 100% | 3.0 | 6,467 (−23%) | n/a | 0.00132 | 0.0114 | 0.0285 | −15% |
B | 83% | 98% | 4.2 | 8,167 (−2%) | 14% | 0.00186 | 0.0129 | 0.0315 | −6% |
D | 83% | 98% | 3.0 | 6,159 (−26%) | 16% | 0.00178 | 0.0116 | 0.0282 | −16% |
T5-incident, court · charge utile dense
| Variante | Parfait | Vérifications | Tours | Jetons en entrée | Charge utile réduite | $ Luna | $ Sonnet 5 | $ Opus 5 | vs 0 |
|---|---|---|---|---|---|---|---|---|---|
0 | 100% | 100% | 3.8 | 8,647 | n/a | 0.00151 | 0.0136 | 0.0340 | n/a |
A | 67% | 96% | 3.0 | 7,004 (−19%) | n/a | 0.00121 | 0.0104 | 0.0259 | −24% |
B | 83% | 98% | 3.7 | 8,153 (−6%) | 6% | 0.00168 | 0.0127 | 0.0313 | −8% |
D | 83% | 98% | 3.0 | 6,935 (−20%) | 5% | 0.00143 | 0.0099 | 0.0241 | −29% |
T6-stale-docs, court · charge utile très clairsemée
| Variante | Parfait | Vérifications | Tours | Jetons en entrée | Charge utile réduite | $ Luna | $ Sonnet 5 | $ Opus 5 | vs 0 |
|---|---|---|---|---|---|---|---|---|---|
0 | 100% | 100% | 4.0 | 19,821 | n/a | 0.00265 | 0.0256 | 0.0639 | n/a |
A | 100% | 100% | 3.0 | 18,468 (−7%) | n/a | 0.00260 | 0.0246 | 0.0614 | −4% |
B | 100% | 100% | 4.0 | 9,639 (−51%) | 78% | 0.00262 | 0.0139 | 0.0329 | −49% |
D | 100% | 100% | 3.0 | 7,387 (−63%) | 84% | 0.00235 | 0.0109 | 0.0252 | −61% |
T7-postmortem, très long · charge utile mixte
| Variante | Parfait | Vérifications | Tours | Jetons en entrée | Charge utile réduite | $ Luna | $ Sonnet 5 | $ Opus 5 | vs 0 |
|---|---|---|---|---|---|---|---|---|---|
0 | 100% | 100% | 6.0 | 21,294 | n/a | 0.00406 | 0.0363 | 0.0906 | n/a |
A | 100% | 100% | 5.3 | 19,224 (−10%) | n/a | 0.00339 | 0.0297 | 0.0743 | −18% |
B | 100% | 100% | 5.7 | 17,064 (−20%) | 34% | 0.00488 | 0.0343 | 0.0841 | −7% |
D | 100% | 100% | 5.7 | 19,430 (−9%) | 33% | 0.00472 | 0.0324 | 0.0792 | −13% |
T8-lookup, un seul appel · charge utile clairsemée
| Variante | Parfait | Vérifications | Tours | Jetons en entrée | Charge utile réduite | $ Luna | $ Sonnet 5 | $ Opus 5 | vs 0 |
|---|---|---|---|---|---|---|---|---|---|
0 | 100% | 100% | 2.2 | 3,314 | n/a | 0.00036 | 0.0033 | 0.0083 | n/a |
A | 100% | 100% | 2.0 | 3,004 (−9%) | n/a | 0.00038 | 0.0030 | 0.0073 | −12% |
B | 100% | 100% | 2.2 | 3,080 (−7%) | 62% | 0.00047 | 0.0026 | 0.0062 | −24% |
D | 100% | 100% | 2.0 | 2,819 (−15%) | 62% | 0.00056 | 0.0029 | 0.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èle | Entrée | Sortie | Lecture 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/M | gratuit | n/a | n/a |
| Variante | Luna | Sonnet 5 | Opus 5 | Part de Jev, Opus 5 |
|---|---|---|---|---|
0 | $0.00182 | $0.01676 | $0.04191 | n/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 :
| Variante | Luna | Sonnet 5 | Opus 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-lunaavec 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
whileavec appels de fonctions. Les sous-agents, les appels d’outils parallèles et les sessions de longue durée modifient tous les calculs.

