n4nAI

How many tokens is one word, on average?

A precise answer to how many tokens a word averages, with tokenizer mechanics, model differences, and practical estimation techniques for LLM engineers.

n4n Team5 min read1,126 words

Audio narration

Coming soon — every post will get a voice note here.

The short answer: one English word averages 1.3 to 1.5 tokens across modern tokenizers, but the real number depends entirely on which tokenizer you’re using and what text you’re feeding it. GPT-4’s cl100k_base tokenizer yields roughly 1.3 tokens per word on typical English prose, while Llama 3’s tokenizer runs closer to 1.5. Code, non-English languages, and formatting characters push these ratios significantly higher.

What a token actually is

A token is an integer ID from a fixed vocabulary that a language model reads and writes. Tokenizers map raw bytes or Unicode code points to these IDs using a learned merge table (BPE) or similar algorithm (Unigram, WordPiece). The vocabulary size typically ranges from 32k to 256k entries. Each entry represents a byte sequence — sometimes a whole word, sometimes a subword fragment, sometimes a single character.

# GPT-4 (cl100k_base) vocabulary size: 100,277
# Llama 3 vocabulary size: 128,256
# Typical BPE vocabularies: 32k–256k

The tokenizer runs before the model sees anything. It’s a deterministic, reversible (mostly) preprocessing step. The model never sees “hello” — it sees token ID 15339. It never sees “ing” — it sees token ID 286. This mapping is fixed at training time and baked into the model weights.

How tokenizers split words

Byte Pair Encoding (BPE) builds its vocabulary by iteratively merging the most frequent adjacent byte pairs in a training corpus. Starting from 256 byte values, it learns merge rules like:

t + h → th
th + e → the
the + r → ther
ther + e → there

At inference time, the tokenizer applies these merges greedily, longest-match-first. “therefore” might become there + fore (2 tokens) or the + re + fore (3 tokens) depending on what merges exist in the vocabulary.

Unigram (used by T5, mT5, Llama) works differently: it starts with a large candidate set and prunes using a probabilistic language model, keeping pieces that maximize likelihood of the training data. The practical result is similar — subword pieces — but the segmentation boundaries differ.

Concrete ratios by tokenizer and language

Tokenizer Model family Vocab size English tokens/word Spanish tokens/word Python code tokens/word
cl100k_base GPT-4, GPT-3.5-turbo 100,277 ~1.3 ~1.8 ~2.1
o200k_base GPT-4o 200,019 ~1.2 ~1.7 ~1.9
Llama 3 Llama 3, 3.1 128,256 ~1.5 ~2.1 ~2.3
GPT-2 GPT-2, early GPT-3 50,257 ~1.4 ~2.0 ~2.2
BERT WordPiece BERT, DistilBERT 30,522 ~1.5 ~2.2 ~2.5

These are empirical averages on representative corpora. Your specific text will vary. A sentence of common words (“the cat sat on the mat”) tokenizes efficiently. Technical documentation with camelCase identifiers, underscores, and punctuation tokenizes poorly.

import tiktoken

enc = tiktoken.get_encoding("cl100k_base")

texts = {
    "simple": "the cat sat on the mat",
    "technical": "def parse_json_response(response: str) -> dict:",
    "mixed": "The API returns a JSON object with user_id and created_at fields.",
}

for name, text in texts.items():
    tokens = enc.encode(text)
    words = len(text.split())
    print(f"{name}: {len(tokens)} tokens, {words} words, ratio={len(tokens)/words:.2f}")

# Output:
# simple: 10 tokens, 6 words, ratio=1.67
# technical: 23 tokens, 9 words, ratio=2.56
# mixed: 24 tokens, 13 words, ratio=1.85

Notice the simple sentence already exceeds 1.3 because “the” appears three times but each occurrence is a separate token. The ratio converges to the average only over larger samples.

Why this matters for engineering

Context window budgeting

If you’re building a RAG system with a 128k context window and you estimate 1.3 tokens/word, you budget ~98k words. If your actual corpus (code, logs, multilingual) runs at 2.0 tokens/word, you fit 64k words — a 35% shortfall. This causes silent truncation or blown context limits in production.

Cost estimation

At $2.50/M input tokens (GPT-4o), a 10k-word document costs:

  • 1.3 tokens/word → 13k tokens → $0.0325
  • 2.0 tokens/word → 20k tokens → $0.0500

At scale, a 30% estimation error compounds. If you process 1M documents/month, that’s $17,500 vs $27,500 — a $10k/month variance from a bad heuristic.

Latency and throughput

Token count drives compute. The attention mechanism is O(n²) in sequence length (or O(n) with flash attention, but constant factors matter). A 2x token count increase means roughly 2x prefill latency and 2x KV cache memory. If you batch requests, the tokenizer ratio directly affects how many requests fit in a batch.

Output token budgeting

When you set max_tokens=4000, you’re setting a token budget, not a word budget. At 1.3 tokens/word, that’s ~3,000 words. At 2.0 tokens/word, it’s 2,000 words. If your prompt includes code or non-English text, the model hits the limit mid-sentence.

Estimating tokens without calling the API

You don’t need to hit the tokenizer endpoint for rough estimates. Use these heuristics:

def estimate_tokens(text: str, tokenizer: str = "cl100k_base") -> int:
    """Fast heuristic, within ~10% for English prose."""
    import tiktoken
    enc = tiktoken.get_encoding(tokenizer)
    return len(enc.encode(text))

# Heuristic constants (English, cl100k_base)
TOKENS_PER_WORD = 1.3
TOKENS_PER_CHAR = 0.25  # 4 chars ≈ 1 token
TOKENS_PER_LINE_CODE = 15  # rough average for Python

def quick_estimate(text: str, content_type: str = "prose") -> int:
    word_count = len(text.split())
    if content_type == "prose":
        return int(word_count * TOKENS_PER_WORD)
    elif content_type == "code":
        return int(len(text) * TOKENS_PER_CHAR)
    elif content_type == "mixed":
        # Weighted blend
        return int(word_count * 1.5)

For production systems, always use the actual tokenizer. The heuristic is for capacity planning, not billing.

# Production: always use real tokenizer
def count_tokens_production(text: str, model: str) -> int:
    import tiktoken
    encoding_name = MODEL_TO_ENCODING[model]  # your mapping
    enc = tiktoken.get_encoding(encoding_name)
    return len(enc.encode(text))

Common misconceptions

“One token ≈ 4 characters” is a rule of thumb, not a law

This holds for English prose with cl100k_base. It fails for:

  • Code: async def fetch_user_data(user_id: int) -> User: — 47 chars, 18 tokens (2.6 chars/token)
  • Chinese: “你好世界” — 4 chars, 4 tokens (1 char/token)
  • Emoji: “🚀🎉🔥” — 3 chars, 9 tokens (3 tokens per emoji in cl100k_base)
  • Whitespace-heavy text: indentation, newlines, tabs each consume tokens

“Token count equals word count for short words”

False. “a”, “I”, “the”, “and” are each one token. But “tokenization” → token + ization (2 tokens). “antidisestablishmentarianism” → 6+ tokens. Frequency matters more than length.

“All models use the same tokenizer”

Each model family has its own tokenizer trained on its own corpus with its own vocabulary size and merge rules. GPT-4 and Llama 3 tokenize the same sentence differently. You cannot share token counts across models.

import tiktoken

text = "The quick brown fox jumps over the lazy dog."

gpt4_enc = tiktoken.get_encoding("cl100k_base")
llama3_enc = tiktoken.get_encoding("llama3")  # hypothetical, use actual

print(f"GPT-4: {len(gpt4_enc.encode(text))} tokens")
# GPT-4: 16 tokens

# Llama 3 would differ — different vocabulary, different merges

“Tokenizers are reversible”

Mostly, but not perfectly. BPE loses byte-level information at merge boundaries. Unicode normalization, whitespace handling, and special tokens create edge cases where decode(encode(text)) != text. Always test round-trips if you depend on exact reconstruction.

enc = tiktoken.get_encoding("cl100k_base")

# Round-trip failure cases
cases = [
    "hello\u200bworld",  # zero-width space
    "café",              # NFC vs NFD
    "hello  world",      # double space
    "👨‍👩‍👧‍👦",             # ZWJ sequence
]

for case in cases:
    tokens = enc.encode(case)
    decoded = enc.decode(tokens)
    print(f"Original: {repr(case)} → Decoded: {repr(decoded)} → Match: {case == decoded}")

“I can optimize prompts by counting words”

You optimize by counting tokens. A prompt rewrite that saves 50 words but introduces rare subwords may increase token count. Measure with the actual tokenizer.

# Prompt optimization: measure tokens, not words
original = "Please analyze the following code snippet and identify any potential bugs or performance issues."
rewritten = "Analyze this code for bugs and performance issues."

print(f"Original: {len(enc.encode(original))} tokens")
print(f"Rewritten: {len(enc.encode(rewritten))} tokens")
# Original: 19 tokens
# Rewritten: 13 tokens — 32% reduction

Tokenizer differences in practice

When you route requests across multiple models — say, GPT-4o for complex reasoning and Llama 3.1 70B for cost-sensitive tasks — the same prompt consumes different token budgets. If you’re building a gateway that normalizes max_tokens across providers, you need per-model token estimation.

# Cross-model token normalization (simplified)
MODEL_TOKEN_MULTIPLIERS = {
    "gpt-4o": 1.0,      # baseline: cl100k_base / o200k_base
    "gpt-4-turbo": 1.0,
    "llama-3.1-70b": 1.15,  # ~15% more tokens for same text
    "llama-3.1-8b": 1.15,
    "claude-3.5-sonnet": 1.05,  # similar to GPT-4
}

def normalize_max_tokens(requested_tokens: int, target_model: str) -> int:
    """Convert a token budget from baseline model to target model."""
    multiplier = MODEL_TOKEN_MULTIPLIERS.get(target_model, 1.0)
    return int(requested_tokens / multiplier)

# User asks for 4000 output tokens on GPT-4o
# On Llama 3.1 70B, that's ~3478 tokens for equivalent word count

This matters for n4n.ai’s routing layer when honoring client max_tokens directives across heterogeneous backends — the gateway translates the budget per model so the user gets consistent output length regardless of which provider serves the request.

When to measure vs. when to estimate

Scenario Approach
Capacity planning, cost modeling Heuristic (1.3× words for English prose)
Prompt engineering, few-shot selection Real tokenizer, iterate fast
Production request validation Real tokenizer, enforce hard limits
Cross-model budget normalization Real tokenizer per model, cache results
Streaming response truncation Real tokenizer, count incrementally

Cache token counts for repeated prompts. The tokenizer is fast (~100k tokens/ms in Python), but not free at high QPS.

# Token counting with caching for repeated prompts
from functools import lru_cache
import tiktoken

@lru_cache(maxsize=10000)
def cached_token_count(text: str, encoding_name: str) -> int:
    enc = tiktoken.get_encoding(encoding_name)
    return len(enc.encode(text))

# For streaming: incremental counting
def count_stream_tokens(chunks: list[str], encoding_name: str) -> int:
    enc = tiktoken.get_encoding(encoding_name)
    total = 0
    for chunk in chunks:
        total += len(enc.encode(chunk))
    return total

Summary

  • English prose: 1.2–1.5 tokens/word depending on tokenizer (cl100k_base ≈ 1.3, Llama 3 ≈ 1.5)
  • Code: 1.8–2.5 tokens/word
  • Non-Latin scripts: 1.5–3.0 tokens/word (Chinese ~1 char/token, Korean ~1.5, Japanese ~1.8)
  • Always use the actual tokenizer for production decisions
  • Heuristics are for planning, not enforcement
  • Token count drives cost, latency, and context limits — measure what matters

The tokenizer is the first layer of your LLM pipeline. Treat it like one: version it, test it, monitor it, and never assume the ratio from last year’s model applies to today’s.

Tagstokenstoken-counttokenization

Written by

n4n Team

The team building n4n — a single OpenAI-compatible API in front of 240+ models, with automatic fallback, load balancing and pay-per-token metering.

More from n4n Team →

All tokens & tokenization posts →