2025, Nov 01 14:31
कानूनी चैटबॉट के लिए कॉर्पस-अवेयर LLM कैशिंग: वेक्टर स्टोर अपडेट संग ताज़ा उत्तर
कानूनी चैटबॉट के लिए LLM कैशिंग को कॉर्पस-अवेयर बनाएं: वेक्टर स्टोर अपडेट पर बासी उत्तरों से बचें, LangChain हुक और रिफ्रेश रणनीति, परफॉर्मेंस टिप्स।
कानूनी प्रश्नोत्तर चैटबॉट में LLM के उत्तरों को हमेशा ताज़ा रखना जितना लगता है, उससे कहीं कठिन है। कैशिंग गति बढ़ाती है और लागत घटाती है, लेकिन जैसे ही आप वेक्टर स्टोर में नए दस्तावेज़ जोड़ते हैं, पहले से कैश किए गए जवाब बासी हो सकते हैं। उपयोगकर्ता लगभग वही प्रश्न पूछते हैं और पुराने उत्तर पाते हैं, क्योंकि कैश बढ़े हुए कॉर्पस को नहीं दर्शाता। चुनौती यह है कि प्रदर्शन गिराए बिना कैश को मौजूदा नॉलेज बेस के साथ तालमेल में रखा जाए।
समस्या, संक्षेप में
आम तौर पर प्रतिक्रियाएँ प्रॉम्प्ट और मॉडल सिग्नेचर के आधार पर कैश की जाती हैं। यह तब तक ठीक चलता है जब तक आपका नॉलेज बेस नहीं बदलता। यदि कैश को कॉर्पस के अपडेट का पता ही नहीं, तो वह कल तक सही रहे उत्तर भी आज अधूरे होने पर भी लौटाता रहेगा।
from langchain_core.caches import BaseCache, RETURN_VAL_TYPE
from typing import Any, Dict, Optional
class NaiveResponseCache(BaseCache):
def __init__(self):
super().__init__()
self._store = {}
def fetch(self, prompt: str, llm_fingerprint: str) -> Optional[RETURN_VAL_TYPE]:
entry = self._store.get((prompt, llm_fingerprint))
if entry:
return entry["value"]
return None
def store(
self,
prompt: str,
llm_fingerprint: str,
value: RETURN_VAL_TYPE,
meta: Dict[str, Any] = None,
) -> None:
self._store[(prompt, llm_fingerprint)] = {
"value": value,
"meta": meta or {},
}
यह तरीका इस बात से अनजान रहता है कि आधारभूत वेक्टर स्टोर N से बढ़कर N+k दस्तावेज़ हो गया है या नहीं। नतीजतन, यह नई जानकारी को नज़रअंदाज़ करते हुए वही उत्तर देता रहेगा।
असल दिक्कत कहाँ आती है
आम तौर पर कैश कुंजी में प्रॉम्प्ट और LLM पैरामीटर्स का कोई प्रतिनिधित्व शामिल होता है। इसमें आपके वेक्टर इंडेक्स की अवस्था के बारे में कुछ नहीं होता। जब आप नई फ़ाइलें जोड़ते हैं, तो रिट्रीवल लेयर अतिरिक्त संदर्भ ला सकती है, पर कैश को इसकी खबर नहीं होती। संग्रहीत प्रविष्टियों को अमान्य करने या दोबारा बनाने का कोई संकेत नहीं मिलता, इसलिए वही या मिलते-जुलते प्रॉम्प्ट पर बाद की रिक्वेस्ट्स कॉर्पस के पुराने स्नैपशॉट से बने जवाब लौटा देती हैं। कानूनी संदर्भ में, थोड़ी-सी चूक भी अस्वीकार्य हो सकती है।
अपडेट्स के साथ कैश को मिलान में रखने का व्यवहारिक तरीका
एक सीधा उपाय है कैश को “कॉर्पस-अवेयर” बनाना—दस्तावेज़ों की संख्या को ट्रैक करें और जैसे ही यह संख्या बदले, कैश प्रविष्टियों को दोबारा जनरेट करें। यह एक सरल ह्यूरिस्टिक है: संख्या बदली तो नॉलेज बेस बदला, इसलिए कैश किए गए उत्तरों को ताज़ा करना होगा। नीचे उसी विचार का न्यूनतम इम्प्लीमेंटेशन है।
from langchain_core.caches import BaseCache, RETURN_VAL_TYPE
from typing import Any, Dict, Optional
class CorpusVersionCache(BaseCache):
def __init__(self, doc_total: int):
super().__init__()
self._entries = {}
self._corpus_size = doc_total
# ज्ञात कॉर्पस आकार सेट या अपडेट करें
def set_corpus_size(self, doc_total: int):
if self._corpus_size == doc_total:
return
self._corpus_size = doc_total
for args, _prev in self._entries.items():
query, llm_repr = args[0], args[1]
value, meta = self.rebuild_entry(query, llm_repr)
self.store(query, llm_repr, value, meta)
def rebuild_entry(self, query: str, llm_repr: str):
# नई जानकारी के साथ प्रतिक्रिया को पुनः जनरेट करें
response = "New LLM Response"
metadata = {}
return response, metadata
# कैश लुकअप
def fetch(self, query: str, llm_repr: str) -> Optional[RETURN_VAL_TYPE]:
cached = self._entries.get((query, llm_repr))
if cached:
return cached["value"]
return None
# कैश अपडेट
def store(
self,
query: str,
llm_repr: str,
value: RETURN_VAL_TYPE,
metadata: Dict[str, Any] = None,
) -> None:
self._entries[(query, llm_repr)] = {
"value": value,
"metadata": metadata or {},
}
LangChain के ग्लोबल कैश हुक में इसे जोड़ने के लिए, इसे इस तरह वायर करें:
from langchain.globals import set_llm_cache
cache = CorpusVersionCache(doc_total=0)
set_llm_cache(cache)
इस पैटर्न में, जब भी आप नई फ़ाइलें जोड़ते हैं और दस्तावेज़ों की संख्या बदलती है, आप ट्रैक किए गए आकार को अपडेट करने वाली मेथड कॉल करते हैं। इसके बाद कैश अपनी संग्रहीत प्रतिक्रियाएँ दोबारा जनरेट कर ताज़ा कर देता है, ताकि आगे की क्वेरीज़ नवीनतम संदर्भ को प्रतिबिंबित करें।
प्रदर्शन से जुड़े समझौते
यदि कैश प्रविष्टियों को दोबारा जनरेट करने की लागत चिंता का विषय है, तो अपडेट्स की आवृत्ति निर्णायक बन जाती है। जब नई जानकारी कम-कम आती है, तो उन प्रविष्टियों को जो शायद फिर कभी उपयोग न हों, अग्रिम पुनर्निर्माण की लागत देने के बजाय आक्रामक एक्सपायरी अधिक कुशल हो सकती है। अपडेट्स बार-बार हों, तो रिफ्रेश को अलग प्रक्रिया के रूप में शेड्यूल करना लोड को नियंत्रित करने और अंतिम उपयोगकर्ताओं के लिए लेटेंसी को अनुमानित रखने में मदद करता है। एक और लीवर है मेटाडेटा: प्रविष्टियों और दस्तावेज़ों से समृद्ध डेस्क्रिप्टर्स जोड़कर, आप पूरे कैश को रिफ्रेश करने की जगह केवल उन कैश्ड प्रतिक्रियाओं के उपसमुच्चय को पुनर्निर्मित कर सकते हैं जो प्रभावित श्रेणियों से मैप होते हैं।
यह क्यों मायने रखता है
कानूनी सहायक के लिए शुद्धता सिर्फ अच्छी बात नहीं—अनिवार्य है। एक ऐसा कैश जो नई जोड़ी गई फ़ाइलों को नज़रअंदाज़ करे, बिना शोर किए ऐसे उत्तर देगा जिनमें अहम संदर्भ छूट जाएगा। कैश को वेक्टर स्टोर के साथ संरेखित रखने से उपयोगकर्ताओं को सबसे ताज़ा जानकारी मिलती है, और आपको कैशिंग पूरी तरह बंद करने की ज़रूरत नहीं पड़ती।
मुख्य बातें
अपने कैश को कॉर्पस में बदलावों से अवगत रखें, ताकि पुराना कंटेंट न परोसा जाए। दस्तावेज़ों की संख्या जैसे सरल संकेत को ट्रैक करें और इसमें बदलाव पर रिफ्रेश ट्रिगर करें। पुनर्जनन लागत और लेटेंसी का संतुलन अपनी अपडेट फ़्रीक्वेंसी के साथ बनाएँ, और जहाँ संभव हो, पुनर्निर्माण को केवल प्रभावित कैश प्रविष्टियों के हिस्से तक सीमित रखें। इससे प्रदर्शन स्थिर रहता है और चैटबॉट ऐसे उत्तर देता है जो नवीनतम नॉलेज बेस को दर्शाते हैं।
यह लेख StackOverflow पर प्रश्न (लेखक: Quyền Phan Thanh) और InsertCheesyLine के उत्तर पर आधारित है।