डेव्हलपर्स आता रिपेअरच्या प्रयत्नांची मर्यादा दोन ठेवून, लार्ज लँग्वेज मॉडेल्सकडून (LLMs) मिळणाऱ्या चुकीच्या (malformed) JSON दुरुस्त करण्याचा खर्च नियंत्रणात ठेवू शकतात, हे एका साध्या पायथन लूपवरून दिसून येते. ही पद्धत—जनरेट करा, पार्स करा, व्हॅलिडेट करा, पुन्हा प्रयत्न करा आणि नंतर स्वीकार करा किंवा अयशस्वी घोषित करा—यामुळे "कदाचित वैध असणाऱ्या JSON" चे रूपांतर मोजण्यायोग्य यश दरात होते आणि टोकनचा अनावश्यक वापर टाळता येतो.
रिपेअर लूप का महत्त्वाचा आहे
LLMs ला अनेकदा "JSON रिटर्न करा" असे निर्देश दिले जातात, तरीही आउटपुटमध्ये वारंवार सिंटॅक्स एरर्स (syntax errors), गहाळ कीज (missing keys) किंवा बिझनेस रूल्स मोडणारी व्हॅल्यूज आढळतात. जर एखाद्या डाउनस्ट्रीम सिस्टमला असे आउटपुट मिळाले, ज्याला स्ट्रिक्ट पेलोडची (strict payload) अपेक्षा आहे, तर ती सिस्टम क्रॅश होऊ शकते किंवा चुकीचे निकाल देऊ शकते. या समस्या शोधण्यासाठी आणि सुधारण्यासाठी पद्धतशीर मार्ग नसल्यास, टीम्सना एकतर उच्च अपयश दर स्वीकारावा लागतो किंवा मॉडेलला योग्य उत्तर मिळेपर्यंत वारंवार प्रॉम्प्ट देऊन पैसे वाया घालवावे लागतात.
व्हॅलिडेशनचे तीन स्तर
एक विश्वसनीय लूप व्हॅलिडेशनचे खालीलप्रमाणे विभाजन करते:
- Syntax (सिंटॅक्स) – स्ट्रिंग खरंच JSON म्हणून पार्स होते का?
- Shape (आकार) – टॉप-लेव्हल ऑब्जेक्टमध्ये नेमक्या अपेक्षित कीज (keys) आहेत का?
- Semantic (सिमँटिक) – व्हॅल्यूज डोमेनच्या मर्यादांचे पालन करतात का (उदाहरणार्थ, "category" ही पूर्व-निर्धारित संचातीलच असावी)?
पहिल्या अयशस्वी स्तरावरच थांबल्यामुळे, लूप मॉडेलला एक अचूक एरर मेसेज देऊ शकते, ज्यामुळे पुढच्या प्रयत्नात दुरुस्ती अचूक होण्याची शक्यता लक्षणीयरीत्या वाढते.
किमान पायथन उदाहरण
खालील कोड केवळ स्टँडर्ड लायब्ररी वापरतो. तो एक लहान स्कीमा ( category आणि summary कीज असलेला डिक्शनरी) आणि परवानगी असलेल्या कॅटेगरीची एक निश्चित यादी परिभाषित करतो.
import json
CATEGORIES = {"bug", "feature", "question"}
def validate(raw: str):
try:
value = json.loads(raw)
except json.JSONDecodeError as exc:
return None, f"syntax: {exc.msg}"
if not isinstance(value, dict):
return None, "shape: root must be an object"
if set(value) != {"category", "summary"}:
return None, "shape: expected category and summary"
if value["category"] not in CATEGORIES:
return None, "semantic: invalid category"
if not isinstance(value["summary"], str) or not value["summary"].strip():
return None, "semantic: summary must be text"
return value, None
रिपेअर लूप स्वतः प्रयत्नांवर एक निश्चित मर्यादा (hard ceiling) घालते:
MAX_ATTEMPTS = 2
raw = model_response # initial LLM output
for attempt in range(MAX_ATTEMPTS + 1):
value, error = validate(raw)
if error is None:
break
if attempt == MAX_ATTEMPTS:
raise RuntimeError(f"failed after {MAX_ATTEMPTS} retries: {error}")
# Send the error and schema back to the model for a fix
raw = ask_model_to_repair(raw, error)
जर JSON पहिल्याच प्रयत्नात व्हॅलिडेशनमध्ये पास झाले, तर लूप लगेच बाहेर पडते. अन्यथा, ते पुन्हा प्रयत्न करते आणि मॉडेलला एक संक्षिप्त पेलोड देते: मूळ आउटपुट, नेमका एरर स्ट्रिंग आणि अपेक्षित स्कीमा. दोन अयशस्वी प्रयत्नांनंतर प्रक्रिया स्पष्ट एक्सेप्शनसह (exception) थांबते.
किफायतशीर दुरुस्तीसाठी दोन नियम
रिपेअर प्रॉम्प्ट्स संक्षिप्त ठेवा – केवळ रॉ JSON, एरर मेसेज आणि स्कीमा समाविष्ट करा. लांब चॅट हिस्ट्री जोडल्यामुळे टोकनचा वापर वाढतो आणि मॉडेल गोंधळू शकते, ज्यामुळे अचूकता न वाढता प्रति रिट्राय खर्च वाढतो.
व्हॅलिडेशन आणि फॅक्ट-चेकिंग वेगळे ठेवा – पार्सर स्ट्रक्चरल समस्या शोधू शकतो, परंतु "summary" विधान सत्य आहे की नाही हे तो तपासू शकत नाही. फॅक्ट-चेकिंग नंतरच्या टप्प्यात असावे; खोट्या विधानाला "दुरुस्त" करण्याचा प्रयत्न केल्याने केवळ ते खोटे विधान अधिक सुटसुटीत दिसते.
यश मोजणे
प्रत्येक प्रयत्नाचा एरर प्रकार (syntax, shape, semantic) आणि लूप यशस्वी झाला की नाही याची नोंद (logging) ठेवल्यास एक ठोस मेट्रिक मिळते: मर्यादित रिट्राईजमध्ये वापरण्यायोग्य ठरलेल्या LLM प्रतिसादांचे प्रमाण. टीम्स कालांतराने याचा मागोवा घेऊ शकतात, प्रॉम्प्ट स्टाईल्सची तुलना करू शकतात किंवा वेगवेगळ्या स्कीमा व्याख्यांसह प्रयोग करू शकतात.
संभाव्य तोटे
लूपला मर्यादा घालण्याचा अर्थ असा आहे की मर्यादा संपल्यानंतर काही चुकीचे (malformed) आउटपुट काढून टाकले जातील, ज्यामुळे मॉडेलची मूळ गुणवत्ता कमी असल्यास एकूण अपयश दर वाढू शकतो. ज्या वातावरणात प्रत्येक प्रतिसाद महत्त्वाचा असतो, तिथे डेव्हलपर्स अतिरिक्त टोकन्सच्या खर्चाने उच्च रिट्राय मर्यादा निवडणे पसंत करू शकतात. यामध्ये स्पष्ट तडजोड आहे: अधिक कव्हरेजसाठी अधिक खर्च, किंवा अंदाजित मर्यादेसह कमी बजेट.
पुढे काय पाहावे
- रिपेअरसाठी प्रॉम्प्ट इंजिनिअरिंग – एरर मेसेजचे फॉरमॅट सुधारल्यास आवश्यक रिट्राईजची संख्या कमी होऊ शकते.
- पर्यायी पार्सर्स – काही लायब्ररीज टॉलरंट पार्सिंग (tolerant parsing) प्रदान करतात जे किरकोळ समस्या आपोआप सुधारू शकतात; मर्यादित लूपच्या तुलनेत त्यांच्या खर्चाची तुलना करणे फायदेशीर ठरेल.
- मॉडेल अपडेट्स – नवीन LLM व्हर्जन थेट अधिक स्वच्छ JSON तयार करू शकतात, ज्यामुळे रिट्राय मर्यादा अधिक कमी करणे शक्य होऊ शकते.
मर्यादित JSON रिपेअर लूप डेव्हलपर्सना खर्च न वाढवता अस्पष्ट (fuzzy) LLM आउटपुटचे रूपांतर विश्वसनीय डेटामध्ये करण्यासाठी एक व्यावहारिक साधन देते. व्हॅलिडेशनला एक महत्त्वाचे पाऊल मानून आणि रिट्राईजवर मर्यादा आणून, टीम्स त्यांचे बजेट आणि डाउनस्ट्रीम सिस्टम्स दोन्ही समाधानी ठेवू शकतात.
