3 LangGraph Rewrites: Wat Production Checkpointing mij heeft geleerd

Drie weken lang verloor onze onboarding-agent elke taak die hij had moeten opslaan. De logs toonden niets. Geen fouten. Geen waarschuwingen. De checkpointer meldde succes, maar de state verdween bij het hervatten.

Ik heb dezelfde LangGraph-pipeline drie keer herschreven voordat ik de waarheid begreep. Het framework deed precies wat ik het vertelde. Ik gaf het simpelweg de verkeerde instructies.

Als je stateful agents bouwt voor productie, ga er dan niet vanuit dat de standaardinstellingen je zullen redden. Hier is wat er misging en hoe ik het heb opgelost.

De eerste fout: Silent State Loss

Mijn agent verwerkte een onboarding-flow van vijf stappen. Ik gebruikte Postgres om de voortgang op te slaan, zodat gebruikers later konden hervatten. Maar elke hervatting begon bij stap één.

De oorzaak was mijn state-schema. In LangGraph geeft elke node een update terug die wordt samengevoegd met de state. Als je niet specificeert hoe dit moet gebeuren, is de standaardinstelling 'overschrijven'.

Ik dacht dat mijn berichtenlijst zou worden aangevuld. In plaats daarvan verving elke nieuwe node de volledige geschiedenis met slechts één bericht. De checkpoint sloeg de verkeerde gegevens perfect op.

De oplossing: Gebruik Annotated velden met expliciete reducers.

• Gebruik de add operator voor berichtenlijsten. • Gebruik een aangepaste merge-functie voor dictionaries. • Gebruik de standaard overschrijfoptie alleen voor enkelvoudige waarden zoals "step".

De tweede fout: Deserialization en Concurrency

De tweede herschrijving kreeg te maken met twee nieuwe problemen:

  1. Corrupte rijen: Ik sloeg aangepaste objecten op in de state. De serializer kon deze niet verwerken. Dit resulteerde in rijen die wel bestonden, maar onbruikbaar waren.
  2. Dubbele sleutels: WhatsApp probeert webhooks opnieuw te verzenden als je niet snel genoeg reageert. Als er twee berichten tegelijk aankwamen, probeerden twee graph-runs naar dezelfde thread te schrijven. Dit veroorzaakte database-conflicten.

De oplossingen: • Verwijder aangepaste objecten. Gebruik alleen gewone dicts en standaard LangChain-typen. • Verwerk webhooks buiten de graph. Gebruik een queue en een idempotency-sleutel om duplicaten te verwijderen. • Voeg een database lock toe. Zorg ervoor dat er slechts één run per thread tegelijk plaatsvindt.

De derde herschrijving: Het stabiele patroon

De definitieve versie richtte zich op drie principes:

• 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