← Semua pembelajaran / Python untuk AI Engineer
Fase 4 · Bicara dengan LLM

Token Counting

Menghitung token secara akurat sebelum mengirim request — dan kenapa tiktoken memberi angka yang salah.

Intisari

  • client.messages.count_tokens() memberi angka pasti; endpoint-nya gratis.
  • Jangan pakai tiktoken — itu tokenizer OpenAI dan salah untuk Claude, meleset 15–20% atau lebih.
  • Hitungan token bersifat per model. Kirim ID model yang sama dengan yang akan kamu pakai.
  • Perhitungannya mencakup system prompt, definisi tool, gambar, dan dokumen — bukan hanya teks pesan.
  • Pakai untuk: estimasi biaya, memangkas riwayat sebelum menabrak batas, dan memilih model.

Cara memakainya

hitung = client.messages.count_tokens(
    model="claude-opus-5",
    system=system_prompt,
    tools=tools,
    messages=messages,
)

print(hitung.input_tokens)

Parameternya sama persis dengan messages.create() — cukup ganti nama method-nya.

Kenapa bukan tiktoken

tiktoken adalah tokenizer OpenAI. Claude memakai tokenizer yang berbeda. Estimasi tiktoken biasanya meleset 15–20% pada teks biasa, dan jauh lebih besar pada kode atau teks non-Inggris — termasuk bahasa Indonesia. Untuk perhitungan biaya atau pemangkasan konteks, kesalahan sebesar itu tidak bisa diterima.

Hal yang sama berlaku untuk gpt-tokenizer dan aturan praktis seperti "1 token ≈ 4 karakter".

Kegunaan praktis

1. Estimasi biaya sebelum mengirim

HARGA_IN = 5.0     # USD per juta token, Claude Opus 5

hitung = client.messages.count_tokens(model=MODEL, messages=messages, system=system)
perkiraan = hitung.input_tokens * HARGA_IN / 1_000_000

if perkiraan > AMBANG:
    logger.warning("request mahal: $%.4f", perkiraan)

2. Memangkas riwayat percakapan

BATAS = 800_000     # sisakan ruang untuk output

async def pangkas(messages: list[dict], system: str) -> list[dict]:
    while True:
        n = (await client.messages.count_tokens(
            model=MODEL, system=system, messages=messages
        )).input_tokens
        if n <= BATAS or len(messages) <= 2:
            return messages
        messages = messages[2:]      # buang satu pasang giliran tertua

Perhatikan pemangkasan dua-dua. Riwayat harus tetap berselang-seling user/assistant. Membuang satu pesan saja bisa membuat dua pesan dengan peran sama berdampingan — dan yang lebih parah, memutus pasangan tool_use/tool_result yang wajib utuh.

3. Memilih model berdasarkan ukuran input

n = hitung.input_tokens
model = "claude-haiku-4-5" if n < 50_000 else "claude-opus-5"

4. Menghitung token sebuah file

from pathlib import Path

def token_file(path: Path, model: str = "claude-opus-5") -> int:
    return client.messages.count_tokens(
        model=model,
        messages=[{"role": "user", "content": path.read_text(encoding="utf-8")}],
    ).input_tokens

Lewat CLI

ant messages count-tokens --model claude-opus-5 \
  --message '{role: user, content: "@./dokumen.md"}' \
  --transform input_tokens -r

Yang ikut dihitung

Perhitungan mencakup seluruh isi request, bukan hanya teks pesan:

Definisi tool sering lebih mahal dari dugaan. Sepuluh tool dengan deskripsi rinci bisa memakan beberapa ribu token — dibayar di setiap request. Hitung sendiri: panggil count_tokens dengan dan tanpa tools, lalu lihat selisihnya. Kalau angkanya besar, pertimbangkan tool search supaya skema hanya dimuat saat relevan.

Token gambar

Gambar resolusi tinggi pada model terkini bisa memakan sampai ~4.784 token per gambar. Kalau pipeline-mu memproses banyak gambar, jalankan count_tokens pada sampel yang representatif sebelum menghitung anggaran — jangan memakai angka dari model generasi sebelumnya.

Membandingkan antar model

for m in ["claude-opus-5", "claude-sonnet-5", "claude-haiku-4-5"]:
    n = client.messages.count_tokens(model=m, messages=messages).input_tokens
    print(f"{m:<24} {n:>8,} token")

Angkanya bisa berbeda antar generasi karena tokenizer-nya berbeda. Kalau kamu bermigrasi model, hitung ulang — jangan memakai baseline lama.

Melacak biaya sungguhan

count_tokens untuk estimasi sebelum; response.usage untuk kenyataan sesudah:

HARGA = {"claude-opus-5": (5.0, 25.0)}

def biaya(usage, model: str) -> float:
    h_in, h_out = HARGA[model]
    return (
        usage.input_tokens * h_in
        + usage.cache_read_input_tokens * h_in * 0.1
        + usage.cache_creation_input_tokens * h_in * 1.25
        + usage.output_tokens * h_out
    ) / 1_000_000

Fungsi seperti ini adalah salah satu poin checkpoint Fase 4: chatbot CLI-mu harus mencetak total biaya di akhir sesi.

Rangkuman ini sengaja dipangkas ke bagian yang dipakai di roadmap. Buka sumber aslinya saat kamu butuh detail lengkap atau referensi parameter.