Async Tool Call untuk AI Agent: Mengapa start() Lebih Unggul dari Blocking run()

Jawaban singkat: Pemanggilan tool asinkron untuk agen AI memecah fungsi run() yang bersifat blocking menjadi sebuah kontrak sederhana: start() langsung mengembalikan handle tugas, status() melaporkan progres, stop() membatalkan tugas, dan hasilnya dikembalikan nanti sebagai event yang dibaca oleh agen pada giliran berikutnya. Agen tetap dapat berinteraksi dan menerima instruksi baru selagi tugas yang memakan waktu lama berjalan.

Coba Apidog sekarang

Sebagian besar agen saat ini memanggil tool lalu menunggu. Jika Anda mengajukan pertanyaan kedua saat pengujian 6 menit sedang berjalan, pertanyaan tersebut akan tertahan di dalam antrean. Hal ini tidak masalah untuk operasi pencarian cepat 200 ms, tetapi sangat menjengkelkan untuk proses deployment atau crawling.

Sebuah esai terbaru dari tim DeepSeek Harness, "Exploring Super-agent Design", menyebut solusi ini sebagai "full-duplex": mengganti fungsi run() yang bersifat blocking dengan start() dan stop(). Panduan ini membahas sisi loop agen: kontrak tool, bagaimana hasil dialirkan kembali, pembatalan tugas, serta API yang dibutuhkan setiap tool. Untuk sisi HTTP dari satu panggilan yang lambat, baca AI Agents and Long-Running API Calls: Polling vs Webhooks.

Apa itu pemanggilan tool asinkron dalam agent loop?

Pemanggilan tool asinkron adalah eksekusi tool yang mengembalikan sebuah handle alih-alih langsung memberikan hasil akhir. Agent loop mencatat handle tersebut, menyelesaikan gilirannya, dan tetap bebas merespons pengguna. Ketika tugas selesai, runtime menyuntikkan event penyelesaian ke dalam percakapan, dan model membacanya pada giliran berikutnya selayaknya pesan lainnya.

Perbedaannya terletak pada siapa yang menunggu: dengan run() model yang menunggu, sedangkan dengan start() giliran runtime yang menunggu.

run() Blocking start() Asinkron
Nilai Kembali Hasil akhir Job id, "Started"
Kondisi agen saat proses berjalan Membeku Bisa merespons, membuat rencana, memulai tugas lainnya
Pesan baru dari pengguna Masuk antrean sampai tool selesai Langsung ditangani saat itu juga
Pembatalan Hentikan paksa seluruh giliran stop(job_id)

Esai DeepSeek menggambarkan pendekatan ini sebagai arsitektur, bukan fitur bawaan yang siap pakai. Esai tersebut menyebutkan bahwa arsitektur full-duplex telah diimplementasikan di DeepSeek Harness tetapi belum diaktifkan secara default, dan sebagian kodenya berada pada plugin purwarupa bernama dsh-superagent-prototype, yang menurut para penulisnya bukanlah produk resmi DeepSeek. Anggap saja ini sebagai pola desain untuk ditiru. Untuk konteks lebih lanjut, lihat apa itu DeepSeek Harness dan artikel pendampingnya tentang cara membangun super agent.

Masalah blocking: satu tool yang lambat membekukan seluruh agen

Bayangkan sebuah coding agent yang diminta menjalankan rangkaian pengujian (5 menit) sekaligus menjawab pertanyaan tentang error impor modul. Dengan pemanggilan yang bersifat blocking, pertanyaan Anda harus mengantre di belakang pengujian tersebut, padahal pertanyaan itu sama sekali tidak membutuhkan hasil dari pengujian. Ada tiga masalah yang muncul:

  1. Latensi menumpuk. Setiap tool yang lambat akan menambahkan seluruh durasi eksekusinya ke semua tugas di belakangnya.
  2. Instruksi menjadi usang. Dua menit berselang Anda berkata, "sebenarnya, lewati saja uji coba e2e". Agen tidak dapat mendengarnya sampai proses pengujian selesai sepenuhnya.
  3. Masalah timeout. Gateway sering kali memutus koneksi yang menggantung selama beberapa menit, sehingga pemanggilan run() yang berjalan lama bisa gagal meskipun proses aslinya sebenarnya berhasil.

Esai tersebut menyebut karakteristik ideal ini sebagai "produktif": agen dapat menerima instruksi berikutnya sebelum instruksi sebelumnya selesai. Tool asinkron adalah cara untuk mewujudkannya.

Timeline comparing a blocking agent that waits idle for a 5-minute test run against an async agent that starts the run, answers two user messages, and reads the result when it lands

start, status, stop: kontrak tool asinkron

Berikan model tiga tool terpisah untuk setiap kapabilitas yang memakan waktu lama alih-alih hanya satu, dengan format respons yang ringkas.

{ "name": "start_test_run", "description": "Start the test suite. Returns immediately with a job_id. The result arrives later as a job_completed event; do not wait for it.", "input_schema": { "type": "object", "properties": { "suite": { "type": "string", "enum": ["unit", "e2e", "all"] }, "idempotency_key": { "type": "string" } }, "required": ["suite", "idempotency_key"] } } 

start_test_run hanya mengembalikan {"job_id": "job_8f2", "status": "queued"}. get_job_status(job_id) mengembalikan status queued, running, done, atau failed, ditambah catatan progres singkat. stop_job(job_id) meminta pembatalan dan mengembalikan status terakhir yang dicapai.

Dua aturan penting agar model bekerja sebagaimana mestinya: cantumkan instruksi "do not wait" di dalam deskripsi tool, jika tidak model akan melakukan polling pada get_job_status dalam perulangan ketat; dan jangan pernah mengembalikan data hasil langsung dari start, karena jika dilakukan model harus menebak struktur data apa yang diterimanya.

Bagaimana hasil dikembalikan ke dalam loop

Polling yang dilakukan oleh model adalah opsi cadangan, bukan rencana utama. Desain yang lebih baik adalah membiarkan runtime memantau tugas dan mengirimkan (push) event penyelesaian ke dalam percakapan sebagai pesan baru:

[event] job_completed job_id=job_8f2 tool=start_test_run status=done summary: 412 passed, 3 failed (auth/session.test.ts) details: get_job_result(job_8f2) 

Jaga agar ukuran event tetap ringkas dan tempatkan payload lengkap di balik tool pengambilan data (fetch tool), sehingga log sebanyak 40.000 baris tidak pernah membebani context window.

Lalu lakukan batching. Esai DeepSeek menjelaskan tentang router yang mengumpulkan pemicu (trigger) yang masuk selama giliran berlangsung dan menggabungkannya ke dalam pemanggilan model berikutnya—input panjang dan output singkat, yang dilipat ke dalam proses prefill. Dalam eksperimen mereka, pemicu meningkat dari 1 menjadi 40 per menit, rata-rata ukuran batch naik dari 1,0 menjadi 2,8, dan waktu per keputusan turun dari 6,4 detik menjadi 1,6 detik. Angka-angka ini berasal dari pengujian internal dalam esai tersebut, bukan tolak ukur umum, namun satu panggilan yang membaca tiga event jelas jauh lebih efisien daripada tiga panggilan yang masing-masing hanya membaca satu event. Aturan sederhananya: saat model sedang menghasilkan respons, antrekan event dan pesan pengguna; saat gilirannya selesai, kirimkan semuanya secara bersamaan sesuai urutan kedatangan.

Diagram of an agent runtime: tools return job ids to the model, a job watcher collects completion events and user messages into a queue, and a router batches them into the next model call

Urutan eksekusi, pembatalan, dan kunci idempotensi

Urutan eksekusi. Tugas bisa selesai dalam urutan apa pun. Jika tugas B bergantung pada tugas A, buat ketergantungan tersebut secara eksplisit: mulai tugas B hanya setelah event penyelesaian tugas A diterima, atau buat API yang mendukung parameter depends_on.

Pembatalan. Pemanggilan stop adalah permintaan, bukan jaminan. Kembalikan status akhir sebenarnya (cancelled, atau done jika tugas terlanjur selesai lebih dulu) dan biarkan model melaporkannya apa adanya. Ekstensi Tasks milik MCP mengadopsi pendekatan serupa: dokumentasinya menyebut pembatalan bersifat kooperatif, sehingga sebuah tugas masih bisa mencapai status akhir selain cancelled.

Kunci idempotensi. Model dapat melakukan percobaan ulang (retry), sehingga respons yang terputus bisa memicu pemanggilan start kedua. Wajibkan parameter idempotency_key pada setiap start dan pastikan API mengembalikan tugas yang sudah ada saat menemukan kunci yang sama. Tanpa mekanisme ini, perintah seperti "jalankan migrasi" bisa tereksekusi dua kali.

Hasil parsial. Sediakan output awal (misalnya 50 halaman pertama hasil crawling) melalui get_job_result(job_id, cursor) alih-alih menunggu hingga seluruh proses selesai.

Pertumbuhan context window. Ringkas tugas-tugas yang telah selesai menjadi satu baris setelah model menindaklanjutinya.

Timeout. Tetapkan batas waktu untuk setiap tugas dan kirimkan event job_timed_out jika batas waktu tersebut terlampaui.

Seperti apa bentuk API pendukung yang dibutuhkan

Keandalan tool asinkron sangat bergantung pada job API di baliknya: menerima pekerjaan, mengembalikan ID, dan memungkinkan pemanggil memeriksa progresnya. RFC 9110 mendefinisikan 202 Accepted sebagai "permintaan telah diterima untuk diproses, tetapi pemrosesan belum selesai," dan referensi MDN tentang 202 membahas penggunaan praktisnya.

Job API minimal untuk tool start():

Panggilan Respons Digunakan oleh
POST /jobs (dengan header Idempotency-Key) 202 + {"job_id", "status":"queued"} + Location: /jobs/{id} start
GET /jobs/{id} 200 + queued, running, done atau failed status, job watcher
GET /jobs/{id}/result 200 beserta output, atau 409 jika belum selesai fetch tool
DELETE /jobs/{id} 202 pembatalan diminta, lalu 404 atau 409 pada panggilan berikutnya stop
URL callback opsional POST ke pemanggil saat tugas selesai job watcher

Callback inilah yang memungkinkan runtime mengirimkan event secara langsung alih-alih melakukan polling. Jika Anda butuh bantuan untuk memilih di antara keduanya, perbandingannya dibahas dalam webhook vs polling, dan sisi API berbasis event diulas dalam apa itu AsyncAPI.

Jika tool Anda menggunakan protokol MCP, kini sudah ada standar untuk hal ini. Spesifikasi MCP (versi 2026-07-28) mencantumkan Tasks sebagai ekstensi opsional: server dapat merespons tools/call dengan CreateTaskResult yang memuat taskId, klien melakukan polling ke tasks/get (atau mendengarkan notifications/tasks), dan tasks/cancel meminta penghentian. Status yang tersedia mencakup working, input_required, completed, failed, dan cancelled. Baik klien maupun server harus mengaktifkan dukungan ini, dan dukungan pada setiap host bisa berbeda-beda, jadi periksalah klien Anda sebelum menjadikannya ketergantungan utama.

Gunakan coding agent Anda untuk membangun dan menguji job API dengan Apidog CLI

Job API adalah bagian yang dapat Anda verifikasi sebelum agen mana pun menggunakannya. Serahkan rancangan dan pengujiannya ke coding agent Anda dan biarkan ia mengoperasikan Apidog CLI. Anda cukup menulis satu prompt; agen akan menyusun spesifikasi, membuat test case, dan menjalankannya.

Penyiapannya hanya membutuhkan tiga perintah:

npm install -g apidog-cli@latest apidog auth login --with-token <YOUR_TOKEN> npx -y skills add https://apidog.com # pick your agent when prompted 

Kemudian berikan satu prompt berikut ke agen Anda:

In Apidog project <projectId>, design the job API a start() tool needs: POST /jobs returns 202 with job_id, GET /jobs/{id} returns queued|running|done|failed, DELETE /jobs/{id} cancels. Create the endpoints, then create test cases that assert: 202 and a job_id on create, a status that reaches done within 60 seconds, the same job_id when the Idempotency-Key repeats, and 409 or 404 on GET result after cancel. Run them against the staging environment <envId> and summarize failures. 

Agen akan membaca setiap struktur payload dari CLI, memvalidasinya, lalu menuliskan dan menjalankan perintah berikut:

apidog cli-schema get endpoint-create apidog cli-schema validate endpoint-create --file post-jobs.json apidog endpoint create --project <projectId> --file post-jobs.json apidog cli-schema get test-case-create apidog cli-schema validate test-case-create --file case-create-202.json apidog test-case create --project <projectId> --file case-create-202.json apidog run --test-case <caseId> --project <projectId> -e <envId> -r cli,json 

Reporter cli akan mencetak status lulus dan gagal untuk setiap asersi di terminal, sementara laporan json memberikan output terstruktur yang dapat dibaca dan dijelaskan kembali oleh agen. Jalankan perintah yang sama di CI dengan opsi -r junit setelah semua test case berhasil; panduan alur kerja agen Apidog CLI mengulas seluruh siklus tersebut, dan artikel tentang Apidog CLI di Claude Code membahas konfigurasi agen. Paket Gratis Apidog mencakup hingga 4 pengguna.

Kapan tool asinkron layak digunakan, dan kapan sebaiknya dihindari

Gunakan asinkron jika:

  • Tool secara rutin membutuhkan waktu lebih dari beberapa detik (proses build, test suite, crawling, rendering, deployment).
  • Pengguna berinteraksi dengan agen saat pekerjaan sedang berlangsung.

Tetap gunakan blocking jika:

  • Panggilan selesai dalam kurun waktu satu atau dua detik.
  • Langkah berikutnya bagaimanapun juga tidak dapat dimulai tanpa hasil tersebut.
  • Anda tidak dapat menyediakannya dengan job API yang sesungguhnya. Tool asinkron semu yang memblokir secara internal hanya menambah kompleksitas tanpa manfaat nyata.

Pembagian praktisnya: pertahankan operasi baca tetap blocking, dan jadikan operasi tulis serta komputasi yang memakan waktu lama bersifat asinkron.

FAQ

Apa perbedaan antara pemanggilan tool asinkron dan paralel? Pemanggilan tool secara paralel menjalankan beberapa tool sekaligus dalam satu giliran, dan model tetap menunggu hingga semuanya selesai. Sementara itu, pemanggilan tool asinkron langsung mengembalikan respons dan selesai pada giliran-giliran berikutnya, sehingga model tetap dapat berinteraksi selagi proses tersebut berjalan.

Apakah saya membutuhkan MCP untuk membuat tool asinkron? Tidak. Tool apa pun yang mengembalikan job ID serta runtime yang menyuntikkan event penyelesaian sudah cukup berfungsi. Ekstensi Tasks opsional milik MCP menstandarisasi handle, proses polling, dan panggilan pembatalan jika klien dan server Anda mendukungnya.

Bagaimana agen mengetahui kapan sebuah tugas selesai? Runtime yang akan memberitahukannya. Pemantau tugas (job watcher) akan melakukan polling ke job API atau menerima callback, lalu menambahkan event penyelesaian singkat ke dalam percakapan. Model akan membacanya pada giliran berikutnya.

Apa yang terjadi jika pengguna membatalkan di tengah proses? Agen memanggil stop(job_id), API mencatat permintaan tersebut, dan tugas akan melaporkan status akhirnya yang sebenarnya. Jika pekerjaan ternyata sudah selesai sebelum permintaan pembatalan tiba, agen sebaiknya menyampaikan hal tersebut alih-alih mengklaim bahwa proses telah dihentikan.

Apakah mode full-duplex DeepSeek merupakan fitur yang bisa langsung saya aktifkan? Bukan sebagai fitur produk yang siap pakai. Esai tersebut menyebutkan bahwa fitur ini diimplementasikan di DeepSeek Harness tetapi dinonaktifkan secara default, dan plugin terkait merupakan purwarupa yang menurut para pembuatnya bukanlah produk resmi DeepSeek. Gunakan konsep ini sebagai desain referensi.