Reranking yang Merusak yang Tidak Bersalah
Di proyek medcoder (asisten AI offline yang saya kerjakan untuk mengusulkan kode diagnosis ICD-10 dan kode tindakan ICD-9-CM dari catatan SOAP), saya sempat punya satu aturan retrieval yang menurut saya sudah lolos validasi dengan baik. Buktinya kuat: dari data nyata, sekitar 86% (152 berbanding 25) mendukung penerapan aturan ini. Saya terapkan dengan percaya diri. Begitu diukur, hasilnya nol bersih — tidak ada perbaikan sama sekali. Butuh beberapa ronde penelusuran sebelum saya sadar bahwa yang salah bukan aturannya, tapi cara saya mengimplementasikannya.
Bukti Kuat, Hasil Nol
Aturan ini menyasar satu perilaku retrieval yang spesifik: kalau kondisinya terpenuhi, satu kandidat kode seharusnya diturunkan prioritasnya, bukan dihapus. Rasio 152:25 itu bukan angka kecil — itu pola yang cukup konsisten untuk membuat saya yakin aturan ini akan langsung kelihatan efeknya begitu masuk ke evaluasi retrieval.
Tapi setelah dijalankan lewat harness eval-retrieval, angkanya rata. Tidak ada kenaikan, tidak ada penurunan yang jelas — seolah aturan itu tidak pernah diterapkan. Reaksi pertama saya adalah menyalahkan hipotesisnya: mungkin pola 152:25 itu cuma korelasi kebetulan di data historis, tidak benar-benar berarti apa-apa untuk kualitas retrieval.
Ternyata Bukan Aturannya, Tapi Cara Menerapkannya
Sebelum membuang hipotesis itu, saya telusuri dulu implementasinya baris per baris. Ternyata caranya menurunkan prioritas satu item adalah dengan memindahkannya ke ekor daftar kandidat. Kedengarannya operasi yang sederhana dan lokal — cuma menyentuh satu item. Tapi begitu saya lacak efeknya ke seluruh daftar, jadi jelas: memindahkan satu item ke ekor otomatis menggeser posisi SEMUA kandidat lain yang tadinya berada di belakangnya, satu tingkat lebih tinggi, di setiap kasus yang punya kandidat itu di daftarnya — termasuk kasus-kasus yang sama sekali tidak ada hubungannya dengan kondisi yang jadi syarat aturan ini.
Jadi kerusakannya menjalar. Perbaikan yang seharusnya terjadi di kasus-kasus yang memang memenuhi syarat aturan, tertutup oleh gangguan acak di kasus-kasus lain yang urutannya ikut bergeser tanpa alasan. Efek bersihnya di angka agregat: nol. Bukan karena tidak ada perbaikan sama sekali, tapi karena perbaikan dan kerusakan saling menghapus di rata-rata.
Versi "Hati-Hati" Malah Paling Buruk
Begitu penyebabnya ketahuan, saya coba beberapa varian implementasi. Salah satunya saya rancang lebih hati-hati — mencoba meminimalkan gangguan ke kandidat lain, dengan logika tambahan supaya pergeseran tidak menjalar terlalu jauh. Logikanya di atas kertas masuk akal: kalau efek samping ke kasus lain itu masalahnya, ya kurangi efek sampingnya.
Hasilnya justru kebalikan dari yang saya harapkan. Dari semua varian yang saya coba, versi "hati-hati" ini yang paling buruk. Dugaan saya, logika tambahan untuk membatasi gangguan itu sendiri menambah titik kegagalan baru — ada lebih banyak cabang kondisi, lebih banyak kemungkinan implementasi keliru menangani kasus tepi, dan itu semua di atas mekanisme reranking yang sudah rawan dari awal. Mencoba memperbaiki masalah dengan menambah kerumitan, di kasus ini, malah menambah cara baru untuk salah.
Hipotesis Benar Secara Statistik Bukan Jaminan Implementasi Menang
Bagian yang paling saya bawa pulang dari kejadian ini adalah beda antara dua hal yang biasanya saya anggap satu paket: hipotesis yang benar secara statistik, dan implementasi yang benar-benar menang di evaluasi. Rasio 152:25 itu tetap valid sebagai bukti pola di data. Yang gagal bukan polanya, tapi jembatan antara pola itu dengan kode yang menerapkannya. Sukses di salah satu sisi ternyata sama sekali tidak menjamin sukses di sisi lain.
Ini pelajaran yang menurut saya berlaku lebih luas dari sekadar kasus retrieval saya. Sebelum menyalahkan sebuah hipotesis karena hasil eksperimennya nol atau datar, saya sekarang selalu cek dulu apakah cara menerapkannya punya efek samping tersembunyi ke bagian sistem lain. Ini penting khususnya untuk operasi apa pun yang menyentuh urutan atau ranking sebuah daftar — mengubah satu posisi di daftar hampir selalu berarti ikut mengubah posisi item lain, dan kalau evaluasi hanya melihat angka agregat, efek samping semacam ini bisa bersembunyi dengan sangat rapi di balik angka yang kelihatannya "tidak ada perubahan".
Yang Belum Selesai
Proyek medcoder ini masih terus berjalan dan aturan reranking ini termasuk salah satu bagian yang masih saya iterasi. Untuk sekarang saya belum punya implementasi yang saya anggap final untuk menurunkan prioritas satu kandidat tanpa mengganggu urutan kandidat lain secara tidak sengaja — kemungkinan solusinya perlu mekanisme yang benar-benar terisolasi per item, bukan operasi list yang menyentuh seluruh struktur. Sampai itu selesai, catatan ini saya simpan sebagai pengingat: angka pendukung yang kuat untuk sebuah aturan tidak otomatis berarti implementasinya akan menang di evaluasi.