RAG और सर्च इंजीनियरिंगमध्यमपाठ 2147 मिनट का पाठ

इंडेक्स को ताज़ा (fresh) रखना

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

पाठ वीडियो में

60 सेकंड में

इंडेक्स को ताज़ा (fresh) रखना

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

1/5
आसान शब्दों में
स्कूल का नोटिस बोर्ड तभी काम का होता है जब कोई पुराने नोटिस हटाकर नए नोटिस लगाए। अगर इस साल की परीक्षा की तारीखों के बगल में पिछले साल की तारीखें भी लगी रहें, तो छात्र उलझन में पड़ जाएंगे। सर्च इंडेक्स भी एक ऐसा ही नोटिस बोर्ड है जिसे उतनी ही देखभाल की ज़रूरत होती है।
इंडेक्स आपके दस्तावेज़ों की खोजने योग्य (searchable) रूप में एक कॉपी होती है। हर कॉपी मूल दस्तावेज़ से अलग (drift) हो सकती है। जब कोई पॉलिसी अपडेट होती है, कोई पेज हटाया जाता है, या किसी यूज़र का एक्सेस खत्म होता है, तो इंडेक्स को भी बदलना चाहिए। एक पुराना (stale) इंडेक्स ऐसे जवाब देता है जो देखने में तो सही और सोर्स वाले लगते हैं, लेकिन गलत होते हैं।

सब कुछ दोबारा बनाने के बजाय इंक्रीमेंटल अपडेट्स

हर रात हर दस्तावेज़ को दोबारा प्रोसेस करना आसान तो है, लेकिन जैसे-जैसे दस्तावेज़ बढ़ते हैं, यह धीमा और महंगा हो जाता है। Incremental updates सिर्फ उन्हीं चीज़ों को प्रोसेस करते हैं जो बदली हैं। बदलाव को पहचानने का एक आसान और भरोसेमंद तरीका content hash है: टेक्स्ट का एक छोटा फिंगरप्रिंट। अगर फिंगरप्रिंट बदलता है, तो इसका मतलब है कि दस्तावेज़ बदल गया है।
Python: find what to add, update and deletepython
import hashlib

def fingerprint(text: str) -> str:
    return hashlib.sha256(text.encode("utf-8")).hexdigest()

def plan_sync(source_docs: dict[str, str], indexed: dict[str, str]) -> dict:
    """source_docs: doc_id -> current text. indexed: doc_id -> stored fingerprint."""
    add, update = [], []
    for doc_id, text in source_docs.items():
        fp = fingerprint(text)
        if doc_id not in indexed:
            add.append(doc_id)
        elif indexed[doc_id] != fp:
            update.append(doc_id)
    delete = [doc_id for doc_id in indexed if doc_id not in source_docs]
    return {"add": add, "update": update, "delete": delete}

source = {"leave-policy": "12 days casual leave", "travel-policy": "Rs 2,000 per day"}
indexed = {"leave-policy": fingerprint("10 days casual leave"), "old-memo": "abc"}
print(plan_sync(source, indexed))
# {'add': ['travel-policy'], 'update': ['leave-policy'], 'delete': ['old-memo']}
अपडेट के लिए, उस दस्तावेज़ के सभी पुराने chunks को हटा दें और नए जोड़ें। अलग-अलग chunks को पैच करने की कोशिश न करें: अगर शुरुआत में एक पैराग्राफ जोड़ा जाता है, तो उसके बाद की हर chunk boundary खिसक सकती है। यही वजह है कि हर chunk में उसका doc_id स्टोर होना चाहिए।

दस्तावेज़ हटाना वह कदम है जिसे लोग भूल जाते हैं

  • उन्हें पहचानें। जो दस्तावेज़ सोर्स से हट जाता है, उसे इंडेक्स से भी हटना चाहिए। ऐसा sync जो केवल नई चीज़ें जोड़ता और अपडेट करता है, हटाए गए दस्तावेज़ों को हमेशा के लिए खोजने लायक बनाए रखेगा।
  • उससे बनी हर चीज़ को हटा दें। Chunks, vectors, कीवर्ड इंडेक्स एंट्रीज़, कैश्ड (cached) जवाब, और उससे बनाई गई कोई भी समरी।
  • जाँचें कि काम हुआ या नहीं। कुछ इंडेक्स आइटम्स को केवल डिलीटेड मार्क कर देते हैं और बाद में साफ़ करते हैं। डिलीट करने के बाद, दस्तावेज़ को सर्च करके पक्का करें कि वह अब दिखाई नहीं दे रहा है।
  • पर्मिशन्स में बदलाव भी एक बदलाव है। अगर कोई यूज़र किसी फ़ोल्डर का एक्सेस खो देता है, तो इंडेक्स फ़िल्टर तुरंत अपडेट होने चाहिए। देखें Securing RAG: permissions for retrieved documents।
  • पर्सनल डेटा से जुड़ी रिक्वेस्ट्स। डेटा हटाना सिर्फ साफ़-सफ़ाई की बात नहीं, बल्कि एक कानूनी ज़िम्मेदारी भी हो सकती है। डेटा मिटाने (erasure) और बैकअप के बारे में जानने के लिए देखें Vector stores and embedding leaks।

वर्शन्स: पुराने और नए एक साथ

कई दस्तावेज़ों के अलग-अलग वर्शन होते हैं: पिछले साल का फ़ीस शेड्यूल और इस साल का, सर्कुलर 09/2024 और उसकी जगह लेने वाला सर्कुलर 14/2025। सोच-समझकर तय करें कि बॉट को क्या दिखना चाहिए।
तरीकायह कब सही है
केवल सबसे नए वर्शन को इंडेक्स करेंज़्यादातर पॉलिसी और FAQ बॉट्स के लिए; सबसे आसान और सबसे सुरक्षित
सभी वर्शन्स को "effective from" तारीख और एक "current" फ़्लैग के साथ इंडेक्स करेंजब लोग पूछते हैं कि "मार्च में क्या नियम था?"; डिफ़ॉल्ट रूप से केवल current पर फ़िल्टर करें
बदले जा चुके दस्तावेज़ों को chunk के टेक्स्ट में साफ़ तौर पर मार्क करेंताकि अगर पुराना वर्शन आ भी जाए (retrieve हो), तो भी मॉडल को दिखे कि "सर्कुलर 14/2025 द्वारा बदला गया"

मॉडल बदलने पर दोबारा एम्बेडिंग (Re-embedding) करना

अलग-अलग एम्बेडिंग मॉडल्स के vectors की तुलना नहीं की जा सकती। अगर आप किसी नए एम्बेडिंग मॉडल पर स्विच करते हैं, या उसी मॉडल के नए वर्शन पर भी जाते हैं, तो आपको हर chunk को re-embed करना होगा, और क्वेरीज़ को भी नए मॉडल से ही एम्बेड करना होगा। एक ही इंडेक्स में पुराने और नए vectors मिलाने से सर्च चुपचाप खराब हो जाती है।
  1. 1

    एक नया इंडेक्स बनाएं

    नए मॉडल के साथ सभी chunks को एक अलग इंडेक्स में एम्बेड करें। पुराना इंडेक्स यूज़र्स के लिए काम करता रहेगा।
  2. 2

    मूल्यांकन करें (Evaluate)

    दोनों इंडेक्स पर अपने गोल्डन क्वेश्चन सेट को चलाएं। रीकॉल (recall) और जवाबों की क्वालिटी की तुलना करें।
  3. 3

    स्विच करें

    ऐप को एक ही कदम में नए इंडेक्स से जोड़ें, उदाहरण के लिए कोई alias या सेटिंग बदलकर।
  4. 4

    पुराने इंडेक्स को कुछ समय के लिए रखें

    ताकि कुछ गड़बड़ होने पर आप तुरंत वापस पुराने पर लौट सकें।
  5. 5

    सफ़ाई करें

    पुराने इंडेक्स को हटा दें और रिकॉर्ड करें कि नया इंडेक्स किस मॉडल वर्शन का इस्तेमाल करता है।
नोट
हर इंडेक्स के साथ एम्बेडिंग मॉडल का नाम और वर्शन, chunking सेटिंग्स और प्रोसेसिंग की तारीख ज़रूर स्टोर करें। जब जवाब बदलते हैं, तो यह रिकॉर्ड आपको बताता है कि क्या बदला था।
कमज़ोर इंडेक्स
  • हाथ से दोबारा बनाया जाता है "जब किसी को याद आए"
  • सिर्फ नई फ़ाइलें जोड़ता है, पुरानी कभी नहीं हटाता
  • एक ही इंडेक्स में पुराने और नए एम्बेडिंग मॉडल मिले हुए
  • कोई रिकॉर्ड नहीं कि इसे किस मॉडल या सेटिंग्स से बनाया गया
बेहतर इंडेक्स
  • शेड्यूल किया गया या इवेंट पर आधारित sync, जिसमें जोड़ना, अपडेट करना और हटाना शामिल है
  • हटाने के बाद सर्च करके जाँचना कि दस्तावेज़ सच में हट गया
  • नए इंडेक्स में पूरा re-embed, टेस्टिंग, और फिर स्विच
  • इंडेक्स के साथ मॉडल, सेटिंग्स और तारीख स्टोर होना
यह करके देखें। किसी ऐसे दस्तावेज़ सेट के बारे में सोचें जिसे आप इस्तेमाल करते हैं, जैसे कॉलेज की वेबसाइट या ऑफ़िस ड्राइव। किसी को कैसे पता चलेगा कि कोई पेज हटा दिया गया है? आपके इंडेक्स में ऐसी कौन सी चीज़ होगी जो अब भी उसकी तरफ इशारा कर रही होगी?

और देखें और पढ़ें

लैब

डिलीशन चेक के साथ काम करने वाला एक sync प्लानर, साथ ही एक लिखित re-embedding योजना।

~30 min

समस्या

पाठ से plan_sync कोड का इस्तेमाल करें (Python 3, standard library)।

  1. तीन काल्पनिक दस्तावेज़ों से बना एक छोटा इन-मेमरी "index" बनाएं: chunk id से {"doc_id": ..., "text": ...} की एक डिक्शनरी।
  2. apply_sync(plan, source_docs, index) लिखें जो डिलीट किए गए और अपडेट किए गए दस्तावेज़ों के सभी chunks को डिलीट करे, और नए व अपडेट किए गए दस्तावेज़ों के chunks को जोड़े।
  3. एक दस्तावेज़ को बदलें, एक को डिलीट करें और एक नया जोड़ें। sync चलाएं। इंडेक्स को प्रिंट करें और पक्का करें कि डिलीट किए गए दस्तावेज़ का कोई भी chunk बाकी नहीं बचा है।
  4. बिना किसी रुकावट (downtime) के इंडेक्स को एक नए एम्बेडिंग मॉडल में ले जाने के लिए पाँच कदमों की योजना लिखें।

आपका काम तब पूरा होगा जब

कठिन सवाल

उत्तर देखने से पहले ख़ुद जवाब देने की कोशिश करें। अगर आप इनके जवाब दे सकते हैं, तो आप पाठ समझ गए हैं।

Q1आपका सोर्स सिस्टम यह नहीं बता सकता कि कौन सी फ़ाइलें डिलीट की गईं; यह केवल मौजूदा फ़ाइलों की लिस्ट दिखाता है। आप फिर भी डिलीट हुई फ़ाइलों का पता कैसे लगाएंगे?दिखाएं

लिस्ट्स की तुलना करें। इंडेक्स में मौजूद हर doc_id का रिकॉर्ड रखें। हर sync पर, सोर्स से मौजूदा doc_ids की पूरी लिस्ट लाएं; जो भी चीज़ इंडेक्स में है लेकिन सोर्स में नहीं है, उसे डिलीट कर दिया गया है। plan_sync यही काम करता है। बहुत बड़े सोर्स के लिए, यह पूरी तुलना लंबे अंतराल पर चलाएं, और बीच-बीच में तेज़ अपडेट्स के लिए change events का इस्तेमाल करें।

Q2आपके दस्तावेज़ डिलीट करने के बाद भी, एक यूज़र को ऐसा जवाब मिलता है जिसमें उसी दस्तावेज़ का हवाला दिया गया है। ऐसी तीन जगहें बताएं जहाँ वह टेक्स्ट अभी भी छिपा हो सकता है।दिखाएं

एक answer cache जिसमें पहले का कोई जवाब स्टोर था; एक दूसरा index (जैसे कि keyword index) जो अपडेट नहीं हुआ था; और उस डॉक्यूमेंट से बना डेटा जैसे कि समरीज़ या "related questions" की लिस्ट। दूसरी संभावनाएँ: ऐसा index जो डिलीट तो मार्क कर देता है लेकिन उसने अभी सफाई नहीं की है, कोई replica जो sync नहीं हुआ है, या कोई बैकअप जिसे restore किया गया था। डिलीट करने के बाद की जाने वाली जांच को हर उस रास्ते में सर्च करना चाहिए जिसका ऐप इस्तेमाल करता है।

जारी रखने के लिए कृपया साइन इन करें।

अक्सर पूछे जाने वाले सवाल

इंडेक्स को कितनी बार sync होना चाहिए?

उतनी ही बार जितनी बार दस्तावेज़ बदलते हैं और यूज़र्स को ताज़ा जानकारी की ज़रूरत होती है। कोई पॉलिसी लाइब्रेरी हर घंटे या कोई नया दस्तावेज़ पब्लिश होने पर sync हो सकती है। खबरों जैसे सोर्स को हर कुछ मिनटों में sync की ज़रूरत हो सकती है। "last updated" का समय दिखाएं ताकि यूज़र्स को पता रहे कि जवाब कितने ताज़ा हैं।

क्या मैं पूरे दस्तावेज़ के बजाय केवल बदले हुए chunk को अपडेट कर सकता हूँ?

सावधानीपूर्वक chunk ids का इस्तेमाल करके ऐसा करना मुमकिन है, लेकिन इसमें गलतियों की गुंजाइश रहती है, क्योंकि एक छोटा-सा बदलाव भी आगे की हर boundary को खिसका सकता है। बदले हुए दस्तावेज़ के सभी chunks को बदलना ज़्यादा आसान और सुरक्षित है, और इसमें लागत भी आमतौर पर बहुत कम आती है।

आंसर कैश (answer cache) का क्या?

जब दस्तावेज़ बदलते हैं, तो कैश को साफ़ किया जाना चाहिए, या उसे इंडेक्स वर्शन के हिसाब से की (keyed) किया जाना चाहिए। वरना कैश पुराने या हटाए गए टेक्स्ट से बने जवाब ही देता रहेगा।

अगर मैं केवल chunk साइज़ बदलता हूँ, तो क्या मुझे re-embed करने की ज़रूरत है?

हाँ। नई chunk boundaries का मतलब है नया chunk टेक्स्ट, और हर एक के लिए नए vector की ज़रूरत होती है। इसे मॉडल बदलने की तरह ही समझें: एक नया इंडेक्स बनाएं, मूल्यांकन करें, और फिर स्विच करें।

पाठ का टेस्ट

5 सवाल। पास होने और इस पाठ को पूरा करने के लिए 3 सही होने चाहिए (60%)।

टेस्ट देने और अपनी प्रोग्रेस सेव करने के लिए साइन इन करें