GitHub Actions च्या मर्ज क्यूमध्ये (merge queue) आठ महिने घालवल्यामुळे तुम्हाला अशी गोष्ट शिकायला मिळते जी फीचर कंपॅरिजन मॅट्रिक्स कधीच शिकवू शकणार नाहीत. एखादे फ्रेमवर्क पन्नास मेट्रिक्स, सुंदर डॅशबोर्ड्स आणि प्रतिष्ठित संशोधन प्रयोगशाळांचे संदर्भ देऊ शकते. पण जर ते तुमच्या कोडमध्ये कोणताही बदल न होता केवळ 'vibe check' स्कोअर ०.७२ वरून ०.६८ झाला म्हणून तुमचे डिप्लॉयमेंट (deploy) रोखत असेल, तर ते निरुपयोगी असण्यापेक्षाही वाईट आहे. ते तुमच्या शिपिंग वेगासाठी (shipping velocity) एक सक्रिय धोका बनून जाते.
बहुतेक LLM इव्हॅल्युएशन राउंडअप्स (evaluation roundups) हा फिल्टर मिस करतात. ते केवळ क्षमता मोजतात. मर्ज क्यूमध्ये महत्त्वाचा असलेला एकमेव प्रश्न ते क्वचितच विचारतात: "हे चेक प्रत्येक वेळी रन होताना अगदी त्याच पद्धतीने पास किंवा फेल होते का?"
मी हे कठीण काम करून शिकलो. मी सहा ओपन-सोर्स LLM इव्हॅल्युएशन फ्रेमवर्क्स एका खऱ्या CI पाइपलाइनमध्ये जोडले. ते आठ महिने लाईव्ह प्रोडक्शन पुल रिक्वेस्ट्सवर (pull requests) चालवले गेले. त्यापैकी दोनने 'गेटकीपर' (gatekeeper) म्हणून राहण्याचा अधिकार मिळवला. उरलेल्यांना केवळ सल्लागार डॅशबोर्ड्समध्ये रूपांतरित करण्यात आले, नाईटली जॉब्समध्ये (nightly jobs) हलवण्यात आले किंवा पूर्णपणे काढून टाकण्यात आले. धडा कडक आणि महागडा होता: जेव्हा तुम्ही 'मेन ब्रांच'चे (main branch) रक्षण करत असता, तेव्हा प्रोबॅबिलिस्टिक क्वालिटीपेक्षा (probabilistic quality) डिटरमिनिस्टिक स्ट्रक्चर (deterministic structure) अधिक प्रभावी ठरते.
The Real Job of a Merge Gate
CI गेट हे संशोधन केंद्र नाही. ते एका बाउन्सरसारखे आहे. त्याचा संपूर्ण उद्देश एका विशिष्ट बदलाकडे पाहणे आणि 'हो' किंवा 'नाही' मध्ये उत्तर देणे हा आहे. "हो, ही PR मेन ब्रांचमध्ये सामील होऊ शकते. नाही, ती होऊ शकत नाही." ते उत्तर काही सेकंदात मिळणे आवश्यक आहे, खर्च अत्यंत कमी असावा आणि ते उत्तर कधीही बदलता कामा नये. जर तुम्ही एका शांत मंगळवारी आणि एका धावपळीच्या शुक्रवारी एकाच कमिटवर (commit) तीच पाइपलाइन पुन्हा चालवली, तर निकाल अगदी सारखाच असायला हवा.
इथेच बहुतेक LLM इव्हॅल्युएशन फ्रेमवर्क्स अडखळतात. ते डेटा सायंटिस्टनी, डेटा सायंटिस्टसाठी बनवलेले असतात. ते इनसाइट्स (insights), एक्सप्लोरेशन आणि सूक्ष्म स्कोअरिंगसाठी ऑप्टिमाइझ केलेले असतात. याउलट, मर्ज क्यू हे बायनरी निर्णय (binary decisions), वेग आणि शून्य फ्लॅकीनेस (zero flakiness) यासाठी ऑप्टिमाइझ केलेले असते. या दोन उद्दिष्टांमध्ये केवळ अंशतः साम्य असते.
Why LLM-as-Judge Breaks the Queue
माझ्या चाचणीत अपयशी ठरलेल्या टूल्समध्ये एकच डिझाइन दोष होता: त्यांनी प्राथमिक गेट मेकॅनिझम म्हणून 'LLM-as-judge' कॉल्सवर खूप जास्त अवलंबून राहणे पसंत केले.
'LLM-as-judge' प्रॉम्प्ट मॉडेलला आउटपुटला १ ते १० च्या स्केलवर स्कोअर करण्यास, दोन प्रतिसादांपैकी चांगला प्रतिसाद निवडण्यास किंवा तथ्यात्मक अचूकतेचे रेटिंग देण्यास सांगतो. गुणवत्तेचे कल (quality trends) समजून घेण्यासाठी हा दृष्टिकोन प्रभावी आहे, पण ब्लॉकिंग CI चेकसाठी तो विष आहे. तापमान (temperature), मॉडेल व्हर्जनिंग आणि प्रॉम्प्ट फॉरमॅटिंगमुळे निर्माण होणाऱ्या गोंधळामुळे (noise), तोच इनपुट वेगवेगळ्या दिवशी वेगवेगळे स्कोअर देऊ शकतो. जेव्हा तो स्कोअर एखाद्या कडक थ्रेशोल्ड (threshold) आणि एक्झिट कोडशी (exit code) जोडलेला असतो, तेव्हा तुमची क्यू काल्पनिक कारणांमुळे (ghosts) अडकते.
हे अपयश वेगाने पसरते. नॉन-डिटरमिनिस्टिक चेकमुळे क्यूमध्ये बॅकअप (backups) तयार होतात. इंजिनिअर्स तो स्कोअर अनुकूल येईपर्यंत पुन्हा पुन्हा प्रयत्न (retry) करायला शिकतात, ज्यामुळे टीमला 'रेड बिल्ड्स' (red builds) दुर्लक्षित करण्याची सवय लागते. प्रत्येक रिट्राईमुळे अधिक API क्रेडिट्स खर्च होतात आणि टोकनचा खर्च वाढत जातो. सर्वात वाईट म्हणजे, तो सिग्नल अर्थहीन होतो. 'रेड बिल्ड'चा अर्थ "तुम्ही एखादी चूक (bug) केली आहे" असा असावा. पण जर त्याचा अर्थ "जज मॉडेल आज जास्त चोखंदळ झाले आहे" असा झाला, तर विश्वास कमी होतो.
What the Survivors Do Differently
Promptfoo आणि DeepEval वाचले कारण ते डिटरमिनिस्टिक चेकला प्राधान्य देतात आणि LLM जज स्कोअरला दुय्यम, नॉन-ब्लॉकिंग सिग्नल म्हणून मानतात. त्यांना समजते की गेटला एका एक्झिट कोडची गरज असते, स्वतःचे मत मांडणाऱ्या फ्लोटिंग-पॉइंट नंबरची नाही.
Promptfoo, MIT लायसन्स अंतर्गत रिलीज झालेले, हे कमांड लाईनसाठी बनवलेले आहे. ते regex matches, JSON schema validation, contains checks आणि exact string comparisons सारखी अॅसर्शन (assertions) चालवते. हे काही खूप भपकेबाज नाही. ते केवळ प्रगत grep आणि jq कमांड्स आहेत. म्हणूनच ते CI मध्ये उत्तम काम करतात. regex एकतर मॅच होतो किंवा होत नाही. JSON schema एकतर व्हॅलिडेट होतो किंवा एरर देतो. Promptfoo स्टँडर्ड Unix exit codes परत करते, त्यामुळे GitHub Actions ला मर्ज कधी थांबवायचा हे नैसर्गिकरित्या समजते. ते CLI टूल म्हणून काम करत असल्यामुळे ते लँग्वेज-अग्नोस्टिक (language-agnostic) आहे. केवळ आउटपुट व्हॅलिडेट करण्यासाठी तुम्हाला Node.js सर्व्हिस रेपोमध्ये पायथन इकोसिस्टम इन्स्टॉल करण्याची गरज नाही.
DeepEval, Apache 2.0 अंतर्गत लायसन्स असलेले, हे पायथन टीम्ससाठी उत्तम आहे. ते pytest प्रमाणे इंटिग्रेट होते. तुम्ही परिचित सिंटॅक्समध्ये टेस्ट लिहिता आणि एखादी टेस्ट फेल झाल्यास ती नैसर्गिकरित्या संपूर्ण सूट (suite) ब्लॉक करते. DeepEval अनेक प्रकारच्या मेट्रिक्सचा मोठा कॅटलॉग देते, पण महत्त्वाची गोष्ट म्हणजे तुम्ही त्यांचा वापर काळजीपूर्वक केला पाहिजे. गेट्ससाठी डिटरमिनिस्टिक किंवा ह्युरिस्टिक (heuristic) मेट्रिक्सचा आधार घ्या. जर तुम्ही G-Eval किंवा इतर जज-आधारित स्कोअरर्स वापरत असाल, तर त्यांना 'हार्ड अॅसर्ट्स' (hard asserts) ऐवजी नॉन-ब्लॉकिंग रिपोर्ट जनरेटर्समध्ये वापरा. अशा प्रकारे वापरल्यास, DeepEval तुम्हाला रिसर्च नोटबुकमधील 'फ्लॅकीनेस'शिवाय टेस्टिंग फ्रेमवर्कचा सोयीस्कर अनुभव देते.
Where the Other Four Fit
जे चार फ्रेमवर्क्स गेट्स म्हणून टिकू शकले नाहीत, त्यांचे मूल्य अजूनही आहे. ते फक्त तुमच्या टूलचेनमध्ये (toolchain) इतर ठिकाणी वापरले जाऊ शकतात.
Future AGI (Apache 2.0) पन्नासपेक्षा जास्त मेट्रिक्स प्रदान करते आणि कस्टम SDK बनवणाऱ्या टीम्सना लक्ष्य करते. हे मेट्रिक्स सखोल आहेत. समस्या अशी आहे की, CI क्यूमध्ये (queue) हे चालवण्यासाठी तुम्हाला स्वतःचा 'हार्नेस' (harness) लिहावा लागतो अशी या टूलची अपेक्षा आहे. संशोधनाच्या संदर्भात, हा एक रास्त व्यवहार आहे. पण मर्ज क्यूमध्ये (merge queue), कस्टम वायरिंगचा प्रत्येक स्तर अस्थिरतेचा एक नवीन स्रोत ठरतो. हे एक सक्षम इव्हॅल्युएशन इंजिन आहे, परंतु तयार 'गेटकीपर' (gatekeeper) नाही.
RAGAS (Apache 2.0) 'रिट्रिव्हल-ऑगमेंटेड जनरेशन' (retrieval-augmented generation) गुणवत्ता मोजण्यात उत्कृष्ट आहे. त्याचे 'faithfulness' आणि 'answer relevance' मेट्रिक्स नॉलेज बेस कालांतराने कसा कामगिरी करतो हे समजून घेण्यासाठी खरोखर उपयुक्त आहेत. दुर्दैवाने, हे मेट्रिक्स LLM जजेसवर (judges) मोठ्या प्रमाणावर अवलंबून आहेत. Slack वर ट्रेंड्स पोस्ट करणाऱ्या नाईटली क्वालिटी जॉबसाठी ते उत्कृष्ट आहेत. परंतु 'पुल रिक्वेस्ट'साठी (pull request) ते खराब 'बाउन्सर्स' (bouncers) आहेत. RAGAS ला तुमच्या शेड्युल्ड ॲनालिसिस पाईपलाईनमध्ये वापरा, मर्ज ब्लॉकर्समध्ये नाही.
Arize Phoenix हे Elastic License 2.0 अंतर्गत येते आणि ते पूर्णपणे वेगळ्या ठिकाणी कार्य करते. हे 'डिस्ट्रिब्युटेड ट्रेसिंग'ला (distributed tracing) इव्हॅल्युएशनशी जोडते, ज्यामुळे मॉडेलने विशिष्ट प्रकारे का वागले याचे 'ऑब्झर्व्हेबिलिटी' (observability) मिळते. जेव्हा तुम्ही प्रोडक्शनमधील एखादी समस्या (incident) डीबग करत असता किंवा 'हॅलुसिनेशन'चा (hallucination) मागोवा एखाद्या चुकीच्या 'रिट्रिव्हल चंक'पर्यंत (retrieval chunk) घेत असता, तेव्हा तुम्हाला याची गरज असते. एखाद्या ज्युनियर डेव्हलपरची 'फीचर ब्रांच' (feature branch) शिप करता येईल की नाही, हे ठरवण्यासाठी तुम्हाला ट्रेसिंग टूल नको असते. याची आर्किटेक्चर 'इनसाइट'साठी (insight) बनलेली आहे, 'बायनरी गेट्स'साठी (binary gates) नाही.
MLflow Evaluate (Apache 2.0) ला 'एक्सपेरिमेंट ट्रॅकिंग'चा वारसा लाभला आहे. ते जड (heavy) आहे. त्याला एका लीन (lean) CI इमेजमध्ये समाविष्ट केल्यामुळे स्टार्टअप वेळ आणि डिपेंडन्सीज वाढतात, ज्यामुळे प्रत्येक जॉबचा वेग मंदावतो. जर तुम्हाला ते पाईपलाईनमध्ये वापरणे अत्यंत आवश्यक असेल, तर स्ट्रक्चरल चेकसाठी फक्त त्याच्या 'ह्युरिस्टिक मेट्रिक्स'चा (heuristic metrics) वापर करा. तरीही, तुम्ही त्या फ्रेमवर्कच्या मूलभूत डिझाइनविरुद्ध लढत असता. MLflow ला रन लॉग करणे आणि आठवड्यांच्या अंतराने प्रयोगांची तुलना करणे आवडते. तर मर्ज क्यूला एका मिनिटाच्या आत निकाल हवा असतो.
गेटिंगसाठी व्यावहारिक नियम
या प्रयोगातून तुम्हाला इतर काहीही शिकायला मिळाले नाही, तरी हे तीन नियम लक्षात ठेवा.
पहिले, 'व्हाइब' (vibe) नाही, तर 'स्ट्रक्चर' (structure) गेट करा. तुम्ही आउटपुट वैध JSON आहे की नाही हे सुनिश्चित करू शकता. त्यात आवश्यक कीज (keys) आहेत की नाही हे तपासू शकता. क्लासिफिकेशन लेबल एका परवानगी असलेल्या 'एनम' (enum) मध्ये येते की नाही हे तपासू शकता. हे चेक जलद, स्वस्त आणि 'डिटरमिनिस्टिक' (deterministic) असतात. सारांश "फ्रेंडली" आहे किंवा पुनर्लेखन "क्रिएटीव्ह" आहे, हे तुम्ही विश्वासार्हतेने तपासू शकत नाही. अशा गुणधर्मांसाठी मानवी पुनरावलोकन (human review) किंवा वेळोवेळी बॅच इव्हॅल्युएशन आवश्यक आहे, ऑटोमेटेड गेट्समध्ये नाही.
दुसरे, जर बदल न झालेल्या इनपुटवर स्कोअर बदलत असेल, तर त्याला त्वरित कमी दर्जाचे (demote) माना. तुमच्या इव्हॅल्युएशन सुईटला (suite) अगदी त्याच आर्टिफॅक्टवर दोनदा चालवून पहा. जर एखादा मेट्रिक 'पास' मधून 'फेल' झाला, तर त्याला मर्ज रोखण्याचा अधिकार राहत नाही. अशा मेट्रिक्सना 'ॲडव्हायझरी डॅशबोर्ड'वर (advisory dashboard) हलवा, जिथे व्हेरिएशन (variance) अपेक्षित आणि सहन करण्यायोग्य असते.
तिसरे, 'एक्झिट कोड'चा (exit code) आदर करा. लाल बॅनर असलेला सुंदर HTML रिपोर्ट मर्ज थांबवत नाही. 'नॉन-झिरो एक्झिट कोड' (nonzero exit code) थांबवतो. तुमचे इव्हॅल्युएशन टूल तुमच्या CI प्लॅटफॉर्मच्या मूळ भाषेत बोलले पाहिजे. 'स्टँडर्ड आउट' (Standard out) माणसांसाठी आहे, तर 'एक्झिट कोड्स' मशीनसाठी आहेत.
निष्कर्ष
LLM-आधारित ॲप्लिकेशन्स कसे तपासावे, हे शोधण्याच्या सुरुवातीच्या टप्प्यावर आपण आहोत. इव्हॅल्युएशनला मानवी ग्रेडिंग रुब्रिकप्रमाणे (grading rubric) पाहण्याची प्रवृत्ती असते: सूक्ष्म, संदर्भासहित आणि थोडे व्यक्तिनिष्ठ. हे रिसर्च पेपरमध्ये काम करते, पण मर्ज क्यूमध्ये अपयशी ठरते.
आठ महिन्यांच्या प्रोडक्शन ट्रॅफिकनंतर, माझी पाईपलाईन आता सर्व्हिसेसमधील स्ट्रक्चरल आणि स्कीमा अॅसर्शनसाठी (schema assertions) Promptfoo आणि पायथन-साइड बिहेवियरल चेकसाठी DeepEval वापरते, जे स्पष्टपणे पास-फेल अटींशी जुळतात. बाकी सर्व गोष्टी नाईटली डॅशबोर्डवर रिपोर्ट केल्या जातात. क्यू स्थिर आहे. सिग्नल स्पष्ट आहे. टीम आता पुन्हा एकदा 'रेड बिल्ड'वर विश्वास ठेवते.
तुम्हाला तुमच्या गेटवर अधिक मेट्रिक्सची गरज नाही. तुम्हाला कमी मेट्रिक्सची गरज आहे जे प्रत्येक वेळी सत्य सांगतील.
मूळ टेस्टिंग आणि लेख Dev.to वर शेअर केल्यावर आधारित. विश्वसनीय AI सिस्टम्स तयार करण्याबद्दल अधिक चर्चेसाठी, Telegram वरील GyaanSetu कम्युनिटीमध्ये सामील व्हा.
