2. Tokens: how text becomes numbers
The model never sees letters or words. Before any thinking happens, prompt is chopped into pieces and each piece is replaced by an integer ids from a fixed vocabulary built by a compression algorithm — and that detail explains a surprising number of LLM quirks.
By the end of this lesson you can
- Say what a tokenizer does and why letters never reach the model
- Explain why models use subword tokens instead of characters or words
- Run the byte-pair encoding merge algorithm by hand
- Predict how a given string will be split, including the leading-space trap
- Connect tokenization to real failures: spelling, arithmetic, rare languages, cost
Why not just use words? Or letters?
Lesson 1 ended with the assembly line, and its first station was the tokenizer. This lesson is that station. One sentence to start, because everything else follows from it: the model is a number machine — letters cannot enter it. Everything must be converted into numbers before any prediction happens, and the conversion has to be mechanical, because it runs on every text in every language, including texts nobody has ever seen.
So: chop the text into pieces, and give each piece a number. The only real question is how big a piece. Three options were tried; the first two fail.
Option 1: one piece per whole word. Sounds natural — words are the units we think in. Two problems. English has millions of word forms, plus names, typos, URLs and code, so the lookup list would be enormous — and still fail constantly, because any word not on the list is simply unrepresentable. And related words would share nothing: tokenization, tokenizations and Tokenizer would be three unrelated numbers, even though you can see they are the same root three ways. The model would have to learn each one from scratch.
Option 2: one piece per letter. Now the list is tiny — 26 letters plus digits and punctuation, or just 256 "bytes" (the numbers 0–255 that computers store every character as) — and nothing can ever be unknown, because every character is on the list. But look what happens to a short sentence:
Hello world → 10 pieces: H e l l o ␣ w o r l d
Recall the loop from Lesson 1: one pass through the whole machine per piece, and the model can only "see" a fixed-length stretch of pieces at a time — its context window. Ten passes instead of two, for the same sentence: five times the compute, and five times the space taken in the window. Too expensive.
Option 3: subwords — the compromise everyone landed on. Common things get one piece; rare things get built from shared fragments. "the" is one piece. "unhappiness" might be un + happi + ness. Nothing is ever unrepresentable (worst case: bytes), and sequences stay short. Real systems average roughly 4 characters per piece in English, and the list runs 32,000–256,000 entries.
One more thing to notice: the pieces are learned from text, not handed down by a linguist. What counts as "common" depends on which text you learned from — and that single fact is responsible for most of this lesson's quirks.
Byte-pair encoding, step by step
So how does the piece-list get built in the first place? Nobody hand-curates it. It is grown by an algorithm from 1994 called byte-pair encoding (BPE), and you are fully able to run it yourself. The whole idea in one sentence: start with everything in pieces, then repeatedly glue together whichever two neighbouring pieces appear together most often.
Do it by hand on a tiny "corpus" — four words: low low low lower. Start by splitting every word into individual letters (imagine each word ends with a marker, </w>, so "low" is really l o w</w> — the marker stops glues from running across words):
- Count every neighbouring pair. The pair
l-oappears once in each "low" (×3) and once in "lower" — 4 times total. The pairo-wappears 3 times. The paire-rappears once. And so on. - Glue the winner.
l-ois the most frequent pair, so it becomes a new single piece. The words are now[lo] w(×3) and[lo] w e r. - Recount and repeat. The pair
[lo]-wappears 4 times — it wins, and "low" now exists as one piece. Next round[low]-ewins, and "lower" ends up aslow+e+rafter a couple more rounds.
That's all it is: count, glue the most common pair, repeat, until the list reaches its size budget (tens of thousands of entries). Run on real text, the same process is what turns frequent English sequences — ing, the, tion, def — into single pieces, while rare sequences stay in fragments. The final product is an ordered list of glue rules, and encoding any new text just means replaying those rules in the order they were learned.
Now run it for real in the trainer below — it is exactly the procedure you just did by hand. Watch which pairs win, and remember the last section's warning: the merges reflect the corpus you feed it, not "English in general". A tokenizer trained on English code splits Japanese badly, and that is a real, measured disadvantage for those languages: more pieces per sentence means more cost and less content fitting in the context window.
Train a BPE tokenizer
Edit the corpus, then run merges one at a time and watch the vocabulary grow.
Encoding: the leading space matters
You now know how the piece-list was built. The other half of the story is how your text gets encoded against that list, and there is one detail there with real consequences. Two stages:
- First, rough cuts. A fixed pattern chops the text into rough pieces — roughly word-sized, and it is this step that decides a space starts a new piece rather than ending the previous one. Glue rules never cross these cut lines.
- Then, glues inside each piece, applied in the order they were learned (earliest first).
The detail with consequences: the space usually travels with the word that follows it. So " dog" (space glued on) and "dog" are two different pieces with different numbers, in GPT-style tokenizers and most others. Nothing is wrong with that — it is just how the list was built — but remember Lesson 1: the model can only predict what comes next, and it predicts from what the pieces actually say.
Here is the failure that follows, end to end. You write a raw completion prompt ending in a space: "The answer is ". The model's favourite continuation is " Paris" — but that piece carries its own leading space, and yours has already been spent. Emitting it would print two spaces ("is Paris"). Pieces for that exist, but text with double spaces almost never appeared during training, so the model never learned to expect anything there — the odds over the whole next piece go flat, and what little weight remains sits on oddities. You get a coin-flip instead of a confident answer, purely because your prompt ended half-way through a piece.
Two things limit the damage in practice. First, it mostly bites raw completion prompts, where your text is literally the beginning being continued; chat apps wrap your message in turn markers and generation starts after those, so the effect largely disappears. Second, it is not a GPT quirk — it follows from subword tokenization itself, so it holds for any model whose tokenizer glues the space to the following word (GPT, Llama, Mistral, Claude and the rest). The rule that survives everywhere: do not end a prompt half-way through what should be a single piece — a space at the end, or a cut in the middle of a word.
Try the live tokenizer below — it uses a cut-down copy of GPT-4's real piece-list (6,057 of the ~100,000 entries, but every id shown is genuine), with the real numbers underneath each piece. Start with the "leading space" preset: strawberry at the start of a line splits into three pieces (str + aw + berry), while ␣strawberry with its leading space is a single piece. Same letters, three pieces versus one: three times the passes through the model, three times the space it takes in the context window, and three different numbers reaching the next stage instead of one. Then try the other presets — numbers, code indentation, a Japanese sentence — and watch the "characters per token" count at the bottom change. That number is the closest thing to a "how good is this tokenizer for this language" score, and it is why the Japanese and Russian you paste in costs more than the English.
Live tokenizer
Real byte-pair encoding against a cut-down cl100k_base table — the vocabulary GPT-4 uses. Colours mark token boundaries; the real token ids are shown underneath.
Quirks that are actually tokenization
Time to collect the payoff. There is a large family of "this model is an idiot" moments that are really one fact in disguise: the model cannot see letters — only piece-numbers. The famous example: ask a chatbot how many r's are in "strawberry" and smart models confidently say 2. You can watch why in the tokenizer above: the model receives roughly str + aw + berry — three opaque numbers. The three r's are physically inside those chunks, but nothing in the input says "letters live here". The model has to know spellings indirectly, from text that talked about spellings, the way you know a word's spelling partly by feel rather than by looking.
The same single fact explains a whole cluster of failures and quirks:
- Reversing words, rhyming, letter games. All of it operates on letters the model never actually receives. It is good at them only to the extent it memorised the answers.
- Fragile arithmetic. Whether
1234arrives as one piece, or12+34, or digit-by-digit, changes how digits line up between the two numbers being multiplied — and alignment is what column arithmetic depends on. Some model families deliberately split every digit for exactly this reason (Exercise 5 quizzes you on the fix). - Per-language cost. Billing is per piece. A language that averages 3 characters per piece costs roughly twice what English costs per sentence, and fills the model's view twice as fast. Not sentiment — arithmetic.
- Glitch tokens. Some pieces made it onto the list but almost never appeared in training text, so their embeddings stayed near-random. Feeding one in can derail a model completely. The famous one is
SolidGoldMagikarp, which for a while made GPT-3 spit out garbled nonsense when it appeared in a prompt.
Practical takeaway: when a model fails at a character-level task, first ask whether the characters were ever visible to it. Often the fix is to add spaces between the characters in your prompt, which forces a finer split — giving the model one piece per letter so it can finally "see" what it is being asked about.
Does this mean you should prompt in English? Slightly, for two separate reasons that are easy to conflate. The tokenizer penalty is real but modest: Polish runs about 2–3 characters per token in English-built vocabularies versus ~4 for English, so you pay roughly 1.5–2× the cost and context space — a length penalty, not an intelligence penalty. The bigger effect for answer quality is usually training-data coverage (Lesson 12), not the tokenizer. For everyday use in a modern model the gap is often not worth switching over; it compounds on long documents and tricky reasoning, where the token multiplier and the coverage gap add up.
Lesson in one breath
A tokenizer is a fixed vocabulary of byte sequences, learned before training by repeatedly merging the most frequent adjacent pair. Text is encoded by applying those merges in the order they were learned, and each resulting chunk becomes an integer. The model's entire universe is those integers.
Practice
Answers are checked in your browser and saved to this device. Get one wrong and you can retry as many times as you like.
Why do modern LLMs use subword tokens rather than one token per word?
You run BPE on the corpus low low low lower, treating spaces as separators and looking only inside words. Counting adjacent character pairs across all four words, how many times does the pair lo occur?
low appears three times and lower once — each contains lo exactly once, so the pair count is 4. It would be the first merge.Which of these behaviours are direct consequences of tokenization? Select all.
Name the algorithm that builds a subword vocabulary by repeatedly merging the most frequent adjacent pair of symbols. (Its three-letter abbreviation is fine.)
A model is bad at multiplying four-digit numbers. Which tokenizer change is most likely to help?
12|34 versus 1|234 destroys the alignment that column arithmetic needs.Done with this lesson?
A lesson counts as complete once it is marked read and every exercise is solved.
Tip: press ← and → to move between lessons.