ലാർജ് ലാംഗ്വേജ് മോഡലുകളിൽ (LLMs) നിന്നുള്ള തെറ്റായ JSON (malformed JSON) ശരിയാക്കുന്നതിനുള്ള ചിലവ് നിയന്ത്രിക്കാൻ ഡെവലപ്പർമാർക്ക് ഇപ്പോൾ സാധിക്കും. റിപ്പയർ ശ്രമങ്ങൾ പരമാവധി രണ്ടായി പരിമിതപ്പെടുത്തുന്നതിലൂടെ ഇത് സാധ്യമാകുമെന്ന് ഒരു ലളിതമായ പൈത്തൺ ലൂപ്പ് കാണിച്ചുതരുന്നു. ജനറേറ്റ് ചെയ്യുക, പാഴ്സ് ചെയ്യുക, വാലിഡേറ്റ് ചെയ്യുക, വീണ്ടും ശ്രമിക്കുക, തുടർന്ന് സ്വീകരിക്കുകയോ പരാജയപ്പെടുകയോ ചെയ്യുക എന്ന രീതി ഉപയോഗിക്കുന്നതിലൂടെ "ഒരുപക്ഷേ ശരിയായ JSON" എന്ന അവസ്ഥയെ അളക്കാവുന്ന വിജയനിരക്കായി മാറ്റാനും ടോക്കൺ ഉപയോഗം അമിതമാകാതിരിക്കാനും സാധിക്കുന്നു.

ഒരു റിപ്പയർ ലൂപ്പ് (repair loop) പ്രധാനമാകുന്നത് എന്തുകൊണ്ട്?

LLM-കളോട് "JSON നൽകുക" എന്ന് പലപ്പോഴും നിർദ്ദേശിക്കാറുണ്ടെങ്കിലും, അവയുടെ ഔട്ട്‌പുട്ടിൽ പലപ്പോഴും സിന്റാക്സ് പിശകുകൾ (syntax errors), വിട്ടുപോയ കീകൾ (missing keys), അല്ലെങ്കിൽ ബിസിനസ് നിയമങ്ങൾ ലംഘിക്കുന്ന മൂല്യങ്ങൾ (values) എന്നിവ ഉണ്ടാകാറുണ്ട്. കൃത്യമായ ഒരു പേലോഡ് (payload) പ്രതീക്ഷിക്കുന്ന ഒരു ഡൗൺസ്ട്രീം സിസ്റ്റം ഇത്തരത്തിലുള്ള ഔട്ട്‌പുട്ട് ലഭിച്ചാൽ തകരാറിലാകുകയോ തെറ്റായ ഫലങ്ങൾ നൽകുകയോ ചെയ്യും. ഇത്തരം പ്രശ്നങ്ങൾ കണ്ടെത്താനും പരിഹരിക്കാനും ഒരു വ്യവസ്ഥാപിത മാർഗ്ഗമില്ലെങ്കിൽ, ടീമുകൾക്ക് ഒന്നുകിൽ ഉയർന്ന പരാജയ നിരക്ക് അംഗീകരിക്കേണ്ടി വരും, അല്ലെങ്കിൽ മോഡൽ ശരിയാകുന്നത് വരെ ആവർത്തിച്ച് പ്രോംപ്റ്റുകൾ നൽകി പണം പാഴാക്കേണ്ടി വരും.

മൂന്ന് വാലിഡേഷൻ പാളികൾ (validation layers)

വിശ്വസനീയമായ ഒരു ലൂപ്പ് വാലിഡേഷനെ താഴെ പറയുന്ന രീതിയിൽ വേർതിരിക്കുന്നു:

  • Syntax – സ്ട്രിംഗ് ഒരു JSON ആയി പാഴ്സ് ചെയ്യാൻ കഴിയുന്നുണ്ടോ?
  • Shape – ടോപ്പ്-ലെവൽ ഒബ്‌ജക്റ്റിൽ പ്രതീക്ഷിച്ച കീകൾ കൃത്യമായി ഉണ്ടോ?
  • 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

റിപ്പയർ ലൂപ്പ് തന്നെ ശ്രമങ്ങളുടെ എണ്ണത്തിന് ഒരു പരിധി നിശ്ചയിക്കുന്നു:

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) പ്രക്രിയ അവസാനിക്കുന്നു.

ചിലവ് കുറഞ്ഞ റിപ്പയറുകൾക്കായി രണ്ട് നിയമങ്ങൾ

  1. റിപ്പയർ പ്രോംപ്റ്റുകൾ ലളിതമായി സൂക്ഷിക്കുക – യഥാർത്ഥ JSON, എറർ മെസ്സേജ്, സ്കീമ എന്നിവ മാത്രം ഉൾപ്പെടുത്തുക. നീളമുള്ള ചാറ്റ് ഹിസ്റ്ററി ചേർക്കുന്നത് ടോക്കൺ ഉപയോഗം വർദ്ധിപ്പിക്കുകയും മോഡലിനെ ആശയക്കുഴപ്പത്തിലാക്കുകയും ചെയ്യും. ഇത് കൃത്യത വർദ്ധിപ്പിക്കാതെ തന്നെ ഓരോ ശ്രമത്തിനും ചെലവ് കൂട്ടാൻ കാരണമാകും.

  2. വാലിഡേഷനും ഫാക്റ്റ്-ചെക്കിംഗും വേർതിരിക്കുക – പാഴ്സറിന് ഘടനാപരമായ പ്രശ്നങ്ങൾ കണ്ടെത്താൻ കഴിയും, എന്നാൽ ഒരു “summary” പ്രസ്താവന സത്യമാണോ എന്ന് പരിശോധിക്കാൻ അതിന് കഴിയില്ല. ഫാക്റ്റ്-ചെക്കിംഗ് പിന്നീടുള്ള ഘട്ടങ്ങളിൽ ചെയ്യേണ്ടതാണ്; തെറ്റായ ഒരു വാദത്തെ “റിപ്പയർ” ചെയ്യാൻ ശ്രമിക്കുന്നത് ആ കള്ളത്തെ കൂടുതൽ വൃത്തിയായി അവതരിപ്പിക്കാൻ മാത്രമേ സഹായിക്കൂ.

വിജയം അളക്കുന്നത് എങ്ങനെ

ഓരോ ശ്രമത്തിലെയും എറർ ടൈപ്പ് (syntax, shape, semantic) രേഖപ്പെടുത്തുന്നതും ലൂപ്പ് വിജയിച്ചോ ഇല്ലയോ എന്ന് നോക്കുന്നതും ഒരു കൃത്യമായ അളവ് നൽകുന്നു: നിശ്ചിത ശ്രമങ്ങൾക്കുള്ളിൽ ഉപയോഗയോഗ്യമാകുന്ന LLM പ്രതികരണങ്ങളുടെ അനുപാതം. ടീമുകൾക്ക് കാലക്രമേണ ഇത് ട്രാക്ക് ചെയ്യാനും, പ്രോംപ്റ്റ് ശൈലികൾ താരതമ്യം ചെയ്യാനും, വ്യത്യസ്ത സ്കീമകൾ പരീക്ഷിക്കാനും സാധിക്കും.

ഉണ്ടായേക്കാവുന്ന ദോഷവശങ്ങൾ

ലൂപ്പിന് ഒരു പരിധി നിശ്ചയിക്കുന്നത് എന്നാൽ പരിധി കഴിഞ്ഞാൽ ചില തെറ്റായ ഔട്ട്‌പുട്ടുകൾ ഒഴിവാക്കപ്പെടും എന്നാണ് അർത്ഥമാക്കുന്നത്. മോഡലിന്റെ ഗുണനിലവാരം കുറവാണെങ്കിൽ ഇത് മൊത്തത്തിലുള്ള പരാജയ നിരക്ക് വർദ്ധിപ്പിച്ചേക്കാം. ഓരോ പ്രതികരണവും നിർണ്ണായകമായ സാഹചര്യങ്ങളിൽ, കൂടുതൽ ടോക്കണുകൾ ചെലവാക്കിയാണെങ്കിലും ഉയർന്ന റിട്രൈ പരിധി ഡെവലപ്പർമാർ തിരഞ്ഞെടുക്കാൻ സാധ്യതയുണ്ട്. ഇതിലെ വിട്ടുവീഴ്ച വ്യക്തമാണ്: ഉയർന്ന കവറേജ് ലഭിക്കാൻ കൂടുതൽ ചിലവ്, അല്ലെങ്കിൽ കൃത്യമായ പരിധിയുള്ള കുറഞ്ഞ ബജറ്റ്.

ശ്രദ്ധിക്കേണ്ട കാര്യങ്ങൾ

  • റിപ്പയറിനായുള്ള പ്രോംപ്റ്റ് എഞ്ചിനീയറിംഗ് – എറർ മെസ്സേജ് ഫോർമാറ്റ് മെച്ചപ്പെടുത്തുന്നതിലൂടെ ആവശ്യമായ റിട്രൈകളുടെ എണ്ണം കുറയ്ക്കാം.
  • മറ്റ് പാഴ്സറുകൾ – ചില ലൈബ്രറികൾ ചെറിയ പ്രശ്നങ്ങൾ സ്വയം തിരുത്താൻ സഹായിക്കുന്ന ടോളറന്റ് പാഴ്സിംഗ് (tolerant parsing) നൽകുന്നുണ്ട്; അവയുടെ ചിലവ് ഒരു പരിമിത ലൂപ്പുമായി താരതമ്യം ചെയ്യുന്നത് ഗുണകരമാണ്.
  • മോഡൽ അപ്‌ഡേറ്റുകൾ – പുതിയ LLM പതിപ്പുകൾ കൂടുതൽ കൃത്യമായ JSON നൽകാൻ സാധ്യതയുണ്ട്, ഇത് റിട്രൈ പരിധി ഇനിയും കുറയ്ക്കാൻ സഹായിച്ചേക്കാം.

പരിമിതമായ ഒരു JSON റിപ്പയർ ലൂപ്പ്, അമിത ചിലവില്ലാതെ LLM ഔട്ട്‌പുട്ടിനെ വിശ്വസനീയമായ ഡാറ്റയാക്കി മാറ്റാൻ ഡെവലപ്പർമാർക്ക് പ്രായോഗികമായ ഒരു ഉപകരണം നൽകുന്നു. വാലിഡേഷനെ ഒരു പ്രധാന ഘട്ടമായി പരിഗണിക്കുന്നതിലൂടെയും റിട്രൈകൾ പരിമിതപ്പെടുത്തുന്നതിലൂടെയും ബജറ്റും ഡൗൺസ്ട്രീം സിസ്റ്റങ്ങളും സുഗമമായി നിലനിർത്താൻ ടീമുകൾക്ക് സാധിക്കും.