जेनरेटिव AI टेस्टिंग सामान्य assertion को क्यों तोड़ देती है

आप assert कीजिए कि response एक तय string के बराबर है — दूसरी ही बार टेस्ट फेल हो जाएगा, और वजह का आपके प्रोडक्ट से कोई लेना-देना नहीं होगा। इसे ढीला करके substring पर ले आइए, तो ऐसा आउटपुट भी पास हो जाएगा जो बारीकी से गलत है। दोनों में से कोई काम का नहीं, और इन्हीं दोनों के बीच झूलते-झूलते टीमें इस नतीजे पर पहुँचती हैं कि जेनरेटिव फीचर्स टेस्ट किए ही नहीं जा सकते।

इसकी जगह क्या assert करें

प्रॉपर्टीज़वैध JSON, ज़रूरी fields मौजूद, तय लंबाई के भीतर, और ऐसे source का हवाला जो सचमुच मौजूद है। ये जाँचे जा सकते हैं और हर run में टिके रहते हैं।
इनकारजिसे मना करना चाहिए, यह उसे मना करता है, और हर बार करता है। अक्सर यही पूरे suite की सबसे काम की जाँच होती है।
ग्राउंडिंगहर दावा दिए गए context में किसी चीज़ तक जाकर जुड़ता है। इससे मनगढ़ंत बातें पकड़ में आती हैं, वह भी शैली पर कोई फ़ैसला सुनाए बिना।

नतीजे नहीं, दरें

एक run से कुछ पता नहीं चलता। एक ही इनपुट को कई बार चलाइए और देखिए कि प्रॉपर्टी कितनी बार टिकती है। आपकी माप की इकाई एक दर है, और आपका संकेत किसी एक फ़ेल्योर में नहीं, उस दर के बदलने में है।

इससे regression का मतलब भी बदल जाता है। सवाल कभी यह नहीं होता कि "क्या यह परफेक्ट है", सवाल यह होता है कि "क्या इस बदलाव ने इसे पिछले हफ़्ते से बदतर कर दिया"।

assert करने लायक प्रॉपर्टीज़ चुनना

इसमें मुश्किल हिस्सा तकनीक नहीं है, बल्कि यह तय करना है कि जब जवाब को ही नहीं जाँचा जा सकता, तो जाँचें क्या। शुरुआत का एक काम का तरीका यह पूछना है कि आउटपुट किस वजह से इस्तेमाल के लायक नहीं रहेगा, न कि यह कि उसे अच्छा क्या बनाएगा।

"इस्तेमाल के लायक नहीं" एक ठोस चीज़ है: ऐसा बिगड़ा हुआ आउटपुट जिसे caller parse ही न कर सके, ऐसी किसी चीज़ का हवाला जो मौजूद ही नहीं, वह इनकार जो असल में जवाब होना चाहिए था, वह जवाब जो असल में इनकार होना चाहिए था, या ऐसा कंटेंट जो आगे कहीं तय सीमा से बाहर चला जाए। इनमें से हर एक हाँ या ना में है और जाँचा जा सकता है, और हर एक किसी असली incident से जुड़ता है, न कि क्वालिटी की किसी राय से।

इसके उलट "अच्छा" एक राय है जो रिव्यू करने वाले के साथ बदल जाती है, और उसे gate की तरह बाँध देना ठीक नहीं। चाहें तो किसी सैंपल पर इंसानी रिव्यू करके उस पर नज़र रखिए, लेकिन उसे pipeline से बाहर ही रखिए — वहाँ वह फ़ैसले नहीं, बहसें पैदा करेगी।

वह हिस्सा जो सामान्य तरीके से टेस्ट होता है

जिस प्रोडक्ट में जेनरेटिव फीचर होता है, उसका ज़्यादातर हिस्सा आम deterministic सॉफ़्टवेयर ही होता है: authentication, storage, rate limiting, और फीचर के इर्द-गिर्द का इंटरफ़ेस। इन सबको पारंपरिक तरीके से ही टेस्ट करना चाहिए; सिर्फ़ इसलिए कि एक हिस्सा non-deterministic है, पूरे प्रोडक्ट को वैसा मान लेने पर आप बहुत सारी सस्ती coverage गँवा देते हैं।

यह सीमा साफ़-साफ़ खींचिए। उसके अंदर प्रॉपर्टीज़ और दरें। उसके बाहर, चल रहे ऐप्लिकेशन पर सामान्य assertions।

टर्मिनल

npm install -g @testsprite/testsprite-cli
testsprite setup

अगर आप कुछ भी इंस्टॉल नहीं करना चाहते, तो डैशबोर्ड से भी यही काम हो जाता है। कमांड लाइन और जो कुछ कर सकती है, उस सबके लिए देखें CLI रिपॉज़िटरी।

दो रास्ते हैं, और चुनाव असल में इस बात का है कि pipeline किसके ज़िम्मे है। डैशबोर्ड से GitHub App जोड़ने पर आपकी रिपॉज़िटरी में कोई बदलाव करने की ज़रूरत ही नहीं पड़ती, क्योंकि यह उसी deployment पर प्रतिक्रिया देता है जो आपका build पहले से निकालता है। एक GitHub Actions स्टेप जोड़ने से यह जाँच रिपो के भीतर आ जाती है, जहाँ बाकी build की तरह उसका भी रिव्यू होता है।

फीचर के इर्द-गिर्द TestSprite क्या कवर करता है

प्रोडक्ट का deterministic बहुमत, जो ज़्यादातर टीमों के लिए कहीं बड़ा हिस्सा होता है। authentication, storage, rate limiting, फीचर के इर्द-गिर्द का इंटरफ़ेस और हर वह flow जिससे यूज़र सचमुच गुज़रता है — ये सब आम सॉफ़्टवेयर हैं और पारंपरिक तरीके से टेस्ट होते हैं। Auto-Authentication पूरे run के दौरान sessions को ज़िंदा रखता है, Dynamic Variables एक call से दूसरी तक वैल्यू ले जाते हैं, Dependency Chains execution का क्रम निकालते हैं, और Auto-Cleanup ठीक वही हटाता है जो उस run ने बनाया था।

Coverage आपके प्रोडक्ट से तैयार होती है और सादी भाषा में उसे निखारा जाता है, और हर बदलाव पर यह deployed ऐप्लिकेशन पर चलती है — यानी सिस्टम के जिन हिस्सों को ठीक-ठीक जाँचा जा सकता है, वे ठीक-ठीक जाँचे जाते हैं।

जेनरेटिव फीचर के लिए खुद प्रॉपर्टीज़ और दरें चाहिए, यानी एक अलग harness जिसमें "पास होने" का मतलब भी अलग है। यह सीमा साफ़ खींचना ही टीम को इन दोनों से बचाता है: deterministic कोड पर सांख्यिकीय तरीके लगा देना, या इसलिए assertions से पूरी तरह हाथ खींच लेना कि exact match बार-बार फेल हो रहे थे।

क्या हम आउटपुट को परखने के लिए किसी AI का इस्तेमाल कर सकते हैं?

यह आम भी है और चल भी जाता है, बस एक शर्त के साथ: परखने वाले के अपने failure mode होते हैं और उसे खुद calibration चाहिए। उस पर भरोसा करने से पहले किसी सैंपल पर उसे इंसानी फ़ैसले से मिलाकर देखिए।

कितने runs से कोई दर मायने रखने लायक बनती है?

इतने कि और जोड़ने पर आँकड़ा हिलना बंद कर दे। सैकड़ों से नहीं, दहाई के आँकड़े से शुरू कीजिए और देखिए कि वह कब स्थिर होती है।

क्या जेनरेटिव टेस्ट को merge रोकना चाहिए?

इनकार की दर में बड़ी गिरावट हो, तो हाँ। क्वालिटी में छोटा-मोटा उतार-चढ़ाव हो, तो नहीं — वरना pipeline सिर्फ़ शोर बनकर रह जाएगी।

और खर्च का क्या?

बार-बार runs चलाने में पैसे लगते हैं। हर बदलाव पर पूरा सेट चलाने के बजाय एक सैंपल चलाइए, और पूरा सेट किसी तय शेड्यूल पर।

क्या prompt टेस्टिंग यही चीज़ है?

उससे जुड़ी हुई है। दरों के बदलने की सबसे आम वजह prompt में हुए बदलाव ही होते हैं, और यही अच्छी दलील है कि prompts को versioned artifacts की तरह रखा जाए।

संक्षेप में

बराबरी नहीं, प्रॉपर्टीज़ और दरें।

जेनरेटिव AI टेस्टिंग exact assertions की जगह प्रॉपर्टीज़, इनकार और ग्राउंडिंग रखती है, जिन्हें कई runs में दर के रूप में मापा जाता है। प्रोडक्ट का जो deterministic बहुमत है उसे सामान्य तरीके से टेस्ट कीजिए और सीमा साफ़-साफ़ खींचिए।