Series 3 - Bài 4: Token Budget Management

Token budget không phải afterthought — là resource management bắt buộc trong production agent. Bài này xây dựng hệ thống đếm, phân bổ và cắt token chủ động.

5 phút đọc
Tập này đang được chuẩn bị, quay lại sau nhé.

Token management trong agent system giống memory management trong low-level programming — bạn có thể ignore nó ở đầu, nhưng production sẽ buộc bạn phải học.

Không có token budget strategy → agent sẽ crash với context overflow, hoặc tốn gấp 10x chi phí không cần thiết.

Token là gì và đếm như thế nào

Token counting:

  "Hello world"     = 2 tokens
  "processLoan"     = 2 tokens (process + Loan)
  "TypeScript"      = 2 tokens (Type + Script)

  Tiếng Anh:  1 word ≈ 0.75 tokens
  Tiếng Việt: 1 word ≈ 1.5-2 tokens (unicode heavy)

Estimation shortcuts:
  1,000 tokens ≈ 750 words (English)
  1 page A4 text ≈ 500-700 tokens
  1 file TypeScript 100 lines ≈ 1,500-3,000 tokens
  1 JSON config 50 lines ≈ 500-1,000 tokens
  1 tool_result (command output) ≈ 200-5,000 tokens

Đối với production, dùng tiktoken (OpenAI) hoặc claude-tokenizer để count chính xác. Estimation đủ cho planning, nhưng không đủ cho hard limits.

Budget Framework

Budget Model:

  Total budget = Model context limit - Safety buffer
  
  Với Claude Sonnet (200,000 tokens):
  Total budget = 200,000 - 10,000 = 190,000 tokens
  
  (Safety buffer 5% để tránh API error)

Budget Allocation:

  ┌─────────────────────────────────────────┐
  │  Component          Budget    % of Total │
  │ ──────────────────────────────────────  │
  │  System prompt       5,000       2.6%   │
  │  Project context    10,000       5.3%   │
  │  Episodic memory     5,000       2.6%   │
  │  File context       50,000      26.3%   │
  │  History            80,000      42.1%   │
  │  Tool results       30,000      15.8%   │
  │  Current message     5,000       2.6%   │
  │  Reserved output    10,000       5.3%   │
  │ ──────────────────────────────────────  │
  │  Total             195,000     100%     │
  └─────────────────────────────────────────┘

Budget này không phải fixed — nó là starting point. Từng session có thể allocate khác nhau dựa trên task.

Trimming Strategy: Ai bị cắt trước

Khi budget bị vượt, phải trim. Thứ tự trim quan trọng:

Trim Priority (cắt trước đến cắt sau):

  Priority 1 - KHÔNG BAO GIỜ TRIM:
    System prompt
    Current user message
    → Đây là context cốt lõi, mất đi = agent mất direction

  Priority 2 - TRIM SAU CÙNG:
    Recent conversation (5 turns gần nhất)
    Last 3 tool results
    → Cần để maintain coherence trong task

  Priority 3 - TRIM KHI CẦN:
    Old conversation history
    Old tool results đã được processed
    → Thông tin đã được LLM dùng, có thể compress

  Priority 4 - TRIM TRƯỚC:
    Episodic memory ít liên quan
    File content của files không được đề cập gần đây
    → Lowest relevance cho current task

Trim Techniques

1. Sliding Window: Giữ N turns gần nhất

Sliding Window:

  Full history: [Turn 1][Turn 2]...[Turn 18][Turn 19][Turn 20]

  Window size = 10 turns:
  Keep:         [Turn 11][Turn 12]...[Turn 18][Turn 19][Turn 20]
  Drop:         [Turn 1] through [Turn 10]

  Simple, predictable, nhưng mất context cũ hoàn toàn.

2. Summary + Recent: Compress cũ, giữ mới

Summary + Recent:

  Old history (turns 1-10):
  → Compress thành summary:
    "Agent đã đọc loan.service.ts, phát hiện bug trong
     processLoan() tại line 45. Đã refactor và run tests.
     Tests pass. Đang chuyển sang fix payment.service.ts."

  Recent history (turns 11-20):
  → Giữ nguyên

  Result: 10 turns old → ~200 tokens summary
  Saving: ~8,000 tokens

Kỹ thuật này tốt hơn sliding window nhưng cần LLM call để generate summary — thêm latency và cost.

3. Selective Tool Result Trimming

Tool results thường là source of token waste lớn nhất:

Before trimming:
  Tool result: read_file("src/loan.service.ts")
  Content: [full 300-line file, ~4,500 tokens]

After trimming (nếu file đã được processed):
  Tool result: read_file("src/loan.service.ts")
  Content: "[File read — 300 lines. Relevant section
             extracted and applied in turn 5.]"
  Size: ~20 tokens

Saving: 4,480 tokens per old tool result

Khi nào trim tool result? Khi có evidence trong conversation rằng LLM đã sử dụng thông tin đó (ví dụ: đã viết code từ file đó).

4. File Context Rotation

Thay vì inject tất cả files liên quan một lúc, rotate theo task progress:

Turn 1-3: Task là "fix loan.service.ts"
  Inject: loan.service.ts, loan.entity.ts
  Drop:   payment.service.ts (chưa cần)

Turn 10: Agent chuyển sang payment
  Inject: payment.service.ts
  Drop:   loan.service.ts content (đã xong)
  Keep:   loan.service.ts path reference

Proactive vs Reactive Trimming

Reactive (xấu):
  Chờ đến khi hit limit → trim → có thể đã mất
  important context trong panic trim

Proactive (tốt):
  Theo dõi budget liên tục
  Khi đạt 70%: start trim low-priority content
  Khi đạt 85%: aggressive trim history
  Khi đạt 95%: emergency — summarize aggressively
  Never reach 100%

Token Counter Component

Token Counter trong Context Layer:

  count(messages[]) → number
    Estimate token count của messages array
    Dùng character-based heuristic:
    English: len / 4 tokens
    Vietnamese: len / 2.5 tokens (unicode adjustment)

  budgetRemaining() → { total, used, remaining, pct }
    Snapshot của budget state hiện tại

  shouldTrim() → boolean
    true nếu used > 70% của total

  trimHistory(messages[], targetTokens) → messages[]
    Trim oldest non-system messages đến targetTokens
    Giữ nguyên system prompt và current message

Trade-off: Aggressive vs Conservative Trimming

Aggressive trimming:
  + Token cost thấp
  + Context clean, ít noise
  - Rủi ro mất context quan trọng
  - Agent có thể "quên" decisions từ early turns

Conservative trimming:
  + Giữ nhiều context hơn
  + Agent ít bị mất direction hơn
  - Token cost cao hơn
  - Performance degradation với very long context

Thực tế: start conservative, measure cost, adjust aggressiveness dựa trên budget và task complexity.

Kết luận

  • Token management là resource management — không phải optimization, là bắt buộc.
  • Budget allocation trước khi start: system, file, history, output đều cần limits.
  • Trim priority: cắt old history và processed tool results trước, không bao giờ cắt system prompt hay current message.
  • Sliding window đơn giản nhưng mất context. Summary + Recent tốt hơn nhưng tốn thêm LLM call.
  • Proactive trimming tốt hơn reactive — không chờ hit limit mới xử lý.
  • Tiếng Việt tốn token gấp 1.5-2x tiếng Anh — factor này vào budget calculation.