പ്രോഗ്രസ് ലേബലിൽ ഒളിഞ്ഞിരിക്കുന്ന Out-of-Memory ക്രാഷ്
സെപ്റ്റംബർ അവസാനത്തെ ഒരു വൈകുന്നേരം, ഒരു ഉപയോക്താവിന്റെ വർക്ക്സ്പേസിലെ AI ഏജന്റ് ഒരു ടേണിന്റെ മധ്യത്തിൽ out-of-memory പിശകോടെ ക്രാഷ് ആയി. വ്യക്തമായ സംശയങ്ങൾ — വളരെയധികം സബ്-ഏജന്റുകൾ ഒരേസമയം ഓടുന്നു, അല്ലെങ്കിൽ സന്ദർഭം വളരെ വലുതായി — രണ്ടും തെറ്റായിരുന്നു. യഥാർത്ഥ കാരണം ഒരു സ്റ്റാറ്റസ് ലേബലായിരുന്നു: മോഡൽ ഒരു വലിയ ഷെൽ കമാൻഡ് കുറച്ച് അക്ഷരങ്ങൾ വീതം സ്ട്രീം ചെയ്യുമ്പോൾ, ഓരോ കഷണത്തിലും ഇതുവരെയുള്ള മുഴുവൻ കമാൻഡും പ്രോഗ്രസ് ലേബലായി ഞങ്ങൾ വീണ്ടും അയച്ചു. 124 KB കമാൻഡ് ഏകദേശം 41,000 ഇവന്റുകളും ഏകദേശം 690 MB ക്യൂവിൽ നിന്ന സ്ട്രിംഗുകളുമായി.
ഏജന്റ് അതിന്റെ ജോലി എങ്ങനെ സ്ട്രീം ചെയ്യുന്നു
Mythex-ൽ നിർമ്മിക്കുമ്പോൾ, ഏജന്റ് നിങ്ങളുടെ പ്രോജക്റ്റിന്റെ സ്വകാര്യ ക്ലൗഡ് സാൻഡ്ബോക്സിനുള്ളിൽ പ്രവർത്തിക്കുന്നു. മോഡൽ എഴുതുമ്പോൾ, അതിന്റെ ഔട്ട്പുട്ട് നിങ്ങളുടെ ബ്രൗസറിലേക്ക് സ്ട്രീം ചെയ്യുന്നു: ടെക്സ്റ്റ് വാക്കുകൾ വീതം പ്രത്യക്ഷപ്പെടുന്നു, ഏജന്റ് ഒരു ടൂൾ പ്രവർത്തിപ്പിക്കുമ്പോൾ — ഉദാഹരണത്തിന് ഒരു ഫയൽ എഴുതുന്ന ഷെൽ കമാൻഡ് — അതിനുള്ള ഒരു ലേബൽ തത്സമയം അപ്ഡേറ്റ് ആകുന്നത് കാണാം, അത് എന്ത് ചെയ്യുന്നു എന്ന് അറിയാൻ.
മോഡൽ ചെറിയ കഷണങ്ങളായാണ് സ്ട്രീം ചെയ്യുന്നത്. ഞങ്ങൾ ഉപയോഗിച്ച മോഡലിൽ, ആ കഷണങ്ങൾ പലപ്പോഴും വെറും മൂന്ന് അക്ഷരങ്ങൾ ആയിരുന്നു.
ആദ്യ സിദ്ധാന്തങ്ങൾ തെറ്റായിരുന്നു
ക്രാഷ് ഒരു സ്കേലിംഗ് പ്രശ്നം പോലെ തോന്നി, അതിനാൽ അവിടെ നിന്ന് തുടങ്ങി.
- സമാന്തര സബ്-ഏജന്റുകളോ? ടേണിൽ രണ്ടെണ്ണം മാത്രമേ ഉപയോഗിച്ചിരുന്നുള്ളൂ, ഓരോന്നും ഏകദേശം 1.5 MB അവസ്ഥ പിടിച്ചിരുന്നു. പോരാ.
- നിലനിർത്തിയ ട്രേസുകളോ? ഞങ്ങളുടെ ട്രേസിംഗ് ഒരു റൺ ട്രീ മെമ്മറിയിൽ സൂക്ഷിച്ചിരുന്നു, പക്ഷേ ക്രാഷിലെ ഹീപ്പിന്റെ വലിപ്പത്തിനടുത്തുപോലുമില്ല.
രണ്ടും വിശ്വസനീയമായ കഥകളായിരുന്നു, വിശ്വസിക്കാൻ രണ്ടും എളുപ്പമായിരുന്നു. ഒന്നും ക്രാഷ് പുനഃസൃഷ്ടിച്ചില്ല. ഞങ്ങൾ വീണ്ടും വീണ്ടും പഠിക്കുന്ന പാഠം: ഒരു സിദ്ധാന്തം പരാജയം പുനഃസൃഷ്ടിക്കുന്നത് വരെ ഒരു കാരണമല്ല.
യഥാർത്ഥത്തിൽ പുനഃസൃഷ്ടിക്കുന്നു
ഉൽപ്പാദനത്തിലെ അതേ മെമ്മറി പരിധികളുള്ള ഒരു താൽക്കാലിക സാൻഡ്ബോക്സും, യാഥാർത്ഥ്യബോധമുള്ള മൂന്ന്-അക്ഷര കഷണങ്ങളിൽ ഒരു വലിയ ഫയൽ സ്ട്രീം ചെയ്യുന്ന ഒരു വ്യാജ മോഡലും ഞങ്ങൾ നിർമ്മിച്ചു. സോക്കറ്റിന്റെ മറുവശത്തെ റീഡർ യഥാർത്ഥ നെറ്റ്വർക്ക് പോലെ പതുക്കെയാക്കി.
അത് ചെയ്തു. ഹീപ്പ് ഉയർന്നു, അതേ പിശകോടെ പ്രോസസ്സ് മരിച്ചു.
മെക്കാനിസം കാണാൻ കഴിഞ്ഞപ്പോൾ ലളിതമായിരുന്നു. മോഡൽ ഒരു വലിയ കമാൻഡ് എഴുതുമ്പോൾ — ഈ സാഹചര്യത്തിൽ 124 KB ഫയൽ എഴുതിയ ഒരു heredoc — ഞങ്ങളുടെ സ്ട്രീമിംഗ് കോഡ് ഓരോ കഷണത്തിലും ടൂളിന്റെ ലേബൽ അപ്ഡേറ്റ് ചെയ്തു. ലേബൽ പുതിയ മൂന്ന് അക്ഷരങ്ങൾ ആയിരുന്നില്ല; അത് ഇതുവരെയുള്ള മുഴുവൻ കമാൻഡ് ആയിരുന്നു. അതിനാൽ ഇവന്റുകൾ വളർന്നു: 3 അക്ഷരം, പിന്നെ 6, പിന്നെ 9, … 124 KB വരെ, ഏകദേശം 41,000 തവണ. സോക്കറ്റിന് അവ ഉത്പാദിപ്പിക്കുന്നത്ര വേഗത്തിൽ അയയ്ക്കാൻ കഴിഞ്ഞില്ല, അതിനാൽ അവ സ്ട്രിംഗുകളായി അതിന്റെ റൈറ്റ് ബഫറിൽ കൂടിക്കൂടി — ഏകദേശം 690 MB.
പരിഹാരം
- ലേബൽ പരിമിതപ്പെടുത്തുക. ഒരു സ്റ്റാറ്റസ് ലേബൽ സംഭവിക്കുന്നത് പറഞ്ഞാൽ മതി. ഇപ്പോൾ അത് 200 അക്ഷരങ്ങളിൽ പരിമിതപ്പെടുത്തിയിരിക്കുന്നു, ഭാഗിക കമാൻഡ് വീണ്ടും സ്കാൻ ചെയ്യുന്നത് എത്ര തവണ എന്നത് ത്രോട്ടിൽ ചെയ്യുന്നു.
- ക്വാഡ്രാറ്റിക് കോൺകാറ്റനേഷൻ ഒഴിവാക്കുക. സ്ട്രീം ചെയ്ത കഷണങ്ങൾ ആവർത്തിച്ചുള്ള സ്ട്രിംഗ് കോൺകാറ്റനേഷൻ വഴി ചേർക്കുന്നത് വലിയ ഔട്ട്പുട്ടുകൾക്ക് O(n²) ആണ്. ലീനിയർ സമയത്ത് ചേർക്കുന്ന ഒരു ചങ്ക് അടിസ്ഥാനമാക്കിയ രീതിയിലേക്ക് മാറി.
തുടർന്ന്, ഒരു ഒഴുക്കിൽ അനിയന്ത്രിതമായി വളരാൻ കഴിയുന്ന മറ്റെന്തെങ്കിലുമുണ്ടോ എന്ന് ഞങ്ങൾ തിരഞ്ഞു, അവയെ പരിമിതപ്പെടുത്തി:
- ചാറ്റിൽ കാണിക്കുന്ന തത്സമയ കമാൻഡ് ഔട്ട്പുട്ട് ബാച്ച് ചെയ്യുകയും അവസാനത്തെ 8,000 അക്ഷരങ്ങൾ മാത്രം സൂക്ഷിക്കുകയും ചെയ്യുന്നു.
- ഓരോ ഇവന്റ് ലൈനും 4 MB ആയി പരിമിതപ്പെടുത്തി.
- വീണ്ടും കണക്റ്റ് ചെയ്ത ശേഷം ബ്രൗസർ പിടിക്കാൻ ഉപയോഗിക്കുന്ന റീപ്ലേ ബഫർ ഒരു പ്രോജക്റ്റിന് 8 MB ആയി പരിമിതപ്പെടുത്തി.
- ടേൺ മുന്നോട്ട് പോകുമ്പോൾ പഴയ ചെക്ക്പോയിന്റുകൾ പ്രൂൺ ചെയ്യുന്നു; ഏറ്റവും പുതിയ അവസ്ഥയും മുമ്പത്തെ ടേണുകൾക്ക് വേണ്ട ആങ്കറുകളും നിലനിർത്തുന്നു.
ഒഴുക്കുകൾ സത്യസന്ധമായി പരീക്ഷിക്കുന്നു
ഇത് പരീക്ഷിക്കുന്നത് ആവശ്യത്തിലധികം ബുദ്ധിമുട്ടാക്കിയ രണ്ട് കാര്യങ്ങൾ:
- യഥാർത്ഥ മോഡലുകൾ സഹകരിക്കില്ല. ഒരു ഭീമൻ ഫയൽ പ്രിന്റ് ചെയ്യാൻ ഒരു മോഡലിനോട് ചോദിച്ചാൽ അത് സാധാരണയായി നിരസിക്കും, സംഗ്രഹിക്കും, അല്ലെങ്കിൽ കൂടുതൽ സമജ്ഞസമായി എഴുതും. ഒഴുക്കുകൾ പരീക്ഷിക്കാൻ, നിങ്ങൾ പറയുന്നത് കൃത്യമായി ചെയ്യുന്ന ഒരു സ്ക്രിപ്റ്റ് ചെയ്ത മോഡൽ വേണം, യഥാർത്ഥ ഏജന്റ് കോഡിലൂടെ പ്രവർത്തിക്കുന്നത്.
- സ്ക്രിപ്റ്റുകൾ മോഡലുകളെപ്പോലെ പെരുമാറണം. ഞങ്ങളുടെ ആദ്യ സ്ക്രിപ്റ്റ് ചെയ്ത മോഡൽ ഓരോ മറുപടിയിലും ഒരേ റെസ്പോൺസ് ID വീണ്ടും ഉപയോഗിച്ചു, അതിനാൽ ഏജന്റ് ഫ്രെയിംവർക്ക് ഓരോ മറുപടിയെയും മുമ്പത്തേതിന്റെ പകരക്കാരനായി കണക്കാക്കി ടേണുകൾ നേരത്തെ അവസാനിപ്പിച്ചു. അത് ഒരു UI റീഫ്രഷ് ബഗ് പോലെ തോന്നി. അത് അങ്ങനെയായിരുന്നില്ല — ടെസ്റ്റ് ഹാർനെസ് ഞങ്ങളോട് കള്ളം പറയുകയായിരുന്നു. മെമ്മറി സംഖ്യകൾ യാഥാർത്ഥ്യബോധമില്ലാത്തതാകാതിരിക്കാൻ മോഡലിന്റെ യഥാർത്ഥ സന്ദർഭ പരിധി സ്ക്രിപ്റ്റിൽ നടപ്പിലാക്കേണ്ടി വന്നു.
ഞങ്ങൾ എടുത്ത പാഠങ്ങൾ
- സ്ട്രീമിംഗ് UI-കൾ ചെറിയ തെറ്റുകളെ പെരുക്കുന്നു. "ഓരോ കഷണത്തിനും" അയയ്ക്കുന്നതെന്തും പതിനായിരക്കണക്കിന് തവണ അയയ്ക്കപ്പെടുന്നു. ഡെൽറ്റകൾ അയയ്ക്കുക, അല്ലെങ്കിൽ പേലോഡ് പരിമിതപ്പെടുത്തുക.
- മന്ദഗതിയിലുള്ള അതിർത്തി കടക്കുന്ന ഓരോ ബഫറും പരിമിതപ്പെടുത്തുക. സോക്കറ്റുകൾ, റീപ്ലേ ലോഗുകൾ, ചെക്ക്പോയിന്റുകൾ എല്ലാത്തിനും ഒരു പരിധി വേണം.
- പരിഹരിക്കുന്നതിന് മുമ്പ് പുനഃസൃഷ്ടിക്കുക. ഞങ്ങളുടെ ആദ്യ രണ്ട് വിശദീകരണങ്ങൾ ശരിയെന്ന് തോന്നി, പക്ഷേ തെറ്റായിരുന്നു.
Mythex ചാറ്റിൽ അടുത്തിടെ വളരെ നീണ്ട ഒരു ഫയൽ ഏജന്റ് സ്തംഭിക്കാതെ പ്രത്യക്ഷപ്പെടുന്നത് നിങ്ങൾ കണ്ടിട്ടുണ്ടെങ്കിൽ, ഇതും അതിന്റെ ഭാഗമാണ്.