अधिकांश टीमें अपना पहला रिट्रीवल सिस्टम एक ही तरह से बनाती हैं: हर दस्तावेज़ को फिक्स्ड 512-टोकन चंक्स में काटें, उन्हें एक वेक्टर डेटाबेस में डालें, और उम्मीद करें कि एम्बेडिंग मॉडल सारा कठिन काम कर देगा। वह उम्मीद आपको एक डेमो में तो सफल बना सकती है, लेकिन वास्तविक उपयोगकर्ताओं के साथ काम करते समय टिक नहीं पाएगी।
प्रोडक्शन में, एक कानूनी अनुबंध तब बिखर जाता है जब आप एक लायबिलिटी क्लॉज (liability clause) को उसके अपवादों (exceptions) से अलग कर देते हैं। API डॉक्यूमेंटेशन तब बेकार हो जाता है जब एक कोड सैंपल अपने फंक्शन सिग्नेचर से अलग हो जाता है। एक कस्टमर सपोर्ट थ्रेड तब शोर बन जाता है जब आप किसी एक शिकायत को उसके बातचीत के इतिहास से अलग कर देते हैं। समस्या शायद पाइपलाइन के अंत में बैठे लैंग्वेज मॉडल की नहीं होती। समस्या वह है जो आप उसे देते हैं।
हमने यह सबक बहुत कठिन अनुभव से सीखा। हमारा शुरुआती रिट्रीवल लेयर मानक दिखता था लेकिन उसका व्यवहार असंगत था। इसलिए हमने इसे एक सरल विचार के इर्द-गिर्द फिर से बनाया: रिट्रीवल को जादू नहीं, बल्कि एक मापे गए इंफ्रास्ट्रक्चर (measured infrastructure) के रूप में देखें। यहाँ बताया गया है कि वास्तव में क्या बदला, और कैसे हमने 95th-percentile लेटेंसी को 850 ms से घटाकर 320 ms करते हुए रिकॉल (recall) को 95 प्रतिशत तक पहुँचाया।
फिक्स्ड-चंक का जाल
एक समान टोकन काउंट को कोड करना और समझाना आसान है। यह सुविधा एक बुनियादी सच्चाई को छिपाती है: दस्तावेज़ों की एक संरचना होती है। जब आप उस संरचना को नज़रअंदाज़ करते हैं, तो आप सिग्नल (signal) को नष्ट कर देते हैं।
दस पन्नों के मास्टर सर्विस एग्रीमेंट पर विचार करें। एक फिक्स्ड 512-टोकन स्लाइस किसी दायित्व (obligation) के बीच में ही रुक जाएगा, जिससे एक क्लॉज उस कैप टेबल (cap table) से अलग हो जाएगा जो उसे सीमित करती है। इसके बाद रिट्रीवल स्टेप केवल आधा विचार ही लौटाता है। जनरेटर बाकी हिस्से का भ्रम (hallucinate) पैदा करता है। API डॉक्यूमेंटेशन में, बहुत बड़ा चंक बॉयलरप्लेट हेडर्स के कारण एम्बेडिंग को कमज़ोर कर देता है, जिससे डेवलपर को जिस विशिष्ट मेथड की आवश्यकता होती है, वह दब जाता है। सपोर्ट टिकटों में, एक फिक्स्ड विंडो बातचीत को वाक्यों के एक ढेर (bag of sentences) की तरह मानती है, जिससे वह आपसी बातचीत (back-and-forth) खत्म हो जाती है जो यह बताती है कि वास्तव में क्या विफल हुआ।
हमने चंक साइज को एक ऐसे हाइपरपैरामीटर के रूप में मानना बंद कर दिया जिसका हम केवल अनुमान लगाते थे। हमने इसे दस्तावेज़ के प्रकार और उसके भीतर की सूचना संरचना (information architecture) के बीच एक मैपिंग अभ्यास के रूप में मानना शुरू किया।
अपने चंकिंग को डेटा के अनुरूप बनाएं
समाधान कोई एक सटीक चंक साइज नहीं है। समाधान तीन अलग-अलग रणनीतियाँ हैं जिन्हें तीन अलग-अलग डेटा आकारों (data shapes) के लिए ट्यून किया गया है।
कानूनी दस्तावेज़ (Legal documents) अब रिकर्सिव स्प्लिटिंग (recursive splitting) से गुजरते हैं। एल्गोरिदम पहले सबसे बड़ी प्राकृतिक सीमाओं—सेक्शन, फिर सब-सेक्शन, फिर नंबर वाले क्लॉज—को खोजता है और केवल आवश्यकता पड़ने पर ही छोटे स्प्लिट्स का सहारा लेता है। यह एक टर्मिनेशन क्लॉज को उसकी उत्तरजीविता शर्तों (survival conditions) के साथ जोड़े रखता है। रिट्रीवल स्टेप पूर्ण तार्किक इकाइयों (logical units) को देखता है, जिससे मॉडल द्वारा गायब अपवादों को गढ़ने की संभावना काफी कम हो जाती है।
API और कोड डॉक्यूमेंटेशन को स्ट्रक्चर-अवेयर चंकिंग (structure-aware chunking) मिलती है। मार्कडाउन हेडर्स, कोड फेन्सेस और पैरामीटर टेबल्स को एटॉमिक यूनिट्स के रूप में पार्स किया जाता है। हम कोड ब्लॉक के अंदर स्प्लिट नहीं करते हैं। हम डॉकस्ट्रिंग्स (docstrings) को उनके सिग्नेचर के पास रखते हैं। इसका परिणाम यह होता है कि किसी विशिष्ट क्लास मेथड के लिए की गई क्वेरी डेवलपर को आवश्यक पूरा संदर्भ प्रदान करती है: विवरण, टाइप किए गए पैरामीटर और वर्किंग उदाहरण।
सपोर्ट और कन्वर्सेशनल डेटा में सिमेंटिक चंकिंग (semantic chunking) का उपयोग किया जाता है। टोकन गिनने के बजाय, हम विषय या इरादे (intent) में बदलाव देखते हैं। यदि कोई ग्राहक तीसरे संदेश में बग का वर्णन करता है और सातवें संदेश में स्टैक ट्रेस पेस्ट करता है, तो हम संदेश इंडेक्स के बजाय अर्थ के आधार पर चंकिंग करते हैं। रिट्रीवल लेयर फिर एक अकेले वाक्य के बजाय समस्या के पूरे घटनाक्रम (full arc) को लौटाती है।
केवल वेक्टर सर्च ही क्यों विफल हो जाता है
एकदम सटीक चंक्स भी शुद्ध वेक्टर सर्च में विफल हो जाते हैं। डेंस एम्बेडिंग्स (Dense embeddings) अर्थ और पर्यायवाची शब्दों को पकड़ने में उत्कृष्ट हैं, लेकिन सटीक स्ट्रिंग्स (exact strings) के मामले में वे काफी अस्पष्ट होते हैं। यदि कोई इंजीनियर सटीक एरर कोड ERR_CONNECTION_REFUSED खोजता है, तो वेक्टर समानता दर्जनों वैचारिक पड़ोसियों (conceptual neighbors) को लौटा सकती है और रैंक चौदह पर दबे सटीक मिलान को छोड़ सकती है।
BM25 के साथ कीवर्ड सर्च में इसके विपरीत समस्या होती है। यह सटीक टोकन तो ढूंढ लेता है लेकिन सिमेंटिक इरादे (semantic intent) को मिस कर देता है। "मेरा डेटाबेस डाउन क्यों है" पूछने वाला उपयोगकर्ता कभी भी उस दस्तावेज़ से मेल नहीं खाएगा जिसमें "कनेक्शन टाइमआउट की समस्या निवारण" (troubleshooting connection timeouts) लिखा हो।
अब हम दोनों का उपयोग करते हैं। वेक्टर और कीवर्ड परिणामों को Reciprocal Rank Fusion में डाला जाता है, जो कैलिब्रेटेड स्कोर की आवश्यकता के बिना दोनों रैंक की गई सूचियों को मिला देता है। इसके बाद फ्यूज्ड लिस्ट को क्रॉस-एनकोडर रीरैंकर (cross-encoder reranker) के माध्यम से भेजा जाता है। रीरैंकर शुरुआती रिट्रीवल की तुलना में धीमा है, लेकिन यह कहीं अधिक सटीक है क्योंकि यह कंप्रेस्ड एम्बेडिंग्स के बजाय सीधे क्वेरी-दस्तावेज़ प्रासंगिकता का निर्णय करता है। केवल उस हाइब्रिड पाइपलाइन ने ही हमारे रिकॉल को 15 प्रतिशत बढ़ा दिया।
इंडेक्स तक पहुँचने से पहले खराब क्वेरीज़ को ठीक करना
उपयोगकर्ता आदर्श सर्च क्वेरी नहीं लिखते हैं। वे अधूरे लॉग लाइन्स (log lines) पेस्ट करते हैं। वे “it’s broken” टाइप करते हैं। वे ऐसे शब्दों (jargon) का उपयोग करते हैं जिन्हें आपके डॉक्यूमेंटेशन ने कभी नहीं अपनाया। यदि आप कच्ची (raw) क्वेरी पर भरोसा करते हैं, तो आप शोर (noise) पर भरोसा कर रहे हैं।
अब हम रिट्रीवल लेयर (retrieval layer) को भेजने से पहले हर आने वाली क्वेरी को तीन से पांच विविधताओं (variations) में विस्तारित करते हैं। एक विविधता सीधा पैराफ्रेज़ (paraphrase) हो सकती है। दूसरी एक काल्पनिक आदर्श डॉक्यूमेंट टाइटल हो सकती है। तीसरी बातचीत वाले शब्दों (conversational filler) को हटाकर केवल तकनीकी कीवर्ड्स को अलग करती है। प्रत्येक वेरिएंट को एम्बेड (embed) और सर्च किया जाता है। फिर हम कैंडिडेट पूल्स (candidate pools) को डीडुप्लिकेट और मर्ज करते हैं।
यह मुफ्त नहीं है। उन अतिरिक्त एम्बेडिंग कॉल्स (embedding calls) की लागत आती है और कुछ मिलीसेकंड का समय भी लगता है। लेकिन रिकॉल (recall) पर इसका प्रभाव नाटकीय था: रिट्रीवल से पहले क्वेरीज़ को विस्तारित करके हम 78 प्रतिशत से 96 प्रतिशत तक पहुँच गए। क्योंकि बेहतर रिट्रीवल जनरेशन विंडो को छोटा करता है और मॉडल को सही संदर्भ (context) प्रदान करता है, इसलिए अंततः हमने बाद के चरणों (downstream) में पैसे बचाए। एक थोड़ा महंगा रिट्रीवल स्टेप, एक लंबे और भ्रामक (hallucinated) जनरेशन स्टेप की तुलना में सस्ता है।
अनुमान लगाना बंद करें। सर्च करना शुरू करें।
एक बार जब हमारे पास सही चंकिंग (chunking), हाइब्रिड रिट्रीवल (hybrid retrieval) और क्वेरी एक्सपेंशन (query expansion) आ गया, तब भी हमें एक जटिल कॉम्बिनेटरियल समस्या (combinatorial mess) का सामना करना पड़ा। चंक साइज (chunk size), चंक ओवरलैप (chunk overlap), टॉप-k रिट्रीवल डेप्थ (top-k retrieval depth), रेंकर कटऑफ (reranker cutoffs) और फ्यूजन वेट्स (fusion weights) - ये सभी एक-दूसरे को प्रभावित करते हैं। एक मैन्युअल ग्रिड सर्च में हफ्तों लग जाते और फिर भी हमें केवल एक लोकल मैक्सिमम (local maximum) ही मिलता।
हमने इस स्पेस को एक्सप्लोर करने के लिए बेयसियन ऑप्टिमाइज़ेशन (Bayesian optimization) का रुख किया। हर कॉम्बिनेशन का थकाऊ परीक्षण करने के बजाय, सर्च एल्गोरिदम इस विश्वास (belief) को बनाए रखता है कि कौन से कॉन्फ़िगरेशन अच्छा प्रदर्शन करने की संभावना रखते हैं और धीरे-धीरे आशाजनक क्षेत्रों (promising regions) पर ध्यान केंद्रित करता है।
इसका आउटपुट कोई एक परफेक्ट सेटिंग नहीं है। यह विकल्पों का एक पारेतो फ्रंटियर (Pareto frontier) है। एक छोर पर, हमारे पास हमारे हाई-थ्रूपुट API सपोर्ट एंडपॉइंट के लिए एक लीन (lean) कॉन्फ़िगरेशन है: तेज़ इन्फरेंस (inference), मध्यम रिकॉल और न्यूनतम संभव लेटेंसी (latency)। दूसरे छोर पर, लीगल रिव्यू के लिए एक आक्रामक (aggressive) कॉन्फ़िगरेशन है: गहरा रिट्रीवल, भारी रेंकिंग और टाइट ओवरलैप, जो गहनता के लिए मिलीसेकंड का त्याग करता है। क्योंकि फ्रंटियर स्पष्ट है, इसलिए हम "एक ही आकार सबके लिए" (one size fits all) का ढोंग करने के बजाय उत्पाद के लिए सही बिंदु चुन सकते हैं।
आंकड़े वास्तव में कैसे दिखते हैं
इन बदलावों ने सिस्टम को एक नाजुक प्रोटोटाइप से एक मापे हुए प्रोडक्शन पाइपलाइन (production pipeline) में बदल दिया।
रिकॉल एट टेन (Recall at ten) 78 प्रतिशत से बढ़कर 95 प्रतिशत हो गया। इसका मतलब है कि जब हमारे कॉर्पस (corpus) में सही उत्तर मौजूद होता है, तो हम बीस में से उन्नीस बार उसे ढूंढ लेते हैं।
95वें पर्सेंटाइल (95th percentile) पर लेटेंसी 850 ms से घटकर 320 ms हो गई। हाइब्रिड स्टैक कागज़ पर भारी लगता है, लेकिन स्मार्ट इंडेक्सिंग, छोटे रेंकर और ज़रूरत पड़ने पर ही आक्रामक चंक्स (aggressive chunks) देने की क्षमता ने पूरे सिस्टम को तेज़ बना दिया।
हैलुसिनेशन रेट (Hallucination rate)—जिसे होल्ड-आउट गोल्डन डेटासेट पर मानव एनोटेटर्स द्वारा ट्रैक किया गया—12 प्रतिशत से गिरकर 3 प्रतिशत हो गया। जब मॉडल को पूर्ण और प्रासंगिक संदर्भ (context) मिलता है, तो वह तथ्य गढ़ना बंद कर देता है।
प्रति क्वेरी लागत $0.008 से घटकर $0.005 हो गई। बेहतर रिट्रीवल का मतलब है छोटे, अधिक केंद्रित LLM प्रॉम्प्ट्स और कम रिकवरी प्रयास। क्वेरी एक्सपेंशन पर किया गया अतिरिक्त एम्बेडिंग खर्च, जनरेशन में होने वाली बचत के सामने बहुत कम है।
एक गोल्डन डेटासेट बनाएं और रिट्रीवल को कोड की तरह मानें
यदि आप इस लेख से एक चीज़ सीखें, तो वह माप का अनुशासन (discipline of measurement) होनी चाहिए। हमने वास्तविक प्रश्नों और सत्यापित उत्तर स्थानों का एक छोटा गोल्डन डेटासेट बनाया। किसी भी बदलाव के प्रोडक्शन में जाने से पहले, उसे उस डेटासेट पर चलाया जाता है। रिकॉल और लेटेंसी की रीयल-टाइम में निगरानी की जाती है, न कि केवल नोटबुक में देखकर अंदाज़ा लगाया जाता है।
रिट्रीवल कोई रिसर्च डेमो नहीं है। यह इंफ्रास्ट्रक्चर है। यह आपके बाकी स्टैक की तरह ही यूनिट टेस्ट, रिग्रेशन बेंचमार्क और ऑटोमेटेड ऑप्टिमाइज़ेशन का हकदार है। चंकिंग डॉक्यूमेंट स्ट्रक्चर के आधार पर करें, न कि टोकन के अंधविश्वास के आधार पर। वेक्टर और कीवर्ड सर्च को रेंकर के साथ जोड़ें। उन क्वेरीज़ को विस्तारित करें जो आपके उपयोगकर्ता वास्तव में लिखते हैं। फिर अपने अंतर्ज्ञान (intuition) के बजाय एक सर्च एल्गोरिदम को नॉब्स (knobs) ट्यून करने दें।
हमने जिस पाइपलाइन का वर्णन किया है वह सैद्धांतिक नहीं है। आप मूल लेख यहाँ पढ़ सकते हैं, और यदि आप उस समुदाय के साथ रिट्रीवल इंजीनियरिंग पर चर्चा करना चाहते हैं जो इस चीज़ की परवाह करता है, तो GyaanSetu AI group खुला है।
