Why tokenize at all?

AI models don't read words — they read numbers. Tokenizers convert text into numbered pieces.

"Hello world"
->
Tokenizer
->
["Hel", "lo", " world"] -> [1542, 287, 892]

The Tokenization Spectrum

There are three levels to split text. Modern models use subword methods — the sweet spot in the middle.

Word-level
Subword
Character-level
Fewer, bigger tokens More, smaller tokens

Word-level

unhappiness

1 token per word. Vocab = every word ever seen (500k+). Problem: can't handle new/misspelled words ("unkown" = ???)

Subword (BPE, WordPiece, Unigram)

un happi ness

Splits into reusable pieces. Vocab ~30k-100k. Sweet spot: handles any word, compact sequences

Character-level

u n h a p p i n e s s

1 token per character. Tiny vocab (~256). Problem: sequences are very long, model must learn spelling from scratch


BPE: Byte-Pair Encoding

A method — a recipe for merging the most frequent character pairs, step by step.

Step 0

Byte-level BPE

What modern LLMs actually use — BPE on raw bytes, not characters. No "unknown token" ever.

The Problem with Character BPE

Character-level BPE (the demo above) works great for English. But what happens with:

? Emojis: 🚀
? Chinese: 你好
? Arabic: مرحبا
? Mixed: café 🍵

Unicode has 150,000+ characters. You'd need a massive base vocabulary just for individual characters, and rare scripts would still be "unknown."

The Byte-level Solution

Instead of starting with characters, start with the 256 possible byte values. Every piece of text — in any language, any script, any emoji — is just bytes underneath.

Base vocabulary: just 256 entries (0x00 to 0xFF)
🚀 rocket = bytes F0 9F 9A 80
= bytes E4 BD A0
Hi = bytes 48 69

Then BPE merges run on these bytes. Common byte sequences (like ASCII letters) merge quickly into familiar pieces. Rare characters stay as byte sequences — ugly but never "unknown."

How GPT-2 made it work

Raw text
"Hello"
->
Regex pre-split
word boundaries
->
UTF-8 bytes
[48, 65, 6C, 6C, 6F]
->
Map bytes
to visible chars
->
BPE merges
["Hello"]

GPT-2's trick: map each of the 256 byte values to a visible Unicode character (so bytes look like printable text), then run standard BPE on those mapped characters. The result: a single algorithm that handles every language, every emoji, every encoding — with a base vocab of just 256.

Used by: GPT-2/3 (50K vocab), GPT-3.5/4 via tiktoken (100K vocab), GPT-4o (200K vocab), Claude, and most modern LLMs. Same byte-level BPE technique, but each model trains its own vocabulary.


WordPiece

A method — like BPE, but picks merges by likelihood instead of raw frequency. Used by BERT.

BPE: Merge the most frequent pair

Pairs in corpus:
t + h appears 50 times
h + e appears 45 times
e + r appears 40 times
BPE picks: t + h (highest count)

Simple rule: whichever pair appears most often, merge it. Fast and effective.

WordPiece: Merge the pair that maximizes likelihood

Pairs scored by:
score(a,b) = freq(ab) / (freq(a) * freq(b))
t + h score: 0.12 (both very common alone)
q + u score: 0.89 (almost always together)
WordPiece picks: q + u (highest score)

Smarter rule: prefer pairs that always go together over pairs that are just individually common. "q" and "u" almost never appear apart, so merging them is very informative.

WordPiece's ## prefix

WordPiece marks continuation tokens with ##. This tells you which pieces start a word vs. continue one:

"unhappiness" -> un ##happi ##ness
"playing" -> play ##ing
"cats" -> cats (common enough to be one token)

Used by: BERT, DistilBERT, Electra, MobileBERT, and other models from Google's NLP line.


SentencePiece: The Toolbox

A software tool by Google — it can run BPE or Unigram inside it.

Raw Text Input

"Hello world"
No spaces needed!

Key Superpower

Treats the input as a stream of bytes — no assumptions about spaces or word boundaries. Works for every language.

-> feeds into

SentencePiece

Pick your algorithm:

BPE vs Unigram inside SentencePiece

BPE mode

Bottom-up: start with characters, greedily merge the most frequent pair. Same algorithm as standalone BPE.

h e l l o
-> h e ll o
-> h ell o
-> hell o
-> hello
Unigram mode

Top-down: start with a huge vocabulary, prune the least useful pieces. Picks the most probable segmentation.

Start big: [hello, hell, hel, he, h, ello, ell, el, llo, ll, lo, o, ...]
X Remove least useful...
X Keep pruning...
-> ["hel", "lo"] (highest probability split)

Interactive BPE Trainer

Write a training corpus, train BPE from scratch, then test the learned tokenizer on new text.

Repeat words to increase their frequency
30
Characters: 0 Tokens: 0 Ratio: 0 chars/token

The Full Picture

Methods are recipes. Tools are kitchens. Models pick a combination of both.

BPE method Byte-level BPE method WordPiece method Unigram method SentencePiece tool
What is it? Algorithm Algorithm (BPE variant) Algorithm Algorithm Software library (Google)
Direction Bottom-up merges Bottom-up merges Bottom-up merges Top-down pruning Runs BPE or Unigram
Merge criterion Most frequent pair Most frequent pair Highest likelihood gain Remove least useful piece Depends on algorithm chosen
Starts from Characters 256 byte values Characters All substrings (huge) Raw text (no pre-splitting)
Unknown tokens? Possible (rare chars) Never (any byte encodable) Possible (uses [UNK]) Rare (falls back to chars) Depends on algorithm
Word boundary Pre-tokenize by spaces Regex pre-split Pre-tokenize, ## prefix No pre-tokenization needed Uses ▁ (space marker)
Typical vocab 30k-100k 50k-100k 30k-110k 32k-64k You choose
Used by Original GPT GPT-2/3/4, Claude BERT, DistilBERT T5, ALBERT, XLNet LLaMA 1/2, T5, ALBERT, mBART

Why Tokens Are Not Words

The same "amount" of text can produce wildly different token counts depending on the content.

Efficient (few tokens)

"The cat sat on the mat"
6 words -> ~6 tokens (common English words are usually 1 token each)

Expensive (many tokens)

{"user_id": "abc123"}
3 "words" -> ~10 tokens (JSON syntax, underscores, and quotes each cost tokens)

Token-expensive content (watch out for these)

Source code
Indentation, brackets, variable names with underscores all add up
JSON / XML
Structural characters, repeated keys, nested quotes
Non-English text
CJK characters often use 2-3 tokens each. Arabic, Thai can be worse.
PDF copy-paste
Invisible characters, weird spacing, ligatures inflate count

Special Tokens

Hidden structural markers that control how the model interprets the sequence. You rarely see them, but they shape everything.

Common special tokens

[BOS] — Beginning of sequence. "Start here."
[EOS] — End of sequence. "Stop generating."
[PAD] — Padding. Fills batches to equal length.
[CLS] — Classification token (BERT). Collects sentence meaning.
[SEP] — Separator. Divides segments (e.g., question | passage).
[MASK] — Masked token (BERT training). "Predict what goes here."

Chat/instruction tokens

Modern chat models use special tokens to mark role boundaries. Getting these wrong causes subtle bugs:

<|system|> You are a helpful assistant.
<|end|>
<|user|> What is 2+2?
<|end|>
<|assistant|> 4.
<|end|>

Each model family has its own format (ChatML, LLaMA's format, etc.). Mismatched turn markers during fine-tuning is a common source of degraded quality.


Context Windows

The maximum number of tokens a model can process at once. Everything — instructions, history, retrieved docs, AND the generated output — must fit.

The context window is a working desk, not a filing cabinet

System Prompt
Tools
Conversation History
Retrieved Context (RAG)
Output Budget
Token 0 |--- 128k total tokens ---| Token 128,000
Truncation

Drop tokens from the front or back. Cheapest but riskiest — you might cut the instruction the model needs most.

Sliding Window

Process long text in overlapping chunks. Preserves local detail but can't do global reasoning across the full document.

Summarization

Compress older context into a summary. Preserves gist but loses exact wording. Used in long chat sessions.

ModelContext Window~Word EquivalentNote
GPT-3 (original)2,048~1,500 wordsCould barely fit a long email
GPT-3.5 Turbo4,096 / 16,384~3K / ~12K wordsOriginal 4K; 16K variant added later
GPT-4 Turbo128,000~96,000 wordsA full novel
Claude 3 (200K) / Claude 4 (1M)200,000 - 1,000,000~150K - 750K wordsMultiple books
Gemini 1.5 Pro1,000,000~750,000 wordsAn entire codebase

Token Budgeting in Production

Tokens = compute = money = latency. Smart budgeting is a first-class engineering problem.

Why tokens matter for cost

LLM APIs bill per token. More tokens = more $$$, more compute, higher latency. Two prompts that look similar to a human can differ dramatically in token count.

Input tokens: ~$3-15 per 1M tokens
Output tokens: ~$15-75 per 1M tokens
Output is 3-5x more expensive! Cap output length
Why is output more expensive?

Input (prefill) — all tokens hit the GPU in one parallel batch. High hardware utilization, very efficient.

Output (decode) — tokens are generated one at a time, sequentially (can't produce token N+1 until token N is known). Each step runs the new token through all layers, attending to the entire KV cache. The actual math per token is small, but the GPU must read all model weights + cached K/V from memory each time — making it memory-bandwidth bound (compute cores sit idle waiting for data). 100 output tokens = 100 serial passes.

Budget backward from the limit

Start from the maximum window and subtract fixed costs. What remains is your retrieval budget.

total_window = 128,000
- system_prompt = 800
- chat_history = 2,000
- output_budget = 1,200
- tool_results = 500
= retrieval_budget = 123,500

In practice, measure average AND worst-case (P99) token usage — the "tail." If your average prompt is 4k tokens but 1% of prompts hit 12k, those outliers will overflow and silently truncate. Budget for the tail, not the average.