From 23ee7e6364a334b8db5516b91a88750a221929b4 Mon Sep 17 00:00:00 2001 From: jsboige Date: Thu, 1 Oct 2026 22:45:14 +0200 Subject: [PATCH 1/2] fix(notebooks,#18735): 09d tarif cache exact 0.1x + deux scenarios de reference R_CACHED passe de 0.5 ("politique standard" fausse) a 0.1, nomme et date (route openai/gpt-5-mini via proxy, releve 2026-10-01). Calcul poste par poste via cout_appel(entree non cachee, entree cachee, sortie). Deux scenarios de reference : prefixe COMMUN (chaque hit economise 0.0002592 USD, rien a amortir) et prefixe AJOUTE (temoin entree seule : requete courte 0.0000250 USD vs prompt long chaud 0.0000668 USD, surcout 0.0000418). La promesse "~2 appels pour rentrer dans les frais" disparait (code, sortie, prose). Carnet re-execute integralement (papermill, kernel python3). Co-Authored-By: Claude Sonnet 5.5 --- .../GenAI/Texte/09d_Production_Caches.ipynb | 377 +++++++++--------- 1 file changed, 199 insertions(+), 178 deletions(-) diff --git a/MyIA.AI.Notebooks/GenAI/Texte/09d_Production_Caches.ipynb b/MyIA.AI.Notebooks/GenAI/Texte/09d_Production_Caches.ipynb index 5065f60fca..3d7a2ac9fc 100644 --- a/MyIA.AI.Notebooks/GenAI/Texte/09d_Production_Caches.ipynb +++ b/MyIA.AI.Notebooks/GenAI/Texte/09d_Production_Caches.ipynb @@ -5,10 +5,10 @@ "id": "2af54d71", "metadata": { "papermill": { - "duration": 0.004305, - "end_time": "2026-09-28T16:33:45.397438+00:00", + "duration": 0.005891, + "end_time": "2026-10-01T20:41:46.787856+00:00", "exception": false, - "start_time": "2026-09-28T16:33:45.393133+00:00", + "start_time": "2026-10-01T20:41:46.781965+00:00", "status": "completed" }, "tags": [] @@ -27,8 +27,8 @@ " presque identiques dont la réponse est différente, servies depuis le cache comme si de rien\n", " n'était ;\n", "2. **Le cache de préfixe fournisseur** — OpenAI facture moins cher les tokens de prompt déjà\n", - " vus (`cached_tokens` dans la réponse). On mesure ce que ça rend vraiment, et le point\n", - " d'équilibre du préfixe long.\n", + " vus (`cached_tokens` dans la réponse). On mesure ce que ça rend vraiment, et à quelles\n", + " conditions l'allonger se justifie.\n", "\n", "> **Terrain réel, lecture seule** : embeddings OpenAI (`text-embedding-3-small`, clé dans `.env`,\n", "> jamais affichée), catalogue de prix du proxy multi-fournisseurs (`/v1/models`), inférence locale\n", @@ -40,10 +40,10 @@ "id": "3120652c", "metadata": { "papermill": { - "duration": 0.005203, - "end_time": "2026-09-28T16:33:45.407081+00:00", + "duration": 0.005784, + "end_time": "2026-10-01T20:41:46.801577+00:00", "exception": false, - "start_time": "2026-09-28T16:33:45.401878+00:00", + "start_time": "2026-10-01T20:41:46.795793+00:00", "status": "completed" }, "tags": [] @@ -58,16 +58,16 @@ "id": "a93fb585", "metadata": { "execution": { - "iopub.execute_input": "2026-09-28T16:33:45.416232Z", - "iopub.status.busy": "2026-09-28T16:33:45.415821Z", - "iopub.status.idle": "2026-09-28T16:33:45.440942Z", - "shell.execute_reply": "2026-09-28T16:33:45.439609Z" + "iopub.execute_input": "2026-10-01T20:41:46.814920Z", + "iopub.status.busy": "2026-10-01T20:41:46.814240Z", + "iopub.status.idle": "2026-10-01T20:41:46.842225Z", + "shell.execute_reply": "2026-10-01T20:41:46.840841Z" }, "papermill": { - "duration": 0.030602, - "end_time": "2026-09-28T16:33:45.441950+00:00", + "duration": 0.036307, + "end_time": "2026-10-01T20:41:46.843486+00:00", "exception": false, - "start_time": "2026-09-28T16:33:45.411348+00:00", + "start_time": "2026-10-01T20:41:46.807179+00:00", "status": "completed" }, "tags": [] @@ -103,16 +103,16 @@ "id": "a5e557f7", "metadata": { "execution": { - "iopub.execute_input": "2026-09-28T16:33:45.452649Z", - "iopub.status.busy": "2026-09-28T16:33:45.451907Z", - "iopub.status.idle": "2026-09-28T16:33:48.393897Z", - "shell.execute_reply": "2026-09-28T16:33:48.392318Z" + "iopub.execute_input": "2026-10-01T20:41:46.857088Z", + "iopub.status.busy": "2026-10-01T20:41:46.856634Z", + "iopub.status.idle": "2026-10-01T20:41:50.133830Z", + "shell.execute_reply": "2026-10-01T20:41:50.132390Z" }, "papermill": { - "duration": 2.949887, - "end_time": "2026-09-28T16:33:48.395622+00:00", + "duration": 3.285901, + "end_time": "2026-10-01T20:41:50.135279+00:00", "exception": false, - "start_time": "2026-09-28T16:33:45.445735+00:00", + "start_time": "2026-10-01T20:41:46.849378+00:00", "status": "completed" }, "tags": [] @@ -123,7 +123,13 @@ "output_type": "stream", "text": [ "Inference locale (Ollama) HTTP 200 2 modèles\n", - "Proxy multi-fournisseurs HTTP 200 458 modèles\n", + "Proxy multi-fournisseurs HTTP 200 464 modèles\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ "Prix catalogue openai/gpt-5-mini : $0.25/M entrée, $2.00/M sortie\n" ] } @@ -169,10 +175,10 @@ "id": "6a187710", "metadata": { "papermill": { - "duration": 0.003864, - "end_time": "2026-09-28T16:33:48.405078+00:00", + "duration": 0.006592, + "end_time": "2026-10-01T20:41:50.147867+00:00", "exception": false, - "start_time": "2026-09-28T16:33:48.401214+00:00", + "start_time": "2026-10-01T20:41:50.141275+00:00", "status": "completed" }, "tags": [] @@ -197,16 +203,16 @@ "id": "ce8c7da3", "metadata": { "execution": { - "iopub.execute_input": "2026-09-28T16:33:48.420548Z", - "iopub.status.busy": "2026-09-28T16:33:48.419805Z", - "iopub.status.idle": "2026-09-28T16:33:48.433784Z", - "shell.execute_reply": "2026-09-28T16:33:48.432524Z" + "iopub.execute_input": "2026-10-01T20:41:50.162782Z", + "iopub.status.busy": "2026-10-01T20:41:50.162072Z", + "iopub.status.idle": "2026-10-01T20:41:50.175738Z", + "shell.execute_reply": "2026-10-01T20:41:50.174193Z" }, "papermill": { - "duration": 0.023731, - "end_time": "2026-09-28T16:33:48.435175+00:00", + "duration": 0.023389, + "end_time": "2026-10-01T20:41:50.177179+00:00", "exception": false, - "start_time": "2026-09-28T16:33:48.411444+00:00", + "start_time": "2026-10-01T20:41:50.153790+00:00", "status": "completed" }, "tags": [] @@ -264,10 +270,10 @@ "id": "8c017cd0", "metadata": { "papermill": { - "duration": 0.007141, - "end_time": "2026-09-28T16:33:48.447939+00:00", + "duration": 0.005705, + "end_time": "2026-10-01T20:41:50.189109+00:00", "exception": false, - "start_time": "2026-09-28T16:33:48.440798+00:00", + "start_time": "2026-10-01T20:41:50.183404+00:00", "status": "completed" }, "tags": [] @@ -288,16 +294,16 @@ "id": "c78de773", "metadata": { "execution": { - "iopub.execute_input": "2026-09-28T16:33:48.469431Z", - "iopub.status.busy": "2026-09-28T16:33:48.468872Z", - "iopub.status.idle": "2026-09-28T16:34:54.212129Z", - "shell.execute_reply": "2026-09-28T16:34:54.210891Z" + "iopub.execute_input": "2026-10-01T20:41:50.204834Z", + "iopub.status.busy": "2026-10-01T20:41:50.204448Z", + "iopub.status.idle": "2026-10-01T20:43:04.407408Z", + "shell.execute_reply": "2026-10-01T20:43:04.405871Z" }, "papermill": { - "duration": 65.757496, - "end_time": "2026-09-28T16:34:54.217651+00:00", + "duration": 74.21729, + "end_time": "2026-10-01T20:43:04.412582+00:00", "exception": false, - "start_time": "2026-09-28T16:33:48.460155+00:00", + "start_time": "2026-10-01T20:41:50.195292+00:00", "status": "completed" }, "tags": [] @@ -307,9 +313,9 @@ "name": "stdout", "output_type": "stream", "text": [ - "Cache rempli : 90 réponses réelles du modèle local en 66 s\n", + "Cache rempli : 90 réponses réelles du modèle local en 74 s\n", "qualité du fond de cache : 78/90 justes (87 %)\n", - "latence de référence d'un appel non caché (médiane) : 574 ms\n" + "latence de référence d'un appel non caché (médiane) : 806 ms\n" ] } ], @@ -355,10 +361,10 @@ "id": "8a394d76", "metadata": { "papermill": { - "duration": 0.004518, - "end_time": "2026-09-28T16:34:54.228081+00:00", + "duration": 0.005866, + "end_time": "2026-10-01T20:43:04.424948+00:00", "exception": false, - "start_time": "2026-09-28T16:34:54.223563+00:00", + "start_time": "2026-10-01T20:43:04.419082+00:00", "status": "completed" }, "tags": [] @@ -380,16 +386,16 @@ "id": "ff89eb3a", "metadata": { "execution": { - "iopub.execute_input": "2026-09-28T16:34:54.240043Z", - "iopub.status.busy": "2026-09-28T16:34:54.239523Z", - "iopub.status.idle": "2026-09-28T16:35:00.402373Z", - "shell.execute_reply": "2026-09-28T16:35:00.400941Z" + "iopub.execute_input": "2026-10-01T20:43:04.439331Z", + "iopub.status.busy": "2026-10-01T20:43:04.438733Z", + "iopub.status.idle": "2026-10-01T20:43:12.789200Z", + "shell.execute_reply": "2026-10-01T20:43:12.787426Z" }, "papermill": { - "duration": 6.169964, - "end_time": "2026-09-28T16:35:00.403624+00:00", + "duration": 8.359348, + "end_time": "2026-10-01T20:43:12.790407+00:00", "exception": false, - "start_time": "2026-09-28T16:34:54.233660+00:00", + "start_time": "2026-10-01T20:43:04.431059+00:00", "status": "completed" }, "tags": [] @@ -457,10 +463,10 @@ "id": "db39fe10", "metadata": { "papermill": { - "duration": 0.004558, - "end_time": "2026-09-28T16:35:00.414091+00:00", + "duration": 0.005892, + "end_time": "2026-10-01T20:43:12.802582+00:00", "exception": false, - "start_time": "2026-09-28T16:35:00.409533+00:00", + "start_time": "2026-10-01T20:43:12.796690+00:00", "status": "completed" }, "tags": [] @@ -480,16 +486,16 @@ "id": "3dcbad44", "metadata": { "execution": { - "iopub.execute_input": "2026-09-28T16:35:00.427594Z", - "iopub.status.busy": "2026-09-28T16:35:00.427038Z", - "iopub.status.idle": "2026-09-28T16:35:00.436608Z", - "shell.execute_reply": "2026-09-28T16:35:00.435393Z" + "iopub.execute_input": "2026-10-01T20:43:12.817514Z", + "iopub.status.busy": "2026-10-01T20:43:12.816985Z", + "iopub.status.idle": "2026-10-01T20:43:12.828333Z", + "shell.execute_reply": "2026-10-01T20:43:12.826733Z" }, "papermill": { - "duration": 0.018454, - "end_time": "2026-09-28T16:35:00.437783+00:00", + "duration": 0.020778, + "end_time": "2026-10-01T20:43:12.829663+00:00", "exception": false, - "start_time": "2026-09-28T16:35:00.419329+00:00", + "start_time": "2026-10-01T20:43:12.808885+00:00", "status": "completed" }, "tags": [] @@ -499,7 +505,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "rejeu de la banque par cache exact : 90/90 hits, 0.1 ms au total\n", + "rejeu de la banque par cache exact : 90/90 hits, 0.2 ms au total\n", "reformulations (n=20) : 0 hit(s) — le cache exact est aveugle à la formulation\n" ] } @@ -529,10 +535,10 @@ "id": "64d7a5ac", "metadata": { "papermill": { - "duration": 0.005373, - "end_time": "2026-09-28T16:35:00.449293+00:00", + "duration": 0.006899, + "end_time": "2026-10-01T20:43:12.843194+00:00", "exception": false, - "start_time": "2026-09-28T16:35:00.443920+00:00", + "start_time": "2026-10-01T20:43:12.836295+00:00", "status": "completed" }, "tags": [] @@ -557,16 +563,16 @@ "id": "70adea70", "metadata": { "execution": { - "iopub.execute_input": "2026-09-28T16:35:00.462228Z", - "iopub.status.busy": "2026-09-28T16:35:00.461706Z", - "iopub.status.idle": "2026-09-28T16:36:00.624765Z", - "shell.execute_reply": "2026-09-28T16:36:00.623515Z" + "iopub.execute_input": "2026-10-01T20:43:12.859954Z", + "iopub.status.busy": "2026-10-01T20:43:12.859426Z", + "iopub.status.idle": "2026-10-01T20:44:19.389976Z", + "shell.execute_reply": "2026-10-01T20:44:19.388685Z" }, "papermill": { - "duration": 60.17635, - "end_time": "2026-09-28T16:36:00.631288+00:00", + "duration": 66.544916, + "end_time": "2026-10-01T20:44:19.394353+00:00", "exception": false, - "start_time": "2026-09-28T16:35:00.454938+00:00", + "start_time": "2026-10-01T20:43:12.849437+00:00", "status": "completed" }, "tags": [] @@ -605,7 +611,7 @@ " faux succès (pièges)\n", " faux succès %\n", " exactitude %\n", - " latence évitée (s, à 574 ms/appel)\n", + " latence évitée (s, à 806 ms/appel)\n", " \n", " \n", " seuil γ\n", @@ -625,7 +631,7 @@ " 30\n", " 100.0\n", " 63.6\n", - " 63.1\n", + " 88.7\n", " \n", " \n", " 0.950\n", @@ -634,7 +640,7 @@ " 30\n", " 100.0\n", " 63.6\n", - " 63.1\n", + " 88.7\n", " \n", " \n", " 0.980\n", @@ -643,7 +649,7 @@ " 21\n", " 70.0\n", " 71.8\n", - " 56.2\n", + " 79.0\n", " \n", " \n", " 0.990\n", @@ -652,7 +658,7 @@ " 12\n", " 40.0\n", " 75.5\n", - " 41.3\n", + " 58.0\n", " \n", " \n", " 0.995\n", @@ -661,7 +667,7 @@ " 1\n", " 3.3\n", " 81.8\n", - " 35.0\n", + " 49.2\n", " \n", " \n", " 0.999\n", @@ -670,7 +676,7 @@ " 0\n", " 0.0\n", " 82.7\n", - " 34.4\n", + " 48.4\n", " \n", " \n", "\n", @@ -686,14 +692,14 @@ "0.995 61 55.5 1 3.3 \n", "0.999 60 54.5 0 0.0 \n", "\n", - " exactitude % latence évitée (s, à 574 ms/appel) \n", + " exactitude % latence évitée (s, à 806 ms/appel) \n", "seuil γ \n", - "0.900 63.6 63.1 \n", - "0.950 63.6 63.1 \n", - "0.980 71.8 56.2 \n", - "0.990 75.5 41.3 \n", - "0.995 81.8 35.0 \n", - "0.999 82.7 34.4 " + "0.900 63.6 88.7 \n", + "0.950 63.6 88.7 \n", + "0.980 71.8 79.0 \n", + "0.990 75.5 58.0 \n", + "0.995 81.8 49.2 \n", + "0.999 82.7 48.4 " ] }, "execution_count": 7, @@ -757,10 +763,10 @@ "id": "64cdd0f0", "metadata": { "papermill": { - "duration": 0.005524, - "end_time": "2026-09-28T16:36:00.643566+00:00", + "duration": 0.006057, + "end_time": "2026-10-01T20:44:19.406303+00:00", "exception": false, - "start_time": "2026-09-28T16:36:00.638042+00:00", + "start_time": "2026-10-01T20:44:19.400246+00:00", "status": "completed" }, "tags": [] @@ -788,10 +794,10 @@ "id": "3fd446a6", "metadata": { "papermill": { - "duration": 0.005022, - "end_time": "2026-09-28T16:36:00.654810+00:00", + "duration": 0.006248, + "end_time": "2026-10-01T20:44:19.418897+00:00", "exception": false, - "start_time": "2026-09-28T16:36:00.649788+00:00", + "start_time": "2026-10-01T20:44:19.412649+00:00", "status": "completed" }, "tags": [] @@ -813,16 +819,16 @@ "id": "1aa99002", "metadata": { "execution": { - "iopub.execute_input": "2026-09-28T16:36:00.672259Z", - "iopub.status.busy": "2026-09-28T16:36:00.671696Z", - "iopub.status.idle": "2026-09-28T16:36:43.095699Z", - "shell.execute_reply": "2026-09-28T16:36:43.094275Z" + "iopub.execute_input": "2026-10-01T20:44:19.432838Z", + "iopub.status.busy": "2026-10-01T20:44:19.432383Z", + "iopub.status.idle": "2026-10-01T20:44:54.368141Z", + "shell.execute_reply": "2026-10-01T20:44:54.366810Z" }, "papermill": { - "duration": 42.438583, - "end_time": "2026-09-28T16:36:43.101971+00:00", + "duration": 34.949764, + "end_time": "2026-10-01T20:44:54.374596+00:00", "exception": false, - "start_time": "2026-09-28T16:36:00.663388+00:00", + "start_time": "2026-10-01T20:44:19.424832+00:00", "status": "completed" }, "tags": [] @@ -864,8 +870,8 @@ " \n", " 1\n", " 1304\n", - " 1152\n", - " 88.3\n", + " 0\n", + " 0.0\n", " \n", " \n", " 2\n", @@ -928,7 +934,7 @@ "text/plain": [ " tokens prompt dont cachés part cachée %\n", "appel \n", - "1 1304 1152 88.3\n", + "1 1304 0 0.0\n", "2 1305 1152 88.3\n", "3 1304 1152 88.3\n", "4 1304 1152 88.3\n", @@ -1045,10 +1051,10 @@ "id": "9305d528", "metadata": { "papermill": { - "duration": 0.010125, - "end_time": "2026-09-28T16:36:43.118967+00:00", + "duration": 0.007398, + "end_time": "2026-10-01T20:44:54.388498+00:00", "exception": false, - "start_time": "2026-09-28T16:36:43.108842+00:00", + "start_time": "2026-10-01T20:44:54.381100+00:00", "status": "completed" }, "tags": [] @@ -1059,11 +1065,13 @@ "Sur cette exécution, le 1ᵉʳ appel affiche déjà 88 % de tokens cachés : ce préfixe avait\n", "déjà été envoyé quelques minutes plus tôt (runs de préparation) — le cache du fournisseur\n", "survit d'une exécution à l'autre, c'est précisément son intérêt en production. Sur un\n", - "préfixe réellement froid, le 1ᵉʳ appel paie le plein tarif. L'économie réelle se calcule avec les **prix du catalogue** lus en section 0 : le\n", - "token caché est facturé à fraction du prix d'entrée (politique fournisseur, `R_CACHED`\n", - "ci-dessous) — on mesure la part servie, le reste est arithmétique. Le **point d'équilibre**\n", - "répond à la question qui précède tout investissement dans un préfixe long : combien d'appels\n", - "partageant ce préfixe faut-il pour que le préfixe se rentabilise ?\n" + "préfixe réellement froid, le 1ᵉʳ appel paie le plein tarif. L'économie réelle se calcule avec les **prix du catalogue** lus en section 0 : le token\n", + "caché est facturé à une fraction du prix d'entrée — 0,1× sur la route mesurée ici, un ratio\n", + "qui dépend du fournisseur et du modèle (`R_CACHED` ci-dessous), à vérifier avant d'estimer\n", + "une facture. Et la bonne question n'est pas un « point d'équilibre » universel : si le\n", + "préfixe est **commun** aux appels — un contexte qu'on enverrait de toute façon —, chaque hit\n", + "est une économie immédiate, il n'y a rien à amortir ; si on **ajoute** un préfixe long pour\n", + "atteindre le cache, il faut le comparer à la requête courte qu'on vient d'allonger.\n" ] }, { @@ -1072,16 +1080,16 @@ "id": "f3e21358", "metadata": { "execution": { - "iopub.execute_input": "2026-09-28T16:36:43.138004Z", - "iopub.status.busy": "2026-09-28T16:36:43.137338Z", - "iopub.status.idle": "2026-09-28T16:36:43.146848Z", - "shell.execute_reply": "2026-09-28T16:36:43.145342Z" + "iopub.execute_input": "2026-10-01T20:44:54.403298Z", + "iopub.status.busy": "2026-10-01T20:44:54.402934Z", + "iopub.status.idle": "2026-10-01T20:44:54.413533Z", + "shell.execute_reply": "2026-10-01T20:44:54.412142Z" }, "papermill": { - "duration": 0.021729, - "end_time": "2026-09-28T16:36:43.148049+00:00", + "duration": 0.019386, + "end_time": "2026-10-01T20:44:54.414823+00:00", "exception": false, - "start_time": "2026-09-28T16:36:43.126320+00:00", + "start_time": "2026-10-01T20:44:54.395437+00:00", "status": "completed" }, "tags": [] @@ -1091,31 +1099,44 @@ "name": "stdout", "output_type": "stream", "text": [ - "préfixe : ~1304 tokens, part cachée mesurée sur le dernier appel : 88 %\n", - "coût plein du préfixe par appel : $0.000326\n", - "économie par appel une fois chaud : $0.000144 (tarif caché = 50% du plein)\n", - "point d'équilibre : ~2 appels par préfixe pour rentrer dans les frais (au-delà, tout est gain)\n" + "route : openai/gpt-5-mini via proxy, catalogue mesuré $0.25/M entrée, $2.00/M sortie, entrée cachée $0.025/M (10% de l'entrée)\n", + "préfixe : ~1304 tokens dont 88 % cachés ; scénario préfixe commun : chaque hit économise $0.0002592 -- gain dès le premier hit, sans seuil\n", + "scénario préfixe ajouté : requête courte = $0.0000250, prompt long déjà chaud = $0.0000668\n", + "le hit fonctionne (entrée servie au tarif réduit) mais la stratégie reste $0.0000418 plus chère : un préfixe ajouté ne se justifie que s'il remplace du travail, jamais pour le cache seul\n" ] } ], "source": [ - "# Point d'équilibre : le préfixe coûte PRIX_IN plein tarif tant qu'il n'est pas caché ;\n", - "# une fois chaud, une part f de ses tokens est facturée au tarif réduit R_CACHED (0,5 = politique\n", - "# fournisseur standard : le token caché vaut la moitié du prix d'entrée).\n", - "R_CACHED = 0.5\n", + "# Tarif cache de la route mesurée : gpt-5-mini facture l'entrée CACHÉE à 0,1 fois le prix\n", + "# d'entrée (politique publiée par le fournisseur, relevée le 2026-10-01). Ce ratio n'est pas\n", + "# universel : il dépend de la route et du modèle -- nommer les deux avant d'estimer une facture.\n", + "R_CACHED = 0.1\n", + "prix_cache = R_CACHED * PRIX_IN\n", "tokens_prompt = mesures_pref[-1][\"prompt\"]\n", - "part_cachee = mesures_pref[-1][\"cached\"] / tokens_prompt if tokens_prompt else 0.0\n", - "cout_prefixe_usd = tokens_prompt * PRIX_IN / 1e6\n", - "economie_par_appel = tokens_prompt * (1 - R_CACHED) * part_cachee * PRIX_IN / 1e6\n", - "\n", - "print(f\"préfixe : ~{tokens_prompt} tokens, part cachée mesurée sur le dernier appel : {100 * part_cachee:.0f} %\")\n", - "print(f\"coût plein du préfixe par appel : ${cout_prefixe_usd:.6f}\")\n", - "print(f\"économie par appel une fois chaud : ${economie_par_appel:.6f} (tarif caché = {R_CACHED:.0%} du plein)\")\n", - "if economie_par_appel > 0:\n", - " n_equilibre = cout_prefixe_usd / economie_par_appel\n", - " print(f\"point d'équilibre : ~{n_equilibre:.0f} appels par préfixe pour rentrer dans les frais (au-delà, tout est gain)\")\n", - "else:\n", - " print(\"aucune économie mesurée sur ce terrain : le point d'équilibre n'existe pas\")\n" + "tokens_cache = mesures_pref[-1][\"cached\"]\n", + "part_cachee = tokens_cache / tokens_prompt if tokens_prompt else 0.0\n", + "\n", + "def cout_appel(entree_non_cachee, entree_cachee, sortie):\n", + " \"\"\"Coût exact d'un appel, poste par poste : entrée non cachée, entrée cachée, sortie.\"\"\"\n", + " return (entree_non_cachee * PRIX_IN + entree_cachee * prix_cache + sortie * PRIX_OUT) / 1e6\n", + "\n", + "print(f\"route : {MODELE_CHAT} via proxy, catalogue mesuré ${PRIX_IN:.2f}/M entrée, \"\n", + " f\"${PRIX_OUT:.2f}/M sortie, entrée cachée ${prix_cache:.3f}/M ({R_CACHED:.0%} de l'entrée)\")\n", + "\n", + "# Scénario 1 -- préfixe COMMUN : les appels paieraient ce contexte au plein tarif même sans\n", + "# cache ; chaque hit économise la différence plein/réduit sur la part servie. Rien à amortir.\n", + "economie_par_hit = tokens_cache * (PRIX_IN - prix_cache) / 1e6\n", + "print(f\"préfixe : ~{tokens_prompt} tokens dont {100 * part_cachee:.0f} % cachés ; scénario préfixe \"\n", + " f\"commun : chaque hit économise ${economie_par_hit:.7f} -- gain dès le premier hit, sans seuil\")\n", + "\n", + "# Scénario 2 -- préfixe AJOUTÉ : on allonge la requête pour atteindre le cache. Témoin,\n", + "# entrée seule : requête courte de 100 tokens contre le même prompt long déjà chaud.\n", + "court = cout_appel(100, 0, 0)\n", + "long_chaud = cout_appel(tokens_prompt - tokens_cache, tokens_cache, 0)\n", + "print(f\"scénario préfixe ajouté : requête courte = ${court:.7f}, prompt long déjà chaud = ${long_chaud:.7f}\")\n", + "print(f\"le hit fonctionne (entrée servie au tarif réduit) mais la stratégie reste \"\n", + " f\"${long_chaud - court:.7f} plus chère : un préfixe ajouté ne se justifie que s'il \"\n", + " \"remplace du travail, jamais pour le cache seul\")\n" ] }, { @@ -1123,10 +1144,10 @@ "id": "e4c5921c", "metadata": { "papermill": { - "duration": 0.007938, - "end_time": "2026-09-28T16:36:43.162494+00:00", + "duration": 0.006644, + "end_time": "2026-10-01T20:44:54.428882+00:00", "exception": false, - "start_time": "2026-09-28T16:36:43.154556+00:00", + "start_time": "2026-10-01T20:44:54.422238+00:00", "status": "completed" }, "tags": [] @@ -1138,7 +1159,7 @@ "|---|---|---|---|\n", "| exact | 100 % des répétitions à l'identique | aucun | plancher gratuit, toujours actif |\n", "| sémantique | les reformulations (hit mesuré au seuil γ) | **faux succès** : pièges jumeaux servis | selon la distribution mesurée en section 3 |\n", - "| préfixe | la part `cached_tokens` du prompt | préfixe payé plein tarif à froid | équilibre mesuré en section 6 |\n", + "| préfixe | la part `cached_tokens` du prompt | préfixe payé plein tarif à froid | économie par hit mesurée en section 6 |\n", "\n", "La leçon transversale : **un cache est un pari sur la distribution des questions**. Le cache\n", "exact parie qu'elles se répètent à l'identique ; le sémantique qu'elles se répètent *en\n", @@ -1157,10 +1178,10 @@ "id": "3db41b3e", "metadata": { "papermill": { - "duration": 0.010578, - "end_time": "2026-09-28T16:36:43.180225+00:00", + "duration": 0.00632, + "end_time": "2026-10-01T20:44:54.442055+00:00", "exception": false, - "start_time": "2026-09-28T16:36:43.169647+00:00", + "start_time": "2026-10-01T20:44:54.435735+00:00", "status": "completed" }, "tags": [] @@ -1193,16 +1214,16 @@ "id": "838780a1", "metadata": { "execution": { - "iopub.execute_input": "2026-09-28T16:36:43.208372Z", - "iopub.status.busy": "2026-09-28T16:36:43.207753Z", - "iopub.status.idle": "2026-09-28T16:36:43.218213Z", - "shell.execute_reply": "2026-09-28T16:36:43.216239Z" + "iopub.execute_input": "2026-10-01T20:44:54.457610Z", + "iopub.status.busy": "2026-10-01T20:44:54.457063Z", + "iopub.status.idle": "2026-10-01T20:44:54.463614Z", + "shell.execute_reply": "2026-10-01T20:44:54.462317Z" }, "papermill": { - "duration": 0.031134, - "end_time": "2026-09-28T16:36:43.219563+00:00", + "duration": 0.016542, + "end_time": "2026-10-01T20:44:54.464787+00:00", "exception": false, - "start_time": "2026-09-28T16:36:43.188429+00:00", + "start_time": "2026-10-01T20:44:54.448245+00:00", "status": "completed" }, "tags": [] @@ -1233,16 +1254,16 @@ "id": "894db209", "metadata": { "execution": { - "iopub.execute_input": "2026-09-28T16:36:43.234877Z", - "iopub.status.busy": "2026-09-28T16:36:43.234295Z", - "iopub.status.idle": "2026-09-28T16:36:43.241179Z", - "shell.execute_reply": "2026-09-28T16:36:43.239892Z" + "iopub.execute_input": "2026-10-01T20:44:54.480352Z", + "iopub.status.busy": "2026-10-01T20:44:54.479779Z", + "iopub.status.idle": "2026-10-01T20:44:54.486324Z", + "shell.execute_reply": "2026-10-01T20:44:54.484869Z" }, "papermill": { - "duration": 0.016488, - "end_time": "2026-09-28T16:36:43.242453+00:00", + "duration": 0.01598, + "end_time": "2026-10-01T20:44:54.487547+00:00", "exception": false, - "start_time": "2026-09-28T16:36:43.225965+00:00", + "start_time": "2026-10-01T20:44:54.471567+00:00", "status": "completed" }, "tags": [] @@ -1273,16 +1294,16 @@ "id": "29ff3335", "metadata": { "execution": { - "iopub.execute_input": "2026-09-28T16:36:43.259478Z", - "iopub.status.busy": "2026-09-28T16:36:43.258894Z", - "iopub.status.idle": "2026-09-28T16:36:43.265668Z", - "shell.execute_reply": "2026-09-28T16:36:43.264238Z" + "iopub.execute_input": "2026-10-01T20:44:54.503183Z", + "iopub.status.busy": "2026-10-01T20:44:54.502625Z", + "iopub.status.idle": "2026-10-01T20:44:54.509197Z", + "shell.execute_reply": "2026-10-01T20:44:54.507756Z" }, "papermill": { - "duration": 0.017244, - "end_time": "2026-09-28T16:36:43.267062+00:00", + "duration": 0.01639, + "end_time": "2026-10-01T20:44:54.510335+00:00", "exception": false, - "start_time": "2026-09-28T16:36:43.249818+00:00", + "start_time": "2026-10-01T20:44:54.493945+00:00", "status": "completed" }, "tags": [] @@ -1312,10 +1333,10 @@ "id": "2641d0c2", "metadata": { "papermill": { - "duration": 0.007192, - "end_time": "2026-09-28T16:36:43.281704+00:00", + "duration": 0.007176, + "end_time": "2026-10-01T20:44:54.524404+00:00", "exception": false, - "start_time": "2026-09-28T16:36:43.274512+00:00", + "start_time": "2026-10-01T20:44:54.517228+00:00", "status": "completed" }, "tags": [] @@ -1371,17 +1392,17 @@ }, "papermill": { "default_parameters": {}, - "duration": 182.013867, - "end_time": "2026-09-28T16:36:44.713024+00:00", + "duration": 191.282333, + "end_time": "2026-10-01T20:44:55.315265+00:00", "environment_variables": {}, "exception": null, - "input_path": "09d_Production_Caches.ipynb", - "output_path": "09d_exec.ipynb", + "input_path": "MyIA.AI.Notebooks/GenAI/Texte/09d_Production_Caches.ipynb", + "output_path": "MyIA.AI.Notebooks/GenAI/Texte/09d_Production_Caches.ipynb", "parameters": {}, - "start_time": "2026-09-28T16:33:42.699157+00:00", + "start_time": "2026-10-01T20:41:44.032932+00:00", "version": "2.7.0" } }, "nbformat": 4, "nbformat_minor": 5 -} +} \ No newline at end of file From 7244a7d2591d1524ed9330a3476ef5e6caa8da04 Mon Sep 17 00:00:00 2001 From: jsboige Date: Fri, 2 Oct 2026 00:54:43 +0200 Subject: [PATCH 2/2] fix(notebooks,#18735): Lecture cache froid -- aligner la prose sur la sortie committee La cellule 9305d528 disait "le 1er appel affiche deja 88 % de tokens caches", phrase heritee de l'execution precedente. La re-execution de cette PR part d'un cache froid : appel 1 = 0 token cache (plein tarif), 88,3 % des l'appel 2. La prose decrit maintenant ce contraste (premier paiement plein tarif, puis part servie au tarif reduit) et garde la note mecanique : le cache survit d'une execution a l'autre. Markdown-only, aucune cellule code touchee. Co-Authored-By: Claude Sonnet 5.5 --- .../GenAI/Texte/09d_Production_Caches.ipynb | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/MyIA.AI.Notebooks/GenAI/Texte/09d_Production_Caches.ipynb b/MyIA.AI.Notebooks/GenAI/Texte/09d_Production_Caches.ipynb index 3d7a2ac9fc..9f736df202 100644 --- a/MyIA.AI.Notebooks/GenAI/Texte/09d_Production_Caches.ipynb +++ b/MyIA.AI.Notebooks/GenAI/Texte/09d_Production_Caches.ipynb @@ -1062,10 +1062,13 @@ "source": [ "### Lecture du cache de préfixe\n", "\n", - "Sur cette exécution, le 1ᵉʳ appel affiche déjà 88 % de tokens cachés : ce préfixe avait\n", - "déjà été envoyé quelques minutes plus tôt (runs de préparation) — le cache du fournisseur\n", - "survit d'une exécution à l'autre, c'est précisément son intérêt en production. Sur un\n", - "préfixe réellement froid, le 1ᵉʳ appel paie le plein tarif. L'économie réelle se calcule avec les **prix du catalogue** lus en section 0 : le token\n", + "Cette exécution est partie d'un cache **froid** : le 1ᵉʳ appel affiche 0 token caché — il paie\n", + "le préfixe au plein tarif — et dès le 2ᵉ appel, 88 % des tokens du prompt sont servis depuis\n", + "le cache. Ce contraste entre la première ligne du tableau et les suivantes EST la mécanique du\n", + "cache fournisseur : un premier paiement plein tarif, puis la même part servie au tarif réduit à\n", + "chaque appel suivant (le cache survit d'une exécution à l'autre ; une série démarrée quelques\n", + "minutes après une autre peut afficher son 1ᵉʳ appel déjà chaud — c'est précisément son intérêt\n", + "en production). L'économie réelle se calcule avec les **prix du catalogue** lus en section 0 : le token\n", "caché est facturé à une fraction du prix d'entrée — 0,1× sur la route mesurée ici, un ratio\n", "qui dépend du fournisseur et du modèle (`R_CACHED` ci-dessous), à vérifier avant d'estimer\n", "une facture. Et la bonne question n'est pas un « point d'équilibre » universel : si le\n", @@ -1405,4 +1408,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +}