𝟯 LangGraph ਰੀ-ਰਾਈਟਸ: ਪ੍ਰੋਡਕਸ਼ਨ ਚੈੱਕਪੁਆਇੰਟਿੰਗ ਨੇ ਮੈਨੂੰ ਕੀ ਸਿਖਾਇਆ
ਤਿੰਨ ਹਫ਼ਤਿਆਂ ਤੱਕ, ਸਾਡੇ ਆਨਬੋਰਡਿੰਗ ਏਜੰਟ ਨੇ ਉਹ ਹਰ ਕੰਮ ਗੁਆ ਦਿੱਤਾ ਜੋ ਉਸਨੂੰ ਸੇਵ ਕਰਨਾ ਸੀ। ਲੌਗਸ ਵਿੱਚ ਕੁਝ ਵੀ ਨਹੀਂ ਦਿਖ ਰਿਹਾ ਸੀ। ਕੋਈ ਐਰਰ ਨਹੀਂ। ਕੋਈ ਵਾਰਨਿੰਗ ਨਹੀਂ। ਚੈੱਕਪੁਆਇੰਟਰ ਨੇ ਸਫਲਤਾ ਦੀ ਰਿਪੋਰਟ ਦਿੱਤੀ, ਪਰ ਰੈਜ਼ਿਊਮ (resume) ਕਰਨ 'ਤੇ ਸਟੇਟ (state) ਗਾਇਬ ਹੋ ਗਈ।
ਸੱਚਾਈ ਸਮਝਣ ਤੋਂ ਪਹਿਲਾਂ ਮੈਂ ਉਸੇ LangGraph ਪਾਈਪਲਾਈਨ ਨੂੰ ਤਿੰਨ ਵਾਰ ਦੁਬਾਰਾ ਲਿਖਿਆ। ਫਰੇਮਵਰਕ ਨੇ ਉਹੀ ਕੀਤਾ ਜੋ ਮੈਂ ਉਸਨੂੰ ਕਰਨ ਲਈ ਕਿਹਾ ਸੀ। ਮੈਂ ਸਿਰਫ਼ ਇਸਨੂੰ ਗਲਤ ਹਦਾਇਤਾਂ ਦੇ ਰਿਹਾ ਸੀ।
ਜੇਕਰ ਤੁਸੀਂ ਪ੍ਰੋਡਕਸ਼ਨ ਲਈ stateful ਏਜੰਟ ਬਣਾਉਂਦੇ ਹੋ, ਤਾਂ ਇਹ ਨਾ ਮੰਨੋ ਕਿ ਡਿਫੌਲਟ ਸੈਟਿੰਗਾਂ ਤੁਹਾਨੂੰ ਬਚਾ ਲੈਣਗੀਆਂ। ਇੱਥੇ ਦੱਸਿਆ ਗਿਆ ਹੈ ਕਿ ਕੀ ਖਰਾਬ ਹੋਇਆ ਅਤੇ ਮੈਂ ਇਸਨੂੰ ਕਿਵੇਂ ਠੀਕ ਕੀਤਾ।
𝗧𝗵𝗲 𝗙𝗶𝗿𝘀𝘁 𝗕𝗿𝗲𝗮𝗸: 𝗦𝗶𝗹𝗲𝗻𝘁 𝗦𝘁𝗮𝘁𝗲 𝗟𝗼𝘀𝘀
ਮੇਰਾ ਏਜੰਟ ਪੰਜ-ਸਟੈਪ ਵਾਲੇ ਆਨਬੋਰਡਿੰਗ ਫਲੋਅ ਨੂੰ ਸੰਭਾਲਦਾ ਸੀ। ਮੈਂ ਪ੍ਰਗਤੀ (progress) ਨੂੰ ਸੇਵ ਕਰਨ ਲਈ Postgres ਦੀ ਵਰਤੋਂ ਕੀਤੀ ਤਾਂ ਜੋ ਯੂਜ਼ਰ ਬਾਅਦ ਵਿੱਚ ਰੈਜ਼ਿਊਮ ਕਰ ਸਕਣ। ਪਰ ਹਰ ਰੈਜ਼ਿਊਮ ਪਹਿਲੇ ਸਟੈਪ ਤੋਂ ਸ਼ੁਰੂ ਹੁੰਦਾ ਸੀ।
ਇਸਦਾ ਕਾਰਨ ਮੇਰਾ state schema ਸੀ। LangGraph ਵਿੱਚ, ਹਰ ਨੋਡ ਇੱਕ ਅਪਡੇਟ ਵਾਪਸ ਕਰਦਾ ਹੈ ਜੋ ਸਟੇਟ ਵਿੱਚ ਮਰਜ (merge) ਹੋ ਜਾਂਦਾ ਹੈ। ਜੇਕਰ ਤੁਸੀਂ ਇਹ ਨਹੀਂ ਦੱਸਦੇ ਕਿ ਮਰਜ ਕਿਵੇਂ ਕਰਨਾ ਹੈ, ਤਾਂ ਡਿਫੌਲਟ ਤੌਰ 'ਤੇ ਇਹ ਪੁਰਾਣੇ ਡੇਟਾ ਨੂੰ ਓਵਰਰਾਈਟ (overwrite) ਕਰ ਦਿੰਦਾ ਹੈ।
ਮੈਨੂੰ ਲੱਗਿਆ ਕਿ ਮੇਰੀ ਮੈਸੇਜ ਲਿਸਟ ਵਿੱਚ ਨਵੇਂ ਮੈਸੇਜ ਜੁੜਦੇ ਜਾਣਗੇ (append)। ਇਸਦੇ ਉਲਟ, ਹਰ ਨਵੇਂ ਨੋਡ ਨੇ ਪੂਰੀ ਹਿਸਟਰੀ ਨੂੰ ਸਿਰਫ਼ ਇੱਕ ਮੈਸੇਜ ਨਾਲ ਬਦਲ ਦਿੱਤਾ। ਚੈੱਕਪੁਆਇੰਟ ਨੇ ਗਲਤ ਡੇਟਾ ਨੂੰ ਬਿਲਕੁਲ ਸਹੀ ਤਰੀਕੇ ਨਾਲ ਸੇਵ ਕਰ ਲਿਆ।
ਹੱਲ: ਸਪੱਸ਼ਟ (explicit) reducers ਦੇ ਨਾਲ Annotated ਫੀਲਡਸ ਦੀ ਵਰਤੋਂ ਕਰੋ।
• ਮੈਸੇਜ ਲਿਸਟਾਂ ਲਈ add ਓਪਰੇਟਰ ਦੀ ਵਰਤੋਂ ਕਰੋ।
• ਡਿਕਸ਼ਨਰੀਜ਼ (dictionaries) ਲਈ ਇੱਕ ਕਸਟਮ ਮਰਜ ਫੰਕਸ਼ਨ ਦੀ ਵਰਤੋਂ ਕਰੋ।
• ਡਿਫੌਲਟ ਓਵਰਰਾਈਟ ਦੀ ਵਰਤੋਂ ਸਿਰਫ਼ "step" ਵਰਗੀਆਂ ਸਿੰਗਲ ਵੈਲਯੂਜ਼ ਲਈ ਕਰੋ।
𝗧𝗵𝗲 𝗦𝗲𝗰𝗼𝗻𝗱 𝗕𝗿𝗲𝗮𝗸: 𝗗𝗲𝘀𝗲𝗿𝗶𝗮𝗹𝗶𝘇𝗮𝘁𝗶𝗼𝗻 𝗮𝗻𝗱 𝗖𝗼𝗻𝗰𝘂𝗿𝗿𝗲𝗻𝗰𝘆
ਦੂਜੀ ਵਾਰ ਲਿਖਣ ਵੇਲੇ ਦੋ ਨਵੀਆਂ ਸਮੱਸਿਆਵਾਂ ਆਹਮੋ-ਸਾਹਮਣੇ ਆਈਆਂ:
- ਖਰਾਬ ਰੋਅਜ਼ (Corrupt rows): ਮੈਂ ਸਟੇਟ ਵਿੱਚ ਕਸਟਮ ਆਬਜੈਕਟਸ ਸਟੋਰ ਕੀਤੇ ਸਨ। ਸੀਰੀਅਲਾਈਜ਼ਰ (serializer) ਉਹਨਾਂ ਨੂੰ ਸੰਭਾਲ ਨਹੀਂ ਸਕਿਆ। ਇਸ ਨਾਲ ਅਜਿਹੀਆਂ ਰੋਅਜ਼ ਬਣੀਆਂ ਜੋ ਮੌਜੂਦ ਤਾਂ ਸਨ ਪਰ ਵਰਤੋਂ ਯੋਗ ਨਹੀਂ ਸਨ।
- ਡੁਪਲੀਕੇਟ ਕੀਜ਼ (Duplicate keys): ਜੇਕਰ ਤੁਸੀਂ ਤੇਜ਼ੀ ਨਾਲ ਜਵਾਬ ਨਹੀਂ ਦਿੰਦੇ ਤਾਂ WhatsApp ਵੈੱਬਹੁਕਸ (webhooks) ਨੂੰ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰਦਾ ਹੈ। ਜੇਕਰ ਇੱਕੋ ਸਮੇਂ ਦੋ ਮੈਸੇਜ ਆ ਗਏ, ਤਾਂ ਦੋ ਗ੍ਰਾਫ ਰਨ ਇੱਕੋ ਥ੍ਰੈਡ (thread) ਵਿੱਚ ਲਿਖਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰਨ ਲੱਗੇ। ਇਸ ਨਾਲ ਡੇਟਾਬੇਸ ਕੋਲੀਜ਼ਨ (collisions) ਹੋਏ।
ਹੱਲ: • ਕਸਟਮ ਆਬਜੈਕਟਸ ਨੂੰ ਹਟਾ ਦਿਓ। ਸਿਰਫ਼ ਸਾਧਾਰਨ dicts ਅਤੇ ਸਟੈਂਡਰਡ LangChain ਟਾਈਪਸ ਦੀ ਵਰਤੋਂ ਕਰੋ। • ਵੈੱਬਹੁਕਸ ਨੂੰ ਗ੍ਰਾਫ ਤੋਂ ਬਾਹਰ ਸੰਭਾਲੋ। ਡੁਪਲੀਕੇਟਸ ਨੂੰ ਹਟਾਉਣ ਲਈ ਇੱਕ ਕਿਊ (queue) ਅਤੇ idempotency key ਦੀ ਵਰਤੋਂ ਕਰੋ। • ਡੇਟਾਬੇਸ ਲੌਕ (lock) ਜੋੜੋ। ਯਕੀਨੀ ਬਣਾਓ ਕਿ ਇੱਕ ਸਮੇਂ 'ਤੇ ਇੱਕ ਥ੍ਰੈਡ ਲਈ ਸਿਰਫ਼ ਇੱਕ ਹੀ ਰਨ ਹੋਵੇ।
𝗧𝗵𝗲 𝗧𝗵𝗶𝗿𝗱 𝗥𝗲𝘄𝗿𝗶𝘁𝗲: 𝗧𝗵𝗲 𝗦𝘁𝗮𝗯𝗹𝗲 𝗣𝗮𝘁𝘁𝗲𝗿𝗻
ਅੰਤਿਮ ਵਰਜ਼ਨ ਤਿੰਨ ਸਿਧਾਂਤਾਂ 'ਤੇ ਕੇਂਦਰਿਤ ਸੀ:
• 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.
Optional learning community: https://t.me/GyaanSetuAi