Tokens & Context Windows — The Hard Budget Every AI Agent Must Respect
Tokens are the atomic unit of LLM memory and cost. Learn subword tokenization, context window math, and agent budgeting before you ship.
Every LLM agent runs on a single scarce resource: tokens {Mọi LLM agent đều chạy trên một nguồn tài nguyên khan hiếm duy nhất: tokens}. Not dollars, not GPU seconds — tokens are the atomic unit of memory, latency, and billing {Không phải đô la, không phải giây GPU — token là đơn vị cơ bản của bộ nhớ, độ trễ, và thanh toán}. If you build agents without internalizing this budget, you will ship systems that silently truncate history, drop tool results, or burn 10× the cost you estimated {Nếu bạn xây agent mà chưa nắm vững ngân sách này, bạn sẽ ship hệ thống âm thầm cắt history, bỏ tool results, hoặc đốt gấp 10 lần chi phí ước tính}.
This post is Part 1 of the Building AI Agents series: the foundation every later topic — sampling, prompting, memory, tool use — assumes you already understand {Bài này là Phần 1 của loạt Building AI Agents: nền tảng mà mọi chủ đề sau — sampling, prompting, memory, tool use — đều giả định bạn đã hiểu}.
Part 1 of the Building AI Agents series {Phần 1 của loạt bài Building AI Agents}. Next {Tiếp theo}: Sampling: temperature, top_p, top_k.
What is a token? {Token là gì?}
A token is a chunk of text the model reads and writes as one integer ID in its vocabulary {Một token là mẩu văn bản mà model đọc và ghi dưới dạng một integer ID trong vocabulary}. The model never sees raw characters or Unicode code points at inference time — it sees a sequence of token IDs {Model không bao giờ thấy ký tự thô hay Unicode code point lúc inference — nó thấy chuỗi token ID}.
"Hello, agent!" → [9906, 11, 8475, 0] (example IDs — model-specific)
Three consequences for agent engineers {Ba hệ quả cho agent engineer}:
- You cannot eyeball length — word count, character count, and token count diverge, sometimes dramatically {Không thể ước lượng bằng mắt — số từ, số ký tự, và số token khác nhau, đôi khi chênh lớn}.
- Everything in the prompt costs tokens — system instructions, JSON schemas, few-shot examples, retrieved documents, prior turns, tool definitions {Mọi thứ trong prompt đều tốn token — system instructions, JSON schemas, few-shot examples, retrieved documents, prior turns, tool definitions}.
- Output tokens share the same budget — generation is not free; it consumes the same context window as input {Output token dùng chung ngân sách — generation không miễn phí; nó tiêu thụ cùng context window với input}.
Mental model: Think of tokens as RAM slots, not words {Mental model: Coi token như ô RAM, không phải từ}. A 128K context window is a fixed array of 128,000 slots. Fill it with history and RAG, and there is less room for the model to think and reply {Context window 128K là mảng cố định 128.000 ô. Nhét history và RAG vào, còn ít chỗ cho model suy nghĩ và trả lời}.
For pricing math and subscription vs API trade-offs, see the dedicated post on AI tokens and pricing — this article focuses on agent architecture implications {Về tính giá và trade-off subscription vs API, xem bài AI tokens and pricing — bài này tập trung vào hệ quả kiến trúc agent}.
Subword tokenization: why tokens ≠ words {Subword tokenization: vì sao token ≠ từ}
Modern LLMs use subword tokenization, most commonly Byte Pair Encoding (BPE) or byte-level variants {LLM hiện đại dùng subword tokenization, phổ biến nhất là Byte Pair Encoding (BPE) hoặc biến thể byte-level}. The algorithm merges frequently co-occurring character pairs during training until the vocabulary reaches a target size (often 50K–200K entries) {Thuật toán merge các cặp ký tự xuất hiện cùng nhau thường xuyên khi training cho đến khi vocabulary đạt kích thước mục tiêu (thường 50K–200K entries)}.
Intuition in four steps {Trực giác trong bốn bước}:
- Start with individual bytes or characters {Bắt đầu với byte hoặc ký tự đơn}.
- Count adjacent pairs in a large corpus {Đếm cặp kề nhau trong corpus lớn}.
- Merge the most frequent pair into a new token {Merge cặp phổ biến nhất thành token mới}.
- Repeat until vocabulary is full {Lặp đến khi vocabulary đầy}.
The result: common English words become single tokens; rare words split into reusable pieces; unknown strings fall back to byte-level encoding {Kết quả: từ tiếng Anh phổ biến thành một token; từ hiếm tách thành mảnh tái sử dụng; chuỗi lạ fallback về byte-level}.
"the" → 1 token
"tokenization" → 2 tokens ["token", "ization"]
"pneumonoultra…"→ many subword pieces
Leading-space rule: GPT-family tokenizers often attach whitespace to the following word —
" world"is a different token than"world"{Quy tắc space đầu: Tokenizer họ GPT thường gắn whitespace vào từ sau —" world"khác token với"world"}. Prompt formatting (newlines, indentation, trailing spaces) changes token count without changing meaning {Format prompt (newline, indent, space thừa) đổi token count mà không đổi nghĩa}.
For BPE merge tables, byte-level fallback, and tokenizer-specific quirks, see LLM tokenization and sampling deep dive — we will not duplicate that internals content here {Về bảng merge BPE, byte-level fallback, và quirks theo tokenizer, xem LLM tokenization and sampling deep dive — không lặp lại nội dung internals ở đây}.
Token count ≠ word count ≠ character count {Số token ≠ số từ ≠ số ký tự}
Engineers routinely mis-estimate context usage because they use the wrong proxy {Engineer thường ước lượng sai context vì dùng proxy sai}.
| Proxy | Typical English prose | Why it fails for agents |
|---|---|---|
| Words ÷ 0.75 | ~1.3 tokens/word | Ignores code, JSON, URLs, non-Latin scripts |
| Chars ÷ 4 | ~4 chars/token | OK as rough heuristic; breaks on CJK, emoji, dense symbols |
| Actual tokenizer | Exact | Required for production budgets |
Example divergences that bite agent pipelines {Ví dụ chênh lệch gây hại pipeline agent}:
{"tool":"search","query":"context window budgeting","top_k":5}
That single line of JSON may tokenize to more IDs than a natural-language sentence of similar character length — punctuation and keys are rarely merged into efficient subwords {Một dòng JSON đó có thể tokenize thành nhiều ID hơn câu natural language cùng độ dài ký tự — punctuation và key hiếm khi merge thành subword hiệu quả}.
Base64 blob (512 chars) → often 150–200+ tokens, not ~128
UUID repeated in logs → each hyphenated segment may split
Markdown code fences → backticks + language tag add overhead
Rule for agents: always measure with the provider’s tokenizer (tiktoken, Anthropic SDK, etc.) at integration time; use char÷4 only for back-of-envelope sketches {Quy tắc cho agent: luôn đo bằng tokenizer của provider (tiktoken, Anthropic SDK, v.v.) lúc tích hợp; char÷4 chỉ dùng ước lượng sơ bộ}.
Multilingual and code: uneven token density {Đa ngôn ngữ và code: mật độ token không đều}
Token efficiency is not uniform across languages or formats {Hiệu quả token không đồng đều giữa ngôn ngữ hay format}. BPE vocabularies reflect training distribution — predominantly English web text {Vocabulary BPE phản ánh phân phối training — chủ yếu web text tiếng Anh}.
| Content type | Relative token cost | Agent impact |
|---|---|---|
| English prose | Baseline (~1 token per 4 chars) | Cheap system prompts, summaries |
| Vietnamese, Thai, Arabic | 2–3× vs equivalent English | User messages + RAG in local languages inflate fast |
| Source code | 1.2–1.8× vs prose | Tool outputs dumping stack traces dominate budget |
| JSON / XML logs | 1.5–2.5× vs prose | Structured tool returns are expensive |
| Base64, hashes, binary | Very high | Never paste raw blobs into context |
English: "The agent retrieved three documents."
~8 tokens
Vietnamese equivalent meaning:
"Agent đã truy xuất ba tài liệu."
~15–20 tokens (approximate — verify with tokenizer)
Implications for multilingual agents {Hệ quả cho agent đa ngôn ngữ}:
- Same context window, less effective capacity for non-English users {Cùng context window, capacity thực tế thấp hơn cho user không dùng tiếng Anh}.
- Summarize before inject — RAG chunks in Vietnamese should be compressed aggressively before concatenation {Summarize trước khi inject — RAG chunk tiếng Việt nên nén mạnh trước khi ghép}.
- Code tools should return structured summaries, not full file dumps, unless the task requires line-level detail {Tool code nên trả summary có cấu trúc, không dump full file, trừ khi task cần chi tiết từng dòng}.
The context window: one bucket for input and output {Context window: một bucket cho input và output}
The context window (context length, max tokens) is the maximum number of tokens the model can process in a single forward pass {Context window (context length, max tokens) là số token tối đa model xử lý trong một forward pass}. Critically: input tokens + output tokens ≤ window size {Quan trọng: input token + output token ≤ window size}.
┌──────────────────────────────────────────────────────────────┐
│ CONTEXT WINDOW (e.g. 128K) │
├──────────────────────────────┬───────────────────────────────┤
│ INPUT │ OUTPUT │
│ system + history + tools │ model generation │
│ + RAG + user message │ (completion) │
└──────────────────────────────┴───────────────────────────────┘
Common window sizes in production (2026) {Kích thước window phổ biến production (2026)}:
| Tier | Tokens | Typical use |
|---|---|---|
| Small | 8K–16K | Legacy APIs, cheap classifiers |
| Standard | 32K–128K | Most agent loops, RAG Q&A |
| Long | 200K–1M | Codebase agents, document analysis |
| Extended | 1M+ | Research previews; latency/cost still scale linearly |
Misconception: “128K context” does not mean you can paste 128K tokens of input and expect a 32K-token answer {Hiểu lầm: “128K context” không có nghĩa paste 128K token input và expect câu trả lời 32K token}. It means the combined sequence must fit {Nghĩa là chuỗi gộp phải vừa}.
Interactive demo: approximate tokenization & budget bar {Demo tương tác: tokenization xấp xỉ & thanh ngân sách}
Try pasting your system prompt, a tool result, or a RAG chunk below {Thử paste system prompt, tool result, hoặc RAG chunk bên dưới}. The demo uses a client-side heuristic (word splits + ~4 chars/token) — real BPE counts will differ, but the budget bar illustrates the agent design question: how much window does input consume, and how much remains for output? {Demo dùng heuristic client-side (tách từ + ~4 chars/token) — BPE thật sẽ khác, nhưng thanh ngân sách minh họa câu hỏi thiết kế agent: input chiếm bao nhiêu window, còn bao nhiêu cho output?}.
Open the full demo {Mở demo đầy đủ}: /tools/ai-tokenizer-demo/.
How agents blow the context window {Cách agent phá context window}
Agent loops accumulate tokens faster than chat UIs suggest {Vòng lặp agent tích lũy token nhanh hơn chat UI gợi ý}. Each turn adds multiple segments:
Turn N input =
system prompt
+ tool definitions (JSON schema × N tools)
+ conversation history (all prior turns)
+ tool call arguments (model output)
+ tool results (often the largest slice)
+ retrieved documents (RAG)
+ user message
Failure modes {Các chế độ lỗi}
| Failure | Symptom | Root cause |
|---|---|---|
| Silent truncation | Agent “forgets” early instructions | Provider drops middle or oldest messages |
| Tool amnesia | Re-queries same API | Prior tool output truncated from history |
| RAG flooding | Answers degrade, latency spikes | Top-k chunks pasted verbatim |
| Runaway generation | Input fits, output hits limit mid-JSON | No output reserve in budget |
| Cost explosion | Bill 10× estimate | Full history resent every turn |
Agent loop (simplified):
User message ──► LLM ──► tool_call(search, "…")
│
▼
search returns 50KB JSON
│
▼
Next turn input = EVERYTHING ABOVE + 50KB ◄── budget crisis
The compounding problem: In a ReAct-style loop, every prior turn is re-tokenized on each call unless you implement compaction or summarization {Vấn đề cộng dồn: Trong vòng ReAct, mọi turn trước được tokenize lại mỗi lần gọi trừ khi bạn implement compaction hoặc summarization}. A 10-turn agent conversation is not 10× a single message — it is the sum of all turns, re-sent repeatedly {Hội thoại agent 10 turn không phải 10× một message — mà là tổng mọi turn, gửi lại lặp lại}.
Deep compaction strategies (summarization, memory tiers, selective recall) are Part 5 of this series: Context Engineering & Memory {Chiến lược compaction sâu (summarization, memory tiers, selective recall) là Phần 5: Context Engineering & Memory}.
Token budgeting for agents {Ngân sách token cho agent}
Production agents need an explicit budget policy, not hope {Agent production cần chính sách ngân sách rõ ràng, không hy vọng mù}.
1. Measure fixed overhead first {Đo overhead cố định trước}
Before user content, these are already spent {Trước nội dung user, các phần này đã tiêu}:
fixed_cost =
system_prompt
+ tool_definitions
+ response_format / JSON schema
+ few_shot_examples (if any)
Log fixed_cost at startup. If it is 8K tokens and your window is 32K, you have 24K for dynamic content — not 32K {Log fixed_cost lúc khởi động. Nếu 8K token và window 32K, bạn còn 24K cho nội dung động — không phải 32K}.
2. Reserve output headroom {Dành headroom cho output}
Never fill the window to 100% with input {Không bao giờ lấp window 100% bằng input}.
max_input_tokens = context_window - reserved_output - safety_margin
Typical reserves:
reserved_output = 15–30% of window (or fixed floor, e.g. 4K)
safety_margin = 256–512 tokens (provider rounding, special tokens)
Example for 128K window, 20% output reserve {Ví dụ window 128K, reserve output 20%}:
| Slice | Tokens |
|---|---|
| Total window | 128,000 |
| Reserved output (20%) | 25,600 |
| Safety margin | 512 |
| Max input budget | 101,888 |
3. Allocate dynamic budget across slices {Phân bổ ngân sách động theo slice}
Once max_input is known, partition among competing slices {Khi biết max_input, chia cho các slice cạnh tranh}:
dynamic_budget =
conversation_history (40–60%)
+ rag_context (20–40%)
+ current_user_message (5–15%)
+ tool_results_buffer (10–25%)
Adjust ratios by agent type: Q&A bots weight RAG; coding agents weight tool results; support bots weight history {Điều chỉnh tỷ lệ theo loại agent: Q&A bot ưu tiên RAG; coding agent ưu tiên tool results; support bot ưu tiên history}.
4. Enforce before the API call {Enforce trước khi gọi API}
function buildPrompt(budget) {
const layers = [
{ name: 'system', tokens: systemPrompt, priority: 0, truncatable: false },
{ name: 'tools', tokens: toolDefs, priority: 1, truncatable: false },
{ name: 'history', tokens: history, priority: 2, truncatable: true },
{ name: 'rag', tokens: ragChunks, priority: 3, truncatable: true },
{ name: 'user', tokens: userMsg, priority: 4, truncatable: false },
];
let used = 0;
const included = [];
for (const layer of layers.sort((a, b) => a.priority - b.priority)) {
if (used + layer.tokens <= budget.maxInput) {
included.push(layer);
used += layer.tokens;
} else if (layer.truncatable) {
included.push(truncate(layer, budget.maxInput - used));
break;
} else {
throw new Error(`Budget exceeded on non-truncatable layer: ${layer.name}`);
}
}
return assemble(included);
}
Priority beats FIFO: When truncating, drop lowest-priority, truncatable slices first — usually oldest history or lowest-scored RAG chunks, not the system prompt {Priority hơn FIFO: Khi truncate, bỏ slice priority thấp, truncatable trước — thường là history cũ nhất hoặc RAG chunk score thấp, không phải system prompt}.
Cost and latency scale with tokens {Chi phí và latency scale theo token}
Tokens are linear in both money and time (first-order approximation) {Token tuyến tính cả tiền lẫn thời gian (xấp xỉ bậc một)}.
cost_per_turn ≈ (input_tokens × input_price) + (output_tokens × output_price)
latency ≈ f(input_tokens) + g(output_tokens) // prefill + decode
Agent-specific multipliers {Hệ số nhân đặc thù agent}:
| Pattern | Token multiplier | Why |
|---|---|---|
| Single-shot Q&A | 1× | One call, bounded RAG |
| ReAct loop (5 steps) | 3–8× | History resent each step |
| Sub-agent delegation | 2–5× per sub-agent | Parallel branches each carry full context |
| Self-reflection | 2–3× | Critique pass duplicates prior output |
Output tokens are often 2–5× more expensive than input tokens on commercial APIs — long tool-call JSON or verbose chain-of-thought directly hits margin {Output token thường đắt gơp 2–5× input trên API thương mại — JSON tool-call dài hoặc chain-of-thought verbose ăn margin trực tiếp}. See AI tokens and pricing for rate tables and optimization tactics {Xem AI tokens and pricing cho bảng giá và tactic tối ưu}.
Truncation and the basics of compaction {Truncation và cơ bản compaction}
When input exceeds budget, something must give {Khi input vượt budget, phải bỏ cái gì đó}. Providers and SDKs handle this differently — never assume graceful behavior {Provider và SDK xử lý khác nhau — đừng giả định graceful}.
| Strategy | Behavior | Agent-safe? |
|---|---|---|
| Hard error | 400 context_length_exceeded | Yes — fail loud |
| Drop oldest messages | Silent removal from start | Risky — loses system context |
| Drop middle | Keep system + recent | Common default; verify per provider |
| Summarize then replace | Compress history into summary block | Best for long sessions |
| Vector recall | Store full history externally; inject relevant slices | Scales beyond window |
Minimum viable compaction for v1 agents {Compaction tối thiểu cho agent v1}:
- Cap tool result size — truncate JSON, keep top-level fields + error summary {Giới hạn kích thước tool result — truncate JSON, giữ field top-level + error summary}.
- Cap RAG top-k and chunk size — score threshold before concat {Giới hạn RAG top-k và chunk size — ngưỡng score trước khi concat}.
- Rolling summary — every N turns, replace turns 1…N-2 with a summary message {Rolling summary — mỗi N turn, thay turn 1…N-2 bằng summary message}.
- Token counter in the hot path — reject or trim before the HTTP request {Token counter trên hot path — reject hoặc trim trước HTTP request}.
Before (turn 12, ~90K tokens):
[system][turn1][turn2]…[turn11][user]
After rolling summary (turn 12, ~35K tokens):
[system][summary_of_turns_1-9][turn10][turn11][user]
Part 5 covers memory architectures (working vs episodic vs semantic), external stores, and when summarization loses fidelity {Phần 5 cover kiến trúc memory (working vs episodic vs semantic), external store, và khi summarization mất fidelity}.
Checklist before you ship an agent {Checklist trước khi ship agent}
- Tokenizer integrated for your exact model + version {Tokenizer tích hợp đúng model + version}
-
fixed_cost(system + tools) logged and monitored {fixed_cost(system + tools) được log và monitor} - Output reserve configured (not zero) {Output reserve cấu hình (không bằng zero)}
- Truncation policy explicit — priority order documented {Truncation policy rõ — thứ tự priority có tài liệu}
- Tool results size-limited at source {Tool results giới hạn size tại nguồn}
- Multilingual / code paths tested with real tokenizer counts {Đường đa ngôn ngữ / code test với số tokenizer thật}
- Cost model accounts for multi-turn re-tokenization {Cost model tính re-tokenization multi-turn}
Bottom line: Tokens are not a billing detail — they are the scheduling constraint of your agent runtime {Kết luận: Token không phải chi tiết billing — chúng là ràng buộc scheduling của agent runtime}. Design the loop around the window, measure every slice, and reserve space for the model to finish thinking {Thiết kế vòng lặp quanh window, đo mọi slice, và dành chỗ cho model hoàn thành suy nghĩ}.
What’s next {Tiếp theo}
Part 2 covers sampling — how the model chooses the next token after your budget is assembled {Phần 2 cover sampling — model chọn token tiếp theo thế nào sau khi budget đã ghép}.
Temperature, top_p, and top_k control creativity vs determinism in tool-calling agents {Temperature, top_p, và top_k điều khiển creativity vs determinism trong agent gọi tool}.
Continue to Sampling: temperature, top_p, top_k.
The Building AI Agents series {Loạt bài Building AI Agents}
- Tokens & Context Windows (current)
- Sampling: temperature, top_p, top_k
- Prompt Engineering for Agents
- Stopping Criteria & Output Control
- Context Engineering & Memory
- Fine-tuning vs Prompting vs RAG
- Evaluating LLMs & Agents
- Choosing a Model
- Function Calling & Tool Use
- Agent Patterns: ReAct, Reflection, Planning