Lab · Advanced · 90 min
LangGraph Interrupt Before a Write Tool
Build a support agent that drafts refunds, pauses with interrupt() for human approval, resumes on the same thread, and never double-charges on resume.
LangChain / LangGraph
Show all 4 stepsHide list
Step 1 of 4
Lab brief
Goal
A checkpointed graph with an approval step, idempotent side effects, and a test that proves resume safety.
Failure mode
The refund API is called before interrupt() in the same node; on resume the node reruns and the customer is refunded twice.
Staff move
Put approval in its own node, perform side effects only after approval with an idempotency key, and test the resume path explicitly.
Step 2 of 4
1. Graph shape
START → classify → draft_refund → approve (interrupt) ─┬─ approve → execute_refund → notify → END
└─ reject → explain → END- State: messages (add_messages reducer), order_id, amount, decision, refund_id
- Compile with a checkpointer (in-memory for tests, Postgres for real)
- approve node: decision = interrupt({order_id, amount, reason}); return Command(goto=...)
Step 3 of 4
2. Make resume safe
- No side effects in approve before interrupt()
- execute_refund passes idempotency_key = f"{thread_id}:{order_id}" to the payments API
- Store refund_id in state; skip the call if it is already set
Step 4 of 4
3. Verify
- Invoke with thread_id t1 → graph pauses, interrupt payload returned
- Invoke Command(resume='approve') on t1 → exactly one refund call
- Simulate a crash after execute_refund and resume → still exactly one refund
- Trace the run in LangSmith (or logs) and screenshot it for your portfolio