Décomposition par section
Le problème de l'extraction en un seul appel
Demander à un seul appel LLM de remplir l'intégralité du schéma JSON Resume pose plusieurs problèmes :
- Charge cognitive élevée — le modèle doit simultanément extraire les coordonnées, l'historique professionnel, la formation, les compétences, les langues et les projets depuis un long document
- Écho de schéma — les petits modèles génèrent une structure syntaxiquement parfaite mais vide
- Pollution inter-sections — les projets se retrouvent dans l'expérience professionnelle, les langues dans les compétences
- Gaspillage de tokens — le texte complet du CV est envoyé une fois, mais la plupart est non pertinent pour chaque section
Comment fonctionne la décomposition
resume-intel exécute des extractions parallèles et ciblées par section :
Texte du CV
↓
┌──────────┬──────────┬──────────┬──────────┬──────────┬──────────┐
│ basics │ work │education │ skills │languages │ projects │
│ prompt │ prompt │ prompt │ prompt │ prompt │ prompt │
│ schéma │ schéma │ schéma │ schéma │ schéma │ schéma │
│maxTokens │maxTokens │maxTokens │maxTokens │maxTokens │maxTokens │
└──────────┴──────────┴──────────┴──────────┴──────────┴──────────┘
↓ ↓ ↓ ↓ ↓ ↓
résultat résultat résultat résultat résultat résultat
↓
fusion → déduplication → validation → retour
Chaque section s'exécute en parallèle. Un échec dans une section ne bloque pas les autres.
Limites de tokens par section
Chaque section a une limite maxTokens calibrée pour éviter la continuation infinie :
| Section | Max tokens | Justification |
|---|---|---|
basics |
400 | Nom, email, téléphone, localisation, résumé |
work |
900 | 3–5 postes avec points clés |
education |
450 | 2–4 entrées |
skills |
300 | Mots-clés groupés |
languages |
150 | 2–4 entrées — produisait des artefacts "|" |
projects |
550 | 2–5 entrées avec URLs |
Retry par section
Si une section échoue la validation Zod, elle réessaie indépendamment avec l'erreur spécifique renvoyée au LLM :
Tentative d'extraction section 1
↓ échec validation
"Le champ 'work.0.startDate' doit être une chaîne au format YYYY-MM"
↓
Tentative d'extraction section 2 (avec prompt de correction)
↓ succès
Résultat fusionné
Un mauvais résultat pour languages ne cause pas le retry de work — seul languages réessaie.
Observabilité
const result = await parseResume(pdfBuffer, { model })
for (const section of result.meta.sectionResults ?? []) {
console.log(`${section.section}: ${section.success ? '✅' : '❌'}`)
if (section.retryCount > 0) {
console.log(` → ${section.retryCount} retry(s) nécessaire(s)`)
}
if (section.error) {
console.log(` → Erreur: ${section.error}`)
}
}Désactiver la décomposition
Pour les CVs simples à une colonne, l'extraction en un seul appel est plus rapide :
const result = await parseResume(pdfBuffer, {
model,
useTaskDecomposition: false, // un seul appel LLM
})Configurer les retries
const result = await parseResume(pdfBuffer, {
model,
maxRetries: 2, // limite de retry par section (défaut: 3)
})