Plan détaillé pour réintégrer la logique de génération par couples
et contraintes de longueur du système legacy.
Analyse COT complète avec:
- Comparaison plan initial vs legacy code
- Identification erreurs de conception
- 2 options d'implémentation (Option A recommandée)
- Risques et mitigations
- Critères de succès
- Stratégie de rollback
Status: EN ATTENTE VALIDATION UTILISATEUR
Action requise: Analyser buildSmartHierarchy() output
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
429 lines
12 KiB
Markdown
429 lines
12 KiB
Markdown
# Plan d'Implémentation : Réintégration InitialGeneration
|
||
|
||
**Date :** 2025-10-12
|
||
**Objectif :** Réintégrer la logique de génération par couples et contraintes de longueur du système legacy
|
||
**Auteur :** Claude Code (avec validation utilisateur requise)
|
||
|
||
---
|
||
|
||
## 🧠 Analyse Chain of Thought
|
||
|
||
### Problèmes Identifiés
|
||
|
||
**Dans le système actuel (`generateSimple()` dans `SelectiveUtils.js`) :**
|
||
|
||
1. ✅ Génération **élément par élément** → lent (33 appels), coûteux
|
||
2. ✅ **Prompt générique** pour tous types → pas de contraintes adaptées
|
||
3. ✅ Pas de **contraintes de longueur** → articles de 400 mots au lieu de 150
|
||
4. ✅ Pas de **gestion des couples** → Q sans R cohérente, Titre sans Texte lié
|
||
5. ✅ MaxTokens insuffisants pour certains modèles
|
||
|
||
**Systèmes legacy existants et fonctionnels :**
|
||
|
||
- ✅ `InitialGeneration.js` : batch generation (chunks de 4) + détection de type + contraintes de longueur
|
||
- ✅ `buildSmartHierarchy()` : associe automatiquement couples titre/texte et paires FAQ
|
||
- ✅ `parseFAQPairsResponse()` : validation stricte de cohérence des paires
|
||
|
||
---
|
||
|
||
## ❌ Erreurs dans le Plan Initial
|
||
|
||
### 1. **Détection de type trop complexe**
|
||
|
||
**Legacy (`InitialGeneration.js:132-146`) :**
|
||
```javascript
|
||
detectElementType(tag) {
|
||
if (tagLower.includes('titre') || tagLower.includes('h1') || tagLower.includes('h2')) {
|
||
return 'titre'; // ← STRING simple
|
||
}
|
||
}
|
||
```
|
||
|
||
**Mon plan initial :**
|
||
```javascript
|
||
detectElementType(tag) {
|
||
return { type: 'titre_h2', maxWords: 12, maxTokens: 30 }; // ← OBJET complexe
|
||
}
|
||
```
|
||
|
||
**❌ Problème :** Sur-ingénierie. Le legacy est plus simple et fonctionne.
|
||
|
||
---
|
||
|
||
### 2. **Chunking sur-complexifié**
|
||
|
||
**Legacy (`InitialGeneration.js:52`) :**
|
||
```javascript
|
||
const chunks = chunkArray(Object.entries(elementsToGenerate), 4); // Simple chunks de 4
|
||
```
|
||
|
||
**Mon plan initial :**
|
||
```javascript
|
||
function groupIntoBatches(hierarchy) {
|
||
// Logique complexe : calcul tokens, groupement intelligent des FAQ, etc.
|
||
// ~60 lignes de code
|
||
}
|
||
```
|
||
|
||
**❌ Problème :** Réinvente la roue. Le chunking simple par 4 marche déjà.
|
||
|
||
---
|
||
|
||
### 3. **Hiérarchie ignorée**
|
||
|
||
**Point critique découvert :**
|
||
|
||
Le pipeline utilise DÉJÀ `buildSmartHierarchy()` qui retourne cette structure :
|
||
|
||
```javascript
|
||
{
|
||
"H2_1": {
|
||
title: { instructions: "..." }, // ← Titre H2_1
|
||
text: { instructions: "..." }, // ← Texte P_1 associé
|
||
questions: [] // ← Vide si pas de FAQ
|
||
},
|
||
"q_1": {
|
||
title: null,
|
||
text: null,
|
||
questions: [ // ← q_1 et a_1 groupées ici
|
||
{ type: 'Faq', level: 'q', ... },
|
||
{ type: 'Faq', level: 'a', ... }
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
**❌ Mon erreur majeure :** Je traite `H2_1`, `P_1`, `q_1`, `a_1` comme éléments séparés au lieu d'exploiter les couples déjà identifiés par `buildSmartHierarchy()`.
|
||
|
||
---
|
||
|
||
## ✅ Architecture Correcte
|
||
|
||
### Principe de base
|
||
|
||
**Réutiliser la logique d'`InitialGeneration.js`** qui :
|
||
1. Prépare les éléments avec type détecté
|
||
2. Groupe en chunks de 4
|
||
3. Génère par batch avec contraintes de longueur
|
||
4. Parse les réponses avec fallback
|
||
|
||
**MAIS** : Adapter pour respecter la structure hiérarchique créée par `buildSmartHierarchy()`.
|
||
|
||
---
|
||
|
||
## 📋 Plan Révisé
|
||
|
||
### Option A : Réutiliser InitialGenerationLayer (RECOMMANDÉ)
|
||
|
||
**Avantages :**
|
||
- ✅ Code déjà testé et fonctionnel
|
||
- ✅ Gestion fallback robuste
|
||
- ✅ Contraintes de longueur intégrées
|
||
- ✅ Chunking optimisé
|
||
|
||
**Modifications nécessaires :**
|
||
|
||
#### 1. Dans `PipelineExecutor.js` (ligne 214-247)
|
||
|
||
**Avant :**
|
||
```javascript
|
||
const result = await generateSimple(hierarchy, csvData, { llmProvider });
|
||
```
|
||
|
||
**Après :**
|
||
```javascript
|
||
const { InitialGenerationLayer } = require('../generation/InitialGeneration');
|
||
const layer = new InitialGenerationLayer();
|
||
|
||
// Aplatir la hiérarchie pour InitialGeneration
|
||
const flatStructure = flattenHierarchy(hierarchy);
|
||
|
||
const result = await layer.apply(flatStructure, {
|
||
llmProvider,
|
||
temperature: 0.9,
|
||
csvData
|
||
});
|
||
```
|
||
|
||
#### 2. Créer fonction `flattenHierarchy()` dans `PipelineExecutor.js`
|
||
|
||
```javascript
|
||
function flattenHierarchy(hierarchy) {
|
||
const flat = {};
|
||
|
||
Object.entries(hierarchy).forEach(([sectionKey, section]) => {
|
||
// Ajouter titre si présent
|
||
if (section.title && section.title.instructions) {
|
||
const titleTag = sectionKey.includes('_') ? sectionKey : `${sectionKey}_title`;
|
||
flat[titleTag] = section.title.instructions;
|
||
}
|
||
|
||
// Ajouter texte si présent
|
||
if (section.text && section.text.instructions) {
|
||
const textTag = sectionKey.includes('_') ? `${sectionKey}_text` : sectionKey;
|
||
flat[textTag] = section.text.instructions;
|
||
}
|
||
|
||
// Ajouter questions FAQ
|
||
if (section.questions && section.questions.length > 0) {
|
||
section.questions.forEach((faq, index) => {
|
||
if (faq.originalElement && faq.originalElement.resolvedContent) {
|
||
const faqTag = faq.hierarchyPath || `faq_${index}`;
|
||
flat[faqTag] = faq.originalElement.resolvedContent;
|
||
}
|
||
});
|
||
}
|
||
});
|
||
|
||
return flat;
|
||
}
|
||
```
|
||
|
||
**Impact :** Minimal, réutilise code existant
|
||
|
||
---
|
||
|
||
### Option B : Adapter generateSimple() pour respecter la hiérarchie
|
||
|
||
**Avantages :**
|
||
- ✅ Pas de changement dans PipelineExecutor
|
||
- ✅ Compatibilité maintenue
|
||
|
||
**Inconvénients :**
|
||
- ❌ Réécriture partielle de generateSimple()
|
||
- ❌ Plus de code à tester
|
||
|
||
#### Modifications dans `SelectiveUtils.js`
|
||
|
||
**Ajouter détection de couples avant la boucle :**
|
||
|
||
```javascript
|
||
async function generateSimple(hierarchy, csvData, options = {}) {
|
||
// ... début identique ...
|
||
|
||
const batches = [];
|
||
|
||
// Grouper éléments par couples et type
|
||
for (const [sectionKey, section] of Object.entries(hierarchy)) {
|
||
const batch = [];
|
||
|
||
// Couple titre + texte
|
||
if (section.title && section.text) {
|
||
batch.push([`${sectionKey}_title`, section.title]);
|
||
batch.push([`${sectionKey}_text`, section.text]);
|
||
} else if (section.title) {
|
||
batch.push([`${sectionKey}_title`, section.title]);
|
||
} else if (section.text) {
|
||
batch.push([`${sectionKey}_text`, section.text]);
|
||
}
|
||
|
||
// Paires FAQ
|
||
if (section.questions && section.questions.length > 0) {
|
||
for (let i = 0; i < section.questions.length; i += 2) {
|
||
const question = section.questions[i];
|
||
const answer = section.questions[i + 1];
|
||
|
||
if (question && answer) {
|
||
batch.push([question.hierarchyPath, question]);
|
||
batch.push([answer.hierarchyPath, answer]);
|
||
}
|
||
}
|
||
}
|
||
|
||
if (batch.length > 0) {
|
||
batches.push(batch);
|
||
}
|
||
}
|
||
|
||
// Générer chaque batch avec prompt adapté
|
||
// ... suite similaire au plan initial mais avec couples respectés ...
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🎯 Décision Requise
|
||
|
||
### Questions Critiques
|
||
|
||
**1. Quelle option choisir ?**
|
||
- [ ] **Option A** : Réutiliser InitialGenerationLayer (moins de code, plus sûr)
|
||
- [ ] **Option B** : Adapter generateSimple() (plus de flexibilité, plus de risque)
|
||
|
||
**2. Structure réelle de `buildSmartHierarchy()` ?**
|
||
|
||
Pour valider le plan, j'ai besoin de voir un exemple concret de ce que retourne `buildSmartHierarchy()` actuellement.
|
||
|
||
**Action :** Ajouter ce log temporaire dans `PipelineExecutor.js:233` :
|
||
```javascript
|
||
const hierarchy = await buildSmartHierarchy(elementsArray);
|
||
logSh(`DEBUG HIERARCHY: ${JSON.stringify(hierarchy, null, 2)}`, 'DEBUG');
|
||
```
|
||
|
||
Puis relancer une génération et me partager les logs.
|
||
|
||
**3. Nombre d'éléments attendus ?**
|
||
|
||
- Si `buildSmartHierarchy()` retourne **23 sections** au lieu de **33 éléments**, c'est normal (couples fusionnés)
|
||
- Si on veut 33 éléments générés, il faut aplatir la hiérarchie (Option A)
|
||
|
||
---
|
||
|
||
## 📊 Comparaison Options
|
||
|
||
| Critère | Option A (Réutiliser) | Option B (Adapter) |
|
||
|---------|----------------------|-------------------|
|
||
| **Code à écrire** | ~30 lignes | ~150 lignes |
|
||
| **Risque** | Faible | Moyen |
|
||
| **Tests nécessaires** | Minimes | Complets |
|
||
| **Maintenance** | Simple | Double système |
|
||
| **Performance** | Identique | Identique |
|
||
| **Compatibilité** | Changement PipelineExecutor | Transparent |
|
||
| **Recommandation** | ✅ **OUI** | ⚠️ Si besoin spécifique |
|
||
|
||
---
|
||
|
||
## 🚀 Étapes d'Implémentation (Option A - Recommandée)
|
||
|
||
### Phase 1 : Validation de la structure (30 min)
|
||
|
||
1. Ajouter logs debug pour comprendre `buildSmartHierarchy()`
|
||
2. Analyser la sortie réelle
|
||
3. Valider que les couples sont bien formés
|
||
|
||
### Phase 2 : Fonction flattenHierarchy (45 min)
|
||
|
||
1. Créer la fonction dans `PipelineExecutor.js`
|
||
2. Tests unitaires avec fixtures
|
||
3. Validation que tous les éléments sont extraits
|
||
|
||
### Phase 3 : Intégration InitialGenerationLayer (60 min)
|
||
|
||
1. Importer InitialGenerationLayer dans PipelineExecutor
|
||
2. Remplacer appel à generateSimple()
|
||
3. Adapter le retour pour compatibilité
|
||
|
||
### Phase 4 : Augmentation maxTokens (15 min)
|
||
|
||
Mettre à jour `LLMManager.js` :
|
||
```javascript
|
||
'claude-sonnet-4-5': { maxTokens: 8000 },
|
||
'gpt-4o-mini': { maxTokens: 6000 },
|
||
'gpt-5-mini': { maxTokens: 10000 },
|
||
// etc.
|
||
```
|
||
|
||
### Phase 5 : Tests et validation (60 min)
|
||
|
||
1. Test génération ligne 2 production
|
||
2. Vérifier 33 éléments générés
|
||
3. Vérifier longueurs respectées
|
||
4. Vérifier cohérence FAQ
|
||
5. Mesurer temps (~40-50s attendu)
|
||
|
||
**Temps total : 3h30**
|
||
|
||
---
|
||
|
||
## 📝 Modifications de Code
|
||
|
||
### Fichiers impactés
|
||
|
||
1. **`lib/pipeline/PipelineExecutor.js`** (ligne 214-247)
|
||
- Import InitialGenerationLayer
|
||
- Fonction flattenHierarchy()
|
||
- Remplacement generateSimple()
|
||
|
||
2. **`lib/LLMManager.js`** (ligne 18-67)
|
||
- Augmentation maxTokens
|
||
|
||
3. **`lib/selective-enhancement/SelectiveUtils.js`** (optionnel)
|
||
- Marquer generateSimple() comme DEPRECATED
|
||
- Ajouter commentaire pointant vers InitialGeneration
|
||
|
||
---
|
||
|
||
## ⚠️ Risques et Mitigations
|
||
|
||
### Risque 1 : Structure hiérarchie différente de l'attendu
|
||
|
||
**Impact :** High
|
||
**Probabilité :** Medium
|
||
**Mitigation :** Logs debug + validation avant implémentation
|
||
|
||
### Risque 2 : Parsing échoue sur certains éléments
|
||
|
||
**Impact :** Medium
|
||
**Probabilité :** Low (code legacy testé)
|
||
**Mitigation :** Fallback déjà présent dans InitialGenerationLayer
|
||
|
||
### Risque 3 : Régression performance
|
||
|
||
**Impact :** Medium
|
||
**Probabilité :** Very Low
|
||
**Mitigation :** Tests avant/après avec métriques
|
||
|
||
### Risque 4 : Incompatibilité avec pipeline actuel
|
||
|
||
**Impact :** High
|
||
**Probabilité :** Low
|
||
**Mitigation :** Tests complets sur environnement dev
|
||
|
||
---
|
||
|
||
## ✅ Critères de Succès
|
||
|
||
1. **Fonctionnel :**
|
||
- [ ] 33/33 éléments générés (pas de skip)
|
||
- [ ] Longueurs respectées (H2: 8-15 mots, P: 80-200 mots)
|
||
- [ ] Paires FAQ cohérentes (Q pertinente pour R)
|
||
- [ ] Aucune erreur FATAL
|
||
|
||
2. **Performance :**
|
||
- [ ] Temps < 60s (vs ~150s actuellement)
|
||
- [ ] Coût -30% minimum
|
||
|
||
3. **Qualité :**
|
||
- [ ] Contenu non générique
|
||
- [ ] Pas de troncature
|
||
- [ ] Style personnalité respecté
|
||
|
||
---
|
||
|
||
## 🔄 Rollback Strategy
|
||
|
||
**En cas de problème :**
|
||
|
||
1. **Phase 1-3 :** `git revert` simple
|
||
2. **Phase 4 :** Restaurer anciennes valeurs maxTokens
|
||
3. **Phase 5 :** Si échec tests, rollback complet
|
||
|
||
**Fallback automatique :** InitialGenerationLayer a déjà un fallback intégré par chunk.
|
||
|
||
---
|
||
|
||
## 📌 TODO Immédiat
|
||
|
||
- [ ] **DÉCISION :** Choisir Option A ou Option B
|
||
- [ ] **ACTION :** Ajouter logs debug buildSmartHierarchy()
|
||
- [ ] **PARTAGE :** Envoyer exemple output buildSmartHierarchy()
|
||
- [ ] Valider avec utilisateur avant implémentation
|
||
|
||
---
|
||
|
||
## 📚 Références Code Legacy
|
||
|
||
- `lib/generation/InitialGeneration.js` (ligne 1-284)
|
||
- `lib/ElementExtraction.js` - `buildSmartHierarchy()` (ligne 276-313)
|
||
- `lib/ElementExtraction.js` - `parseFAQPairsResponse()` (ligne 402-451)
|
||
- `lib/pipeline/PipelineExecutor.js` - `runGeneration()` (ligne 214-247)
|
||
|
||
---
|
||
|
||
**Status :** ⏸️ **EN ATTENTE VALIDATION UTILISATEUR**
|
||
|
||
Avant de commencer l'implémentation, il faut :
|
||
1. Décider de l'option (A recommandée)
|
||
2. Analyser la structure réelle de buildSmartHierarchy()
|
||
3. Valider que le plan correspond aux besoins
|