Jetons et tokenisation
Les modèles ne voient jamais des mots ni des lettres. Ils voient des identifiants de jetons — des entiers qui indexent un vocabulaire fixe de fragments de sous-mots, construit par encodage de paires d'octets (BPE) ou une variante proche. La tokenisation est le poste frontière de tout : votre prompt, la réponse, la fenêtre de contexte, le compteur de jetons par seconde, les factures d'API. Une fois que vous pensez en jetons, la moitié du folklore sur le comportement des LLM se dissout.
Comment un vocabulaire est construit
Le BPE part des octets bruts et fusionne répétitivement la paire adjacente la plus fréquente jusqu'à ce que le vocabulaire atteigne son budget. Résultat : les mots courants deviennent des jetons uniques, les mots rares deviennent 2 à 5 fragments, et rien n'est inrepresentable — le repli octet couvre toute chaîne, fautes de frappe et emoji compris. Les vocabulaires vont de ~30k entrées (modèles anciens) à ~250k (multilingues modernes) :
| Tokenizer | Taille de vocabulaire | Remarque |
|---|---|---|
| GPT-2 | ~50k | Anglais/web dominant |
| Llama 2 | ~32k | Le coréen se coupe douloureusement |
| Llama 3 | ~128k | Grand saut multilingue |
| Qwen 2 / 2.5 / 3 | ~151k | Fortes fusions CJK |
| Gemma | ~256k | Plus grand vocabulaire courant |
Un tokenizer entraîné surtout sur l'anglais fusionne agressivement les fragments anglais ; les paires de syllabes coréennes obtiennent bien moins de fusions utiles. Le vocabulaire décide de votre taxe coréenne bien avant que le modèle lui-même soit bon ou mauvais en coréen.
Exemple détaillé : anglais
"Tokenization turns text into pieces."
→ ["Token", "ization", " turns", " text", " into", " pieces", "."]
→ 37 characters → 7 tokens ≈ 5.3 chars/token
Notez les détails : le mot courant « Token » est un fragment ; le suffixe a le sien ; et l'espace initial appartient au jeton suivant (« turns », pas « turns »). C'est pourquoi « hello », « hello » et « Hello » sont des jetons différents — des prompts qui diffèrent d'un espace ou d'une majuscule se tokenisent différemment.
Exemple détaillé : coréen
Même phrase, économie pire. Le hangûl s'écrit en blocs syllabiques, et les fusions coréennes sont plus rares dans les vocabulaires dominés par l'anglais (les découpages ci-dessous sont plausibles, pas exacts) :
"안녕하세요, 만나서 반가워요." # 17 caractères
vocabulaire multilingue fort (~150k entrées) :
["안녕", "하세요", ",", " 만나", "서", " 반", "가", "워", "요", "."]
→ ~10 tokens ≈ 1.7 chars/token
vocabulaire faible (~32k entrées, découpes au niveau jamo) :
["안", "녕", "하", "세", "요", ",", " 만", "나", "서", ...]
→ 15+ tokens ≈ 1.1 chars/token
L'anglais tourne autour de ~4 caractères/jeton. Le coréen tombe couramment à 1–1.5. Même sens, 3–4× plus de jetons. C'est pourquoi :
- Les prompts CJK consomment les fenêtres de contexte à une vitesse alarmante — une fenêtre de 8k jetons contient à peu près 3–4× plus d'anglais que de coréen.
- La génération « paraît » plus lente en coréen à tok/s identique : plus de jetons par phrase, moins de texte par jeton.
- Le coréen coûte plus cher sur les APIs facturées au jeton, et les traces de raisonnement écrites en coréen brûlent le budget pareil.
Pourquoi les questions de comptage de lettres échouent
Demandez « combien de r dans strawberry » et même les grands modèles trébuchent. Raison : le modèle ne voit jamais les lettres. « strawberry » arrive à peu près comme ["straw", "berry"] — deux entiers. Il n'y a pas de compte de lettres dans un entier, pas plus qu'un numéro de page ne vous donne l'orthographe de la page. Le modèle peut réciter des orthographes mémorisées ou raisonner pas à pas, et les deux sont peu fiables. Si vous avez besoin du résultat : forcez le modèle à épeler le mot une lettre par ligne, puis comptez les lignes.
Le vocabulaire est livré avec le modèle
- Les fichiers du tokenizer (vocabulaire, fusions) font partie de la livraison ; le GGUF les intègre, les dépôts safetensors les portent à côté des poids.
- Les moteurs (llama.cpp, LM Studio, vLLM, ...) chargent le bon tokenizer automatiquement. Vous n'en choisissez jamais un.
- Les comptes de jetons sont relatifs au modèle : le même texte peut faire 1,000 jetons avec le vocabulaire d'une famille et 1,150 avec celui d'une autre. Ne codez jamais en dur des budgets de jetons entre modèles.
- La qualité du vocabulaire et celle du modèle sont des axes séparés : un modèle à vocabulaire 32k peut gérer le coréen (il comprend ses jetons) ; il dépense juste plus de jetons par phrase.
Tout est facturé en jetons
| Ce qui vous importe | Facturé en |
|---|---|
| Fenêtre de contexte (4k → 128k+) | jetons entrants + jetons sortants ensemble |
| Vitesse de génération | jetons par seconde |
| Mémoire du cache KV | croît par jeton de contexte (cache KV) |
| Tarification API | au million de jetons |
| Plafonds de longueur de sortie | jetons de sortie max |
| Budgets de raisonnement/réflexion | jetons que le modèle peut dépenser avant de répondre |
| Vectorisation de documents pour le RAG | fragmentés et comptés au million de jetons |
Jetons spéciaux et gabarit de conversation
En plus des fragments de texte, le vocabulaire réserve des identifiants de contrôle : début de séquence, fin de séquence et marqueurs de rôle. Quand votre interface de chat envoie un message, elle n'envoie pas du texte brut — elle remplit un gabarit de conversation qui entrelace des jetons spéciaux comme <|im_start|>user ... <|im_end|> autour de vos mots. Cet habillage explique pourquoi le compte de jetons rapporté par le moteur est toujours un peu plus élevé que le seul texte de votre message, et pourquoi mélanger des gabarits de familles différentes embrouille les modèles.
Règles d'estimation : caractères anglais ÷ 4. Caractères coréens ÷ 1.0–1.5 — supposez le pire. Le simulateur utilise l'approximation ~4 caractères/jeton et est calibré pour l'anglais ; majorez mentalement pour le coréen.
Compter les jetons vous-même
pip install tiktoken
python -c "import tiktoken as t; e = t.get_encoding('o200k_base'); print(len(e.encode('hello world')))"
- tiktoken (https://github.com/openai/tiktoken) couvre les encodages de la famille OpenAI ; les autres familles diffèrent mais restent dans environ ±15% pour l'anglais.
- Les pages de modèles Hugging Face incluent une visionneuse de tokenizer ; les playgrounds de tokenization vous laissent coller du texte et voir les découpages en direct.
- Les moteurs locaux affichent les comptes de jetons de prompt dans leurs journaux — vérifiez une fois sur vos vrais prompts, puis estimez au ratio.
Voir aussi : l'intérieur du transformer · préremplissage vs décodage · cache KV