SSD Nodes Learn
Panduan Matt ConnorOleh Matt Connor · Diperbarui 2026-07-24

cara kontrol biaya agen AI di VPS

Cegah pembengkakan biaya token akibat loop tanpa pengawasan. Gunakan prompt caching, pembatasan iterasi, dan pantau penggunaan API per respons secara akurat.

Cara mencegah agen AI yang selalu aktif menghabiskan biaya berlebih

Pengendalian biaya agen AI pada VPS (virtual private server) dilakukan dengan menetapkan batas sebelum agen berjalan, karena tidak ada yang memantau penggunaan saat proses berlangsung. Batasi setiap respons dengan max_tokens, batasi iterasi loop pada kode Anda, simpan bagian prompt yang tidak berubah ke dalam cache, dan catat angka penggunaan setiap respons untuk melihat pekerjaan mana yang menghabiskan biaya. Biaya sewa server bersifat tetap setiap bulan. API model dihitung per token, dan loop yang berjalan tanpa pengawasan dapat menghabiskan token secara diam-diam.

Ini mengasumsikan agen sudah ada dan memanggil Messages API dari server milik Anda. Membangun agen AI dengan Claude pada VPS membahas mekanisme tersebut.

Mengapa biaya agen unattended berbeda

Sesi interaktif melibatkan manusia. Jika model melakukan kesalahan atau membaca log sepanjang 40.000 baris, pengamat dapat menghentikannya. Agen unattended tidak memiliki kendali tersebut: ia terus berjalan hingga loop berakhir, lalu timer akan menjalankannya kembali.

Frekuensi adalah faktor pengali yang sering diabaikan. Pekerjaan dengan jadwal lima menit berjalan 288 kali sehari atau sekitar 8.640 kali sebulan. Berapapun biaya satu kali jalan, itulah angka yang harus dikalikan. Banyak agen "always-on" sebenarnya tidak perlu selalu aktif. Mereka hanya perlu merespons dalam rentang waktu tertentu, yang merupakan sebuah jadwal.

Agen juga memakan biaya untuk hal-hal yang tidak ada pada jendela chat.

  • Definisi tool disertakan pada setiap request. System prompt tool-use memakan 290 token pada Claude Opus 4.8 dengan tool_choice dari auto atau none, dan 410 token dengan any atau tool. Tool bash menambah 325 token lagi. Setiap MCP server yang Anda pasang menambah beban tersebut melalui skemanya; MCP adalah model context protocol.
  • Hasil tool adalah input token. Perintah yang mencetak 8.000 baris akan memasukkan 8.000 baris tersebut ke dalam request berikutnya, dan ke setiap request selanjutnya dalam giliran tersebut.
  • Halaman yang diambil adalah input token. Rata-rata halaman web 10 kB setara dengan 2.500 token dan PDF riset 500 kB setara dengan 125.000 token. max_content_tokens hanya memotong konten teks, karena "berlaku untuk konten teks, bukan konten biner seperti PDF". Gunakan max_uses dan allowed_domains untuk membatasi PDF.
  • Web search dikenakan biaya per pencarian, yaitu $10 per 1.000 pencarian, berapa pun jumlah hasil yang didapat. Pencarian yang error tidak ditagih.

Semua hal di atas tidak mahal jika hanya dilakukan satu kali. Semuanya menjadi mahal jika dilakukan sebanyak 8.640 kali.

Hard ceilings dan soft ceilings menyelesaikan masalah yang berbeda

max_tokens diterapkan. Ini adalah batas maksimal pada total output satu permintaan, yang mencakup teks pemikiran dan teks respons. Claude tidak akan pernah menghasilkan teks melebihi batas ini, dan model tidak dapat melihat angka tersebut. Mencapai batas ini akan menyebabkan stop_reason: "max_tokens" dan jawaban terpotong. Kendala bagi agen: setiap permintaan dalam loop penggunaan alat memiliki max_tokens sendiri, sehingga batas ini hanya membatasi satu respons, bukan seluruh tugas. Sepuluh panggilan alat dengan 4,000 token menghasilkan batas 40,000 token untuk satu giliran.

Anggaran tugas bersifat saran. task_budget berada di dalam output_config dan memberi tahu model berapa banyak token yang tersedia untuk seluruh loop agen, termasuk pemikiran, panggilan alat, hasil alat, dan output.

resp = client.beta.messages.create(
    model="claude-opus-4-8",
    max_tokens=4096,
    betas=["task-budgets-2026-03-13"],
    output_config={"task_budget": {"type": "tokens", "total": 64000}},
    messages=messages,
)

"Anggaran tugas adalah petunjuk lunak, bukan batas keras." Claude mungkin melampaui satu batas di tengah tindakan, dan batas output yang diterapkan tetaplah max_tokens. "Hitung mundur hanya terlihat oleh model", dan respons tidak menyertakan bidang sisa anggaran. task_budget.total minimum yang diterima adalah 20,000 token; nilai di bawah itu akan menghasilkan error 400. Anggaran yang terlalu kecil untuk suatu pekerjaan akan menghasilkan perilaku seperti penolakan, sehingga model akan memperkecil cakupan tugas atau berhenti lebih awal.

Satu detail akan memakan biaya alih-alih menghematnya. Jika klien Anda mengurangi task_budget.remaining pada setiap permintaan lanjutan, nilai yang berubah tersebut akan membatalkan semua prefix yang tersimpan di cache yang mengandung nilai tersebut. Atur satu kali pada permintaan pertama.

Anggaran tugas masih dalam tahap beta pada Claude Fable 5, Claude Opus 4.8, dan Claude Opus 4.7. Claude Sonnet 5 dan Claude Haiku 4.5 terdaftar sebagai Not supported, dan anggaran tugas tidak berlaku untuk Claude Code, sehingga sesi Claude Code yang terlepas di tmux bergantung pada kebersihan sesi.

Batas ketiga berada di Claude Console: berikan agen workspace sendiri, lalu tetapkan batas pengeluaran bulanan dan batas laju per menit padanya. "Anda tidak dapat menetapkan batas pada Default Workspace", dan "Batas tingkat organisasi selalu berlaku, meskipun total batas workspace lebih besar". Tambahkan notifikasi pengeluaran agar ambang batas memberi peringatan kepada Anda sebelum mencapai batas maksimal.

Pemilihan model per-job, dan faktor apa yang sebenarnya mengubah biaya

Pemilihan model adalah keputusan per-job. Per Juli 2026, per satu juta token, urutan input lalu output adalah: Claude Fable 5 seharga $10 dan $50, Claude Opus 4.8 dan Opus 4.7 seharga $5 dan $25, Claude Sonnet 5 seharga $3 dan $15, Claude Haiku 4.5 seharga $1 dan $5. Harga Sonnet 5 saat ini lebih rendah dari harga label karena "Harga perkenalan sebesar $2/$10 per satu juta token input/output berlaku hingga 31 Agustus 2026". Langkah yang hanya mengklasifikasikan baris log tidak memerlukan Opus.

Effort adalah variabel kedua. output_config.effort menerima low, medium, high, xhigh, dan max, dengan default adalah high, sehingga mengatur high secara eksplisit sama saja dengan menghapusnya. Effort yang lebih rendah mengurangi lebih dari sekadar panjang penalaran: dokumentasi menyatakan bahwa hal ini membuat Claude melakukan lebih sedikit tool calls dan menggabungkan operasi menjadi satu. Pada sebuah agent, ini memberikan penghematan lebih besar, karena satu tool call yang dihindari berarti satu permintaan utuh yang tidak pernah terjadi.

Kesalahannya adalah effort berbenturan dengan cache. Mengubah nilai di antara permintaan akan membatalkan prompt caching. Dalam contoh yang didokumentasikan, permintaan 2 melaporkan cache_read_input_tokens: 3546; permintaan 3, dengan effort diubah dari high ke medium, melaporkan cache_creation_input_tokens sebesar 3546 dan cache_read_input_tokens sebesar 0. Jadi, variasikan effort antar beban kerja, jangan di dalam satu percakapan yang di-cache. Untuk mengatur kedalaman tanpa merusak cache, lakukan di dalam prompt: baris seperti "Answer directly without deliberating." pada pesan pengguna terbaru akan menjaga breakpoint sebelumnya tetap utuh.

Thinking tokens ditagih dengan tarif output dan dihitung terhadap max_tokens, itulah sebabnya jawaban yang terpotong sering kali berarti proses thinking menghabiskan anggaran. Baca usage.output_tokens_details.thinking_tokens untuk jumlahnya. Apa yang sebenarnya mengisi tagihan token Claude menjelaskan rinciannya.

Simpan prefix stabil dalam cache, dan hindari kerusakan tidak sengaja

Biaya penulisan cache adalah 1.25 kali harga input dasar pada cache lima menit, dan 2 kali pada cache satu jam. Biaya pembacaan cache adalah 0.1 kali, sehingga "caching menguntungkan setelah hanya satu pembacaan cache untuk durasi 5 menit (1.25x penulisan), atau setelah dua pembacaan cache untuk durasi 1 jam (2x penulisan)".

Satu baris menjelaskan mengapa hal ini cocok untuk agen yang selalu aktif: "Cache diperbarui tanpa biaya tambahan setiap kali konten yang di-cache digunakan." Pekerjaan yang berjalan setiap dua menit terhadap cache lima menit akan menjaga prefix tetap hangat sepanjang hari hanya dengan satu penulisan.

Tiga cara kehilangan cache tanpa disadari.

Prefix yang berubah. "Prefix cache dibuat dalam urutan berikut: tools, system, lalu messages." Perubahan byte apa pun pada urutan sebelumnya akan membatalkan semua data setelahnya, dan mengedit definisi tool akan membatalkan seluruh cache. Kesalahan umum yang disebabkan sendiri adalah penggunaan timestamp atau run id dalam system prompt: setiap permintaan kemudian membawa prefix yang berbeda, menulis entri baru sebesar 1.25x, dan tidak membaca data apa pun. Tandanya adalah usage.cache_read_input_tokens bernilai 0 pada panggilan yang terlihat identik. Pindahkan teks yang berubah-ubah tersebut ke dalam pesan user terbaru.

Prefix yang terlalu pendek. Setiap model memiliki panjang minimum yang dapat di-cache, dan di bawah panjang tersebut permintaan diproses tanpa caching dan "tidak ada error yang dikembalikan". Angka tersebut mencakup 1,024 token pada Claude Opus 4.8 dan Claude Sonnet 5, serta 4,096 pada Claude Haiku 4.5, sehingga memindahkan pekerjaan dari Sonnet ke Haiku dapat mematikan caching secara diam-diam.

Percakapan yang melebihi jendela lookback. "Jendela lookback adalah 20 blok." Sistem memeriksa maksimal 20 posisi per breakpoint, lalu berhenti. Dalam contoh yang didokumentasikan, sebuah giliran yang berisi 35 blok dengan breakpoint pada blok 35 memeriksa blok 35 hingga 16, dan entri giliran sebelumnya pada blok 15 berada di luar jendela, sehingga tidak ada hit. Agen yang menambahkan beberapa blok tool-use dan tool-result per giliran akan melewati batas 20 dalam dua atau tiga giliran. Anda mendapatkan empat breakpoint per permintaan, jadi gunakan satu breakpoint untuk pesan terbaru.

Kirim tugas yang tidak mendesak ke Batches API

"Semua penggunaan dikenakan biaya 50% dari harga API standar", baik untuk input maupun output. Pemrosesan batch bersifat asinkron, "dengan sebagian besar batch selesai dalam waktu kurang dari 1 jam", dengan hasil tersedia setelah semua permintaan selesai atau setelah 24 jam, mana yang lebih dulu. Hal tersebut adalah estimasi, bukan jaminan.

Lakukan polling pada processing_status hingga terbaca ended. Permintaan yang mengembalikan errored, canceled, atau expired tidak dikenakan biaya. Satu catatan jika Anda menggunakan batas pengeluaran: "batch mungkin sedikit melebihi batas pengeluaran yang dikonfigurasi pada Workspace Anda."

Diskon bersifat kumulatif, dan karena sebuah batch dapat memakan waktu lebih dari lima menit, dokumentasi menyarankan penggunaan cache satu jam untuk batch yang berbagi konteks. Oleh karena itu, bagi beban kerja Anda: tugas yang ditunggu oleh manusia atau webhook tetap gunakan jalur live, sedangkan ringkasan harian atau klasifikasi log kemarin masukkan ke dalam batch dengan harga setengahnya.

Catat setiap field penggunaan respons ke penyimpanan Anda sendiri

Anda tidak dapat melacak pengeluaran yang tidak pernah dicatat. Setiap respons menunjukkan biaya yang dikeluarkan.

u = resp.usage
row = {
    "job": job_name,
    "model": resp.model,
    "uncached_input": u.input_tokens,
    "cache_write": u.cache_creation_input_tokens,
    "cache_read": u.cache_read_input_tokens,
    "output": u.output_tokens,
    "stop_reason": resp.stop_reason,
}

Tambahkan satu baris untuk setiap panggilan API ke file JSON-lines, dengan label nama job Anda. Seminggu kemudian, Anda dapat mengetahui job mana yang menghabiskan biaya dan mana yang hanya terlihat sibuk. Perhatikan cache_read: kolom berisi angka nol adalah bug biaya paling umum pada agent self-hosted.

Satu field mudah salah baca. input_tokens hanya menghitung token setelah breakpoint cache terakhir, sehingga ukuran prompt yang sebenarnya adalah total_input_tokens = cache_read_input_tokens + cache_creation_input_tokens + input_tokens. Agent yang melaporkan input_tokens: 400 pada prompt besar tidaklah murah: sisa biayanya berasal dari cache.

Hitung sebelum mengirim. Penghitungan token itu gratis dan limit ratenya terpisah dari pembuatan pesan, jadi gunakan count_tokens untuk menolak lampiran yang terlalu besar daripada membayar untuk mengetahuinya. Hasilnya adalah estimasi, jadi ukur ulang per model dan jangan gunakan hitungan dari tokenizer vendor lain. Claude Opus 4.7 dan model Opus terbaru, Claude Fable 5 dan Claude Sonnet 5 menggunakan tokenizer baru yang "menghasilkan sekitar 30% lebih banyak token untuk teks yang sama". Claude Sonnet 4.6 dan versi sebelumnya, termasuk Claude Haiku 4.5, menggunakan tokenizer lama.

Untuk data yang akurat, Admin API melaporkan penggunaan pada https://api.anthropic.com/v1/organizations/usage_report/messages dan biaya pada https://api.anthropic.com/v1/organizations/cost_report. Keduanya memerlukan admin key (sk-ant-admin01-...) sebagai x-api-key: $ANTHROPIC_ADMIN_KEY dengan anthropic-version: 2023-06-01, dan menerima bucket_width=1d, group_by[]=model dan api_key_ids[]=. Satu batasan: "Admin API tidak tersedia untuk akun individu."

Parameter terakhir tersebut adalah trik atribusi yang murah: berikan setiap job API key sendiri, filter dengan api_key_ids[], dan pisahkan laporan per key dengan group_by[]=api_key_id. Filter bersifat jamak, dimensi pengelompokan bersifat tunggal. Simpan key di dalam environment daripada di dalam kode, seperti cara aplikasi Claude API pertama pada VPS menanganinya.

Batasi loop, karena tidak ada cara lain

Jumlah iterasi yang dibatasi bersifat wajib di sini. Loop adalah kendali Anda, maka penghitungnya juga kendali Anda:

for step in range(MAX_STEPS):          # MAX_STEPS = 12, never "while True"
    resp = client.messages.create(...)
    if resp.stop_reason != "tool_use":
        break
else:
    log.warning("job %s hit MAX_STEPS=%d, giving up", job_name, MAX_STEPS)

Kedua batasan di atas tidak membantu Anda: max_tokens membatasi satu respons, dan model hanya diberi tahu mengenai anggaran tugas.

Pasang pembatas kedua di luar proses. Jalankan pekerjaan menggunakan systemd timer alih-alih proses permanen, dan atur RuntimeMaxSec= pada unit servicenya. Dengan RuntimeMaxSec=600, proses yang macet akan dihentikan setelah sepuluh menit alih-alih terus berjalan sampai Anda menyadarinya. Menjalankan program sebagai systemd service dan timer membahas file unit itu sendiri. Baca hasil eksekusi dengan journalctl -u triage-agent.service --since "1 hour ago".

Batasi juga percobaan ulang (retries), karena handler yang mencoba terus-menerus akan memakan biaya pada setiap upaya. Kode 429 atau 500 layak mendapatkan beberapa kali percobaan dengan backoff. Kode 400 tidak memerlukan percobaan ulang, karena permintaan yang sama akan gagal dengan cara yang sama.

Kontrol biaya AI agent dimulai dengan membaca angka Anda sendiri

Tidak ada yang bisa menentukan biaya agent yang berjalan terus-menerus, karena biayanya adalah jumlah token per eksekusi dikalikan jumlah eksekusi per hari, dan kedua variabel tersebut adalah milik Anda. Jalankan satu kali, baca baris penggunaan yang Anda catat, lalu kalikan dengan jadwal Anda. Periksa laporan biaya dua hari kemudian dan bandingkan dengan perhitungan tersebut. Jika hasilnya berbeda, selisihnya hampir selalu disebabkan oleh cache yang rusak atau loop yang berjalan lebih lama dari perkiraan Anda.

Hal ini mengasumsikan penggunaan API key, karena agent adalah program Anda sendiri yang memanggil Messages API. Untuk pekerjaan interaktif Anda, rencana Claude mana yang sesuai dengan cara kerja Anda membahas sisi langganan. Setiap harga dan batas di sini telah diperiksa terhadap dokumentasi Anthropic pada Juli 2026, jadi baca kembali halaman harga sebelum Anda menyusun anggaran.

FAQ

Berapa biaya menjalankan AI agent yang selalu aktif pada VPS?

Ada dua tagihan dan hanya satu yang dapat diprediksi. Server memiliki harga bulanan tetap. API model menggunakan sistem meteran per token, sehingga biayanya adalah jumlah konsumsi satu kali jalan dikalikan dengan frekuensi jalan. Anthropic tidak menerbitkan angka untuk agent selalu aktif yang di-host sendiri, jadi anggap angka kutipan apa pun sebagai perkiraan. Catat usage dari satu sesi nyata dan kalikan dengan jadwal Anda.

Apa perbedaan antara max_tokens dan task budget?

max_tokens diterapkan secara paksa dan tidak terlihat oleh model. Ini membatasi output dari satu permintaan, termasuk proses berpikir, dan jika mencapai batas tersebut akan menghasilkan stop_reason: "max_tokens". Task budget adalah kebalikannya: model diberi tahu jumlahnya dan mengatur ritme loop agentik berdasarkan angka tersebut, tetapi "Task budgets adalah petunjuk lunak, bukan batas keras" dan batas yang diterapkan tetaplah max_tokens.

Mengapa cache_read_input_tokens selalu nol pada agent saya?

Karena prefix berubah di antara panggilan, atau terlalu pendek untuk disimpan dalam cache. Penyebab umum adalah timestamp atau run id yang dimasukkan ke dalam system prompt: cache menggunakan prefix sebagai kunci, sehingga perubahan byte apa pun membatalkan semua data setelahnya. Mengubah definisi tool atau nilai effort akan memberikan hasil yang sama. Selain itu, masalahnya bisa berupa ukuran, karena prompt yang lebih pendek tidak disimpan dalam cache dan tidak ada error yang dikembalikan.

Bagaimana cara menghentikan AI agent agar tidak looping selamanya?

Hitung iterasi dalam kode loop Anda dan berhenti pada batas maksimum tetap, karena max_tokens membatasi satu respons sedangkan agent melakukan banyak respons. Tambahkan batas waktu (wall-clock limit) di luar proses: jalankan tugas dari systemd timer dengan RuntimeMaxSec= yang telah diatur, sehingga proses yang macet akan dihentikan sesuai jadwal. Batasi juga jumlah percobaan ulang (retry), karena loop retry akan menagih setiap percobaan.

Bisakah saya menetapkan batas pengeluaran pada satu Claude API key?

Batas pengeluaran yang didokumentasikan adalah per workspace, bukan per key, jadi berikan agent workspace sendiri dan batasi pengeluaran bulanannya di sana. "You cannot set limits on the Default Workspace". Tambahkan notifikasi pengeluaran agar ambang batas dapat memberi peringatan kepada Anda terlebih dahulu. Untuk atribusi, berikan setiap tugas key sendiri, lalu kelompokkan laporan penggunaan dengan group_by[]=api_key_id.

#claude#ai#agents#api#cost