Pelayan MCP saya dahulunya sering berhenti berfungsi begitu sahaja. Tiada dump ralat (crash dump). Tiada jejak timbunan (stack trace) dalam log. Klien menyambung tanpa sebarang aduan, kemudian selepas beberapa jam, semuanya menjadi senyap. Permintaan hilang dan ejen AI di hujung sana tidak menerima apa-apa melainkan ruang kosong.
Ini adalah kisah yang sangat lazim dan mengecewakan dalam ekosistem Model Context Protocol (MCP). Protokol ini menentukan cara ejen AI menemui dan memanggil alatan luaran, tetapi spesifikasinya mengandaikan anda akan mengendalikan ralat sendiri. Kebanyakan tutorial dan pelaksanaan permulaan melangkau bahagian tersebut. Mereka fokus pada "laluan lancar" (happy path): anotasi fungsi, dedahkan melalui pelayan, dan pulangkan hasil yang bersih. Mereka jarang menunjukkan apa yang berlaku apabila gangguan rangkaian berlaku pada API luaran anda, atau apabila model berhalusinasi tentang nama parameter dan menghantar input sampah. Hasilnya ialah pelayan rapuh yang kelihatan sihat tetapi sebenarnya telah mati selama berjam-jam.
Mengapa Respons Kosong Lebih Teruk Daripada Kegagalan (Crashes)
Apabila pengecualian (exception) yang tidak dikendalikan terlepas dalam pengendali alatan MCP, lapisan pengangkutan (transport layer) sering kali menelannya. Proses pelayan kekal hidup, soket kekal terbuka, tetapi klien mendapat respons kosong. Ini lebih berbahaya daripada kegagalan (crash) yang nyata kerana pemantauan anda mungkin tidak menyedarinya. Proses masih berjalan. Port masih mendengar. Namun, setiap panggilan alatan tidak memulangkan apa-apa.
Model AI tidak mentafsirkan kesunyian sebagai kegagalan. Ia mentafsirkan kesunyian sebagai panggilan berjaya yang tidak menghasilkan sebarang data. Respons kosong itu melatih model untuk berimprovisasi. Ia mula berhalusinasi fakta untuk mengisi kekosongan, atau ia memasuki gelung (loop) cubaan semula panggilan yang rosak yang sama. Isu kecil seperti tamat masa rangkaian sementara atau argumen alatan yang tidak sah tidak sepatutnya dibenarkan menyebabkan tingkah laku seperti ini.
Corak Wrapper: Tiga Barisan Pertahanan
Saya membaiki perkara ini dengan membungkus setiap pengendali alatan dalam lapisan pemulihan ralat yang nipis. Wrapper tersebut tidak cuba meramal setiap kegagalan yang mungkin berlaku. Ia mengkategorikannya dan bertindak balas sewajarnya.
ConnectionError dan TimeoutError
Ini berlaku apabila pelayan anda berkomunikasi dengan API luaran dan rangkaian mengalami gangguan. Penyelesaian spontan adalah dengan memulakan semula keseluruhan proses pelayan MCP. Jangan lakukan itu. Memulakan semula (rebooting) akan memutuskan sambungan klien yang aktif, memadamkan sebarang keadaan dalam memori (in-memory state), dan memaksa inisialisasi penuh. Sebaliknya, tangkap kegagalan sambungan dan sambungkan semula hanya lapisan pengangkutan atau klien HTTP yang digunakan oleh alatan anda. Pelayan kekal sedia dan bersedia untuk permintaan seterusnya dengan segera.
ValueError
Inilah yang anda lihat apabila klien AI menghantar argumen yang salah format. Mungkin model mencipta parameter baharu, menghantar string di mana integer diperlukan, atau terlupa medan yang diperlukan. Jika anda membiarkan ralat ini naik tanpa dikendalikan, klien akan mendapat sama ada kegagalan (crash) atau balasan kosong. Tangkap ralat tersebut di dalam wrapper, kemudian bina mesej yang jelas dan khusus yang memberitahu model dengan tepat apa yang salah. Jelaskan parameter mana yang gagal dan apa yang diharapkan. Kebanyakan model AI moden akan membaca mesej tersebut dan membetulkan diri pada pusingan seterusnya. Ralat yang samar-samar membazirkan kitaran penaakulan. Ralat yang tepat membaiki masalah dengan serta-merta.
General Exceptions
Sediakan jaring keselamatan. Jika ralat jatuh di luar kategori di atas, log butirannya untuk kegunaan anda sendiri dan pulangkan respons kegagalan generik yang bersih kepada klien. Ini menghalang satu kes terpencil (edge case) yang pelik daripada menghentikan sesi untuk semua orang. Pelayan tetap bertahan, klien mendapat isyarat bahawa sesuatu telah gagal, dan anda menyimpan konteks yang mencukupi dalam log anda untuk menyahpepijat (debug) kemudian.
Flag isError Adalah Wajib
Inilah perincian yang sebenarnya menentukan sama ada pembaikan anda berjaya atau tidak. Respons MCP menyertakan medan boolean isError. Jika pengecualian berlaku dan anda memulangkan mesej ralat tanpa menetapkan isError kepada true, klien akan menganggap teks ralat tersebut sebagai hasil alatan yang berjaya.
Bayangkan API luaran anda mencapai had kadar (rate limit). Anda menangkap pengecualian tersebut dan memulangkan string "API rate limit exceeded" tetapi membiarkan isError sebagai false. Klien akan memasukkan string tersebut ke dalam tetingkap konteks model seolah-olah ia adalah output alatan yang sebenar. Model kemudian cuba menaakul teks tersebut seolah-olah ia adalah data. Ia mungkin memetik ralat tersebut dalam ringkasan, atau lebih teruk lagi, ia mungkin berhalusinasi tentang hubungan antara teks ralat tersebut dengan fakta lain. Anda telah mengubah gangguan infrastruktur sementara menjadi punca maklumat salah.
Sentiasa tetapkan isError kepada true apabila anda mengembalikan payload ralat. Ini memberikan isyarat yang jelas kepada klien bahawa panggilan alat (tool call) telah gagal, yang membolehkan model memutuskan sama ada untuk mencuba semula, meminta penjelasan, atau mencuba alat yang lain sepenuhnya.
Ketahui Apa yang Perlu Ditangkap dan Apa yang Perlu Dihentikan
Jangan bungkus keseluruhan pelayan anda dalam try-catch buta yang menelan segala-galanya. Sesetengah ralat bermakna pelayan harus berhenti serta-merta. Jika pemboleh ubah persekitaran (environment variable) yang diperlukan hilang semasa permulaan, atau fail konfigurasi anda rosak, sebarang usaha menangkap ralat pada peringkat permintaan (request-level) tidak akan membantu. Cipta kelas pengecualian (exception class) khusus untuk ralat maut (fatal errors) seperti ini dan biarkan ia menghentikan proses tersebut.
Peraturannya mudah. Jika ralat itu bersifat sementara atau terpencil pada satu permintaan sahaja, tangkap ralat tersebut dan pulihkan. Jika ralat itu bermakna setiap permintaan seterusnya dijamin akan gagal, biarkan pelayan terhenti dengan jelas. Kegagalan pantas semasa permulaan adalah jauh lebih baik daripada pelayan yang terus berfungsi secara tidak stabil selama berhari-hari dalam keadaan rosak.
Tambah Kebolehlihatan (Observability) Sebelum Anda Memerlukannya
Sebaik sahaja anda mempunyai pembungkus (wrapper) tersebut, padankannya dengan log berstruktur. Log setiap panggilan alat dan hasilnya dalam format JSON. Sertakan nama alat, argumen mentah, kependaman (latency), dan sama ada ia berjaya, gagal, atau dicuba semula.
Disiplin ini membuahkan hasil dengan cepat. Apabila anda menyedari lonjakan ralat, anda boleh menapis mengikut alat dan mengesan corak dalam masa beberapa minit. Mungkin API luaran tertentu mula mengalami masa tamat (timeout) pada waktu yang sama setiap hari, menunjukkan tetingkap penyelenggaraan berjadual yang anda tidak ketahui. Mungkin satu alat menerima argumen yang sentiasa tidak sah (malformed), mendedahkan kecacatan kejuruteraan prompt (prompt engineering) di peringkat hulu. Log teks biasa yang tertanam dalam jejak timbunan (stack traces) menjadikan kerja penyiasatan ini menyakitkan. JSON berstruktur menjadikannya sangat mudah.
Hasil di Produksi
Saya telah menjalankan corak pembungkus ini pada dua pelayan MCP produksi selama tiga minggu yang lalu. Dalam tempoh tersebut, saya tidak melihat sebarang kegagalan senyap (silent failures). Sebelum menambah pembungkus tersebut, saya mencatatkan purata kira-kira satu kegagalan yang tidak dapat dijelaskan setiap hari. Corak ini tidak kompleks, tetapi impaknya sangat besar kerana ia memisahkan gangguan (noise) yang boleh diatasi daripada masalah sebenar.
Kegagalan senyap lebih merugikan daripada kegagalan sistem (crash). Kegagalan sistem akan mencetuskan sistem amaran anda. Kesenyapan pula hanya menghakis kepercayaan. Suatu hari ejen AI anda mengembalikan data alat yang berguna, dan keesokan harinya ia mula mereka-reka maklumat kerana pelayan telah berhenti menjawab beberapa jam yang lalu. Corak pembungkus ini merapatkan jurang tersebut. Ia memastikan pelayan anda terus berjalan melalui gangguan kecil, memberikan konteks yang mencukupi kepada model untuk membetulkan kesilapannya sendiri, dan memastikan apabila sesuatu yang benar-benar maut berlaku, anda akan mengetahuinya dengan segera.
Jika anda sedang membina alat MCP hari ini, mulakan dengan pembungkus dan bendera isError. Segalanya yang lain hanyalah kerja pembersihan.
