Skip to content

Scraper Chat AI: Saat Kata 'Sumber' Menipu Gate Selesai

Adityo Guni Waluyo

Gate selesai scraper chat AI lolos di jawaban setengah jadi karena satu kata. Empat perbaikan dari satu audit loop polling, dari regex heading sampai clipboard.

Ringkasan

Scraper riset sempat ngira jawaban tuntas padahal cuma setengah ditulis, gara-gara gate kegagalan lolos dari kata "Sumber" di tengah prosa. Empat perbaikan lahir dari satu audit: pola kegagalan cuma dicek sebelum jawaban ada, gate tuntas wajib heading "## Sumber" dijangkar, plus diagnostik clipboard. Intinya, kontrak eksplisit lebih tahan banting daripada heuristik longgar.

Malam itu log tools/chat-research.py menyatakan satu jawaban riset sudah lengkap. File jawaban tersimpan, siklus artikel lanjut. Sampai saya membuka isinya: model baru menulis setengah bagian, belum ada daftar sumber, tapi scraper sudah menganggap semuanya tuntas. Pelakunya satu baris sitasi Sumber: https://... di tengah prosa. Gate penyelesaian versi lama meloloskan kata "Sumber" di mana pun, padahal kontrak yang saya tempel ke setiap prompt mensyaratkan heading ## Sumber di akhir jawaban.

Tebakan pertama saya soal deteksi kegagalan: tambah pola, tambah kata kunci, biar makin pintar. Commit 2f42ccd justru berjalan ke arah sebaliknya. Empat perbaikan lahir dari satu audit loop polling, dan semuanya mempersempit apa yang boleh dipercaya, bukan menambahnya. Alur yang diaudit ini jalan di atas otomasi browser ke chat AI gratis, tanpa API berbayar.

Kontrak Eksplisit Mengalahkan Heuristik Longgar

Perbaikan pertama memindahkan waktu kapan pola kegagalan boleh dipercaya. Dulu, kata seperti rate limit, Cloudflare, atau halaman login dicocokkan ke teks halaman di setiap putaran polling. Masalahnya, begitu model mulai menjawab, teks halaman berisi jawaban itu sendiri. Kalimat model yang kebetulan membahas password atau rate limit bisa dipeluk sebagai status sesi, dan run yang sehat langsung dibunuh. Sekarang pola itu hanya dijalankan sebelum ada satu karakter pun jawaban tertangkap. Konsekuensinya saya terima: logout atau rate limit sungguhan di tengah streaming baru ketahuan saat deadline --timeout, bukan di detik ketiga. Rantai riset tetap jalan, tidak ada run sehat yang dikorbankan.

Perbaikan kedua memperketat tanda jawaban tuntas. Gate baru menuntut heading kontrak berdiri sendiri: ## Sumber atau ## Sources sebagai satu baris utuh, lewat regex ^#{1,3}\s+(?:Sumber|Sources)\s*:?\s*$ dengan flag re.M. Dua fondasinya standar: tanda ^ dalam mode MULTILINE mencocokkan awal string dan tepat setelah tiap newline [1], sementara heading ATX dalam CommonMark wajib dibuka 1 sampai 6 karakter pagar yang diikuti spasi, tab, atau akhir baris [3]. Dengan jangkar baris, heading interim seperti ## Latar Belakang di jawaban setengah jadi tidak lagi lolos, begitu pula baris sitasi yang dulu menipu.

Dua Jalur Ekstraksi, Dua Aturan

Jawaban diambil lewat dua pintu: tombol Copy dan teks halaman. Keduanya punya sifat berbeda, tapi dulu dibersihkan dengan aturan yang sama; soal ini pernah saya bahas di artikel pemulihan jawaban yang nyangkut. Fix ketiga menghadirkan diagnostik khusus: opsi --probe-copy mengirim satu pesan uji berisi fenced code block, membandingkan panjang kandidat clipboard versus kandidat halaman, lalu menulis hasilnya ke evidence.jsonl. Format JSON Lines memang dirancang untuk data terstruktur yang diproses satu rekaman per baris, dan nyaman dipakai sebagai file log [4]. Satu baris bukti per eksperimen mengalahkan ingatan yang menipu saat sesi debugging berikutnya.

Fix keempat melonggarkan satu aturan di jalur clipboard. Isi clipboard ter-scope per pesan, jadi string UI sampah yang terbawa di dalamnya biasanya kutipan prosa dari jawaban sungguhan, bukan kerangka antarmuka. Menolak kandidat karena itu sama dengan membuang jawaban valid. Sekarang kecocokan UI_JUNK di clipboard hanya memunculkan peringatan di log, sementara jalur teks halaman tetap menolak keras. Pencatatan ini berdiri di atas modul logging standar: semua modul bisa ikut serta lewat getLogger sehingga log aplikasi menyatu dengan log pustaka [2]. Fungsi clip_junk_hit() dan beberapa assert baru mengunci perilakunya.

Empat Perbaikan, Satu Prinsip

Setelah commit masuk, selftest naik dari 72 ke 79 asserts. Angkanya kecil, arahnya jelas: aturan yang lebih sempit justru menutup lebih banyak celah. Kalau ada satu prinsip yang bisa dibawa dari audit ini, saya rumuskan begini. Kata kunci kegagalan yang muncul di dalam konten sukses adalah konten, bukan sinyal; batasi deteksi sebelum konten ada. Kontrak output yang eksplisit selalu lebih tahan banting daripada heuristik yang santai. Dua jalur ekstraksi yang mirip belum tentu butuh aturan yang sama. Dan saat perilaku sistem diciduk, pastikan ada file bukti yang bisa dibuka ulang, bukan kesan dari ingatan.

Scraper di atas UI non-API memang tidak pernah selesai dibereskan. Tapi empat pagar dari satu audit kecil membuat cycle riset berikutnya cuma butuh log yang jujur, bukan tebakan.

Sumber

  1. Python docs: re, Regular expression operations
  2. Python docs: logging
  3. CommonMark Spec 0.31.2
  4. JSON Lines

Artikel terkait