From c454a67b8414645b6ceafe10957312585d681ba6 Mon Sep 17 00:00:00 2001 From: ctan Date: Fri, 25 Sep 2026 23:24:29 +0200 Subject: [PATCH] docs(phase2): record the P5.2 few-shot prompts and repair loop --- docs/phase-2-llm-architecture.md | 49 ++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/docs/phase-2-llm-architecture.md b/docs/phase-2-llm-architecture.md index 4c8894d..5a75447 100644 --- a/docs/phase-2-llm-architecture.md +++ b/docs/phase-2-llm-architecture.md @@ -638,6 +638,49 @@ la taxonomie, la résolution de clé par environnement, le ledger de tokens et le cache — à travers un transport `urlopen` injectable, jamais le réseau. Gate verte : **2186 tests**. +### Few-shot et réparation complète (P5.2) + +**Few-shot externe** (`prompt.py` + `prompt_builder.py`) : un pack peut +porter, à côté de chaque `{name}.md`, un fichier `{name}.examples.json` — +une **liste JSON** de paires d'enseignement `{"observation": {...}, +"actions": [...]}` (clés strictement validées, toute clé inconnue est un +`PromptPackError`). La découverte est optionnelle et triée ; un fichier +orphelin (sans `{name}.md` correspondant) est une erreur de pack ; un +contenu non-JSON, un non-tableau, un item non-objet, une `observation` +non-objet ou des `actions` non-tableau/non-objets sont rejetés à la même +taxonomie (`_pack_error`, message citant le chemin et l'index). Le paquet +expose les paires via `PromptPack.examples(name)` (tuple de +`FewShotExample` frozen) ; le **hash de version couvre désormais aussi le +contenu des exemples** : `prompt_version = sha256(content + "\0" + +examples_text)[:12]`, **byte-identique** quand aucun fichier d'exemples +n'existe (le cache/ledger D6 existant n'est pas invalidé). `PromptBuilder` +insère entre le template et l'observation une section `## few-shot examples` +dont chaque bloc `### example {n}` rend `observation:` puis `response:` en +JSON trié (`sort_keys=True`) — bit-identique sans exemples (garde de +régression testée sur l'ordre des sections). + +**Réparation complète** (`nl_policy.py`) : la boucle de réparation de P1.3 +devient **bornée et tracée**. `NLPolicy` porte `max_repairs` (défaut `1` — +comportement d'origine) : chaque réponse invalide est suivie d'un retry dont +le prompt accumule le **trail chronologique** des échecs précédents +(`-- previous reply invalid (attempt N) --` + message), refermé par +`Return a valid JSON action sequence.` ; au-delà de `max_repairs` tentatives +échouées, le fallback scripté prend le relais (`fallbacks`). `max_repairs=0` +désactive la réparation (fallback immédiat) ; une valeur négative est +rejetée au `__post_init__` (`ValueError`). Les compteurs vivent dans +`NLPolicyStats` (dataclass mutable, `policy.stats`) : `calls`, +`repairs_attempted`, `repairs_succeeded` et `fallbacks` — la matière des +rapports de P5.3 et du sweep. + +Fixture `tests/fixtures/prompt_pack_fs/` (pack « few-shot » : version +`0.1.0-test`, même prompt texte que le pack source, un micro-exemple +goblin→orc). Les 25 nouveaux cas pinent : la validation de +`tests/test_phase2_prompt.py` (12), le rendu et l'ordre des sections de +`tests/test_phase2_prompt_builder.py` (5, dont le tableau vide → pas de +section) et la boucle bornée de `tests/test_phase2_nl_policy.py` (8, via un +client enregistreur dérivé de `FakeLLMClient` qui capture chaque prompt +envoyé — trail vérifié tentative par tentative). Gate verte : **2211 tests**. + ### État du plan - **P0** ✅ · **P1** ✅ (`LLMClient` + `FakeLLMClient` scripté + cache @@ -646,11 +689,13 @@ Gate verte : **2186 tests**. (`scenarios.py` + `search.py`, playbook représentatif mesuré) · **P4** ✅ (`adversary.py` + `robustness.py`, adversaire `AdversarySpec` + carte de danger complète) · **P5.1** ✅ (`provider.py`, fournisseur OpenAI-compatible - HTTP au format chat-completions) — gate verte (**2186 tests**). + HTTP au format chat-completions) · **P5.2** ✅ (few-shot externe + `*.examples.json` hashé dans `prompt_version` + boucle de réparation bornée + `max_repairs` tracée par `NLPolicyStats`) — gate verte (**2211 tests**). - Détail P0 : **P0.0 (D1)** ✅ · **P0.1 (`schema_version`)** ✅ · mesures ✅ · `objectives.py` ✅ · `collect_runs` ✅ · **P0.2** (vue compacte) ✅ · **P0.3** (`candidates`) ✅ · **P0.4** (`llm_policy` + `policy_factory`) ✅ · **P0.5** (ReplayLog `call_seq` + `replay()` identique) ✅. - **Frontière P0 atteinte** : gate verte (2022 tests) ; un run enregistré se rejoue à l'identique. -- Suite : **P5.2** (few-shot + réparation complète) · **P5.3** (rapport FR). +- Suite : **P5.3** (rapport FR).