diff --git a/experiments/llm-tech-step-poc/README.md b/experiments/llm-tech-step-poc/README.md index 56a9d53..db2dc28 100644 --- a/experiments/llm-tech-step-poc/README.md +++ b/experiments/llm-tech-step-poc/README.md @@ -51,15 +51,20 @@ résolution/téléchargement Hugging Face. pnpm bench ``` -Charge le modèle, puis lance 3 répétitions sur chacune des 3 phrases de test -(2 FR + 1 EN, voir `TEST_SENTENCES` dans -[`src/llm-tech-step-poc.ts`](./src/llm-tech-step-poc.ts) — l'une d'elles est -délibérément le cas piège documenté dans le commentaire de +Charge le modèle, puis lance 3 répétitions sur chacune des 7 phrases de test +(4 FR + 3 EN, voir `TEST_SENTENCES` dans +[`src/llm-tech-step-poc.ts`](./src/llm-tech-step-poc.ts)) — les 3 premières +couvrent le cas courant (actions enchaînées, dont le cas piège documenté dans `tech-step-matcher.ts` lui-même : "jusqu'à ce que le beurre ait disparu dans -la poêle", aucun verbe de cuisson littéral, seul le sens implique `COOK`). -Imprime, par phrase : le JSON détaillé de chaque action détectée, puis un -tableau récapitulatif (latence moyenne/min/max, delta RSS moyen, nombre -d'actions détectées). +la poêle", aucun verbe de cuisson littéral, seul le sens implique `COOK`), +les 4 suivantes poussent délibérément plus loin pour chercher le point de +rupture : actions simultanées plutôt que séquentielles, action conditionnelle +("if the batter looks too thick..."), négation explicite d'action ("sans +jamais laisser bouillir"), fin de cuisson par état/test de résultat plutôt +que par durée fixe, et un champ température qui désigne un seuil de cuisson +à cœur plutôt qu'un réglage de feu. Imprime, par phrase : le JSON détaillé de +chaque action détectée, puis un tableau récapitulatif (latence moyenne/min/max, +delta RSS moyen, nombre d'actions détectées). ## Méthodologie de comparaison avec le pipeline `node-nlp` @@ -91,7 +96,7 @@ piège FR sans verbe littéral. ## Limites de ce PoC - Pas de jeu d'évaluation étiqueté ni de métrique de précision automatisée - — les 3 phrases sont inspectées à l'œil, pas notées. + — les 7 phrases sont inspectées à l'œil, pas notées. - La grammaire GBNF ne garantit qu'une syntaxe JSON conforme au schéma, jamais la justesse sémantique du contenu (catégorie choisie, durée correctement extraite...) — voir le commentaire sur diff --git a/experiments/llm-tech-step-poc/src/llm-tech-step-poc.ts b/experiments/llm-tech-step-poc/src/llm-tech-step-poc.ts index f16d048..8fd062f 100644 --- a/experiments/llm-tech-step-poc/src/llm-tech-step-poc.ts +++ b/experiments/llm-tech-step-poc/src/llm-tech-step-poc.ts @@ -375,8 +375,12 @@ interface BenchmarkSentence { } /** - * Trois phrases complexes, FR et EN, choisies pour couvrir des difficultés - * différentes : + * Sept phrases complexes, FR et EN, choisies pour couvrir des difficultés + * différentes — les trois premières sont la base initiale du PoC, les + * quatre suivantes poussent volontairement plus loin (simultanéité, + * conditions, négations, ambiguïté sémantique d'un même champ) pour + * chercher le point de rupture des deux pipelines, pas juste confirmer + * qu'ils gèrent le cas courant : * * 1. FR, plusieurs actions explicites enchaînées avec une durée et un * ingrédient qui change de forme grammaticale ("les" reprend "oignons"). @@ -390,6 +394,28 @@ interface BenchmarkSentence { * point 3 de sa doc). Comparer les deux pipelines sur cette phrase * précise est le test le plus direct de "précision sémantique, pas * seulement mot-clé" que ce PoC cherche à évaluer. + * 4. FR, deux techniques qui se déroulent EN PARALLÈLE ("pendant que...") + * plutôt qu'en séquence — un pipeline qui suppose un ordre strictement + * chronologique (comme le découpage en clauses de `splitIntoClauses`, + * voir `tech-step-matcher.ts`) peut mal restituer que les deux actions + * se chevauchent dans le temps plutôt que de se succéder. + * 5. EN, une action CONDITIONNELLE ("if the batter looks too thick, add a + * splash of milk") noyée entre des actions fermes, plus une fin de + * cuisson exprimée comme un test de résultat ("until a toothpick comes + * out clean") et non comme une durée fixe — deux formes d'incertitude + * qu'un extracteur naïf a tendance à aplatir en une action normale. + * 6. FR, très technique (crème pâtissière) : une action MIX et une action + * COOK simultanées ("tout en fouettant" pendant qu'on verse le lait + * chaud), une NÉGATION explicite d'action ("sans jamais laisser + * bouillir" — l'inverse d'une action à ne pas enregistrer comme une + * vraie étape), et une fin de cuisson par état ("jusqu'à épaississement") + * plutôt que par durée. + * 7. EN, deux occurrences de `REST` au sens différent (mariner au + * réfrigérateur vs. laisser revenir à température ambiante avant + * cuisson) dans la même phrase, une durée "par face" (6-7 minutes per + * side, pas la durée totale), et un champ température qui désigne un + * SEUIL DE CUISSON à cœur (165°F) plutôt qu'un réglage de feu — un piège + * sémantique direct pour le champ `temperature` de {@link KitchenAction}. */ const TEST_SENTENCES: readonly BenchmarkSentence[] = [ { @@ -410,6 +436,30 @@ const TEST_SENTENCES: readonly BenchmarkSentence[] = [ text: "Dans une poêle chaude, faites chauffer une noix de beurre jusqu'à ce qu'il ait disparu, puis ajoutez les échalotes ciselées.", note: "Cas piège documenté dans tech-step-matcher.ts : aucun verbe de cuisson littéral, seul le sens implique COOK (fonte du beurre).", }, + { + id: "fr-actions-paralleles", + locale: "fr", + text: "Pendant que les pâtes cuisent 8 à 10 minutes dans une grande casserole d'eau bouillante salée, faites revenir l'ail et les champignons émincés à la poêle avec un peu de beurre jusqu'à ce qu'ils soient dorés, puis égouttez les pâtes en réservant un peu d'eau de cuisson avant de tout mélanger ensemble hors du feu.", + note: "Deux COOK simultanés (pas séquentiels) + OTHER (égoutter/réserver) + MIX final 'hors du feu' — teste la simultanéité, pas juste l'enchaînement.", + }, + { + id: "en-action-conditionnelle", + locale: "en", + text: "Whisk the eggs and sugar together until pale and fluffy, then gradually fold in the sifted flour; if the batter looks too thick, add a splash of milk, and bake at 350°F (175°C) for 25 to 30 minutes, or until a toothpick inserted in the center comes out clean.", + note: "Action conditionnelle ('if...') au milieu d'actions fermes + fin de cuisson par test de résultat plutôt que par durée fixe.", + }, + { + id: "fr-simultaneite-et-negation", + locale: "fr", + text: "Faites chauffer le lait avec la gousse de vanille fendue en deux jusqu'à frémissement, puis versez-le progressivement sur le mélange jaunes d'œufs-sucre-maïzena tout en fouettant énergiquement, avant de reverser le tout dans la casserole et de cuire à feu doux en remuant sans arrêt jusqu'à épaississement, sans jamais laisser bouillir.", + note: "MIX+COOK simultanés ('tout en fouettant'), négation explicite d'action ('sans jamais laisser bouillir') et fin de cuisson par état, pas par durée.", + }, + { + id: "en-double-rest-et-seuil-cuisson", + locale: "en", + text: "Marinate the chicken thighs in the yogurt mixture for at least 2 hours (overnight if possible), then remove them from the fridge 20 minutes before cooking, pat them dry, and grill over medium-high heat for 6-7 minutes per side until the internal temperature reaches 165°F, letting it rest for 5 minutes before slicing.", + note: "Deux REST de sens différent (marinade vs. retour à température ambiante) + durée 'par face' + température = seuil de cuisson à cœur, pas un réglage de feu.", + }, ]; /** Nombre de répétitions mesurées par phrase — atténue le bruit d'une mesure isolée sans allonger excessivement le run. */