എന്റെ പ്രൊഡക്ഷൻ ഏജന്റിനെ തകർത്ത ആ 'Null' ഇൻപുട്ട്
മൂന്നാഴ്ചക്കാലം ഡെമോ കൃത്യമായി പ്രവർത്തിച്ചു. എല്ലാ ടെസ്റ്റ് ഇൻപുട്ടുകളും ശരിയായിരുന്നു. എല്ലാ ഔട്ട്പുട്ടുകളും കൃത്യമായ സ്ഥലത്ത് എത്തിച്ചേർന്നു. സിസ്റ്റം വിശ്വസനീയമാണെന്ന് ഞാൻ കരുതി.
എന്നാൽ, ഒരു സപ്ലയർ സബ്ജക്ട് ലൈൻ (subject line) ഇല്ലാത്ത ഒരു ഇമെയിൽ അയച്ചു.
ഒരു ഓർഡർ റഫറൻസ് വേർതിരിച്ചെടുക്കാൻ ഏജന്റ് ഒരു സ്ട്രിംഗ് (string) പ്രതീക്ഷിച്ചു. എന്നാൽ അതിന് ലഭിച്ചത് ഒരു 'null' വാല്യൂ ആയിരുന്നു. അത് ക്രാഷ് ആയില്ല. അത് സംഭവിക്കുമായിരുന്നെങ്കിൽ കൂടുതൽ നന്നായേനെ. പകരം, യഥാർത്ഥമെന്ന് തോന്നിക്കുന്ന ഒരു വ്യാജ ഓർഡർ റഫറൻസ് അത് നിർമ്മിച്ചു. ഡൗൺസ്ട്രീം സിസ്റ്റം (downstream system) അത് പ്രോസസ്സ് ചെയ്തു. നാല് മണിക്കൂർ നേരം ആരും അത് ശ്രദ്ധിച്ചതേയില്ല.
ഡെമോകളിൽ നിങ്ങൾ പ്രതീക്ഷിക്കുന്ന ഇൻപുട്ടുകളാണ് ഉപയോഗിക്കുന്നത്. എന്നാൽ പ്രൊഡക്ഷനിൽ നിങ്ങൾ പ്രതീക്ഷിക്കാത്ത ഇൻപുട്ടുകളാണ് വരുന്നത്.
ഞാൻ ഏജന്റ് ഓപ്പറേഷൻ aienterprise.dk-ൽ നടത്തുന്നു. അതിന്റെ മുഴുവൻ ട്രാസും (trace) ഞാൻ കണ്ടു. സബ്ജക്ട് ലൈനിൽ നിന്ന് ഓർഡർ റഫറൻസ് വേർതിരിച്ചെടുക്കാൻ പ്രോംപ്റ്റ് (prompt) ഏജന്റിനോട് നിർദ്ദേശിച്ചിരുന്നു. സബ്ജക്ട് ലൈൻ ഉണ്ടെങ്കിൽ ഇത് കൃത്യമായി പ്രവർത്തിക്കും.
സബ്ജക്ട് ലൈൻ ഇല്ലാതിരിക്കുമ്പോൾ, ഒരു ലാർജ് ലാംഗ്വേജ് മോഡൽ (large language model) ആ വിടവ് നികത്തുന്നു. ശരിയാണെന്ന് തോന്നുന്ന എന്തെങ്കിലും അത് നിർമ്മിച്ചെടുക്കുന്നു. ഇത് വെറുമൊരു ക്രമരഹിതമായ ശബ്ദമല്ല (random noise). ഇതൊരു ഘടനാപരമായ ശബ്ദമാണ് (structured noise). ഇത് ശരിയാണെന്ന് തോന്നുന്നതുകൊണ്ട് തന്നെ അപകടകരമാണ്. ഒരു പരാജയം നിങ്ങൾക്ക് തിരിച്ചറിയാൻ സാധിക്കും. എന്നാൽ ആത്മവിശ്വാസത്തോടെ നൽകുന്ന ഒരു തെറ്റായ ഉത്തരം തിരിച്ചറിയുക എന്നത് എളുപ്പമല്ല.
ഞാൻ മോഡലിനെ വീണ്ടും പരിശീലിപ്പിച്ചില്ല (retrain). പ്രോംപ്റ്റിലും മാറ്റം വരുത്തിയില്ല. മോഡൽ കോളിന് (model call) മുൻപായി ഞാൻ ഒരു ഗാർഡ് (guard) ചേർത്തു.
ഇപ്പോൾ, ആദ്യം ഒരു ലളിതമായ പരിശോധന നടക്കുന്നു. സബ്ജക്ട് ഫീൽഡ് ഉണ്ടോ എന്നും അത് കാലിയല്ലെന്നും അത് പരിശോധിക്കുന്നു. ഉത്തരം 'ഇല്ല' എന്നാണെങ്കിൽ, ആ മെസ്സേജ് ഒരു മനുഷ്യൻ പരിശോധിക്കാനായി ഹോൾഡ് ക്യൂവിലേക്ക് (hold queue) മാറ്റുന്നു. ഏജന്റ് ആ തെറ്റായ ഇൻപുട്ട് കാണുന്നില്ല.
ഈ ഗാർഡ് വെറും പന്ത്രണ്ട് വരി കോഡ് മാത്രമാണ്. ഈ വർഷം ഞാൻ നിർമ്മിച്ചതിൽ വെച്ച് ഏറ്റവും പ്രധാനപ്പെട്ട കാര്യമാണിത്.
ഇതിലെ പാറ്റേൺ ലളിതമാണ്. ഒരു ഏജന്റ് ഒരു ഘടന (structure) പ്രതീക്ഷിക്കുന്നുണ്ടെങ്കിൽ, പ്രൊഡക്ഷനിൽ എപ്പോഴെങ്കിലും അൺസ്ട്രക്ചേർഡ് ഡാറ്റ (unstructured data) വരാൻ സാധ്യതയുണ്ട്. ഇതിനുള്ള പരിഹാരം കൂടുതൽ സ്മാർട്ട് ആയ ഒരു മോഡലല്ല. മറിച്ച്, ഒരു അതിർവരമ്പ് (boundary) ഉണ്ടാക്കിയെടുക്കുക എന്നതാണ്. മോഡലിനെ ഊഹിക്കാൻ വിടുന്നതിന് പകരം, തെറ്റായ ഇൻപുട്ടുകളെ ഒരു മനുഷ്യനിലേക്ക് എത്തിക്കുന്ന ഒരു പരിശോധന നിങ്ങൾക്ക് ആവശ്യമാണ്.
വിശ്വസനീയത (Reliability) മാത്രമാണ് ഏക ഫീച്ചർ. ഒരു ഏജന്റിന് ഒരു ജോലി ചെയ്യാൻ കഴിയുമെന്ന് ഡെമോ കാണിക്കുന്നു. എന്നാൽ തെറ്റായ ഇൻപുട്ട് ലഭിക്കുമ്പോഴും പുലർച്ചെ 3 മണിയിലും ആ ജോലി കൃത്യമായി ചെയ്യുന്നുണ്ടോ എന്ന് പ്രൊഡക്ഷൻ തെളിയിക്കുന്നു. നിങ്ങളുടെ ഉപഭോക്താക്കൾക്ക് രണ്ടാമത്തെ കാര്യമാണ് പ്രധാനം.
എന്റെ ഏജന്റ് ഇപ്പോൾ പ്രതിദിനം 200 ഓപ്പറേഷനുകൾ തടസ്സമില്ലാതെ ചെയ്യുന്നു. ആഴ്ചയിൽ രണ്ടുതവണ ഹോൾഡ് ക്യൂ പ്രവർത്തിക്കുന്നു. ഒരു മനുഷ്യൻ ആ വിചിത്രമായ ഡാറ്റ പരിശോധിക്കുന്നു. പ്രൊഡക്ഷൻ യഥാർത്ഥത്തിൽ എങ്ങനെയാണെന്ന് ഇതിലൂടെ ഞാൻ മനസ്സിലാക്കുന്നു.
നിങ്ങൾ EU AI ആക്ട് പ്രകാരം ഉയർന്ന റിസ്ക് ഉള്ള വിഭാഗങ്ങൾക്കായി ഏജന്റുകൾ നിർമ്മിക്കുകയാണെങ്കിൽ, അതിന്റെ സമയപരിധി 2027 ഡിസംബർ 2 ആണ്. ഇതിൽ തൊഴിൽ, ബയോമെട്രിക്സ്, വിദ്യാഭ്യാസം എന്നിവ ഉൾപ്പെടുന്നു. തെറ്റായ ഇൻപുട്ട് ലഭിക്കുമ്പോൾ ഊഹിച്ചു മറുപടി നൽകുന്ന ഒരു സിസ്റ്റം ഓഡിറ്റിൽ പരാജയപ്പെടും. ഈ ഗാർഡ് ഒരു കംപ്ലയൻസ് മിനിമം (compliance minimum) ആണ്.
വിശ്വസനീയത എന്നത് പിന്നീട് ചേർക്കാൻ കഴിയുന്ന ഒരു ഫീച്ചറല്ല.
എന്റെ പ്രൊഡക്ഷൻ ഏജന്റിനെ തകർത്ത ആ 'null' ഇൻപുട്ടും അത് എങ്ങനെ പരിഹരിച്ചു എന്നതും
എന്റെ ഏജന്റ് വളരെ വിശ്വസനീയമാണെന്ന് (robust) ഞാൻ കരുതിയിരുന്നതാണ്. എന്നാൽ ഒരു ചെറിയ null ഇൻപുട്ട് എന്റെ പ്രൊഡക്ഷൻ എൻവയോൺമെന്റിനെ മുഴുവൻ തകർത്തപ്പോൾ ഞാൻ വലിയൊരു പാഠം പഠിച്ചു.
സംഭവം
എല്ലാം കൃത്യമായി നടന്നുകൊണ്ടിരിക്കുകയായിരുന്നു, പെട്ടെന്നാണ് എറർ ലോഗുകൾ കുതിച്ചുയർന്നത്. എന്റെ ഏജന്റ് മറുപടികൾ നൽകുന്നതിന് പകരം വീണ്ടും വീണ്ടും ക്രാഷ് ആകാൻ തുടങ്ങി.
മൂലകാരണം
കാരണം കണ്ടെത്താൻ ഞാൻ ലോഗുകൾ പരിശോധിച്ചു. എറർ മെസ്സേജ് ഇപ്രകാരമായിരുന്നു:
TypeError: Cannot read properties of null (reading 'trim')
എന്റെ കോഡിൽ, ഇൻപുട്ട് എപ്പോഴും ഒരു സ്ട്രിംഗ് (string) ആയിരിക്കുമെന്ന് ഞാൻ ഉറപ്പിച്ചു വിശ്വസിച്ചിരുന്നു.
// എന്റെ പഴയ കോഡ്
async function handleUserQuery(query) {
const sanitizedQuery = query.trim();
// ... ബാക്കി പ്രോസസ്സിംഗ്
}
ഇവിടെ query എന്നത് null ആയി വന്നപ്പോൾ, query.trim() എന്ന ഫംഗ്ഷൻ പ്രവർത്തിക്കാൻ കഴിയില്ല. ഇത് ആ പ്രോസസ്സിനെ പൂർണ്ണമായും തടസ്സപ്പെടുത്തി.
എങ്ങനെ പരിഹരിച്ചു?
ഈ പ്രശ്നം പരിഹരിക്കാൻ ഞാൻ രണ്ട് പ്രധാന മാറ്റങ്ങൾ വരുത്തി:
1. ഇൻപുട്ട് വാലിഡേഷൻ (Input Validation)
ഏതൊരു ഡാറ്റയും പ്രോസസ്സ് ചെയ്യുന്നതിന് മുൻപ് അത് ശരിയായ തരത്തിലുള്ളതാണോ എന്ന് പരിശോധിക്കുന്നത് നിർബന്ധമാണ്.
async function handleUserQuery(query) {
if (!query || typeof query !== 'string') {
console.warn("അസാധുവായ ഇൻപുട്ട് ലഭിച്ചു!");
return "ക്ഷമിക്കണം, എനിക്ക് നിങ്ങളുടെ ചോദ്യം മനസ്സിലായില്ല.";
}
const sanitizedQuery = query.trim();
// ... ബാക്കി പ്രോസസ്സിംഗ്
}
2. ഡിഫൻസീവ് പ്രോഗ്രാമിംഗ് (Defensive Programming)
ഭാവിയിൽ ഇത്തരം പിശകുകൾ ഒഴിവാക്കാൻ കോഡ് കൂടുതൽ സുരക്ഷിതമാക്കുക. optional chaining പോലുള്ള ഫീച്ചറുകൾ ഉപയോഗിക്കുന്നത് ഇതിന് സഹായിക്കും.
പാഠം
ഒരു പ്രൊഡക്ഷൻ എൻവയോൺമെന്റിൽ, ഇൻപുട്ട് എപ്പോഴും നിങ്ങൾ പ്രതീക്ഷിക്കുന്ന രീതിയിലായിരിക്കില്ല എന്ന് എപ്പോഴും ഓർക്കുക. "എല്ലാം ശരിയായിരിക്കും" എന്ന് കരുതുന്നതിനേക്കാൾ, "എന്തെങ്കിലും തെറ്റായ ഡാറ്റ വന്നാൽ എന്ത് ചെയ്യും?" എന്ന് ചിന്തിക്കുന്നതാണ് ഒരു നല്ല ഡെവലപ്പർക്ക് വേണ്ട ഗുണം.
Optional learning community: https://t.me/GyaanSetuAi