3 LangGraph റീറൈറ്റുകൾ: പ്രൊഡക്ഷൻ ചെക്ക്‌പോയിന്റിംഗ് എന്നെ പഠിപ്പിച്ചത്

മൂന്ന് ആഴ്ചകളോളം, ഞങ്ങളുടെ ഓൺബോർഡിംഗ് ഏജന്റ് സേവ് ചെയ്യേണ്ടിയിരുന്ന എല്ലാ ജോബുകളും നഷ്ടപ്പെട്ടു. ലോഗുകളിൽ ഒന്നും കാണിച്ചില്ല. പിശകുകളോ (errors) മുന്നറിയിപ്പുകളോ (warnings) ഇല്ല. ചെക്ക്‌പോയിന്റർ വിജയം റിപ്പോർട്ട് ചെയ്തു, പക്ഷേ വീണ്ടും തുടങ്ങുമ്പോൾ (resume) സ്റ്റേറ്റ് (state) അപ്രത്യക്ഷമായി.

സത്യം മനസ്സിലാക്കുന്നതിന് മുമ്പ് ഞാൻ ഒരേ LangGraph പൈപ്പ്‌ലൈൻ മൂന്ന് തവണ റീറൈറ്റ് ചെയ്തു. ഫ്രെയിംവർക്ക് ഞാൻ പറഞ്ഞത് കൃത്യമായി ചെയ്തു. ഞാൻ തെറ്റായ നിർദ്ദേശങ്ങളാണ് നൽകിക്കൊണ്ടിരുന്നത്.

നിങ്ങൾ പ്രൊഡക്ഷനായി സ്റ്റേറ്റ്‌ഫുൾ ഏജന്റുകൾ (stateful agents) നിർമ്മിക്കുകയാണെങ്കിൽ, ഡിഫോൾട്ട് സെറ്റിംഗുകൾ മാത്രം വിശ്വസിക്കരുത്. എന്താണ് തകരാറിലായതെന്നും ഞാൻ അത് എങ്ങനെ പരിഹരിച്ചുവെന്നും താഴെ നൽകുന്നു.

ആദ്യത്തെ തകരാർ: സൈലന്റ് സ്റ്റേറ്റ് ലോസ് (Silent State Loss)

എന്റെ ഏജന്റ് അഞ്ച് ഘട്ടങ്ങളുള്ള ഒരു ഓൺബോർഡിംഗ് ഫ്ലോ കൈകാര്യം ചെയ്യുന്നുണ്ടായിരുന്നു. ഉപയോക്താക്കൾക്ക് പിന്നീട് തുടരാൻ പാകത്തിൽ പ്രോഗ്രസ് സേവ് ചെയ്യാൻ ഞാൻ Postgres ഉപയോഗിച്ചു. എന്നാൽ ഓരോ തവണ വീണ്ടും തുടങ്ങുമ്പോഴും ഒന്നാം ഘട്ടത്തിൽ നിന്നാണ് തുടങ്ങുന്നത്.

ഇതിന്റെ കാരണം എന്റെ സ്റ്റേറ്റ് സ്കീമ (state schema) ആയിരുന്നു. LangGraph-ൽ, ഓരോ നോഡും സ്റ്റേറ്റിലേക്ക് ലയിപ്പിക്കുന്ന (merge) ഒരു അപ്‌ഡേറ്റ് നൽകുന്നു. എങ്ങനെ മെർജ് ചെയ്യണമെന്ന് നിങ്ങൾ നിർദ്ദേശിച്ചില്ലെങ്കിൽ, പഴയത് മാറ്റി പുതിയത് ചേർക്കുക (overwrite) എന്നതാണ് ഡിഫോൾട്ട് രീതി.

എന്റെ മെസ്സേജ് ലിസ്റ്റ് കൂട്ടിച്ചേർക്കപ്പെടുമെന്നാണ് (append) ഞാൻ കരുതിയത്. എന്നാൽ ഓരോ പുതിയ നോഡും മുഴുവൻ ഹിസ്റ്ററിയും മാറ്റി പകരം ഒരു മെസ്സേജ് മാത്രം നൽകി. ചെക്ക്‌പോയിന്റർ തെറ്റായ ഡാറ്റ കൃത്യമായി സേവ് ചെയ്തു.

പരിഹാരം: വ്യക്തമായ റിഡ്യൂസറുകൾ (reducers) ഉള്ള Annotated ഫീൽഡുകൾ ഉപയോഗിക്കുക.

• മെസ്സേജ് ലിസ്റ്റുകൾക്കായി add ഓപ്പറേറ്റർ ഉപയോഗിക്കുക. • ഡിക്ഷണറികൾക്കായി ഒരു കസ്റ്റം മെർജ് ഫംഗ്ഷൻ ഉപയോഗിക്കുക. • "step" പോലുള്ള ഒറ്റ മൂല്യങ്ങൾക്ക് (single values) മാത്രം ഡിഫോൾട്ട് ഓവർറൈറ്റ് ഉപയോഗിക്കുക.

രണ്ടാമത്തെ തകരാർ: ഡീസീരിയലൈസേഷനും കൺകറൻസിയും (Deserialization and Concurrency)

രണ്ടാമത്തെ റീറൈറ്റിൽ രണ്ട് പുതിയ പ്രശ്നങ്ങൾ നേരിട്ടു:

  1. കറപ്റ്റ് റോകൾ (Corrupt rows): ഞാൻ സ്റ്റേറ്റിൽ കസ്റ്റം ഒബ്‌ജക്റ്റുകൾ സൂക്ഷിച്ചു. സെറിയലൈസർക്ക് (serializer) അവ കൈകാര്യം ചെയ്യാൻ കഴിഞ്ഞില്ല. ഇത് ഉപയോഗശൂന്യമായ റോകൾ സൃഷ്ടിച്ചു.
  2. ഡ്യൂപ്ലിക്കേറ്റ് കീകൾ (Duplicate keys): നിങ്ങൾ വേഗത്തിൽ പ്രതികരിച്ചില്ലെങ്കിൽ WhatsApp വെബ്‌ഹുക്കുകൾ (webhooks) വീണ്ടും അയക്കും. ഒരേസമയം രണ്ട് മെസ്സേജുകൾ വന്നാൽ, രണ്ട് ഗ്രാഫ് റണ്ണുകൾ ഒരേ ത്രെഡിൽ (thread) എഴുതാൻ ശ്രമിക്കും. ഇത് ഡാറ്റാബേസ് കൊളിഷനുകൾക്ക് (database collisions) കാരണമായി.

പരിഹാരങ്ങൾ: • കസ്റ്റം ഒബ്‌ജക്റ്റുകൾ ഒഴിവാക്കുക. പ്ലെയിൻ ഡിക്റ്റുകളും (plain dicts) സ്റ്റാൻഡേർഡ് LangChain ടൈപ്പുകളും മാത്രം ഉപയോഗിക്കുക. • വെബ്‌ഹുക്കുകൾ ഗ്രാഫിന് പുറത്ത് കൈകാര്യം ചെയ്യുക. ഡ്യൂപ്ലിക്കേറ്റുകൾ ഒഴിവാക്കാൻ ഒരു ക്യൂവും (queue) ഐഡെംപോട്ടൻസി കീയും (idempotency key) ഉപയോഗിക്കുക. • ഒരു ഡാറ്റാബേസ് ലോക്ക് (database lock) ചേർക്കുക. ഓരോ ത്രെഡിലും ഒരേസമയം ഒരു റൺ മാത്രമേ നടക്കുന്നുള്ളൂ എന്ന് ഉറപ്പാക്കുക.

മൂന്നാമത്തെ റീറൈറ്റ്: സ്റ്റേബിൾ പാറ്റേൺ (The Stable Pattern)

അവസാന പതിപ്പ് മൂന്ന് തത്വങ്ങളിൽ ശ്രദ്ധ കേന്ദ്രീകരിച്ചു:

• Small graphs: I broke one massive graph into three smaller subgraphs. This reduced the blast radius of bugs. • Explicit checkpoints: I stopped checkpointing after every single node. I only checkpoint at meaningful resume points. This cut database writes by 60%. • Idempotent nodes: This is vital. Every node must produce the same result if it runs twice. If a node sees that a task is already done in the state, it should return immediately. This prevents double-charging for expensive model calls.

𝗟𝗲𝘀𝘀𝗼𝗻𝘀 𝗳𝗼𝗿 𝘆𝗼𝘂:

  • Read reducer semantics before you write code.
  • Do not store custom objects in state.
  • Move concurrency control outside the graph.
  • Make every node idempotent.

The framework did not fail. My assumptions did.

Source: https://dev.to/elenarevicheva/three-langgraph-rewrites-what-production-checkpointing-actually-taught-me-ok9

Optional learning community: https://t.me/GyaanSetuAi