Agen AI dan Panggilan API Berjalan Lama: Polling vs Webhooks

Agen membaca 202 Accepted sebagai selesai dan melaporkan keberhasilan pada pekerjaan yang tidak pernah selesai. Pelajari kontrak asinkron yang diikuti agen, dan cara menguji jalur batas waktu.

Ashley Innocent

Ashley Innocent

26 August 2026

Agen AI dan Panggilan API Berjalan Lama: Polling vs Webhooks

Apidog untuk Perusahaan

Penerapan On-Premises

SSO & RBAC

Sesuai SOC 2

Jelajahi Apidog Enterprise

Agen memanggil titik akhir transkode video Anda. Titik akhir mengembalikan 202 Accepted dan ID tugas. Agen, yang tidak tahu apa arti 202 dalam sistem Anda, melaporkan bahwa transkode telah selesai dan melanjutkan ke langkah berikutnya, yaitu membaca file yang belum ada.

Operasi yang berjalan lama merusak agen dengan cara tertentu. Panggilan sinkron memiliki kontrak yang jelas: Anda mengirim, Anda menunggu, Anda mendapatkan jawaban. Panggilan asinkron membagi itu menjadi awal dan akhir, dan celah di antara keduanya adalah tempat agen menjadi bingung. Mereka menyatakan keberhasilan terlalu dini, mereka melakukan polling seribu kali dalam loop ketat, atau mereka duduk terblokir selama enam menit menahan giliran percakapan tetap terbuka.

Panduan ini mencakup cara merancang kontrak asinkron agar agen dapat mengikutinya, kapan harus melakukan polling dan kapan harus menyerahkan, cara menulis alat agar model berperilaku, dan cara menguji seluruh jalur termasuk kasus yang lambat dan gagal. Artikel kami tentang pemulihan kesalahan agen AI membahas sisi kegagalan panggilan API; artikel ini membahas yang berhasil secara perlahan.

Apidog cocok pada titik di mana Anda perlu membuktikan agen menangani tugas yang membutuhkan waktu empat menit dan kemudian gagal, yang bukan sesuatu yang ingin Anda temukan di produksi.

Mengapa agen salah menangani asinkron

Tiga kebiasaan menyebabkan sebagian besar masalah.

Model memperlakukan kode 2xx sebagai selesai. Kode 202 mengatakan permintaan diterima untuk diproses, dan spesifikasi semantik HTTP secara eksplisit menyatakan bahwa pemrosesan mungkin belum selesai. Model yang dilatih pada lalu lintas permintaan/respons biasa cenderung membaca kode 2xx apa pun sebagai penyelesaian kecuali jika respons mengatakan sebaliknya dalam kata-kata.

Loop itu mahal. Jika agen melakukan polling di dalam loop penalarannya, setiap pemeriksaan membutuhkan satu giliran model ditambah token dari percakapan sebelumnya. Melakukan polling setiap dua detik untuk tugas empat menit adalah 120 giliran, dan eksekusi akan menghabiskan konteks atau anggaran. Artikel kami tentang menjaga respons alat keluar dari jendela konteks menjelaskan mengapa itu menumpuk lebih cepat dari yang orang perkirakan.

Agen kehilangan jejak tugas. Alat yang memulai pekerjaan dan mengembalikan ID tugas telah membuat status yang harus dibawa oleh agen. Jika ID mendarat di tengah percakapan panjang, itu bisa terkompresi, dan agen lupa bahwa ia memiliki tugas yang sedang berjalan.

Rancang respons agar model tidak salah membacanya

Perbaikan yang paling efektif adalah tata bahasa, bukan arsitektur. Apa pun kode status Anda, buat isi respons menyatakan dengan jelas apa yang terjadi dan apa yang harus dilakukan selanjutnya.

{
  "status": "processing",
  "job_id": "job_7f21c",
  "message": "Transkode telah DIMULAI dan BELUM selesai. Jangan laporkan keberhasilan. Periksa status dengan getJobStatus(job_id) setelah setidaknya 30 detik.",
  "poll_after_seconds": 30,
  "estimated_duration_seconds": 240,
  "status_url": "/v1/jobs/job_7f21c"
}

Itu terdengar sangat langsung untuk konsumen API manusia. Ini ditujukan untuk model, dan model mengikuti instruksi eksplisit dalam isi respons jauh lebih andal daripada menginterpretasikan makna dari kode status. Tiga detail yang berfungsi: kata "belum selesai", alat berikutnya yang dinamai, dan waktu tunggu minimum.

AIP-151 Google tentang operasi yang berjalan lama menjelaskan bentuk sumber daya yang bersih untuk ini, dengan satu objek Operation yang membawa bidang done, error, dan response. Menyalin struktur tersebut memberi Anda permukaan yang konsisten di setiap titik akhir yang lambat, yang penting karena agen yang mempelajari satu pola polling kemudian dapat menangani semuanya.

Jaga agar respons status sama blak-blakannya:

{
  "job_id": "job_7f21c",
  "status": "processing",
  "done": false,
  "progress_percent": 45,
  "elapsed_seconds": 108,
  "poll_after_seconds": 45,
  "message": "Masih dalam proses. Jangan lanjutkan ke langkah berikutnya."
}

Dan setelah selesai, kembalikan hasilnya secara langsung jika kecil, sehingga agen tidak memerlukan panggilan ketiga:

{
  "job_id": "job_7f21c",
  "status": "succeeded",
  "done": true,
  "result": { "output_url": "https://cdn.example.com/out/7f21c.mp4", "duration_seconds": 372 }
}

Polling di luar model, bukan di dalamnya

Pilihan implementasi yang paling penting: letakkan waktu tunggu di pembungkus alat Anda, bukan di loop penalaran agen.

import time

def start_and_await_transcode(client, source_url, max_wait=600):
    job = client.post("/v1/transcode", json={"source_url": source_url}).json()
    job_id = job["job_id"]
    delay = job.get("poll_after_seconds", 5)
    waited = 0

    while waited < max_wait:
        time.sleep(delay)
        waited += delay
        status = client.get(f"/v1/jobs/{job_id}").json()

        if status.get("done"):
            if status["status"] == "succeeded":
                return {"status": "succeeded", "result": status["result"]}
            return {"status": "failed", "error": status.get("error")}

        delay = min(int(delay * 1.5), 60)

    return {
        "status": "timed_out",
        "job_id": job_id,
        "message": f"Masih berjalan setelah {max_wait} detik. Pekerjaan {job_id} terus berlanjut di latar belakang.",
    }

Dari sisi model, ini adalah satu panggilan alat yang membutuhkan waktu dan mengembalikan jawaban akhir. Tidak ada loop polling dalam konteks, tidak ada ID tugas yang terlupakan, tidak ada 120 giliran. Backoff menjaga jumlah permintaan tetap wajar, dan batasan menghentikan tugas yang macet agar tidak menggantung eksekusi selamanya. Artikel Amazon tentang waktu tunggu, coba ulang, dan backoff dengan jitter adalah referensi yang layak dibaca sebelum Anda menyetel angka-angka tersebut.

Dua aturan membuat ini aman. Selalu batasi waktu tunggu, dan selalu kembalikan ID tugas saat waktu habis agar agen atau manusia dapat memeriksa nanti. Jangan pernah mengembalikan hasil yang ambigu: succeeded, failed, dan timed_out adalah tiga hasil yang berbeda dan model harus melihat tiga kata yang berbeda.

Untuk tugas yang diukur dalam jam daripada menit, polling di dalam pembungkus menjadi tidak masuk akal. Maka bentuk yang tepat adalah dua alat, satu untuk memulai dan satu untuk memeriksa, ditambah catatan permanen tugas yang sedang berjalan di luar percakapan agar tidak ada yang hilang karena kompresi. Simpan job_id, tugas yang di milikinya, dan waktu mulai, dan minta agen membaca daftar itu di awal setiap eksekusi.

Kapan webhook menjadi jawaban yang lebih baik

Polling sederhana dan berfungsi di mana saja. Callback lebih efisien dan lebih banyak pekerjaan untuk dijalankan. Pertukaran ini tercakup dengan baik dalam perbandingan webhook vs polling kami, dan versi khusus agen lebih sempit.

Gunakan polling saat tugas membutuhkan waktu beberapa detik hingga menit, saat agen menunggu hasilnya untuk melanjutkan, atau saat Anda tidak dapat meng-host titik akhir publik. Sebagian besar beban kerja agen ada di sini.

Gunakan webhook saat tugas membutuhkan waktu berjam-jam, saat agen memulai pekerjaan dan melanjutkan, atau saat banyak tugas berjalan secara bersamaan dan melakukan polling setiap tugas adalah pemborosan. Biayanya nyata: Anda memerlukan penerima publik, verifikasi tanda tangan, penanganan percobaan ulang, dan cara untuk membangunkan agen saat callback tiba. Panduan kami tentang merancang webhook yang andal dan verifikasi tanda tangan webhook mencakup dasar-dasar tersebut.

Opsi tengah layak diketahui. Streaming kemajuan tugas melalui peristiwa yang dikirim server (server-sent events) memberi Anda semantik push tanpa titik akhir publik, karena klien memegang koneksi. Ini cocok untuk agen interaktif di mana manusia mengawasi, dan panduan kami untuk streaming respons API dengan SSE mencakup implementasinya.

Mana pun yang Anda pilih, jalur penyelesaian harus idempoten. Webhook mencoba ulang, polling berlomba, dan agen yang melihat "succeeded" dua kali tidak boleh memulai langkah hilir dua kali. Artikel kami tentang idempoten untuk agen AI mencakup kunci yang membuat itu aman.

Uji jalur lambat, bukan hanya yang cepat

Bug asinkron tersembunyi karena lingkungan pengujian cepat. Tugas yang membutuhkan waktu empat menit di produksi selesai dalam 200 milidetik terhadap stub lokal, sehingga agen tidak pernah mengalami status yang sebenarnya akan ditemuinya.

Empat skenario layak dibangun secara sengaja.

Tugas yang benar-benar lambat. Mock titik akhir status agar mengembalikan processing untuk beberapa panggilan pertama dan succeeded setelah itu. Ini membuktikan bahwa pembungkus melakukan polling, melakukan backoff, dan akhirnya mengembalikan. Di Apidog Anda dapat mengaturnya dengan mock yang bervariasi berdasarkan jumlah permintaan atau parameter kontrol, sehingga pengujian yang sama berjalan dengan cara yang sama setiap saat.

Tugas yang gagal terlambat. Kembalikan processing tiga kali, lalu failed dengan isi kesalahan. Agen harus melaporkan kegagalan daripada memperlakukan polling yang selesai sebagai tugas yang selesai. Ini adalah kasus yang menghasilkan kehilangan data secara diam-diam jika salah.

Waktu habis (timeout). Terus buat mock mengembalikan processing melewati batas pembungkus dan pastikan alat mengembalikan timed_out dengan ID tugas utuh, bukan pengecualian dan bukan keberhasilan palsu.

Penyelesaian duplikat. Kirim keberhasilan dua kali, baik melalui percobaan ulang webhook atau polling yang berlomba, dan pastikan langkah hilir berjalan sekali.

Simpan keempatnya sebagai skenario agar berjalan di CI. Mereka tidak memerlukan biaya untuk dijalankan kembali dan mereka menangkap regresi di mana seseorang memperpendek waktu habis atau menelan kesalahan. Pendekatan yang lebih luas ada di panduan pengujian kontrak API kami.

Tiga tugas yang menunjukkan masalah

Pembuatan laporan. Agen keuangan meminta ekspor triwulanan. Butuh 90 detik. Dengan alat yang naif, agen mendapatkan ID tugas, mengumumkan bahwa laporan sudah siap, dan kemudian memberikan tautan unduhan yang rusak kepada pengguna. Dengan pembungkus yang memblokir, ia menunggu 90 detik dan mengembalikan URL yang sebenarnya. API yang sama, hasil yang berlawanan, dan satu-satunya perbedaan adalah di mana penungguan terjadi.

Impor massal. Agen operasi mengunggah 20.000 catatan. Impor berjalan selama delapan menit dan sebagian gagal pada baris 14.000. Ini adalah kasus yang menghukum pemeriksaan keberhasilan yang naif: tugas selesai, jadi status done adalah benar, tetapi hasilnya membawa daftar baris yang ditolak. Kembalikan hasil parsial secara eksplisit, dengan hitungan, dan minta agen membacanya sebelum melanjutkan.

Pipa model dan pembangunan. Agen memicu proses pelatihan atau pembangunan CI yang membutuhkan waktu 40 menit. Polling di dalam pembungkus adalah bentuk yang salah di sini; eksekusi akan menahan giliran terlalu lama. Mulai tugas, catat ID di penyimpanan permanen, akhiri giliran, dan biarkan pemeriksaan terjadwal atau callback membangunkan tindak lanjut. Artikel kami tentang serah terima multi-agen dan transfer konteks membahas pemindahan status tersebut antar eksekusi tanpa kehilangannya.

Berikan bentuk pada hasil parsial

Tugas yang panjang sering berakhir di suatu tempat antara keberhasilan dan kegagalan, dan model dua status memaksa Anda untuk berbohong tentangnya. Buat status ketiga eksplisit:

{
  "job_id": "job_a11f",
  "status": "completed_with_errors",
  "done": true,
  "summary": { "processed": 20000, "succeeded": 19860, "failed": 140 },
  "errors_url": "/v1/jobs/job_a11f/errors?limit=50",
  "message": "Impor selesai. 140 baris gagal dan tidak ditulis. Tinjau kesalahan sebelum melaporkan keberhasilan."
}

Dua hal penting dalam payload itu. Hitungannya ada di dalam, sehingga agen dapat memutuskan tanpa panggilan lain. Baris yang gagal ada di balik URL dengan batas, sehingga 140 objek kesalahan tidak masuk ke konteks tanpa diundang.

Seseorang harus melihat tugas yang terhenti

Jalur waktu habis (timeout) berakhir dengan ID tugas dan pesan yang menyatakan pekerjaan masih berjalan. Itu adalah nilai pengembalian yang benar, dan itu hanya berguna jika mencapai seseorang.

Di mana agen adalah layanan Anda sendiri, arahkan ke antrean apa pun yang sudah dipantau tim Anda. Di mana agen adalah runtime pengkodean yang mengerjakan tugas yang ditetapkan, platform yang menjalankannya biasanya memiliki tempat untuk ini. Di Sharkly, eksekusi yang berakhir terblokir tetap pada Tugasnya dengan status eksekusi dan hasilnya, dan Kotak Masuk memisahkan item yang memerlukan balasan atau ulasan manusia dari pembaruan biasa. Intinya bukan alat tertentu. Intinya adalah "masih berjalan, periksa nanti" memerlukan pemilik, atau itu menjadi "tidak ada yang memeriksa."

Daftar periksa singkat

Atur tata bahasa respons dan pembungkus dengan benar, dan operasi yang berjalan lama tidak lagi menjadi kasus khusus bagi agen. Ia memanggil alat, menunggu, dan mendapatkan jawaban, yang merupakan kontrak yang paling baik ditanganinya. Unduh Apidog untuk membangun mock tugas lambat bersama dengan pengujian.

Pertanyaan yang sering diajukan

Haruskah API mengembalikan 202 atau 200 untuk awal asinkron? 202 Accepted adalah kode yang jujur dan memberi sinyal kepada klien standar bahwa pemrosesan belum selesai. Jangan mengandalkannya saja untuk agen, karena isi respons adalah apa yang paling andal dibaca oleh model. Gunakan keduanya.

Berapa lama pembungkus alat harus menunggu sebelum menyerah? Atur batas atas sedikit di atas skenario terburuk yang realistis dari titik akhir, biasanya dua hingga sepuluh menit. Lewat dari itu, pembungkus memblokir giliran percakapan terlalu lama, dan alat "periksa nanti" adalah bentuk yang lebih baik.

Interval polling apa yang harus saya gunakan? Mulai dari petunjuk poll_after_seconds server sendiri jika ada, lalu lakukan backoff dengan faktor sekitar 1,5 dengan batas sekitar 60 detik. Polling satu detik yang tetap membuang-buang permintaan dan dapat memicu batas laju, seperti yang tercakup dalam panduan batas laju terlampaui kami.

Bisakah agen melakukan sesuatu yang berguna saat menunggu? Hanya jika orkestrator Anda mendukung panggilan alat bersamaan. Jika demikian, mulai tugas, lakukan pekerjaan independen, lalu periksa status. Jika tidak, pembungkus yang memblokir lebih sederhana dan tidak mudah salah daripada penjadwal buatan tangan.

Bagaimana cara menghentikan agen agar tidak mengklaim keberhasilan terlalu dini? Katakanlah dalam kata-kata di isi respons, ekspos bidang boolean done, dan jadikan alat penyelesaian satu-satunya tempat hasilnya muncul. Jika respons awal tidak mengandung hasil, tidak ada yang bisa dilaporkan oleh model sebagai hasil.

Apakah webhook berfungsi untuk agen yang berjalan di laptop? Tidak secara langsung, karena tidak ada titik akhir publik. Gunakan terowongan untuk pengembangan, seperti dalam panduan kami untuk menguji API localhost dengan layanan webhook, atau tetap menggunakan polling sampai agen berjalan di tempat yang dapat dialamatkan.

Mengembangkan API dengan Apidog

Apidog adalah alat pengembangan API yang membantu Anda mengembangkan API dengan lebih mudah dan efisien.