Cara memberi tugas ke agen AI: satu fitur per waktu, daftar fitur, dan kriteria selesai
Tugas untuk agen AI diberikan satu per satu: dalam pengerjaan selalu ada tepat satu fitur, fitur itu punya perilaku yang bisa diamati dan perintah verifikasi yang bisa dijalankan, sementara semua hal lain yang ditemukan di jalan dicatat ke backlog, bukan diperbaiki. Status semua fitur disimpan dalam daftar yang bisa dibaca mesin (misalnya feature_list.json), dan hanya skrip verifikasi yang boleh menandai fitur sebagai selesai, bukan agen itu sendiri.
Mengapa agen mengerjakan semuanya sekaligus
Anda meminta agen membuat registrasi. Beberapa jam kemudian, diff berisi dua belas berkas yang berubah dan delapan ratus baris baru: model pengguna, verifikasi email, layanan surel yang tersambung, hashing kata sandi, middleware yang direfaktor, dan tes yang dipindahkan. Semuanya saling terkait, dan tidak ada satu pun skenario yang berjalan dari awal sampai akhir. Sesi berikutnya membuka kode ini dan tidak tahu harus mulai dari mana.
Penyebabnya bukan «model yang buruk». Manusia punya perasaan «untuk hari ini cukup» dan rasa lelah, yang membatasi cakupan pekerjaannya sendiri. Agen tidak punya keduanya. Menambahkan «sekalian saya perbaiki penanganan error» hanya memakan beberapa puluh token baginya, tetapi biayanya bagi proyek nyata: perhatian terpecah, keterkaitan antarbagian meningkat, dan tidak ada yang benar-benar selesai.
Ada juga aritmetika sederhana. Misalkan C adalah kapasitas konteks yang berguna, dan k adalah jumlah tugas yang dipegang agen sekaligus. Untuk setiap tugas tersedia sekitar C/k kapasitas penalaran. Ketika nilai ini turun di bawah kebutuhan untuk menyelesaikan satu tugas, tidak ada satu tugas pun yang selesai. Karena itu jawaban atas pertanyaan «bagaimana memberi tugas ke agen AI» tidak dimulai dari rumusan prompt, melainkan dari batasan: satu tugas dalam pengerjaan.
Aturan satu fitur (WIP=1)
WIP adalah work in progress, jumlah tugas yang sedang dikerjakan. Untuk agen nilainya dibuat sama dengan satu: setiap saat hanya ada tepat satu fitur yang aktif, dan fitur berikutnya baru dimulai setelah yang sekarang lolos verifikasi. Aturan ini dicatat dalam berkas instruksi proyek (AGENTS.md atau CLAUDE.md) agar agen melihatnya di setiap sesi:
## Aturan kerja
- Pada setiap saat, tepat SATU fitur berada dalam status `active`.
- Fitur berikutnya boleh dimulai hanya setelah fitur yang sekarang berpindah ke `passing`.
- Dilarang «sekalian» merefaktor, mengganti nama, menata ulang direktori,
atau memperbaiki bug yang tidak terkait. Jika menemukan masalah, catat di
`BACKLOG.md` lalu lanjutkan.
- Perubahan di luar lingkup fitur yang aktif dihitung sebagai pelanggaran,
meskipun perubahan itu berguna.
Poin terakhir lebih penting daripada kelihatannya. Agen dengan tulus menganggap «sekalian»-nya bermanfaat, dan sering kali memang benar. Tetapi perbaikan di luar lingkup tetap mencampur dua tugas dalam satu diff, sehingga keduanya tidak bisa lagi dibatalkan atau diverifikasi secara terpisah.
BACKLOG.md: ke mana perginya «sekalian»
Dorongan untuk «sekalian memperbaiki» tidak cukup hanya dilarang; ia butuh jalur resmi. Jalur itu adalah berkas BACKLOG.md: agen menulis masalah yang ditemukan dalam satu-dua baris lalu kembali ke fitur yang sedang dikerjakan. Informasinya tidak hilang, dan lingkup tidak membengkak. Tanpa backlog, aturan satu fitur cepat atau lambat akan dilanggar agen, karena diam-diam membiarkan bug terasa lebih buruk baginya daripada melanggar aturan.
# BACKLOG.md
- [ ] middleware/errors.py: format error berbeda di /auth dan /orders
- [ ] tests/: fixture pengguna diduplikasi di tiga berkas
- [ ] perlukah verifikasi email saat registrasi? — tanyakan
Kriteria selesai: «selesai» harus berupa perintah
Separuh masalah lainnya: agen sendiri memutuskan kapan tugas dianggap selesai. «Kodenya terlihat normal», «fungsinya ada», «tidak ada error kompilasi» adalah perasaan, bukan fakta. Kriteria selesai untuk tugas agen harus berupa perintah yang bisa dijalankan dengan hasil yang tidak ambigu: lolos atau tidak.
F01: registrasi pengguna
verification: pytest tests/e2e/test_auth.py::test_register_flow
state: active
Perbedaan antara kriteria lemah dan kuat terlihat jelas pada contoh berikut:
| Kriteria lemah | Kriteria kuat |
|---|---|
| Kode dikompilasi | pytest tests/e2e/test_cart.py -q lolos |
| Tidak ada error sintaks | curl ke /cart mengembalikan kode 200 |
Fungsi addToCart ada | Setelah menambah produk, GET /cart menampilkannya dengan total yang benar |
| Terlihat benar | npx playwright test cart.spec.ts lolos |
Perintah verifikasi yang baik bersifat deterministik (kode yang sama menghasilkan hasil yang sama), berjalan tanpa campur tangan manusia, dan memeriksa perilaku dari luar, seperti yang akan dilihat pengguna atau klien API. Jika Anda kesulitan menulis perintah seperti itu, itu tanda bahwa tugasnya belum dirumuskan dengan jelas.
Dekomposisi: seberapa besar seharusnya sebuah fitur
Pertanyaan yang paling sering muncul setelah «satu fitur per waktu» adalah: apa yang disebut fitur. Tugas yang terlalu lebar tidak akan selesai dalam satu sesi, sedangkan tugas yang terlalu sempit tenggelam dalam biaya memulai, konteks, dan verifikasi.
- Terlalu lebar: «implementasikan keranjang belanja». Ini seminggu kerja dan puluhan skenario.
- Pas: «pengguna bisa menambah produk ke keranjang dan melihatnya di sana». Satu perilaku yang bisa diamati, satu skenario verifikasi.
- Terlalu sempit: «buat kolom quantity di model CartItem». Ini langkah implementasi, bukan perilaku; memverifikasinya sendiri tidak ada artinya.
Pengukur praktis: satu fitur = satu sesi agen = satu commit yang bermakna = satu skenario end-to-end (E2E). Jika fitur tidak muat dalam satu sesi, pecah lagi. Jika tidak bisa dibuatkan skenario tersendiri, fitur itu terlalu kecil dan sebaiknya digabung dengan fitur tetangganya.
Contoh dekomposisi tugas «keranjang»
Kebutuhan yang lebar dipecah menjadi unit atomik, dan setiap unit punya satu perilaku serta perintah verifikasinya sendiri:
- Menambah produk ke keranjang dan melihatnya di daftar.
- Mengubah jumlah produk — total dihitung ulang.
- Menghapus produk dari keranjang.
- Keranjang tamu tetap tersimpan setelah login ke akun.
- Produk yang tidak tersedia tidak bisa ditambahkan — muncul pesan error yang jelas.
Pemeriksaan akhir dekomposisi: tidak ada unit yang mengharuskan «sekalian» menyentuh unit lain. Jika untuk poin 4 Anda harus menulis ulang poin 1, maka urutan atau batasnya kurang tepat.
Daftar fitur: feature_list.json
Aturan satu fitur menjaga urutan di dalam sesi. Tetapi siapa yang mengingat apa yang sudah selesai di antara sesi? Catatan di chat seperti «auth dan katalog sudah jadi, keranjang hampir selesai, tapi ada bug» tidak membantu sesi baru: apa arti «hampir», tes mana yang lolos, dan apa yang menghambat pembayaran tidak diketahui. Setiap sesi baru seperti pengemudi baru di mobil yang sama: jika catatan hanya ada di kepala pengemudi lama, pengemudi baru tidak tahu apa-apa.
Karena itu keadaan dipindahkan ke berkas yang bisa dibaca mesin. Dalam kursus ini berkasnya adalah .agent/feature_list.json:
[
{
"id": "F01",
"behavior": "Pengguna mendaftar dengan e-mail dan kata sandi lalu langsung masuk",
"verification": "pytest tests/e2e/test_auth.py::test_register_flow",
"state": "passing",
"evidence": "a3f9c12: 1 passed in 2.31s"
},
{
"id": "F02",
"behavior": "Pengguna menambah produk ke keranjang dan melihatnya di daftar",
"verification": "pytest tests/e2e/test_cart.py::test_add_item -q",
"state": "active"
},
{
"id": "F03",
"behavior": "Pembayaran pesanan dengan kartu",
"verification": "pytest tests/e2e/test_payment.py -q",
"state": "blocked",
"blocker": "tidak ada kunci uji gateway pembayaran"
}
]
Setiap entri memiliki tiga kolom wajib: deskripsi perilaku (yang dapat diamati dari luar), perintah verifikasi (dapat dijalankan tanpa manusia), dan status. Kolom keempat yang opsional adalah evidence: hash commit dan keluaran verifikasi, sebagai bukti bahwa perpindahan ke passing benar-benar terjadi.
Mengapa JSON dan bukan daftar Markdown? Berkas ini dibaca tidak hanya oleh agen, tetapi juga oleh skrip: penjadwal memilih fitur berikutnya dengan status not_started, verifikator mengambil perintah verifikasi, laporan sesi tersusun otomatis, dan distribusi status memberikan metrik kesehatan proyek. Daftar fitur adalah tulang punggung harness, bukan sekadar catatan pengingat.
Empat status dan transisi yang diizinkan
| Transisi | Kapan |
|---|---|
not_started → active | Fitur diambil untuk dikerjakan; tidak ada fitur aktif lain |
active → passing | Skrip verifikasi selesai dengan kode 0 |
active → blocked | Ada penghambat eksternal; alasannya dicatat di blocker |
blocked → active | Penghambat sudah teratasi |
Tidak ada transisi lain. Khususnya, tidak ada jalan menuju passing yang melewati verifikasi, dan tidak ada status «hampir selesai».
Gerbang passing: agen boleh meminta, tetapi tidak boleh menyatakan sendiri
Aturan inti seluruh skema ini: agen tidak mengedit kolom state dengan tangan. Ia boleh menjalankan verifikasi, tetapi tidak boleh menyatakan hasilnya sendiri; yang melakukannya adalah skrip. Perbedaan antara «agen melaporkan» dan «skrip mengonfirmasi» adalah perbedaan antara teks dan fakta. Aturan ini juga dicatat dalam berkas instruksi:
## Aturan daftar fitur
- Berkas: `.agent/feature_list.json`. Ini satu-satunya sumber kebenaran untuk lingkup.
- Tepat satu fitur berstatus `active`.
- Kamu TIDAK mengedit kolom `state` secara manual. Kolom itu diubah oleh `scripts/verify.sh`.
- Untuk memindahkan fitur ke `passing`, jalankan `./scripts/verify.sh F02` dan pastikan kodenya 0.
- Jika fitur terhambat, pindahkan ke `blocked` dan wajib isi `blocker`.
- Fitur baru hanya boleh ditambahkan ke `not_started` dan wajib disertai perintah verifikasi.
Skrip itu sendiri memeriksa di dua tingkat: pertama pemeriksaan proyek secara umum (fitur tidak boleh merusak bagian lain), kemudian perintah khusus fitur. Keberhasilan lokal yang disertai regresi global tidak dihitung sebagai keberhasilan.
#!/usr/bin/env bash
# Satu-satunya komponen yang berhak menetapkan passing.
set -uo pipefail
FID="$1"
FILE=".agent/feature_list.json"
CMD=$(jq -r --arg id "$FID" '.[] | select(.id==$id) | .verification' "$FILE")
if [ -z "$CMD" ] || [ "$CMD" = "null" ]; then
echo "FAIL: tidak ada perintah verifikasi untuk $FID"; exit 2
fi
echo "== pemeriksaan global =="
make check || { echo "FAIL: pemeriksaan global merah, $FID tidak bisa passing"; exit 1; }
echo "== pemeriksaan fitur: $CMD =="
if OUT=$(eval "$CMD" 2>&1); then
SHA=$(git rev-parse --short HEAD)
LAST=$(printf '%s\n' "$OUT" | tail -n 1)
TMP=$(mktemp)
jq --arg id "$FID" --arg ev "$SHA: $LAST" \
'map(if .id==$id then .state="passing" | .evidence=$ev else . end)' \
"$FILE" > "$TMP" && mv "$TMP" "$FILE"
echo "PASS: $FID"
else
printf '%s\n' "$OUT"
echo "FAIL: $FID"; exit 1
fi
Aturan «jangan edit state» dalam teks masih berupa permintaan. Agar menjadi batasan, penulisan ke berkas bisa dikunci secara mekanis: dengan pemeriksaan di CI yang mencocokkan evidence dengan riwayat commit, atau dengan membatasi hak akses agen di alat Anda. Prinsipnya sama seperti di seluruh harness: aturan penting harus didukung mekanisme.
Cara mengukur apakah agen menuntaskan tugas
Metrik yang menggoda adalah volume kode per sesi. Dalam praktik justru sebaliknya: diff yang besar lebih sering berarti agen tercerai-berai di beberapa arah. Hitung fitur yang berstatus passing, bukan jumlah baris.
Metrik praktis dari kursus adalah VCR (Verified Completion Rate): jumlah tugas yang terverifikasi dibagi jumlah tugas yang diaktifkan. Aturannya sederhana: selama VCR belum mencapai satu, tugas baru tidak boleh diaktifkan. Ini adalah tekanan balik yang diberikan harness kepada agen, sekaligus cara menjadikan pekerjaan yang belum tuntas terlihat sebagai angka, bukan perasaan.
Kesalahan umum saat memberi tugas ke agen
- Tugas tanpa perintah verifikasi. «Buat registrasi» tanpa skenario membuat agen memutuskan sendiri kapan berhenti, dan ia akan memutuskannya dengan keliru.
- Beberapa fitur dalam satu permintaan. «Buat keranjang dan pembayaran» berarti dua tugas aktif, dan tidak satu pun akan selesai.
- Keadaan hanya ada di chat. Kemajuan yang tercatat dalam percakapan hilang bersama berakhirnya sesi. Ia harus hidup di dalam berkas.
- Laporan diri sendiri sebagai pengganti verifikasi. «Agen bilang tesnya lolos» tidak sama dengan kode keluar dari skrip.
- Tidak ada backlog. Larangan «sekalian» tanpa tempat untuk mencatat temuan akan diakali agen.
Kapan satu fitur per waktu tidak lagi cukup
Skema «satu fitur — satu sesi — satu verifikasi» bekerja baik untuk satu agen dalam satu siklus. Ketika tugas makin banyak dan muncul cabang yang independen, skema ini diperluas menjadi sistem dengan beberapa siklus: simpul perencanaan, simpul implementasi, simpul verifikasi, dan sisi di antaranya yang bisa paralel, bersyarat, atau kembali ke implementasi jika verifikasi gagal. Namun di setiap simpul implementasi tetap berlaku aturan yang sama: satu tugas, kriteria selesai yang bisa dieksekusi, dan keadaan yang berada di luar kepala agen. Graf tidak meniadakan disiplin satu fitur, melainkan dibangun di atasnya.
Peringatan penting dari pembahasan yang sama: siklus akan dengan jujur mengoptimalkan metrik yang diberikan kepadanya. Jika kriteria selesai dipilih dengan buruk, misalnya «tiket ditutup» alih-alih «masalah terselesaikan», agen akan belajar memenuhi kriteria, bukan menyelesaikan tugas. Karena itu rumusan perilaku dan perintah verifikasi layak mendapat waktu lebih banyak daripada yang terlihat.
Ringkasnya
Singkatnya, cara memberi tugas ke agen AI: satu per satu, dengan perilaku yang bisa diamati dan perintah verifikasi yang bisa dijalankan, dengan backlog untuk semua yang ditemukan di jalan, dan dengan daftar fitur dalam berkas tempat perpindahan ke «selesai» dilakukan oleh skrip, bukan oleh agen. Rem bagi agen dipasang oleh harness, bukan oleh agen itu sendiri. Aturan WIP=1, feature_list.json, dan verify.sh dibahas dengan praktik nyata dalam kursus harness engineering menggunakan proyek end-to-end.
Pertanyaan umum
Bolehkah saya memberi agen beberapa tugas sekaligus jika tugasnya kecil?
Boleh dimasukkan ke daftar fitur, tetapi dalam pengerjaan hanya boleh ada satu. Agen mengambil yang berikutnya hanya setelah yang sekarang lolos verifikasi, sehingga setiap tugas benar-benar selesai.
Bagaimana jika untuk suatu tugas tidak mungkin ditulis verifikasi otomatis?
Biasanya itu berarti tugasnya dirumuskan sebagai tindakan, bukan sebagai perilaku. Rumuskan ulang melalui apa yang akan dilihat pengguna atau klien API; untuk bagian visual, tes e2e di browser cocok.
Siapa yang menulis feature_list.json, manusia atau agen?
Daftar awal sebaiknya disusun bersama: agen mengusulkan dekomposisi, manusia merevisinya. Setelah itu agen boleh menambah fitur baru, tetapi hanya dengan status not_started dan disertai perintah verifikasi.
Apa bedanya feature_list.json dengan tugas di pelacak tugas?
Pelacak tugas dirancang untuk manusia, sedangkan daftar fitur untuk dibaca mesin: setiap entri punya perintah yang bisa dieksekusi dan status ketat yang hanya diubah oleh skrip. Keduanya bisa disinkronkan, tetapi agen membutuhkan berkas di dalam repositori.
Apakah aturan satu fitur memperlambat pekerjaan?
Sesinya menjadi lebih pendek, tetapi proporsi tugas yang benar-benar selesai meningkat. Waktu yang biasanya habis untuk memilah kode setengah jadi dari tiga fitur yang bercampur menjadi hemat.
Topik ini dibahas mendalam dengan praktik di kursus “Harness Engineering: инженерия надёжности AI-агентов”.
- feature_list.json для AI-агента: WIP=1, статусы фич и верификация через verify.sh
- Graph Engineering для AI-агентов: когда одного цикла мало и нужен граф задач