𝟯 𝗟𝗮𝗻𝗴𝗚𝗿𝗮𝗽𝗵 𝗥𝗲𝘄𝗿𝗶𝘁𝗲𝘀: 𝗪𝗵𝗮𝘁 𝗣𝗿𝗼𝗱𝘂𝗰𝘁𝗶𝗼𝗻 𝗖𝗵𝗲𝗰𝗸𝗽𝗼𝗶𝗻𝘁𝗶𝗻𝗴 𝗧𝗮𝘂𝗴𝗵𝘁 𝗠𝗲
तीन आठवड्यांपासून, आमचा ऑनबोर्डिंग एजंट (onboarding agent) त्याने सेव्ह करायला हवे असलेले प्रत्येक काम गमावत होता. लॉग्समध्ये काहीही दिसत नव्हते. कोणतीही एरर नाही. कोणतीही वॉर्निंग नाही. चेकपॉइंटरने (checkpointer) यश दर्शवले होते, परंतु रिझ्युम (resume) करताना स्टेट (state) गायब होत होती.
सत्य समजण्यापूर्वी मी तीच LangGraph पाइपलाइन तीन वेळा पुन्हा लिहिली. फ्रेमवर्कने अगदी तसेच केले जे मी त्याला सांगितले होते. मी फक्त त्याला चुकीच्या सूचना देत होतो.
जर तुम्ही प्रोडक्शनसाठी स्टेटफुल एजंट्स (stateful agents) बनवत असाल, तर डिफॉल्ट सेटिंग्स तुम्हाला वाचवतील असे समजू नका. काय बिघडले आणि मी ते कसे दुरुस्त केले, ते खाली दिले आहे.
𝗧𝗵𝗲 𝗙𝗶𝗿𝘀𝘁 𝗕𝗿𝗲𝗮𝗸: 𝗦𝗶𝗹𝗲𝗻𝘁 𝗦𝘁𝗮𝘁𝗲 𝗟𝗼𝘀𝘀
माझा एजंट पाच-टप्प्यांचा ऑनबोर्डिंग फ्लो (onboarding flow) हाताळत होता. युजर्सना नंतर पुन्हा सुरू करता यावे यासाठी मी प्रोग्रेस सेव्ह करण्यासाठी Postgres वापरले होते. परंतु, प्रत्येक वेळी रिझ्युम केल्यावर प्रक्रिया पहिल्या टप्प्यापासून सुरू होत होती.
याचे कारण माझे स्टेट स्कीमा (state schema) होते. LangGraph मध्ये, प्रत्येक नोड (node) एक अपडेट रिटर्न करतो जो स्टेटमध्ये मर्ज होतो. जर तुम्ही मर्ज कसे करायचे हे निर्दिष्ट केले नाही, तर डिफॉल्टनुसार ते ओव्हरराईट (overwrite) होते.
मला वाटले की माझी मेसेज लिस्ट ॲपेंड (append) होईल. त्याऐवजी, प्रत्येक नवीन नोडने संपूर्ण हिस्ट्री बदलून फक्त एकच मेसेज ठेवला. चेकपॉइंटने चुकीचा डेटा अगदी अचूकपणे सेव्ह केला होता.
उपाय: स्पष्ट रिड्यूसर्ससह (explicit reducers) Annotated फील्ड्स वापरा.
• मेसेज लिस्टसाठी add ऑपरेटर वापरा.
• डिक्शनरीसाठी कस्टम मर्ज फंक्शन वापरा.
• "step" सारख्या सिंगल व्हॅल्यूजसाठीच डिफॉल्ट ओव्हरराईट वापरा.
𝗧𝗵𝗲 𝗦𝗲𝗰𝗼𝗻𝗱 𝗕𝗿𝗲𝗮𝗸: 𝗗𝗲𝘀𝗲𝗿𝗶𝗮𝗹𝗶𝘇𝗮𝘁𝗶𝗼𝗻 𝗮𝗻𝗱 𝗖𝗼𝗻𝗰𝘂𝗿𝗿𝗲𝗻𝗰𝘆
दुसऱ्या रीराईटमध्ये दोन नवीन समस्या आल्या:
- करप्ट रो (Corrupt rows): मी स्टेटमध्ये कस्टम ऑब्जेक्ट्स स्टोअर केले होते. सीरियलायझर (serializer) ते हाताळू शकला नाही. यामुळे अशा रो (rows) तयार झाल्या ज्या अस्तित्वात होत्या पण वापरण्यायोग्य नव्हत्या.
- डुप्लिकेट कीज (Duplicate keys): जर तुम्ही वेगाने प्रतिसाद दिला नाही तर WhatsApp वेबहुक्स (webhooks) पुन्हा प्रयत्न करते. जर दोन मेसेज एकाच वेळी आले, तर दोन ग्राफ रन एकाच थ्रेडमध्ये लिहिण्याचा प्रयत्न करतात. यामुळे डेटाबेस कोलिजन (database collisions) झाले.
उपाय: • कस्टम ऑब्जेक्ट्स काढून टाका. फक्त साधे dicts आणि स्टँडर्ड LangChain टाइप्स वापरा. • वेबहुक्स ग्राफच्या बाहेर हाताळा. डुप्लिकेट्स टाळण्यासाठी क्यू (queue) आणि आयडेम्पोटन्सी की (idempotency key) वापरा. • डेटाबेस लॉक जोडा. एका वेळी एका थ्रेडसाठी फक्त एकच रन होईल याची खात्री करा.
𝗧𝗵𝗲 𝗧𝗵𝗶𝗿𝗱 𝗥𝗲𝘄𝗿𝗶𝘁𝗲: 𝗧𝗵𝗲 𝗦𝘁𝗮𝗯𝗹𝗲 𝗣𝗮𝘁𝘁𝗲𝗿𝗻
अंतिम आवृत्ती तीन तत्त्वांवर लक्ष केंद्रित करते:
• लहान ग्राफ्स: मी एका मोठ्या ग्राफला तीन लहान सबग्राफ्समध्ये विभागले. यामुळे बग्सचा प्रसार (blast radius) कमी झाला. • स्पष्ट चेकपॉइंट्स: मी प्रत्येक नोड नंतर चेकपॉइंटिंग करणे थांबवले. मी फक्त अर्थपूर्ण रिझ्युम पॉइंट्सवर (resume points) चेकपॉइंट करतो. यामुळे डेटाबेस राइट्समध्ये ६०% घट झाली. • Idempotent नोड्स: हे अत्यंत महत्त्वाचे आहे. जर एखादा नोड दोनदा चालला, तर त्याने तोच निकाल देणे आवश्यक आहे. जर नोडला आढळले की स्टेटमध्ये एखादे काम आधीच पूर्ण झाले आहे, तर त्याने लगेच रिझल्ट परत केला पाहिजे. यामुळे महागड्या मॉडेल कॉल्ससाठी (model calls) दुहेरी शुल्क आकारले जाण्यापासून बचाव होतो.
तुमच्यासाठी धडे:
- कोड लिहिण्यापूर्वी reducer semantics वाचा.
- स्टेटमध्ये (state) कस्टम ऑब्जेक्ट्स साठवू नका.
- concurrency control ग्राफच्या बाहेर हलवा.
- प्रत्येक नोड idempotent बनवा.
फ्रेमवर्कमध्ये चूक नव्हती. माझ्या गृहितकांमध्ये चूक होती.
वैकल्पिक लर्निंग कम्युनिटी: https://t.me/GyaanSetuAi