Pelajari pola task lanjutan untuk produksi multi-agent: orchestrasi fan-out dan fan-in, workflow human-in-the-loop dengan state input-required dan resubmission, serta manajemen state seperti idempotency, retry, long-running task, dan checkpoint-resume.

Di episode 16 kita membuat agent-agent bisa saling menemukan dan memilih lewat registry dan routing. Sekarang task yang mereka tukarkan bisa menjadi lebih kompleks dari sekadar tanya-jawab. Di dunia produksi, satu permintaan user sering menjadi pohon task: dipecah ke banyak agent, menunggu keputusan manusia, lalu disatukan kembali.
Protokol A2A memang dirancang untuk pola ini. Task punya lifecycle lengkap dengan state submitted, working, input-required, completed, failed, dan canceled. Episode ini memanfaatkan lifecycle tersebut untuk membangun pola-pola task lanjutan: fan-out/fan-in, human-in-the-loop, resubmission, idempotency, dan checkpoint-resume.
Roadmap episode ini: kita mulai dari orchestrasi fan-out dan fan-in, lalu human-in-the-loop dengan state input-required, resubmission, idempotency dan retry, dan menutup dengan long-running task beserta checkpoint-resume.
Fan-out berarti satu task dipecah menjadi banyak sub-task yang dikirim ke beberapa agent secara paralel. Fan-in berarti mengumpulkan semua hasil dan menggabungkannya menjadi satu output. Pola ini sangat umum: cek harga dari tiga vendor sekaligus, tanya cuaca di lima kota, atau ringkas dokumen dari banyak sumber.
Implementasi orkestrator dengan fan-out lalu fan-in:
import asyncio
async def fan_out_and_fan_in(agent_clients, sub_tasks):
pending = [
client.send_task(task) for client, task in zip(agent_clients, sub_tasks)
]
results = await asyncio.gather(*pending, return_exceptions=True)
ok = [r for r in results if not isinstance(r, Exception)]
merged = merge_results(ok)
return await aggregator_client.send_task({"parts": [merged]})Beberapa catatan praktis fan-out/fan-in:
taskId sendiri — korelasi dengan task induk dilakukan lewat metadata trace seperti di episode 15.Beberapa keputusan tidak boleh ditentukan agent sendirian — transfer uang, approval dokumen hukum, atau aksi yang merusak. A2A menyediakan state input-required untuk pola ini: agent berhenti bekerja dan menunggu input dari manusia atau sistem eksternal.
Alurnya: task masuk, agent bekerja sebentar, menemukan butuh persetujuan, lalu mengembalikan task dalam state input-required dengan detail apa yang dibutuhkan. Client menampilkan pertanyaan ke manusia, lalu mengirimkan message/send baru dengan jawabannya; agent melanjutkan task.
Contoh respons saat agent membutuhkan persetujuan:
{
"jsonrpc": "2.0",
"id": "7",
"result": {
"id": "task-4821",
"status": "input-required",
"artifacts": [
{
"parts": [
{ "kind": "text", "text": "Transaksi di atas limit otomatis. Persetujuan dibutuhkan." }
]
}
],
"metadata": {
"inputModal": { "type": "approval" }
}
}
}Warning
Jangan membiarkan task menggantung di state input-required selamanya. Setel timeout: jika manusia tidak merespons dalam batas waktu tertentu, batalkan task atau kembalikan ke antrean. Kebocoran task seperti ini sering menjadi akar "antrean yang tak pernah selesai".
Kadang task gagal karena faktor sementara — LLM timeout, server overload, atau gangguan jaringan. Resubmission adalah pola mengirim ulang task yang gagal, dengan harapan percobaan berikutnya berhasil. Kuncinya adalah memutuskan: kapan boleh diulang, dan berapa kali.
Aturan praktis:
taskId yang sama saat mengulang, agar server tahu ini percobaan ulang dari task yang sama.Alur resubmission dalam kode orkestrator:
MAX_ATTEMPTS = 3
async def send_with_resubmit(client, task):
for attempt in range(1, MAX_ATTEMPTS + 1):
result = await client.send_task(task)
if result.status == "failed" and result.retryable:
await asyncio.sleep(2 ** attempt)
continue
return result
return escalate_to_human(task)Idempotency menjamin bahwa mengulang aksi yang sama tidak menghasilkan efek ganda. Bayangkan client timeout setelah mengirim message/send, lalu mengirim ulang. Jika server memproses dua kali, agent bisa memesan tiket dobel atau mengirim duplikat. Solusinya: client menyertakan identitas task yang konsisten, dan server mendeteksi serta menolak duplikat.
Di A2A, setiap message membawa messageId, dan setiap task memiliki taskId. Server harus menyimpan riwayat task dan: jika messageId sudah pernah diproses, kembalikan hasil yang sama tanpa menjalankan ulang.
Pola retry yang aman — dan untuk implementasi backoff di Python, pustaka seperti tenacity yang dipasang lewat pip install tenacity sangat membantu:
retry:
max_attempts: 5
backoff:
type: exponential
base_ms: 500
multiplier: 2
retryable_statuses:
- failed
- timeout
idempotency_key: messageIdInfo
Retry dan idempotency adalah pasangan yang tak terpisahkan. Tanpa idempotency, retry berbahaya; tanpa retry, idempotency tak berguna. Selalu terapkan keduanya bersama, dan pastikan server menyimpan cukup riwayat untuk mendeteksi duplikat dalam jendela waktu yang wajar.
Task A2A bisa berjalan lama — analisis data besar, pipeline multi-step, atau proses yang menunggu banyak sub-task. Risikonya: proses server bisa restart, network bisa terputus, dan task yang setengah jalan akan hilang. Di sinilah checkpoint/resume berperan.
Konsepnya: simpan snapshot state task secara berkala ke penyimpanan eksternal. Saat proses restart, agent memuat snapshot terakhir dan melanjutkan dari sana, alih-alih mengulang dari awal.
Pola implementasinya:
import json
def save_checkpoint(task_id, state, step):
snapshot = {"task_id": task_id, "state": state, "step": step}
state_store.put(f"checkpoint:{task_id}", json.dumps(snapshot))
def resume_task(task_id):
raw = state_store.get(f"checkpoint:{task_id}")
if not raw:
return None
snapshot = json.loads(raw)
return snapshotBeberapa praktik checkpoint yang baik:
tasks/get.Success
Lifecycle task A2A sudah dirancang untuk ini: task tidak bergantung pada satu koneksi. Client bisa melakukan polling status, server menyimpan state task secara independen, dan dengan checkpoint yang benar, restart server tidak menghapus progress. Inilah fondasi task yang benar-benar production-grade.
Pada episode ini kita merakit pola task lanjutan di atas lifecycle A2A. Fan-out dan fan-in memecah task besar menjadi paralel dan menyatukannya kembali, state input-required menghadirkan manusia dalam alur kerja, resubmission menangani kegagalan sementara, idempotency dan retry menjaga konsistensi, dan checkpoint-resume membuat task panjang bertahan dari restart.
Inti yang harus dibawa pulang:
input-required menghentikan task untuk menunggu keputusan manusia, lengkap dengan timeout agar tidak menggantung.messageId dan taskId agar retry tidak menimbulkan efek ganda.Dengan pola-pola ini, orchestration multi-agent kalian sudah setara praktik produksi. Namun ada pertanyaan lain yang menunggu: ketika ratusan agent memproses ribuan task, berapa biayanya dan seberapa cepat?
Di episode 18 selanjutnya kita akan membahas Performance & Scale: menangani banyak remote agent dengan connection pooling, caching agent card, load balancing, serta tradeoff streaming versus polling dan minimasi payload untuk throughput tinggi. Sampai jumpa!