Saat aplikasi memanggil model AI eksternal, masalah utama biasanya bukan pada cara membuat request HTTP, melainkan pada ketahanan integrasi saat kondisi produksi tidak ideal: latensi vendor naik, koneksi putus di tengah jalan, callback terlambat, respons vendor berubah, atau request yang sama terkirim dua kali. Inilah alasan desain API ke model AI eksternal perlu memperhatikan timeout, retry, dan idempotensi sejak awal.
Tren seperti Apertus menunjukkan semakin banyak tim mulai mengintegrasikan model pihak ketiga, private model, atau sovereign AI sesuai kebutuhan kepatuhan dan kontrol data. Namun, terlepas dari vendornya, pola integrasi yang aman tetap sama: gunakan kontrak yang eksplisit, korelasikan setiap request, beri batas waktu per tahap, lakukan retry hanya pada kasus yang aman, dan pastikan operasi berbiaya tidak diproses ganda.
Masalah yang Sering Muncul pada Integrasi Model AI Eksternal
Berbeda dari API CRUD biasa, pemanggilan model AI cenderung memiliki karakteristik berikut:
- Latensi tidak stabil, terutama untuk prompt besar, dokumen panjang, atau antrean vendor yang sedang padat.
- Biaya per request dapat signifikan, sehingga request ganda berarti biaya ganda.
- Respons bisa sinkron atau asinkron, misalnya request diterima sekarang tetapi hasil final dikirim via webhook nanti.
- Failure mode lebih kompleks: timeout jaringan, vendor error, callback hilang, status job tidak konsisten, atau parsing output gagal.
- Semantik sukses tidak selalu sederhana; HTTP 200 belum tentu berarti hasil model valid untuk kebutuhan bisnis Anda.
Karena itu, desain yang tahan produksi harus membedakan beberapa hal dengan jelas: apakah request accepted atau benar-benar selesai, apakah operasi aman untuk diulang, bagaimana mendeteksi duplikasi, dan bagaimana aplikasi melanjutkan jika vendor tidak memberi jawaban tepat waktu.
Kontrak Request/Response yang Eksplisit
Kesalahan umum adalah meneruskan payload mentah ke vendor dan menganggap respons vendor sebagai kontrak internal aplikasi. Ini membuat sistem rapuh karena perubahan kecil di sisi vendor dapat merusak alur bisnis Anda.
Apa yang sebaiknya ada di request internal
Gunakan kontrak internal yang stabil, lalu buat adapter ke vendor di lapisan integrasi. Minimal, request internal sebaiknya memuat:
- request_id: identitas unik request di sistem Anda.
- correlation_id: untuk melacak request lintas service dan vendor.
- idempotency_key: untuk mencegah operasi berbiaya diproses dua kali.
- tenant_id atau customer_id: jika sistem multi-tenant.
- model_target: model atau kebijakan routing yang diminta.
- input: prompt, dokumen, parameter inferensi, atau referensi file.
- callback_url atau mode respons: sinkron/asinkron.
- deadline atau timeout policy: batas waktu bisnis, bukan hanya timeout HTTP.
Bedakan status teknis dan status bisnis
Respons internal sebaiknya tidak hanya membawa payload model. Tambahkan status yang menjelaskan fase request, misalnya:
- accepted: request valid dan sedang diproses.
- completed: hasil final tersedia.
- failed: gagal permanen.
- retryable_failure: gagal sementara, aman untuk dicoba lagi oleh orchestrator.
- unknown: status akhir belum bisa dipastikan, misalnya timeout setelah request dikirim.
Status unknown sangat penting. Dalam sistem terdistribusi, kadang Anda tidak tahu apakah vendor menerima request atau tidak. Jangan paksa semua kegagalan menjadi “gagal total”, karena itu bisa memicu duplikasi saat retry.
Contoh bentuk kontrak internal
{
"request_id": "req_01J...",
"correlation_id": "corr_8d0f...",
"idempotency_key": "idem_invoice_123_v1",
"tenant_id": "tenant_42",
"operation": "document_summarization",
"model_target": "external-fm-policy-a",
"input": {
"document_url": "s3://bucket/doc.pdf",
"language": "id",
"max_output_tokens": 600
},
"response_mode": "async",
"callback_url": "https://api.example.com/ai/callbacks/vendor-x",
"deadline_at": "2026-06-22T10:30:00Z"
}Kontrak seperti ini memudahkan Anda mengganti vendor tanpa mengubah API internal aplikasi.
Correlation ID dan Jejak Request End-to-End
Saat debugging insiden, pertanyaan pertama biasanya: request ini sebenarnya berhenti di mana? Tanpa correlation ID, Anda akan menebak-nebak dari log aplikasi, queue, gateway, dan webhook receiver.
Praktik yang umum dipakai:
- Buat correlation_id di entry point request pengguna jika belum ada.
- Propagasikan correlation ID ke semua service internal.
- Kirim correlation ID sebagai header ke vendor jika didukung, atau simpan di metadata request vendor.
- Masukkan correlation ID ke log, trace, metric labels yang relevan, dan event audit.
Jangan gunakan correlation ID sebagai pengganti idempotency key. Keduanya berbeda fungsi: correlation ID untuk observabilitas, idempotency key untuk kontrol duplikasi.
Timeout per Tahap, Bukan Satu Timeout Besar
Desain API ke model AI eksternal sering gagal karena hanya memakai satu timeout global, misalnya 60 detik. Ini membuat debugging sulit: Anda tahu request lambat, tetapi tidak tahu lambat di DNS, koneksi TCP, TLS handshake, upload payload, menunggu header, atau membaca body.
Pecah timeout menjadi beberapa tahap
Jika stack HTTP Anda mendukung, bedakan beberapa kategori timeout:
- Connect timeout: waktu maksimum untuk membuka koneksi.
- TLS/handshake timeout: jika terpisah dari connect timeout.
- Write timeout: penting bila mengirim payload besar, misalnya dokumen atau multipart upload.
- Read timeout: waktu menunggu respons setelah request terkirim.
- Total deadline: batas total di level bisnis atau orchestrator.
Alasannya sederhana: timeout yang tepat membantu Anda memutuskan tindakan berikutnya. Misalnya, connect timeout biasanya aman untuk retry. Sebaliknya, read timeout setelah request terkirim bisa berbahaya jika operasi di vendor sebenarnya sudah berjalan.
Gunakan deadline bisnis
Timeout HTTP tidak sama dengan business deadline. Contoh: aplikasi Anda hanya butuh hasil dalam 15 detik untuk pengalaman pengguna, tetapi pemrosesan vendor bisa memakan 45 detik. Solusinya bukan menaikkan timeout request sinkron, melainkan beralih ke pola async: kembalikan status accepted, simpan job, lalu kirim hasil via callback atau polling.
Aturan praktis: jika latensi model dapat melewati batas toleransi user request, jangan paksa alur sinkron. Gunakan job async dengan state machine yang jelas.
Contoh kebijakan timeout
ai_request_policy:
connect_timeout_ms: 1000
write_timeout_ms: 3000
read_timeout_ms: 10000
total_deadline_ms: 15000
response_mode: async_after_deadlineNilai spesifik harus mengikuti karakteristik workload Anda, bukan angka generik. Yang penting adalah pemisahan tahap dan keputusan fallback yang konsisten.
Retry dengan Backoff: Kapan Aman dan Kapan Dilarang
Retry memang membantu mengatasi kegagalan sementara, tetapi retry yang salah bisa memperburuk keadaan: menambah beban vendor, menggandakan biaya, dan menciptakan hasil duplikat.
Kasus yang umumnya aman untuk retry
- Connect timeout sebelum request diyakini terkirim.
- DNS/transient network failure.
- HTTP 429 jika vendor secara eksplisit menyarankan retry.
- HTTP 502/503/504 atau error sementara dari gateway/vendor.
Meski begitu, tetap gunakan backoff, idealnya dengan jitter, agar banyak worker tidak menyerbu vendor pada saat bersamaan.
Kasus yang sebaiknya tidak langsung di-retry
- HTTP 400/422: biasanya ada masalah validasi input atau kontrak request.
- HTTP 401/403: masalah autentikasi/otorisasi, bukan error sementara.
- Read timeout setelah body request terkirim: status operasi bisa tidak diketahui; retry buta berisiko menduplikasi pekerjaan berbiaya.
- Operasi non-idempoten tanpa idempotency key yang didukung oleh sistem Anda atau vendor.
Pola retry yang lebih aman
- Tentukan apakah kegagalan terjadi sebelum atau setelah request kemungkinan diterima vendor.
- Jika status akhir tidak pasti, tandai sebagai unknown.
- Coba status check ke vendor bila ada endpoint lookup berdasarkan request reference.
- Jika tidak ada, gunakan idempotency key dan retry hanya melalui jalur yang menjaga deduplikasi.
Contoh pseudo-code retry policy
if error is connect_timeout or transient_network_error:
retry with exponential_backoff_and_jitter
elif response.status in [429, 502, 503, 504]:
retry with exponential_backoff_and_jitter
elif error is read_timeout_after_request_sent:
mark request as UNKNOWN
attempt vendor_status_lookup()
if status found:
reconcile internal state
else:
schedule delayed recovery job
else:
fail without retryKuncinya bukan banyaknya retry, tetapi kejelasan semantik retry.
Idempotensi untuk Operasi Berbiaya
Pada integrasi model AI, idempotensi bukan sekadar kenyamanan; sering kali ini adalah pengaman biaya dan konsistensi data. Jika pengguna menekan tombol dua kali, worker crash lalu memproses ulang job, atau gateway melakukan retransmisi, request yang sama bisa terkirim lebih dari sekali.
Apa itu idempotency key
Idempotency key adalah kunci unik yang merepresentasikan satu niat operasi bisnis. Misalnya, “hasilkan ringkasan untuk dokumen X versi Y”. Jika request yang sama datang lagi dengan kunci yang sama, sistem harus mengembalikan hasil yang sama atau status yang sama, bukan membuat pekerjaan baru.
Di mana idempotensi harus diterapkan
- Di API Anda sendiri: wajib.
- Di penyimpanan state/job: simpan mapping idempotency key ke hasil atau status request.
- Ke vendor: jika vendor mendukung idempotency key, manfaatkan. Jika tidak, Anda tetap perlu deduplikasi di sisi Anda.
Pola implementasi sederhana
-- Tabel contoh
CREATE TABLE ai_requests (
request_id TEXT PRIMARY KEY,
idempotency_key TEXT NOT NULL,
operation TEXT NOT NULL,
status TEXT NOT NULL,
vendor_request_ref TEXT,
response_payload TEXT,
created_at TIMESTAMP NOT NULL,
UNIQUE (idempotency_key, operation)
);Saat request masuk:
- Cek apakah kombinasi idempotency_key + operation sudah ada.
- Jika belum ada, buat record status pending lalu proses.
- Jika sudah ada, kembalikan status yang ada, misalnya pending/completed/failed sesuai kebijakan.
Jika request yang sama benar-benar perlu menghasilkan output baru, jangan gunakan idempotency key yang sama. Misalnya, sertakan versi dokumen atau hash input yang relevan.
Kesalahan umum pada idempotensi
- Menggunakan timestamp acak sebagai idempotency key, sehingga setiap retry dianggap request baru.
- Menjadikan correlation ID sebagai idempotency key.
- Tidak menyimpan status intermediate, sehingga request kedua tidak tahu request pertama masih berjalan.
- Hanya deduplikasi di memori proses, yang hilang saat service restart.
Penanganan Partial Failure dan Status Unknown
Partial failure terjadi ketika sebagian alur berhasil, sebagian lagi gagal. Ini sangat umum pada integrasi AI eksternal.
Contoh partial failure yang nyata
- Vendor menerima request dan memulai job, tetapi respons HTTP ke aplikasi Anda timeout.
- Vendor selesai memproses, tetapi webhook ke sistem Anda gagal karena endpoint sedang down.
- Webhook diterima, tetapi penyimpanan hasil di database internal gagal.
- File input berhasil diunggah ke object storage, tetapi referensi file ke vendor gagal terkirim.
Jika Anda hanya punya dua status, sukses atau gagal, kasus-kasus ini sulit dipulihkan. Gunakan state machine yang lebih kaya, misalnya:
RECEIVED
VALIDATED
DISPATCHING_TO_VENDOR
VENDOR_ACCEPTED
PROCESSING
COMPLETED
FAILED_RETRYABLE
FAILED_PERMANENT
UNKNOWN
RECONCILINGState seperti UNKNOWN dan RECONCILING membantu sistem melakukan pemulihan otomatis, misalnya dengan lookup status vendor, replay webhook yang aman, atau kompensasi internal.
Mapping Error Vendor ke Error Internal
Jangan biarkan layanan internal Anda bergantung langsung pada kode error vendor. Vendor bisa memiliki pesan yang tidak stabil, terlalu teknis, atau tidak sesuai kebutuhan bisnis Anda.
Buat taksonomi error internal
Misalnya:
- INVALID_INPUT
- AUTH_ERROR
- RATE_LIMITED
- UPSTREAM_UNAVAILABLE
- UPSTREAM_TIMEOUT
- OUTPUT_PARSE_ERROR
- UNKNOWN_UPSTREAM_STATE
Lalu map error vendor ke kategori internal tersebut. Dengan begitu, logika retry, alerting, dan respons ke klien tidak tersebar di banyak tempat.
Contoh mapping sederhana
{
"vendor_error_mapping": {
"400": "INVALID_INPUT",
"401": "AUTH_ERROR",
"403": "AUTH_ERROR",
"429": "RATE_LIMITED",
"500": "UPSTREAM_UNAVAILABLE",
"502": "UPSTREAM_UNAVAILABLE",
"503": "UPSTREAM_UNAVAILABLE",
"504": "UPSTREAM_TIMEOUT"
}
}Yang lebih penting dari tabel mapping adalah aksi per kategori: mana yang bisa di-retry, mana yang harus diinvestigasi, dan mana yang harus langsung dikembalikan sebagai error bisnis ke pemanggil.
Fallback untuk Webhook atau Async Callback yang Terlambat
Banyak integrasi AI modern memakai pola asinkron: Anda mengirim request, vendor memproses, lalu hasil dikirim melalui webhook. Ini mengurangi timeout sinkron, tetapi menambah failure mode baru: callback bisa terlambat, hilang, atau datang dua kali.
Prinsip dasar webhook yang tahan gangguan
- Webhook receiver harus idempoten.
- Verifikasi autentikasi callback, misalnya signature atau token khusus.
- Jangan proses berat di request handler webhook; simpan event lalu proses di background.
- Simpan raw payload dan header penting untuk audit/debugging.
- Bisa menangani callback duplikat atau out-of-order.
Apa yang dilakukan saat callback terlambat
Jangan hanya menunggu webhook tanpa batas. Buat recovery loop:
- Setelah vendor menerima job, simpan expected callback deadline.
- Jika deadline terlewati dan callback belum datang, jadwalkan status polling atau rekonsiliasi.
- Jika vendor menyatakan job selesai, tarik hasil secara aktif jika memungkinkan.
- Jika status vendor tidak tersedia, tandai job untuk investigasi atau retry yang aman sesuai idempotensi.
Dengan pola ini, webhook menjadi jalur utama, tetapi bukan satu-satunya sumber penyelesaian state.
Contoh Skenario Bug Integrasi dan Perbaikannya
Bug 1: Read timeout memicu duplikasi biaya
Skenario: service Anda mengirim request inferensi ke vendor. Setelah 12 detik, koneksi read timeout. Worker langsung retry request yang sama. Ternyata request pertama sebenarnya sudah diproses vendor. Hasilnya, dua inferensi berjalan dan biaya terduplikasi.
Akar masalah: sistem memperlakukan semua timeout sebagai aman untuk retry.
Perbaikan:
- Bedakan connect timeout vs read timeout setelah request terkirim.
- Tandai status sebagai UNKNOWN saat read timeout ambigu.
- Gunakan idempotency key yang persisten.
- Lakukan status lookup atau delayed reconciliation sebelum mengirim ulang operasi berbiaya.
Bug 2: Callback vendor datang dua kali dan menimpa state final
Skenario: vendor mengirim webhook dua kali karena tidak menerima ack cepat. Handler Anda menulis ulang state dan mengirim notifikasi dua kali ke pengguna.
Akar masalah: webhook handler tidak idempoten dan tidak punya deduplikasi event.
Perbaikan:
- Simpan event ID vendor atau hash payload sebagai dedup key.
- Gunakan transaksi atau compare-and-set pada update state.
- Pastikan efek samping seperti notifikasi hanya jalan sekali.
Bug 3: Vendor mengubah format error, dashboard internal rusak
Skenario: sistem Anda mengandalkan string error vendor untuk klasifikasi. Ketika format pesan berubah, semua error masuk kategori unknown dan on-call kehilangan visibilitas.
Akar masalah: kontrak internal terlalu bergantung pada detail vendor.
Perbaikan:
- Map error vendor ke kategori internal yang stabil.
- Gunakan kode/status yang terstruktur, bukan parsing string bebas.
- Simpan detail vendor sebagai metadata tambahan, bukan sebagai sumber keputusan utama.
Pola Desain yang Lebih Tahan Edge Case
1. Adapter per vendor, kontrak internal tunggal
Aplikasi bisnis berbicara ke satu kontrak internal. Adapter vendor menangani transformasi request, autentikasi, endpoint khusus, parsing respons, dan error mapping. Ini mengurangi vendor lock-in di level aplikasi.
2. State machine eksplisit
Daripada menyimpan boolean sederhana seperti done=true, gunakan status yang merepresentasikan lifecycle request. Ini penting untuk retry orchestration, rekonsiliasi, dan debugging insiden.
3. Outbox atau event log untuk efek samping
Jika setelah hasil AI diterima Anda perlu mengirim notifikasi, update billing, atau meneruskan ke service lain, pertimbangkan pola outbox agar perubahan state dan publikasi event tidak terpisah secara rapuh.
4. Recovery worker terjadwal
Jangan bergantung penuh pada request path utama. Buat worker yang secara periodik memindai request berstatus UNKNOWN, PROCESSING terlalu lama, atau callback overdue, lalu melakukan rekonsiliasi.
5. Validasi output model sebelum dianggap sukses
Vendor bisa mengembalikan HTTP 200 tetapi output tidak memenuhi skema yang Anda butuhkan. Bila output harus terstruktur, validasi schema internal dan pisahkan upstream success dari business success.
Checklist Observabilitas untuk Integrasi AI Eksternal
Jika tidak bisa diamati, integrasi sulit dioperasikan. Minimal, siapkan checklist berikut:
Log
- request_id, correlation_id, idempotency_key
- vendor name dan operation type
- timeout stage yang gagal
- retry attempt ke berapa
- mapped internal error code
- vendor request reference jika ada
Metrics
- jumlah request per operation dan per vendor
- success rate, failure rate, unknown rate
- latensi per tahap: connect, vendor processing, callback delay
- retry count distribution
- rate limit hit
- jumlah request yang direkonsiliasi oleh recovery worker
Tracing
- span untuk validasi input
- span untuk dispatch ke vendor
- span untuk polling atau callback handling
- atribut trace: vendor ref, status internal, retryable/non-retryable
Alerting
- lonjakan status UNKNOWN
- callback overdue di atas ambang tertentu
- kenaikan HTTP 429/503 dari vendor
- rasio retry yang melonjak
- queue backlog untuk processing callback atau reconciliation
Contoh Alur Implementasi yang Praktis
- API menerima request dan membentuk request_id, correlation_id, dan idempotency_key.
- Sistem mengecek tabel deduplikasi. Jika request sudah ada, kembalikan status existing.
- Jika baru, simpan record dengan status RECEIVED lalu validasi input.
- Worker mengirim request ke vendor dengan timeout per tahap dan metadata korelasi.
- Jika vendor mengembalikan hasil sinkron dalam batas deadline, validasi output lalu tandai COMPLETED.
- Jika vendor menerima tetapi hasil belum siap, tandai VENDOR_ACCEPTED/PROCESSING dan tunggu callback.
- Jika callback datang, verifikasi, deduplikasi, simpan hasil, dan transisikan state secara atomik.
- Jika callback terlambat, recovery worker melakukan polling atau rekonsiliasi berdasarkan vendor reference.
- Jika status tidak bisa dipastikan, tandai UNKNOWN dan eskalasi sesuai runbook.
Penutup
Desain API ke model AI eksternal: timeout, retry, dan idempotensi bukan detail tambahan, melainkan fondasi keandalan sistem. Integrasi yang terlihat berjalan normal saat beban rendah bisa gagal diam-diam di produksi jika Anda tidak membedakan timeout per tahap, menerapkan retry tanpa semantik yang jelas, atau mengabaikan idempotensi untuk operasi berbiaya.
Pola yang paling tahan terhadap edge case biasanya sederhana secara prinsip: kontrak internal yang eksplisit, correlation ID di semua hop, timeout yang terukur, retry hanya untuk kegagalan yang benar-benar sementara, idempotency key yang persisten, state machine yang jelas, dan recovery path untuk callback yang terlambat. Dengan fondasi ini, Anda lebih siap mengintegrasikan model pihak ketiga, private model, maupun sovereign AI tanpa membuat backend Anda rapuh.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!