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
- É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. Par défaut, 8 sections s'exécutent en parallèle :
Texte du CV
↓
┌─────────┬──────┬───────────┬────────┬───────────┬──────────┬──────────────┬───────────┐
│ basics │ work │ education │ skills │ languages │ projects │ certificates │ volunteer │
│ prompt │ ... │ ... │ ... │ ... │ ... │ ... │ ... │
│ schéma │ ... │ ... │ ... │ ... │ ... │ ... │ ... │
│maxTokens│ ... │ ... │ ... │ ... │ ... │ ... │ ... │
└─────────┴──────┴───────────┴────────┴───────────┴──────────┴──────────────┴───────────┘
↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
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.
Choisir les sections à extraire
Par défaut, 8 sections sont extraites. Vous pouvez surcharger cela avec l'option sections :
// Extraire uniquement ce dont vous avez besoin — économise des tokens
const result = await parseResume(buffer, {
model,
sections: ['basics', 'work', 'education'],
})
// Extraire les 12 sections disponibles
import { ALL_SECTIONS } from '@edwinfom/resume-intel'
const result = await parseResume(buffer, {
model,
sections: [...ALL_SECTIONS],
})Les 12 sections disponibles
| Section | Max tokens | Contenu |
|---|---|---|
basics |
500 | Nom, email, téléphone, localisation, résumé, profils |
work |
1200 | Expérience professionnelle avec points clés |
education |
600 | Diplômes, certifications, cours |
skills |
400 | Compétences techniques groupées par catégorie |
languages |
200 | Langues parlées avec niveau de maîtrise |
projects |
700 | Projets personnels et side projects |
awards |
300 | Prix et distinctions |
certificates |
300 | Certifications professionnelles |
publications |
400 | Articles, livres, publications |
volunteer |
450 | Bénévolat et service communautaire |
interests |
200 | Centres d'intérêt et loisirs |
references |
250 | Références professionnelles |
Retry par section
Si une section échoue la validation Zod, elle réessaie indépendamment avec l'erreur renvoyée au LLM :
Tentative 1 : échec — "work.0.startDate doit être au format YYYY-MM"
↓
Tentative 2 (avec prompt de correction) : succès
↓
Résultat fusionné
Observabilité
const result = await parseResume(pdfBuffer, { model })
console.log(result.meta.sectionsRequested)
// ['basics', 'work', 'education', 'skills', 'languages', 'projects', 'certificates', 'volunteer']
for (const s of result.meta.sectionResults ?? []) {
const status = s.success ? 'OK ' : 'FAIL'
const retries = s.retryCount > 0 ? ` (${s.retryCount} retries)` : ''
console.log(`${status} ${s.section}${retries}`)
}Désactiver la décomposition
Pour les CVs simples ou avec un outputSchema personnalisé, le mode single-shot est plus rapide :
const result = await parseResume(pdfBuffer, {
model,
useTaskDecomposition: false,
})