मुख्य नेव्हिगेशन

सानुकूलित RAG उपायांची व्यावहारिक उदाहरणे

विशिष्ट गरजांनुसार तयार केलेल्या माहिती पुनर्प्राप्तीने समृद्ध निर्मिती प्रणाली उद्योगांतील ज्ञानाशी संबंधित गुंतागुंतीच्या समस्या कशा सोडवतात, हे प्रत्यक्ष उदाहरणे दाखवतात.

आजकाल RAG बद्दल कधी कधी नकारात्मक मत ऐकायला मिळते. काहींना आता ते अगदीच सोपे वाटते (सुरुवात करणे सोपे असले, तरी मोठ्या प्रमाणावर राबवणे तितके सोपे नाही), तर काहींना वाटते की ‘एजंटिक प्रणालींनी’ त्याला मागे टाकले आहे (पण अनेकदा वरवरचा थर बाजूला केला, तर त्या लगेचच RAG सारख्या दिसू लागतात...).

काही सामान्य आव्हानांना आम्ही कसे हाताळतो हे दाखवण्यासाठी या ब्लॉगमध्ये एक-दोन प्रत्यक्ष उदाहरणे दिली आहेत. ती आव्हाने म्हणजे:

  • मजकूर आणि संख्यात्मक डेटा एकत्र हाताळणे आणि त्यामुळे साधे RAG का अपयशी ठरते: महत्त्वाचे शब्द एकमेकांत मिसळतात आणि संख्यांना स्वतःचा अर्थविषयक संदर्भ नसतो.

  • आधी सारांश तयार करून मग एम्बेडिंग करणे उपयुक्त का ठरते: प्रत्येक खंडाचा छोटा वर्णनात्मक सारांश तयार करा आणि नंतर त्याच सारांशाचे एम्बेडिंग करून त्यावर क्वेरी करा.

  • संदर्भयुक्त सारांश कसे तयार करावेत: समान स्वरूपाची आकडेवारी वेगळी ओळखता यावी यासाठी मूळ दस्तऐवजाचा संदर्भ समाविष्ट करा.

  • कोड आणि Pydantic मॉडेल कधी वापरावीत: जिथे मजकूर जसाच्या तसा असणे महत्त्वाचे आहे, तिथे विश्वासार्हतेसाठी सानुकूल कोड आणि/किंवा Pydantic मॉडेलचा LLM कॉलसह वापर करा.

सानुकूल RAG उपाय तयार करणे

मूलभूत बाबी

ग्राहक सहाय्य बॉटपासून अंतर्गत ज्ञान सहाय्यकांपर्यंत अनेक गोष्टी RAG प्रणालींवर चालतात.

या प्रणालीच्या अंतर्गत प्रक्रियेत साधारणपणे तुम्ही:

  1. तुमचे स्रोत दस्तऐवज खंडांमध्ये विभागता.

  2. प्रत्येक खंड एम्बेड करून सदिश अवकाशात रूपांतरित करता.

  3. क्वेरी करताना सर्वाधिक संबंधित K खंड मिळवता.

  4. त्या खंडांच्या आधारे उत्तर तयार करता.

LangChain, LlamaIndex आणि OpenAI चे Filestore यांसारख्या लोकप्रिय साधनसंचांमुळे या पायऱ्या जवळजवळ अगदी सोप्या होतात. पण प्रत्यक्ष वापरातील प्रक्रियांमध्ये केवळ सघन मजकूर नसलेला डेटाही आढळतो आणि तो हाताळताना मूलभूत RAG कमी पडू शकते. पुढील विभागांमध्ये आम्ही डेटासंबंधी आव्हानांची ठोस उदाहरणे दाखवू आणि गुंतागुंत वाढत जाईल तसा उपाय टप्प्याटप्प्याने विकसित करू.

गोष्टी अधिक अवघड होतात तेव्हा

  1. तुमचा डेटा केवळ मजकूर नसतो तेव्हा (आणि हे बरेचदा घडते)

खेळाच्या संदर्भातील पुढील डेटा खंड विचारात घ्या:

JSON

{ "Attack": { "Range": { "default": 5, "with_Draconic_Ascension": 5.5, }, "Speed": { "default": "2 seconds", "with_Draconic_Ascension": "2.2 seconds", }, "Damage": { "default": 10, "with_Draconic_Ascension": 12, } }} 

शब्दांचा अर्थ आणि व्याकरण यांच्या आधारे शिकलेल्या परस्परसंबंधांमुळे एम्बेडिंग प्रभावी ठरतात. वरील डेटामध्ये मजकूर आणि संख्या यांचे मिश्रण आहे. या नेमक्या संदर्भाबाहेर त्या संख्यांचा शब्दांशी कोणताही संबंध राहत नाही. त्यामुळे हा डेटा खंड म्हणजे काही वर्णनात्मक शब्दांपाठोपाठ आलेल्या काही अनियमित संख्यांचे मिश्रण आहे, असे म्हणता येईल.

आपल्याकडे फक्त याच प्रकारचा डेटा असता, तर ही अडचण ठरली नसती. कारण उपलब्ध असलेल्या मोजक्या वर्णनात्मक शब्दांच्या एम्बेडिंगवरूनही डेटा मिळवता आला असता (किंवा मजकूर-ते-SQL वापरता आले असते). पण हेच शब्द असलेल्या सघन मजकुराच्या अनेक खंडांमध्ये हा खंड दडलेला असेल तर काय? उदाहरणार्थ:

JSON

{"Draconic_Ascension": { "description": "Transform into dragon form. Attack range and speed are increased by 10%, damage is boosted by 20%.", "details": { "activation_conditions": "Can only be activated when HP is below 50%or Fury meter is full.", "visual_effects": "Wings unfurl, scales shimmer with embers, voice lines change to echoing growls.", "lore": "An ancient bloodline awakens. The bearer of the mark channels the soul of the last Flamewing Wyrm, becoming a living storm of fire and fury." } }}

आता समजा, आपल्याला “ड्रॅकॉनिक असेंशनसह हल्ल्याची व्याप्ती किती आहे?” या प्रश्नाशी संबंधित खंड मिळवायचा आहे. समान महत्त्वाचे शब्द असलेल्या इतर खंडांच्या गोंधळात तो दडलेला असल्यामुळे हवा असलेला खंड बहुधा मिळणार नाही.

मूळ समस्या अशी आहे की हे डेटा खंड एकाच विषयावरील वेगवेगळ्या प्रकारची माहिती देत असले, तरी आपण त्यांच्यात अचूक फरक करू शकत नाही. आपण हा डेटा काही प्रकारे अधिक समृद्ध किंवा परिणामकारक करू शकतो का? नक्कीच करू शकतो:smile:

  1. डेटाचा सारांश तयार करून तो समृद्ध करा. हो, तुम्ही बरोबर वाचले

खंड थेट एम्बेड करण्याऐवजी, तो डेटा कशाविषयी आहे हे सांगणारा सारांश आधी तयार करता येतो आणि मग त्या सारांशाचे एम्बेडिंग करून त्यावरून माहिती मिळवता येते. उत्तर तयार करताना मात्र सारांशाशी जोडलेला मूळ डेटाच वापरला जाईल.

म्हणून वर दाखवलेल्या दोन खंडांसाठी आपण पुढीलप्रमाणे सारांश तयार करू:

  1. हल्ल्याची व्याप्ती, वेग आणि हानी यांची आकडेवारी (मूळ स्थितीत आणि ड्रॅकॉनिक असेंशनसह).

  2. ड्रॅकॉनिक असेंशनचे वर्णन आणि तपशील, ज्यात ते सक्रिय होण्याच्या अटी, दृश्य परिणाम आणि कथाविश्व समाविष्ट आहे.

त्यानंतर सारांशाशी “जुळण्यासाठी” क्वेरीतही भर घालतो. उदाहरणार्थ, “ड्रॅकॉनिक असेंशनसह हल्ल्याची व्याप्ती किती आहे?” हा प्रश्न बदलून “ड्रॅकॉनिक असेंशनसह हल्ल्याच्या व्याप्तीची आकडेवारी काय आहे?” असा करू. विशेषतः तांत्रिक क्षेत्राबाहेरील वापरकर्ते ~~“मनाला येईल त्या”~~ सामान्य मानवी भाषेत प्रश्न विचारतात तेव्हा हे महत्त्वाचे ठरते. शेवटी, अचूकता आणि सर्वसमावेशकता वाढवण्यासाठी RAG कसे काम करते, हे जाणणे त्यांच्या कक्षेत किंवा चिंतेत नसते.

गोष्टी अधिक अवघड कधी होतात हे दाखवणारा आकृतीबंध.

  1. गोष्टी संदर्भाबाहेर नेऊ नका (हा सल्ला सामान्यतः आयुष्यातही लागू होतो)

आता पुढील परिस्थितीत खाली दाखवल्याप्रमाणे अगदी सारखे दिसणारे असंख्य डेटा खंड हाताळावे लागतात:

Plain Text

# Chunk one{ "Attack": { "Range": { "default": 9, }, ... }}# Chunk two{ "Attack": { "Range": { "default": 6, }, ... }}# Chunk three{ "Attack": { "Range": { "default": 7, }, ... }}

आपण हाच दृष्टिकोन कायम ठेवला, तर “पात्र X च्या हल्ल्याची व्याप्ती किती आहे?” असा प्रश्न विचारल्याची कल्पना करा. आपण नुकतेच तयार केलेले सारांशही अगदी सारखे दिसत असल्याने योग्य उत्तर मिळणे नशिबावर अवलंबून राहील. मग त्यांच्यात फरक कसा करता येईल?

सोपे उत्तर म्हणजे संदर्भ द्या. डेटा खंडात त्याच्या मूळ दस्तऐवजाचा संदर्भ सहज समाविष्ट करता येईल. उदाहरणार्थ, या प्रकरणात {”character”: “X”}. अशा प्रकारे पात्र Y आणि Z साठीही समान डेटा असला, तरी पात्र X चा योग्य डेटा अचूकपणे मिळवता येईल.

मात्र खंडाचा संदर्भयुक्त सारांश तयार करणे हा अधिक चांगला आणि व्यापकपणे लागू करता येणारा दृष्टिकोन आहे. म्हणजे केवळ डेटा खंडाचाच सारांश तयार करण्याऐवजी, त्याचा मूळ दस्तऐवज आणि खंड हे दोन्ही देऊन सर्वसाधारण संदर्भयुक्त सारांश तयार करता येईल. त्या सारांशात हा खंड मूळ दस्तऐवजाशी कसा संबंधित आहे हे नमूद केले जाईल. उदाहरणार्थ:

  1. हा खंड पात्र X साठी ...ची सविस्तर आकडेवारी देतो. हल्ल्याच्या वेगातील X चे सामर्थ्य दाखवून हा खंड संपूर्ण दस्तऐवजाशी जोडला जातो...

  2. हा खंड पात्र Y साठी ...ची सविस्तर आकडेवारी देतो. Y ची विशेष क्षमता वापरल्यावर वाढणारी आकडेवारी दाखवून हा खंड संपूर्ण दस्तऐवजाशी जोडला जातो...

  3. हा खंड पात्र Z साठी ...ची सविस्तर आकडेवारी देतो. सांघिक सामन्यांमध्ये संरक्षकाची भूमिका निभावण्यासाठी योग्य असलेली Z ची आकडेवारी दाखवून हा खंड संपूर्ण दस्तऐवजाशी जोडला जातो...

ही पद्धत (ज्याची काही प्रेरणा Anthropic कडून मिळाली आहे) वरील उदाहरणासाठी गरजेपेक्षा जास्त वाटू शकते. मात्र “संदर्भाबाहेर” चुकीचा अर्थ लावला जाऊ शकणाऱ्या खंडांसाठी ती खूप प्रभावी आहे. शिवाय, सर्व खंडांसाठी चालणारा एकसंध दृष्टिकोन मिळाल्याने अभियांत्रिकी प्रक्रिया नीटनेटकी राहते.

गोष्टी अधिक अवघड कधी होतात हे दाखवणारा आकृतीबंध.

  1. तुम्हाला ~~प्रत्येक गोष्ट नियंत्रणात ठेवण्याऐवजी~~ काटेकोर राहावे लागते तेव्हा

RAG प्रणालीसाठी सहसा आपल्याला डेटा संपूर्ण स्वरूपात मिळतो आणि आपण त्याचे खंड करतो. या उदाहरणात आपण थोडी वेगळी परिस्थिती पाहू. येथे डेटा आधीच खंडांमध्ये विभागलेला आहे, पण ते खंड सदोष आहेत. ते एका तार्किक खंडाचे अनियमित भाग असून त्यांना पुन्हा एकत्र करणे आवश्यक आहे. तार्किक खंड म्हणजे स्वाभाविकपणे एकत्र असायला हवा असा आशयाचा भाग, जसे दस्तऐवजाचा उपविभाग किंवा अर्थपूर्ण परिच्छेद.

गोष्टी अधिक अवघड कधी होतात हे दाखवणारा आकृतीबंध.

या डेटावरील पहिल्या प्रयत्नात आम्ही सर्व काही एका LLM कॉलला देतो, त्याला योग्य वाटेल त्याप्रमाणे भागांचे गट करण्यास सांगतो आणि नंतर गटबद्ध आशय परत मागतो. LLM हे काम चांगले करू शकायला हवे, नाही का? होही आणि नाहीही.

इतर अनेक प्रसंगांतही आम्हाला आढळले आहे की, पूर्ण आणि तंतोतंत आशय हवा असताना LLM आळशीपणे वागतात आणि विश्वासार्ह राहत नाहीत. विशेषतः संदर्भ मोठा असताना हे अधिक जाणवते. आणि ते अगदी स्वाभाविक आहे. पण या विशिष्ट वापरासाठी ही मोठी अडचण होती, कारण आम्हाला शब्द न् शब्द अगदी तंतोतंत आशय हवा होता. सारांश नको आणि मूळ आशयाचा कोणताही भाग वगळायचा नाही. एकही तपशील सुटता कामा नये.

अर्थात, “हो” म्हणण्याचे कारण असे की तुटलेल्या खंडांचा अर्थ आणि रचना समजून घेण्याचे काम त्याने उत्कृष्टपणे केले. फक्त त्याने तंतोतंत आशय पुन्हा उद्धृत करण्यास नकार देऊ नये. अरेरे:/

मग LLM ज्या कामात उत्तम आहे त्याचा लाभ घेऊन, ज्या कामात ते अविश्वसनीय आहे ते कसे टाळायचे? आम्ही आमच्या जुन्या विश्वासू मित्राची, म्हणजे कोडची मदत घेतली (याचा अर्थ सानुकूल Python फंक्शन असा घ्या). आणि त्यासोबत “याहून सोपे असूच शकत नाही” असे Pydantic मॉडेल वापरले. हा आहे उपाय:

  • सध्याचा तार्किक खंड कायम ठेवून सर्व विभागांवर क्रमाने प्रक्रिया करा.

  • प्रत्येक विभागासाठी LLM ला विचारा: हा विभाग सध्याच्या तार्किक खंडाचा भाग आहे का? उत्तर होय किंवा नाही असे द्या (Pydantic मॉडेलनुसार).

  • उत्तर होय असल्यास विभाग खंडाला जोडा. उत्तर नाही असल्यास पूर्ण झालेला सध्याचा तार्किक खंड जसा आहे तसा बाहेर पाठवा आणि त्या विभागापासून नवीन खंड सुरू करा.

गोष्टी अधिक अवघड कधी होतात हे दाखवणारा आकृतीबंध.

संपूर्ण आशयावर एकाच वेळी प्रक्रिया करण्यापेक्षा येथे थोडी जास्त टोकेन वापरली जातात. पण तंतोतंत आशय जतन करणे ही सर्वोच्च प्राथमिकता असलेल्या या विशिष्ट वापरासाठी हा किरकोळ अतिरिक्त खर्च पूर्णपणे योग्य होता.

हा अगदी सोपा उपाय आहे, पण तो एका महत्त्वाच्या तत्त्वाचे पालन करतो: काटेकोरपणा आवश्यक असताना केवळ LLM वर अवलंबून राहू नये, कारण शेवटी ती संभाव्यतेवर आधारित असतात.

सानुकूल कोड किंवा फंक्शन्स आणि Pydantic मॉडेल वापरून अपेक्षित व विश्वासार्ह परिणाम साधता येतो आणि त्याच वेळी LLM च्या क्षमतांचाही पूर्ण लाभ घेता येतो.

समारोप

निर्मितिक्षम कृत्रिम बुद्धिमत्तेचा उपाय तयार करणे हे कृत्रिम बुद्धिमत्तेइतकेच अभियांत्रिकीचेही आव्हान आहे. या उदाहरणांमुळे तुम्हाला तुमची वैशिष्ट्यपूर्ण आव्हाने हाताळण्याची प्रेरणा मिळाली असेल, अशी आम्हाला आशा आहे. अभियांत्रिकीला प्राधान्य देणाऱ्या निर्मितिक्षम कृत्रिम बुद्धिमत्ता उपायांविषयी अधिक वाचण्यासाठी, मार्गनिर्धारकावर आधारित एजंटिक प्रणालीच्या रचनेवरील आमचा ब्लॉग लेख पाहा.

लेखक

Cynthia Yu