Tokens and context windows
How text becomes tokens, why non-English text and code cost more, how the context window works as a budget shared by prompt and reply, what the KV cache costs in memory and how to avoid silent truncation.
Models do not read characters or words. They read tokens: chunks of text produced by a tokenizer (usually byte-pair encoding, BPE). Common words are a single token; rare words, code, numbers and non-English text split into more. Everything about speed, memory and cost in LLM systems is measured in tokens, so it pays to understand them well.
"Local inference is fun" -> ["Local", " inference", " is", " fun"] (4 tokens)
"Quantization" -> ["Quant", "ization"] (2 tokens)
"2026-03-03" -> ["202", "6", "-", "03", "-", "03"] (6 tokens; varies by model)Notice that the leading space belongs to the token ( inference), and that the splits above are illustrative: every tokenizer cuts differently.
Characters
76
Tokens
19
Chars per token
4.0
19 of 4,096 tokens (0.5%). Prompt and answer share this budget.
Illustrative tokenizer. Real models use a learned vocabulary (BPE or similar), so exact splits and ids differ, but the idea is identical: text becomes a sequence of integer ids.
#How a tokenizer is built
A BPE tokenizer is trained on a large text sample by repeatedly merging the most frequent adjacent pairs of symbols. It starts from bytes (so any text can be encoded) and builds a vocabulary of typically 32,000 to 200,000 pieces. Frequent English words become single tokens; rare strings fall back to smaller pieces, down to single bytes if needed.
Consequences you will notice:
- The same text has different token counts in different models. A Llama tokenizer, a Qwen tokenizer and a Mistral tokenizer disagree. Always count with the model you actually run.
- Whitespace and capitalisation matter.
Hello,helloandHELLOcan be different tokens. - Numbers split awkwardly. Many tokenizers cut numbers into short digit groups, one reason arithmetic on long numbers is error-prone for LLMs.
- Special tokens exist for structure: beginning and end of text, role markers (
<|im_start|>user), end-of-turn. They are part of the chat template (chat templates).
#Rules of thumb (English prose)
- 1 token is about 4 characters or 0.75 words.
- 1,000 tokens is roughly 750 words, or 1.5 pages of text.
- A typical email is 150 to 400 tokens; a long article 2,000 to 5,000; a 300-page book around 100,000.
These shift noticeably outside plain English:
| Content | Tokens per word or character (rough) |
|---|---|
| English prose | 1.3 tokens per word |
| Code | 1.5 to 2.5 tokens per word-like chunk; indentation and symbols add up |
| JSON and tables | Heavy: braces, quotes and repeated keys all cost tokens |
| German, French, Spanish | 1.5 to 2 tokens per word |
| Arabic, Hindi, Thai, Chinese, Japanese | 2 to 4 times English per unit of meaning, depending on the tokenizer |
| Emoji and rare symbols | Often several tokens each |
This matters for cost and speed: a Hindi or Japanese user may get a smaller effective context window and slower responses from the same model than an English user. Newer tokenizers with larger vocabularies reduce the gap.
#Counting tokens properly
Use the model's own tokenizer:
# llama.cpp server
curl -s localhost:8080/tokenize -d '{"content":"Local inference is fun"}'
# Python, with the Hugging Face tokenizer for the model you run
from transformers import AutoTokenizer
tok = AutoTokenizer.from_pretrained("Qwen/Qwen2.5-7B-Instruct")
print(len(tok.encode("Local inference is fun")))Count the whole prompt as the model sees it, including the system message, the chat template's special tokens and every previous turn. The text you typed is only part of it.
#The context window
The context window is the maximum number of tokens the model can attend to at once, and it must hold everything: system prompt, chat history, retrieved documents, your question and the reply being generated.
context_size >= prompt_tokens + max_new_tokensA worked budget for a 8,192-token window:
| Part | Tokens |
|---|---|
| System prompt and tool descriptions | 600 |
| Retrieved documents (5 chunks of 400) | 2,000 |
| Chat history (last 6 turns) | 1,200 |
| Current user question | 150 |
| Prompt total | 3,950 |
| Reserved for the reply | 1,000 |
| Used | 4,950 |
| Left over | 3,242 |
When the history keeps growing, something has to give: drop old turns, summarise them, or retrieve less. This is the central design problem in chat and RAG applications (local RAG, agents).
Model (Q4 weights)
KV cache precision
GPU memory
16 GB limit
Fits with 6.3 GB to spare (9.7 GB total).
KV bytes per token = 2 ร layers ร KV heads ร head dim ร bytes per value. The cache grows linearly with context and is on top of the weights.
#Why context costs memory
Each token in context stores key and value vectors for every layer: the KV cache. Its size is:
KV bytes per token = 2 ร layers ร kv_heads ร head_dim ร bytes_per_valueFor Llama 3.1 8B (32 layers, 8 KV heads, 128 dimensions) with 16-bit values:
2 ร 32 ร 8 ร 128 ร 2 = 131,072 bytes = 128 KiB per tokenSo an 8,192-token context uses 8,192 ร 128 KiB = 1 GiB, and 128K tokens would use 16 GiB, more than three times the 4-bit weights of the model. Larger models cost more per token (a 70B can need 320 KiB per token or more). Concurrent users multiply it.
Longer context also slows decoding, because every new token must read the whole cache, and slows prefill, which grows with prompt length. See VRAM math for the full memory budget, and the Pro lessons on KV-cache quantization and long-context performance for ways to reduce it.
#Chat templates and special tokens
Chat models are trained on text wrapped in a specific format, for example:
<|im_start|>system
You are a helpful assistant.<|im_end|>
<|im_start|>user
Hello!<|im_end|>
<|im_start|>assistantThis wrapping is the chat template, and different model families use different ones. If you feed a model text in the wrong format, it still produces output, but worse: it may ramble, ignore the system prompt, or never stop. Runtimes normally apply the right template for you (Ollama does automatically; llama.cpp uses the template stored in the model file, and --jinja enables the model's full template). If a model behaves strangely, suspect the template first.
#When you overflow
Runtimes handle a full window differently: some truncate the oldest tokens, some shift the window (discarding old tokens and keeping the rest), and some error out. The dangerous case is silent truncation: the system prompt sits at the start, so it is the first thing lost, and the model appears to "forget the instructions".
Defences:
- Set the context size explicitly. Defaults are often 2,048 or 4,096 even for models that support much more (
-c 8192in llama.cpp,num_ctxin Ollama). - Measure your prompt and reserve space for the reply.
- Keep the system prompt short and put critical instructions where they will not be truncated; some runtimes can pin the first tokens.
- Summarise history instead of dropping it blindly.
- Log prompt token counts in applications so you notice growth.
Tip: a model that supports 128K tokens does not mean you should run 128K. Memory and speed both degrade with length, and quality often drops for facts buried in the middle ("lost in the middle"). Use the smallest window that fits your task.
#Why long context is not free quality
Even when everything fits:
- Attention dilutes. The model has more to look at, and relevant details can be missed, especially in the middle of a long input.
- Distractors hurt. Stuffing ten loosely related documents in the prompt often gives worse answers than the three best ones (testing RAG).
- Cost and latency grow with every token you add.
- Claimed window is not effective window. Test retrieval of facts at different positions in your actual prompts ("needle in a haystack" style) before relying on a long context.
#Exercise
You run Llama 3.1 8B (128 KiB of KV per token in 16-bit) with a 16,384-token window and expect 4 concurrent users.
- How much KV memory do you need in total?
- A teammate asks for a 128K window "just in case". What would that cost for one user, and what is your answer?
Answers:
16,384 ร 128 KiB = 2 GiBper user, so 8 GiB for four users (if each fills its window).131,072 ร 128 KiB = 16 GiBfor a single user. Unless you have a concrete task that needs that much context, keep the window small, and use retrieval or summarisation for long documents.
Quick quiz
+10 XP per correct answer, +25 XP for a perfect score
1. Roughly how many English words is one token?
2. The context window must hold...
3. A 128K-context model is run with a 128K window on a machine with limited memory. What is the likely problem?
4. Why might the same sentence cost more tokens in another language or in code?
5. The model 'forgets' your instructions halfway through a long chat. A likely cause is...