ഒരു തിങ്കളാഴ്ച രാവിലെ അഞ്ച് നിർണ്ണായകമായ ബഗ് റിപ്പോർട്ടുകളോടെയാണ് നിങ്ങൾ ഉണരുന്നത്. നിങ്ങളുടെ റിവ്യൂ മോണിറ്ററിംഗ് ടൂൾ അതിന്റെ ജോലി കൃത്യമായി ചെയ്തിട്ടുണ്ട്. ഓരോ ക്രാഷ് റിപ്പോർട്ടും, ഓരോ ദേഷ്യപ്പെട്ട വൺ-സ്റ്റാർ റിവ്യൂവും, "സേവ് ടാപ്പ് ചെയ്യുമ്പോൾ ആപ്പ് ഫ്രീസ് ആകുന്നു" എന്ന പരാതിയും അത് കണ്ടെത്തിയിട്ടുണ്ട്. എവിടെയാണ് തകരാർ സംഭവിക്കുന്നതെന്ന് നിങ്ങൾക്ക് കൃത്യമായി അറിയാം. എന്നാൽ എവിടെയാണ് തിരയേണ്ടതെന്ന കാര്യം നിങ്ങൾക്ക് അറിയില്ല.

എന്റെ ആദ്യത്തെ പൈപ്പ്‌ലൈൻ നിർമ്മിച്ചതിന് ശേഷം ഞാൻ നേരിട്ട പ്രതിസന്ധിയായിരുന്നു അത്. അത് ആപ്പ് റിവ്യൂകളും ക്രാഷ് ലോഗുകളും തടസ്സമില്ലാതെ നിരീക്ഷിക്കുകയും, ഓരോ ഫീഡ്‌ബാക്കിനെയും ബഗുകൾ, ക്രാഷുകൾ, അല്ലെങ്കിൽ ഫീച്ചർ റിക്വസ്റ്റുകൾ എന്നിങ്ങനെ കൃത്യമായ വിഭാഗങ്ങളായി തരംതിരിക്കുകയും ചെയ്തിരുന്നു. ഡാഷ്‌ബോർഡ് നോക്കുമ്പോൾ എല്ലാം ശരിയാണെന്ന് തോന്നും, എന്നാൽ യഥാർത്ഥ ഡിബഗ്ഗിംഗ് പ്രക്രിയ അത്ര എളുപ്പമായിരുന്നില്ല.

ഒരു ബഗ് ഉണ്ടെന്ന് അറിയുന്നത് ഒരു മൈൽ ദൂരയാത്രയിലെ ആദ്യത്തെ ഇഞ്ച് മാത്രമാണ്. എനിക്ക് ഇപ്പോഴും IDE തുറക്കേണ്ടി വരും, മോഡ്യൂളുകൾക്കിടയിൽ grep ഉപയോഗിച്ച് തിരയണം, നിലവിലുള്ള കോഡ്‌ബേസുമായി സ്റ്റാക്ക് ട്രാസുകൾ താരതമ്യം ചെയ്യണം, കൂടാതെ പരാജയപ്പെട്ട പാത്ത് (failure path) മനസ്സിൽ പുനർനിർമ്മിക്കണം. ടിക്കറ്റുകൾ കുന്നുകൂടിക്കൊണ്ടിരിക്കുമ്പോഴും കോഫി ചൂടാറുന്നതിന് മുൻപ് ഈ മാനുവൽ പരിശോധനകൾക്കായി നിങ്ങളുടെ കൈവശമുള്ള വിലപ്പെട്ട സമയം നഷ്ടപ്പെടും. പ്രശ്നങ്ങൾ കണ്ടെത്തുക എന്നതിലുപരി അവയെക്കുറിച്ച് അന്വേഷിക്കാനും (investigate) പൈപ്പ്‌ലൈന് കഴിയണമായിരുന്നു.

അതിനാൽ, ഒരു ബഗ് റിപ്പോർട്ട് സ്വീകരിച്ച് അത് ശരിയാണെന്ന് ഉറപ്പുവരുത്തിയുള്ള ഒരു ഡയഗ്നോസിസ് (diagnosis) നൽകുക എന്ന ഏക ലക്ഷ്യത്തോടെ ഞാൻ സിസ്റ്റം വീണ്ടും നിർമ്മിച്ചു. വെറുമൊരു LLM വിവരണമല്ല എനിക്ക് വേണ്ടത്. ഫയൽ ഏതാണെന്ന് പറയുന്നതും, ഏത് വരിയിലാണെന്ന് ചൂണ്ടിക്കാണിക്കുന്നതും, റിസ്ക് എത്രത്തോളമുണ്ടെന്ന് കണക്കാക്കുന്നതും, പരിഹാരം നിർദ്ദേശിക്കുന്നതുമായ ഒരു ഘടനാപരമായ (structured) കണ്ടെത്തലാണ് എനിക്ക് ആവശ്യം. അത് എങ്ങനെയാണ് സാധ്യമായതെന്ന് താഴെ വിവരിക്കുന്നു.

എന്തുകൊണ്ട് ഘടന (Structure) ഒരു ചാറ്റ് ലോഗിനേക്കാൾ മികച്ചതാകുന്നു

ഞാൻ ഈ ഇൻവെസ്റ്റിഗേറ്റിംഗ് ഏജന്റിനെ നിർമ്മിച്ചത് PydanticAI ഉപയോഗിച്ചാണ്. അതിന്റെ കാരണം ലളിതമാണ്. ഒരു ലാംഗ്വേജ് മോഡലിനോട് കോഡിനെക്കുറിച്ച് ചിന്തിക്കാൻ ആവശ്യപ്പെടുമ്പോൾ, അതിന്റെ ഡിഫോൾട്ട് ഔട്ട്‌പുട്ട് ഒരു സുഹൃദ്conversational ടെക്സ്റ്റ് ആയിരിക്കും. അത് ഒരു മനുഷ്യന് വായിക്കാൻ എളുപ്പമായിരിക്കാം, എന്നാൽ ഒരു ഡൗൺസ്ട്രീം സ്ക്രിപ്റ്റിന് അത് ഉപയോഗശൂന്യമാണ്. എനിക്ക് മെഷീൻ റീഡബിൾ ആയ ഒരു കരാർ (contract) ആവശ്യമായിരുന്നു.

ഈ ഏജന്റ് നാല് പ്രത്യേക ഫീൽഡുകളുള്ള ഒരു വാലിഡേറ്റഡ് ഡാറ്റാ മോഡൽ നൽകുന്നു: റൂട്ട് കോസ് (root cause), ബാധിക്കപ്പെട്ട ഫയലുകൾ (affected files), നിർദ്ദേശിക്കപ്പെട്ട മാറ്റങ്ങൾ (proposed changes), കൂടാതെ സങ്കീർണ്ണതയുടെയും റിസ്കിന്റെയും വിലയിരുത്തൽ (assessment of complexity and risk). മോഡലിൽ ഒരു ഫീൽഡ് വിട്ടുപോവുകയോ അല്ലെങ്കിൽ ഒരു ഫയൽ പാത്ത് തെറ്റായി നൽകുകയോ ചെയ്താൽ വാലിഡേഷൻ പരാജയപ്പെടുകയും ഞാൻ അത് ഉടൻ തന്നെ കണ്ടെത്തുകയും ചെയ്യും. ഈ കൃത്യത പൈപ്പ്‌ലൈനിനെ വിശ്വസനീയമാക്കുന്നു.

യഥാർത്ഥ ഡിറ്റക്റ്റീവ് ജോലി ചെയ്യാൻ, ഏജന്റിന് നാല് റീഡ്-ഓൺലി (read-only) ടൂളുകൾ മാത്രമേ ലഭിക്കൂ. അതിന് grep വഴി കോഡ് തിരയാനും, ഒരു ഫയലിലെ പ്രത്യേക വരികൾ വായിക്കാനും, ഡയറക്ടറി ഉള്ളടക്കം ലിസ്റ്റ് ചെയ്യാനും, ക്ലാസുകൾ അല്ലെങ്കിൽ ഫംഗ്ഷനുകൾ പോലുള്ള സിംബലുകൾ കണ്ടെത്താനും കഴിയും. 'റീഡ്-ഓൺലി' എന്നത് വളരെ പ്രധാനപ്പെട്ട ഭാഗമാണ്. രാത്രി രണ്ട് മണിക്ക് എന്റെ റെപ്പോസിറ്ററിയിൽ എന്തെങ്കിലും മാറ്റം വരുത്താൻ ഏജന്റിന് അനുമതി നൽകാൻ ഞാൻ ആഗ്രഹിച്ചില്ല. ആദ്യം മനസ്സിലാക്കുക, അതിനുശേഷം മാത്രം എഡിറ്റ് ചെയ്യുക.

റെപ്പോ മാപ്പ് (Repo Map): ടൂളുകൾക്ക് മുൻപ് കോൺടെക്സ്റ്റ്

ഏജന്റിന്റെ ആദ്യ പതിപ്പ് കൃത്യമായിരുന്നുവെങ്കിലും വളരെ ചിലവേറിയതായിരുന്നു. ഒരു ടൂറിസ്റ്റ് വഴിതെറ്റി ചുറ്റിക്കറങ്ങുന്നത് പോലെ അത് ടോക്കണുകൾ പാഴാക്കിയിരുന്നു. മോഡൽ ആദ്യം list-dir വിളിക്കുന്നു, പിന്നെ grep, പിന്നെ ഒരു ഫയൽ വായിക്കുന്നു, വീണ്ടും list-dir വിളിക്കുന്നു... ഇങ്ങനെ ഓരോ ടോക്കണുകൾ ഉപയോഗിച്ച് പ്രോജക്റ്റ് ഘടനയെക്കുറിച്ച് മനസ്സിലാക്കാൻ ശ്രമിക്കുന്നു.

ഇതിനുള്ള പരിഹാരം ഏജന്റ് പ്രവർത്തിച്ചു തുടങ്ങുന്നതിന് മുൻപ് തന്നെ ഒരു കോംപാക്ട് റെപ്പോ മാപ്പ് (compact repo map) തയ്യാറാക്കുക എന്നതായിരുന്നു. ഈ മാപ്പ് റെപ്പോസിറ്ററിയുടെ ഒരു സംക്ഷിപ്ത രൂപമാണ്: പ്രധാന ഫയലുകൾ, അവയുടെ പ്രധാന ഫംഗ്ഷനുകൾ അല്ലെങ്കിൽ ക്ലാസുകൾ, കൂടാതെ പ്രധാന മോഡ്യൂളുകൾ എങ്ങനെ പരസ്പരം ബന്ധപ്പെട്ടിരിക്കുന്നു എന്നിവ ഇതിൽ ഉൾപ്പെടുന്നു. ഏജന്റിനോട് വഴി തെറ്റിയുള്ള പരീക്ഷണങ്ങൾ നടത്തി റോഡുകൾ കണ്ടെത്താൻ ആവശ്യപ്പെടുന്നതിന് പകരം ഒരു ജിപിഎസ് (GPS) നൽകുന്നതുപോലെയാണിത്.

ആ മാപ്പ് കോൺടെക്സ്റ്റ് വിൻഡോയിൽ ഉള്ളതുകൊണ്ട്, src/utils/parser.ts ഉണ്ടോ എന്ന് കണ്ടെത്താൻ ഏജന്റ് സമയം കളയില്ല. അതിന് ആ പ്രദേശം നേരത്തെ തന്നെ അറിയാം. പുക ഉയരുന്ന ഇടത്തേക്ക് അത് നേരിട്ട് നീങ്ങുന്നു. ഈ ഒരു മാറ്റം വഴി അനാവശ്യമായ തിരച്ചിലുകൾ പൂർണ്ണമായും ഒഴിവാക്കാൻ സാധിച്ചു.

ടൂൾ ഫണൽ (Tool Funnel): ഒരു നിഗമനത്തിലേക്ക് എത്തിക്കുക

ഒരു മാപ്പ് ഉണ്ടെങ്കിൽ പോലും ഏജന്റ് ആശയക്കുഴപ്പത്തിലായേക്കാം. ഒരു സംശയാസ്പദമായ ഫയൽ കണ്ടെത്തിക്കഴിഞ്ഞാൽ, അത് വീണ്ടും സ്വയം സംശയിക്കുകയും, വീണ്ടും തിരയുകയും, മറ്റൊരു ഫയൽ വായിക്കുകയും ചെയ്തുകൊണ്ട് ഒരു അനന്തമായ ലൂപ്പിൽ കുടുങ്ങിക്കിടക്കാം. ഇതിന് ഒരു വേഗത നൽകാൻ എനിക്ക് ഒരു മാർഗ്ഗം ആവശ്യമായിരുന്നു.

ഏജന്റ് മുന്നോട്ട് പോകുന്തോറും അതിന്റെ പ്രവർത്തനങ്ങളെ നിയന്ത്രിക്കുന്ന മൂന്ന് ഘട്ടങ്ങളുള്ള ഒരു ടൂൾ ഫണൽ ഞാൻ നടപ്പിലാക്കി.

ഒന്നാം ഘട്ടം പര്യവേക്ഷണമാണ് (exploration). ഏജന്റിന് നാല് ടൂളുകളിലും പൂർണ്ണമായ ആക്സസ് ഉണ്ടായിരിക്കും. അതിന്റെ യുക്തിയിൽ ബഗ് പുനരാവിഷ്കരിക്കാൻ ആവശ്യമായ കാര്യങ്ങൾ തിരയാനും ബ്രൗസ് ചെയ്യാനും വായിക്കാനും അതിന് കഴിയും.

രണ്ടാം ഘട്ടം ഡീപ്പ്-ഡൈവ് (deep-dive) ആണ്. ഏജന്റ് പ്രശ്നത്തിന്റെ ഉറവിടം കണ്ടെത്തിക്കഴിഞ്ഞാൽ, അതിന് ഡിസ്കവറി ടൂളുകൾ ലഭിക്കില്ല. അതിന് ഫയലുകൾ വായിക്കാൻ മാത്രമേ കഴിയൂ. ഇനി grep ചെയ്യാനോ ഡയറക്ടറി ലിസ്റ്റ് ചെയ്യാനോ കഴിയില്ല. ഈ ഘട്ടത്തിൽ, അത് കണ്ടെത്തിയ കോഡ് പഠിക്കുകയും തെളിവുകൾ ശേഖരിക്കുകയും വേണം.

മൂന്നാം ഘട്ടം ഔട്ട്‌പുട്ട് (output) ആണ്. എല്ലാ ടൂളുകളും ലോക്ക് ചെയ്യപ്പെടുന്നു. ഏജന്റിന് ഇനി കോഡ്‌ബേസ് പരിശോധിക്കാൻ കഴിയില്ല. അതിന് റിപ്പോർട്ട് തയ്യാറാക്കി എഴുതുക മാത്രമേ ചെയ്യാൻ കഴിയൂ. ഇത് "ഒന്ന് കൂടി പരിശോധിക്കട്ടെ" എന്ന അനന്തമായ ചക്രം ഒഴിവാക്കാൻ സഹായിക്കുന്നു.

ഈ ഫണൽ ഉപയോഗിച്ചതോടെ ഒരു അനാലിസിസിനായി ആവശ്യമായ ശരാശരി ടൂൾ കോളുകളുടെ എണ്ണം നാൽപ്പതിലധികം എന്നതിൽ നിന്ന് ഏകദേശം പത്തിൽ എത്തി. ഏജന്റ് കൂടുതൽ വേഗതയുള്ളതും ചിലവ് കുറഞ്ഞതും, ഒപ്പം കൂടുതൽ ആത്മവിശ്വാസമുള്ളതുമായി മാറി; കാരണം അതിന് ഒരു നിഗമനത്തിൽ എത്തേണ്ടത് നിർബന്ധമായിരുന്നു.

ബാക്കെൻഡ് മാറ്റാൻ സാധിക്കുന്ന രീതിയിൽ നിലനിർത്തുക

ഒരു സിംഗിൾ മോഡൽ പ്രൊവൈഡറിൽ മാത്രം ഈ സിസ്റ്റത്തെ ഒതുക്കി നിർത്താൻ ഞാൻ ആഗ്രഹിച്ചില്ല. ജോലിയുടെ സ്വഭാവമനുസരിച്ച് ഞാൻ വ്യത്യസ്ത എഞ്ചിനുകൾ ഉപയോഗിക്കുന്നു. ചിലപ്പോൾ Claude Code, ചിലപ്പോൾ Grok Build, അല്ലെങ്കിൽ ആ സമയത്ത് ഏറ്റവും കുറഞ്ഞ ചിലവുള്ളത് എന്താണോ അത്. കോർ ലോജിക് പ്രൊവൈഡറെ ആശ്രയിക്കാത്ത രീതിയിൽ (provider-agnostic) നിലനിർത്താൻ, ഞാൻ ഈ ജോലിയെ രണ്ട് ഘട്ടങ്ങളായി തിരിച്ചിരിക്കുന്നു.

ഒന്നാം ഘട്ടം എക്സ്പ്ലോറേഷൻ (exploration) ആണ്. ഏത് ശേഷിയുള്ള മോഡലും കോഡിംഗ് ഏജന്റായി ഉപയോഗിക്കാം; ഇത് റെപ്പോ മാപ്പ് (repo map) വായിക്കുകയും ടൂളുകൾ ഉപയോഗിക്കുകയും ഒരു റോ മാർക്ക്ഡൗൺ റിപ്പോർട്ട് (raw markdown report) തയ്യാറാക്കുകയും ചെയ്യുന്നു. ഇത് കൂടുതൽ ചിലവേറിയ ചിന്താപരമായ ഭാഗമാണ്.

രണ്ടാം ഘട്ടം സ്ട്രക്ചറിംഗ് (structuring) ആണ്. കുറഞ്ഞ ചിലവുള്ളതും വേഗതയേറിയതുമായ ഒരു LLM ആ മാർക്ക്ഡൗൺ എടുത്ത് കൃത്യമായ ഒരു Pydantic മോഡലിലേക്ക് മാറ്റുന്നു. ഈ ഘട്ടത്തിന് കാര്യമായ യുക്തിചിന്ത (reasoning) ആവശ്യമില്ല. ഇത് വെറും എക്സ്ട്രാക്ഷനും ഫോർമാറ്റിംഗും മാത്രമാണ്, അതിനാൽ ലഘുവായ ഹാർഡ്‌വെയറുകളിൽ പോലും ഇത് പ്രവർത്തിപ്പിക്കാം.

ഈ വിഭജനം വളരെ വ്യക്തമായതുകൊണ്ട്, വാലിഡേഷൻ ലോജിക്കിൽ (validation logic) മാറ്റം വരുത്താതെ തന്നെ എനിക്ക് ബാക്കെൻഡ് മാറ്റാൻ സാധിക്കും. എക്സ്പ്ലോറേറ്ററി ബ്രെയിനും (exploratory brain) ഞാൻ ഉപയോഗിക്കുന്ന സ്ട്രക്ചർ ചെയ്ത ഔട്ട്പുട്ടും തമ്മിലുള്ള ഒരു യൂണിവേഴ്സൽ അഡാപ്റ്റർ ആയി ഈ മാർക്ക്ഡൗൺ റിപ്പോർട്ട് പ്രവർത്തിക്കുന്നു.

യഥാർത്ഥത്തിൽ ഫലപ്രദമായത്

ഈ സംവിധാനം വരുന്ന ഇഷ്യൂകൾ കൈകാര്യം ചെയ്യുന്ന രീതി തന്നെ മാറ്റിമറിച്ചു. ക്ലാസിഫിക്കേഷൻ ലെയർ ഇപ്പോഴും ബഗ്ഗുകളെയും ഫീച്ചർ റിക്വസ്റ്റുകളെയും വേർതിരിക്കുന്നു, എന്നാൽ ഇപ്പോൾ അനാലിസിസ് ലെയർ തൊട്ടുപിന്നാലെ തന്നെ പ്രവർത്തനം തുടങ്ങുന്നു. ഞാൻ എന്റെ എഡിറ്റർ തുറക്കുമ്പോഴേക്കും, ഒരു ഫയൽ പാത്തും, ലൈൻ റേഞ്ചും, നിർദ്ദേശിക്കപ്പെട്ട മാറ്റവും എനിക്ക് മുന്നിലുണ്ടാകും. ഞാൻ ഇപ്പോഴും എല്ലാം നേരിട്ട് പരിശോധിക്കാറുണ്ട്. ഇത് ഒരു സഹായം മാത്രമാണ്, ഓട്ടോപൈലറ്റ് അല്ല. എന്നാൽ മുമ്പ് ചെയ്തിരുന്ന കോൺടെക്സ്റ്റ് ശേഖരണം...