From d4db4f6d33b53a173bc3db85e1324073357a5fe1 Mon Sep 17 00:00:00 2001 From: ctan Date: Fri, 25 Sep 2026 22:22:30 +0200 Subject: [PATCH] docs(phase2): record the P5.1 provider client and plan status --- docs/phase-2-llm-architecture.md | 40 ++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/docs/phase-2-llm-architecture.md b/docs/phase-2-llm-architecture.md index 32cb788..4c8894d 100644 --- a/docs/phase-2-llm-architecture.md +++ b/docs/phase-2-llm-architecture.md @@ -245,8 +245,9 @@ politique de monstres renforcée — ce dernier point prouve immédiatement la v | — | Prompts | **Externes / dépôt séparé** (voir §14) | Reste à préciser au fil des lots (non bloquant) : forme exacte des leviers de -`StrategySpec`/`AdversarySpec`, choix de l'algorithme d'optimisation, seuils -statistiques par défaut, et le fournisseur distant concret. +`StrategySpec`/`AdversarySpec`, choix de l'algorithme d'optimisation et seuils +statistiques par défaut (le fournisseur distant est **arbitré en P5.1** : un +gateway OpenAI-compatible, §16). ## 14. Prompts externes (décision utilisateur) @@ -607,6 +608,36 @@ référence 3v2 du côté sûr de l'équilibre : TPK nul, plancher de survie sou 10 % de PV, et le seul levier adverse qui y compte est le ciblage par défaut. +### Fournisseur réel OpenAI-compatible (P5.1) + +Le « ProviderClient » du §10 est **`OpenAILLMClient`** (`provider.py`) : il +parle le format wire **chat-completions** d'OpenAI sur la bibliothèque +standard (`urllib.request`) — aucune dépendance HTTP dans le dépôt. +L'endpoint, le modèle et la clé viennent de l'environnement (§15) : +`PF1E_LLM_BASE_URL` (défaut `https://api.openai.com/v1`), `PF1E_LLM_MODEL` +(défaut `gpt-4o-mini`) et `PF1E_LLM_API_KEY` (jamais codée en dur) ; un +gateway vLLM / llama.cpp / compatible se branche par variables d'environnement, +sans toucher au code. + +Taxonomie d'erreurs (partagée avec `client.py`) : + +- `ProviderError` (transitoire) : erreur de transport, HTTP 429 et tout 5xx — + rejoués par la boucle de backoff de `LLMClient` et comptés par le + coupe-circuit ; +- `ProviderRejectedError` (permanent) : tout autre 4xx (clé invalide, modèle + inconnu, quota) — levée immédiatement, jamais rejouée ; +- `ProviderResponseError` (permanent) : un corps 2xx qui n'est pas un payload + chat-completions valide (JSON invalide, `choices`/`message`/`content` + absents, `usage` malformé) — levée immédiatement. + +Le corps de requête demande `response_format` JSON (`json_object`, mode +JSON/schéma requis, D arbitrées §13) ; l'usage est lu du bloc `usage` du +payload et estimé au caractère (`estimate_tokens`) quand le fournisseur +l'omet. Les 17 cas de `tests/test_phase2_provider.py` pinent le format wire, +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**. + ### État du plan - **P0** ✅ · **P1** ✅ (`LLMClient` + `FakeLLMClient` scripté + cache @@ -614,11 +645,12 @@ défaut. **P2** ✅ (`strategy.py` + `SweepRunner`, sortie mesurée) · **P3** ✅ (`scenarios.py` + `search.py`, playbook représentatif mesuré) · **P4** ✅ (`adversary.py` + `robustness.py`, adversaire `AdversarySpec` + carte de - danger complète) — gate verte (**2169 tests**). + danger complète) · **P5.1** ✅ (`provider.py`, fournisseur OpenAI-compatible + HTTP au format chat-completions) — gate verte (**2186 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** (fournisseur réel + rapport). +- Suite : **P5.2** (few-shot + réparation complète) · **P5.3** (rapport FR).