Notre banc A/B, en public. Mesurez-nous.
Nous publions chaque exécution : quatre batteries sur des jeux de données publics, 10 modèles, et les deux bras mesurés avec le compteur d'usage du fournisseur lui-même. Chaque chiffre porte son n, son intervalle et sa date. Ce qui ne fait pas économiser est là aussi.
- batteries
- 4
- modèles testés
- 10
- modèles avec une mesure
- 10
- rapports en direct
- 15
- dernière exécution
- 29 sept. 2026
Ce qui est mesuré, et comment
- Deux bras, la même requête. A va directement au fournisseur, sans la couche ; B passe par la couche avec sa configuration par défaut. Même prompt, même échantillonnage, même plafond de sortie.
- Le coût est compté par le fournisseur. Chaque bras est valorisé à partir de l<code>usage</code> que lAPI renvoie à chaque appel, au prix catalogue. L'économie est 1 − coût(B) / coût(A) de la même exécution, pas ce que la couche dit d'elle-même.
- Intervalles au 95 %. Chaque harnais les calcule (rééchantillonnage par familles de questions, Wilson pour les taux de refus). Un intervalle qui traverse zéro veut dire « indiscernable de zéro », et nous le disons.
- Le paquet que vous installez. Le bras B exécute la source du tag 0.4.31 ; son
dist/index.jsest identique octet pour octet à celui du tarball npm (sha256b52f99cacf9804ecd3153e56f26ec3adcdc2510d52a8446a369ecf914e0b5731). - Pas de raccourcis. Chaque harnais surveille les hôtes auxquels il parle et porte un plafond de dépense par modèle écrit dans le code. Un modèle qui n'a pas pu être mesuré apparaît comme « non mesuré », avec le motif.
Quatre batteries, jeux de données publics, figés
| Batterie | Ce qui est vérifié | Jeu de données | Fichiers figés | Licence |
|---|---|---|---|---|
| GSM8K | Problèmes de mathématiques avec répétitions et paraphrases : combien le cache fait économiser et si l'exactitude baisse. | openai/grade-school-mathcommit 3101c7d5072418e28b9008a6636bde82a006892c | gsm8k-test sha256 3730d312f6e3440559ace48831e51066acaca737f6eabec99bccb9e4b3c39d14gsm8k-trainsha256 17f347dc51477c50d4efb83959dbb7c56297aba886e5544ee2aaed3024813465 | MIT |
| BFCL | Appels d'outils : la couche ne doit en changer aucun, et le catalogue entier doit arriver. | ShishirPatil/gorillacommit f7cf7359b7ac615a0b294831c5ba2bc95ee4a000 | figé par commit | Apache-2.0 |
| XSTest | Refus : la couche ne doit pas changer quand le modèle refuse, ni servir un refus depuis le cache. | paul-rottger/exaggerated-safetycommit d7bb5bd738c1fcbc36edd83d5e7d1b71a3e2d84d | xstest_prompts.csv sha256 11783fb294ed017473ee53c207d71f2161c7672c8d0b037501e78387f801cb5a | CC-BY-4.0 |
| MT-Bench | Chat en deux tours sans répétitions : la couche ne doit pas dégrader le coût, la latence ni la qualité. | lm-sys/FastChatcommit 587d5cfa1609a43d192cedb8441cac3c17db105d | question.jsonl sha256 119565adbab82227089cefdb44c8d7e2cf04dc0a0ec233634c82e7d4e2a944f7gpt-4.jsonlsha256 f957a5bc977badb66885ec970e6cd08527845780313f0995764260e5777b9b3fjudge_prompts.jsonlsha256 fd283293406d024f44c174b094ef48031d0687a4682fd3a56b29b138f80281b6 | Apache-2.0 |
Économie mesurée par modèle
GSM8K, avec un flux de requêtes où 30 % sont des répétitions exactes et 20 % des paraphrases. C'est la batterie au trafic répété : votre économie dépend de la répétitivité du vôtre. Sans répétitions, voir « Ce qui ne fait pas économiser ».
| Modèle | n | Économie mesurée [IC] | Depuis le cache exact | Dans les appels (préfixe) | Exactitude A → B | Version · date |
|---|---|---|---|---|---|---|
openai/gpt-4o-mini | 200 requêtes · 100 uniques | 31,5 % [25,7 % – 36,7 %] | 0,0124 $US | 0,0006 $US | 95,0 % → 96,1 %Δ +1,1 pp [0,0, +2,8] | 0.4.31 · 28 sept. 2026 |
openai/gpt-5.4-mini | 176 requêtes · 88 uniques | 31,7 % [25,6 % – 37,6 %] | 0,0734 $US | 0,0003 $US | 95,6 % → 93,7 %Δ -1,9 pp [-5,0, 0,0] | 0.4.31 · 28 sept. 2026 |
openai/gpt-5.5 | 22 requêtes · 11 uniques | 33,4 % [6,8 % – 53,8 %] | 0,0790 $US | -0,0023 $US | 100,0 % → 100,0 %Δ 0,0 pp [0,0, 0,0] | 0.4.31 · 28 sept. 2026 |
openai/gpt-5.6-sol | 32 requêtes · 16 uniques | 29,2 % [9,5 % – 46,8 %] | 0,0252 $US | -0,0003 $US | 100,0 % → 100,0 %Δ 0,0 pp [0,0, 0,0] | 0.4.31 · 28 sept. 2026 |
anthropic/claude-haiku-4-5 | 116 requêtes · 58 uniques | 32,2 % [23,6 % – 40,2 %] | 0,0773 $US | 0,0002 $US | 99,0 % → 99,0 %Δ 0,0 pp [0,0, 0,0] | 0.4.31 · 28 sept. 2026 |
anthropic/claude-opus-5-5 | 32 requêtes · 16 uniques | 77,2 % [67,1 % – 83,9 %] | 0,0974 $US | 0,1391 $US | 100,0 % → 100,0 %Δ 0,0 pp [0,0, 0,0] | 0.4.31 · 28 sept. 2026 |
anthropic/claude-sonnet-5 | 62 requêtes · 31 uniques | 75,1 % [69,3 % – 79,6 %] | 0,1054 $US | 0,1313 $US | 100,0 % → 100,0 %Δ 0,0 pp [0,0, 0,0] | 0.4.31 · 28 sept. 2026 |
anthropic/claude-sonnet-5-5 | 62 requêtes · 31 uniques | 77,5 % [72,0 % – 81,7 %] | 0,0924 $US | 0,1289 $US | 100,0 % → 100,0 %Δ 0,0 pp [0,0, 0,0] | 0.4.31 · 28 sept. 2026 |
google/gemini-3.1-pro-preview | la couche a échoué : les requêtes ne sont pas passées par la couche | 0.4.31 · 28 sept. 2026 | ||||
google/gemini-3.8-flash | la couche a échoué : les requêtes ne sont pas passées par la couche | 0.4.31 · 28 sept. 2026 | ||||
D'où vient l'économie, position par position : « depuis le cache exact » est ce que A a payé sur les requêtes que la couche a servies sans appeler le fournisseur ; « dans les appels » est la différence sur celles qui l'ont effectivement atteint, surtout le cache de préfixe du fournisseur (plus une part de variation de la sortie). Les deux s'additionnent pour donner l'économie totale.
L'exactitude est mesurée sur les questions avec une réponse publiée ; les variantes avec un nombre modifié servent uniquement à vérifier que la couche ne renvoie jamais la réponse d'une autre question.
Garanties, comptées
La couche n'a jamais changé un appel d'outil
0 appels modifiés sur 1 325 comparaisons BFCL, 6 modèles, depuis 0.4.31. Si la couche échoue (une erreur en B que A n'avait pas), ce n'est pas compté ici : c'est sous « Bugs trouvés par le banc ».
Aucune réponse d'une autre question depuis 0.4.31
0 variantes sur 198 (la même question avec un autre nombre, donc une autre réponse) servies avec la réponse d'une autre question, sur 8 modèles en direct et toutes les configurations de cache mesurées.
Rejeu hors ligne de tout le split de test GSM8K : 0 sur 5 813 requêtes, dans chacune des 5 configurations de cache.
Le même taux de refus, avec et sans la couche
XSTest, 10 modèles mesurés : aucune différence A/B en dessous de p = 0,05 (McNemar, prompts appariés). La couche a livré sans altération le texte de 4 668 réponses (0 altérées).
| Modèle | Prompts | Refus, prompts sûrs (A → B) | Refus, prompts dangereux (A → B) | Version · date |
|---|---|---|---|---|
openai/gpt-4o-mini | 450 | 5,2 % → 5,2 % (n = 250, p = 1,00) | 81,5 % → 81,5 % (n = 200, p = 1,00) | 0.4.31 · 28 sept. 2026 |
openai/gpt-5.4-mini | 441 | 11,0 % → 9,8 % (n = 245, p = 0,63) | 87,2 % → 86,7 % (n = 196, p = 1,00) | 0.4.31 · 28 sept. 2026 |
openai/gpt-5.5 | 120 | 6,3 % → 4,7 % (n = 64, p = 1,00) | 80,0 % → 80,0 % (n = 55, p = 1,00) | 0.4.31 · 29 sept. 2026 |
openai/gpt-5.6-sol | 199 | 2,7 % → 2,7 % (n = 111, p = 1,00) | 75,6 % → 76,7 % (n = 86, p = 1,00) | 0.4.31 · 29 sept. 2026 |
anthropic/claude-haiku-4-5 | 450 | 1,6 % → 2,0 % (n = 250, p = 1,00) | 42,5 % → 42,5 % (n = 200, p = 1,00) | 0.4.31 · 29 sept. 2026 |
anthropic/claude-opus-5-5 | 81 | — | 67,1 % → 67,1 % (n = 79, p = 1,00) | 0.4.31 · 29 sept. 2026 |
anthropic/claude-sonnet-5 | 264 | 2,7 % → 2,0 % (n = 147, p = 1,00) | 68,4 % → 71,8 % (n = 117, p = 0,34) | 0.4.31 · 29 sept. 2026 |
anthropic/claude-sonnet-5-5 | 311 | 1,5 % → 0,0 % (n = 135, p = 0,50) | 64,3 % → 65,3 % (n = 98, p = 1,00) | 0.4.31 · 29 sept. 2026 |
google/gemini-3.1-pro-preview | 58 | 0,0 % → 0,0 % (n = 32, p = 1,00) | 80,8 % → 84,6 % (n = 26, p = 1,00) | 0.4.31 · 29 sept. 2026 |
google/gemini-3.8-flash | 450 | 0,4 % → 0,4 % (n = 249, p = 1,00) | 67,8 % → 66,8 % (n = 199, p = 0,73) | 0.4.31 · 29 sept. 2026 |
Ce qui ne fait pas économiser
Sans répétitions, l'économie est ≈ 0 %. Nous le publions quand même, parce que c'est ce que vous verrez si votre trafic ne se répète pas.
MT-Bench est un chat en deux tours avec une couche neuve à chaque question : il n'y a rien que le cache puisse réutiliser, et le prompt n'atteint presque jamais le minimum requis par le fournisseur pour mettre un préfixe en cache. Dans BFCL, chaque appel d'outil est différent. Ce que ces deux batteries mesurent, c'est que la couche ne dégrade rien ; la différence de coût restante est du bruit dans la sortie du modèle, pas la couche.
| Batterie | Modèle | n | Économie mesurée [IC] | Lecture | Version · date |
|---|---|---|---|---|---|
| BFCL | openai/gpt-4o-mini | 400 éléments | 0,1 % [0,0 % – 0,3 %] | indiscernable de zéro | 0.4.31 · 28 sept. 2026 |
| BFCL | openai/gpt-5.4-mini | 400 éléments | -0,2 % [-1,0 % – 0,5 %] | indiscernable de zéro | 0.4.31 · 28 sept. 2026 |
| BFCL | anthropic/claude-haiku-4-5 | 48 éléments | 0,1 % [0,0 % – 0,2 %] | indiscernable de zéro | 0.4.31 · 29 sept. 2026 |
| BFCL | anthropic/claude-sonnet-5 | 48 éléments | 1,5 % [-1,6 % – 5,8 %] | indiscernable de zéro | 0.4.31 · 29 sept. 2026 |
| BFCL | google/gemini-3.1-pro-preview | 97 éléments | 4,8 % [-6,6 % – 15,6 %] | indiscernable de zéro | 0.4.31 · 29 sept. 2026 |
| BFCL | google/gemini-3.8-flash | 324 éléments | -10,7 % [-27,8 % – 3,2 %] | indiscernable de zéro | 0.4.31 · 29 sept. 2026 |
| MT-Bench | openai/gpt-4o-mini | 80 questions | 3,3 % [0,8 % – 6,0 %] | économie · non attribuable à la couche | 0.4.31 · 28 sept. 2026 |
| MT-Bench | openai/gpt-5.4-mini | 80 questions | -3,5 % [-8,6 % – 1,6 %] | indiscernable de zéro · non attribuable à la couche | 0.4.31 · 28 sept. 2026 |
| MT-Bench | openai/gpt-5.5 | 8 questions | 2,1 % [-4,4 % – 9,7 %] | indiscernable de zéro | 0.4.31 · 29 sept. 2026 |
| MT-Bench | openai/gpt-5.6-sol | 13 questions | -0,4 % [-21,2 % – 13,5 %] | indiscernable de zéro · non attribuable à la couche | 0.4.31 · 29 sept. 2026 |
| MT-Bench | anthropic/claude-haiku-4-5 | 80 questions | -2,6 % [-4,6 % – -0,9 %] | surcoût · non attribuable à la couche | 0.4.31 · 28 sept. 2026 |
| MT-Bench | anthropic/claude-opus-5-5 | 18 questions | 1,1 % [-2,0 % – 4,9 %] | indiscernable de zéro | 0.4.31 · 29 sept. 2026 |
| MT-Bench | anthropic/claude-sonnet-5 | 23 questions | 1,7 % [-8,9 % – 12,7 %] | indiscernable de zéro | 0.4.31 · 28 sept. 2026 |
| MT-Bench | anthropic/claude-sonnet-5-5 | 37 questions | -0,8 % [-2,5 % – 0,9 %] | indiscernable de zéro | 0.4.31 · 29 sept. 2026 |
État par modèle et batterie
Chaque cellule montre l'exécution sur la version la plus haute de la couche. Si un modèle n'a pas pu être mesuré, nous disons pourquoi plutôt que de laisser un vide.
| Modèle | GSM8K | BFCL | XSTest | MT-Bench |
|---|---|---|---|---|
openai/gpt-4o-mini | mesuré · n = 200 0.4.31 · 28 sept. 2026 | mesuré · n = 400 0.4.31 · 28 sept. 2026 | mesuré · n = 450 0.4.31 · 28 sept. 2026 | mesuré · n = 80 0.4.31 · 28 sept. 2026 |
openai/gpt-5.4-mini | mesuré · n = 176 0.4.31 · 28 sept. 2026 | mesuré · n = 400 0.4.31 · 28 sept. 2026 | mesuré · n = 441 0.4.31 · 28 sept. 2026 | mesuré · n = 80 0.4.31 · 28 sept. 2026 |
openai/gpt-5.5 | mesuré · n = 22 0.4.31 · 28 sept. 2026 | non mesuré : plafond de dépense épuisé 0.4.31 · 29 sept. 2026 | mesuré · n = 120 0.4.31 · 29 sept. 2026 | mesuré · n = 8 0.4.31 · 29 sept. 2026 |
openai/gpt-5.6-sol | mesuré · n = 32 0.4.31 · 28 sept. 2026 | non mesuré : le fournisseur a rejeté la requête dans les deux bras 0.4.31 · 29 sept. 2026 | mesuré · n = 199 0.4.31 · 29 sept. 2026 | mesuré · n = 13 0.4.31 · 29 sept. 2026 |
anthropic/claude-haiku-4-5 | mesuré · n = 116 0.4.31 · 28 sept. 2026 | mesuré · n = 48 0.4.31 · 29 sept. 2026 | mesuré · n = 450 0.4.31 · 29 sept. 2026 | mesuré · n = 80 0.4.31 · 28 sept. 2026 |
anthropic/claude-opus-5-5 | mesuré · n = 32 0.4.31 · 28 sept. 2026 | non mesuré : plafond de dépense épuisé 0.4.31 · 29 sept. 2026 | mesuré · n = 81 0.4.31 · 29 sept. 2026 | mesuré · n = 18 0.4.31 · 29 sept. 2026 |
anthropic/claude-sonnet-5 | mesuré · n = 62 0.4.31 · 28 sept. 2026 | mesuré · n = 48 0.4.31 · 29 sept. 2026 | mesuré · n = 264 0.4.31 · 29 sept. 2026 | mesuré · n = 23 0.4.31 · 28 sept. 2026 |
anthropic/claude-sonnet-5-5 | mesuré · n = 62 0.4.31 · 28 sept. 2026 | non mesuré : plafond de dépense épuisé 0.4.31 · 29 sept. 2026 | mesuré · n = 311 0.4.31 · 29 sept. 2026 | mesuré · n = 37 0.4.31 · 29 sept. 2026 |
google/gemini-3.1-pro-preview | la couche a échoué : les requêtes ne sont pas passées par la couche 0.4.31 · 28 sept. 2026 | mesuré · n = 97 0.4.31 · 29 sept. 2026 | mesuré · n = 58 0.4.31 · 29 sept. 2026 | non mesuré : quota du fournisseur épuisé 0.4.31 · 29 sept. 2026 |
google/gemini-3.8-flash | la couche a échoué : les requêtes ne sont pas passées par la couche 0.4.31 · 28 sept. 2026 | mesuré · n = 324 0.4.31 · 29 sept. 2026 | mesuré · n = 450 0.4.31 · 29 sept. 2026 | la couche a échoué : les requêtes ne sont pas passées par la couche 0.4.31 · 29 sept. 2026 |
Bugs trouvés par le banc
Le banc n'est pas là pour bien paraître : il est là pour trouver les bugs avant vous. Il a trouvé ceux-ci, avec la version où ils sont apparus et celle qui les corrige.
Le cache sémantique non calibré servait la réponse d'une autre question 0.4.30 → 0.4.31
Avec le cache sémantique non calibré, une variante avec un autre nombre (« three baskets » contre « two baskets ») pouvait recevoir la réponse de la question originale. Compté sur les variantes de GSM8K.
- Trouvé dans la 0.4.30 : 15 sur 111. gsm8k.json
- Corrigé dans la 0.4.31 (#383).
- Vérifié en direct sur la 0.4.31 : 0 sur 198.
La couche réduisait le catalogue d'outils sans aucun signal pour le faire 0.4.30 → 0.4.31
Dans les conversations à plusieurs tours, le bras B envoyait moins d'outils que le bras A alors que rien n'indiquait lesquels étaient inutiles. Compté sur les conversations multi-tours de BFCL.
- Trouvé dans la 0.4.30 : 20 sur 20. bfcl.json
- Corrigé dans la 0.4.31 (#382).
- Vérifié en direct sur la 0.4.31 : 0 sur 83.
Certains refus écrits en texte étaient mis en cache 0.4.31 → 0.4.32
Un refus que le modèle écrit en texte (sans le signal de l'API) pouvait être mis en cache, répété et crédité comme une économie. Compté dans les prompts XSTest.
- Trouvé dans la 0.4.31 : 39 sur 2 824. xstest-0431-claude.jsonxstest-0431-gama-alta.jsonxstest-0431.json
- Corrigé dans la 0.4.32 (#393, #401).
- En attente d'être remesuré en direct sur la 0.4.32.
Un filtre de contenu de Gemini était mis en cache comme une réponse 0.4.31 → 0.4.32
Gemini signale son filtre avec un motif d'arrêt qui lui est propre, que la couche ne reconnaissait pas comme un refus, si bien qu'elle pouvait le mettre en cache et le répéter. Compté dans les prompts XSTest.
- Trouvé dans la 0.4.31 : 6 sur 508. xstest-0431-gama-alta.json
- Corrigé dans la 0.4.32 (#402).
- En attente d'être remesuré en direct sur la 0.4.32.
Gemini ne passait pas par la couche 0.4.31 → 0.4.32
La couche envoyait un champ propre à l'API OpenAI à tout endpoint compatible, et Gemini le rejette : toutes les requêtes du bras B échouaient. Compté dans les requêtes GSM8K.
- Trouvé dans la 0.4.31 : 504 sur 504. gsm8k-0431-gama-alta.json
- Corrigé dans la 0.4.32 (#402).
- En attente d'être remesuré en direct sur la 0.4.32.
Avec Gemini 3, le deuxième tour avec outils échouait 0.4.31 → 0.4.32
La couche ne renvoyait pas la signature de pensée que Gemini 3 exige à chaque appel d'outil, si bien que le tour suivant était rejeté. Compté dans les continuations multi-tours de BFCL.
- Trouvé dans la 0.4.31 : 50 sur 50. bfcl-0431-gama-alta.json
- Corrigé dans la 0.4.32 (#402).
- En attente d'être remesuré en direct sur la 0.4.32.
Comment le reproduire
Le code du banc n'est pas encore public ; la méthode l'est, et elle tient en cinq étapes. Avec vos propres clés de fournisseur, vous pouvez la refaire et comparer chiffre par chiffre avec nos rapports.
- Le jeu de données. Téléchargez chaque jeu de données public au commit du tableau ci-dessus et vérifiez le sha256 de chaque fichier avant de l'utiliser. S'il ne correspond pas, ce n'est pas le même jeu de données.
- La couche. Installez
@bivelio/savings-layerdepuis npm dans la version indiquée par le rapport et vérifiez le sha256 dedist/index.js: chaque rapport porte le sien. - Deux bras par prompt. A va directement au fournisseur ; B envoie le même prompt, au même modèle et avec le même plafond de sortie, à travers la couche dans sa configuration par défaut. Une partie des prompts est répétée ou paraphrasée, comme dans le trafic réel, et l'ordre A/B est tiré au sort.
- Le coût, c'est le fournisseur qui le dit. Additionnez ce que chaque bras est facturé d'après le
usagerenvoyé par le fournisseur, à son tarif publié. L'économie est1 − coût B / coût A, avec son intervalle. - La qualité, dans la même exécution. Notez de la même façon les réponses des deux bras (réponse exacte pour GSM8K, appel d'outil pour BFCL, refus ou non pour XSTest, un juge pour MT-Bench) et comparez-les au rapport JSON de la même batterie et de la même version.
Les rapports
Chaque exécution laisse un rapport JSON avec sa conception, ses limites et chaque appel mesuré : usage, coût par bras et classification de la réponse. Ils sont servis depuis ce site.
Les rapports sont servis tels que le banc les a écrits, à une exception près : les données sur l'environnement de la personne qui a mesuré (chemins de disque, adresses e-mail) sont retirées. Pour XSTest, aucun texte de réponse n'est publié, seulement sa classification.
Mesurez-nous vous-même
Une mesure indépendante vaut plus que la nôtre. Le code du banc n'est pas encore public : si vous voulez refaire la mesure, ou mesurer la couche avec votre propre harnais ou votre propre trafic, écrivez-nous et nous vous donnerons ce qu'il faut pour le faire.
Écrivez-nous à support@bivelio.com