Model agent workflows as state graphs with checkpoints and explicit control flow.
LangGraph gives agent apps named state transitions.
Learners see LangGraph as explicit workflow modeling.
Why this matters: This prevents using graph machinery without a state problem to solve.
Problem anchor: a tutor must retrieve sources, answer, run a citation check, and ask for human review when the check fails. A single loop hides those stages. A graph names them.
LangGraph nodes read and update shared state; edges decide the next node. The compiled graph runs until END, and checkpoints can persist thread state.
State fields include question, evidence, draft, review_status, and final_answer. Nodes retrieve, draft, review, and either finish or request revision.
The graph makes the failure branch visible: unsupported citations route back to retrieval or revision instead of slipping into final output.
State design is the heart of LangGraph.
Learners design graph state safely.
Why this matters: Unstructured state makes routes brittle and privacy harder.
It is tempting to put every message, scratch note, tool result, and prompt into state. That creates a junk drawer. Keep exact user requirements, durable decisions, needed evidence IDs, and route status; store bulky artifacts elsewhere by reference.
Reducers or merge rules matter when nodes append messages, evidence, or findings. Without them, later nodes may overwrite or duplicate data silently.
| Option | Field type | Keep when | Risk | When to choose | Cost | Complexity |
|---|---|---|---|---|---|---|
| Exact constraints | User requirements and approval decisions. | Needed by later routes. | Summaries can erase them. | Keep in typed state. | Low | Medium |
| Evidence IDs | Source IDs and snippets. | Review/final answer needs grounding. | Too much text bloats state. | Store IDs plus compact snippets. | Medium | Medium |
| Secrets/full prompts | Credentials or giant prompt dumps. | Almost never. | Privacy, retention, replay bloat. | Use references or secure stores instead. | High | High |
LangGraph interrupts turn waiting into resumable control flow.
Learners understand persistence and interrupt flow.
Why this matters: Approval gates break if state cannot resume safely.
With a checkpointer, a graph run can be associated with a thread_id and resumed later. Interrupts surface a JSON-serializable request to the caller and continue when the graph is invoked with a resume command.
Avoid irreversible side effects immediately before an interrupt, because resume semantics and retries can surprise you. Put side effects after approval or behind idempotent tools.
The graph drafts lesson content, runs a citation check, then interrupts with the draft, sources, and risk summary. The human approves or requests revision.
The resumed graph branches to publish only if approval is explicit.
Conditional edges deserve unit tests.
Learners see graph decisions in runnable code.
Why this matters: Route bugs can silently skip safety nodes.
The model may produce a draft, but route functions decide whether the graph ends, retries, or interrupts. Treat them like production code with tests.
Spaced recall: from evaluation, hard assertions should catch missing citations or invalid schema before final output. Route based on those checks, not vibes.
def review_answer(state): citations_ok = all(claim in state["evidence"] for claim in state["claims"]) return {**state, "review_status": "pass" if citations_ok else "needs_revision"} def route(state): if state["review_status"] == "pass": return "final" return "revise" state = {"claims": ["LangGraph uses nodes"], "evidence": ["LangGraph uses nodes"], "review_status": None} reviewed = review_answer(state) print(route(reviewed))
It prints final because every claim appears in the evidence list.
LangGraph eval includes topology behavior.
Learners define LangGraph release checks.
Why this matters: A graph can render valid output while hiding skipped nodes or bad state merges.
Trace representative runs and assert that retrieval, review, approval, and final nodes appear when expected. Compare graph outcomes against a simpler baseline to justify complexity.
Failure modes include junk-drawer state, wrong conditional routes, non-idempotent side effects before interrupts, stale checkpoints, and overlong state histories.
Review the graph trace with final answer.
Retrieval prompt: reconstruct LangGraph by naming state schema, nodes, updates, edges, conditional routing, checkpointer, thread_id, interrupt, and route tests.
Sketch a LangGraph tutor workflow with plan, retrieve, answer, review, and interrupt-before-publish nodes. Define state fields, routes, checkpoint key, tests, and what must stay out of state. Next rung: build agent workflows with LangGraph.
A StateGraph node receives the current state and returns {"status": "approved"}. The state also has a count field that the node never touches. What happens to count after this node runs?
LangGraph applies partial state updates — a node only needs to return the fields it changed, and all other fields carry over untouched.
You want every tool call result to be appended to a tool_outputs list rather than overwriting it. Which approach is correct?
Reducers tell LangGraph how to combine a new value with the existing field value — operator.add on a list means append, not overwrite.
A human-approval step uses interrupt() before sending an email. The graph is replayed after approval. Why is it important that the email-sending side effect happens AFTER the interrupt, not before?
When a graph resumes from a checkpoint, nodes before the interrupt can be re-run, so non-idempotent actions like sending an email must come after the interrupt to avoid duplicates.
Write the Python return value a conditional routing function should produce to direct the graph to a node called "escalate" instead of "auto_approve".
A conditional edge routing function returns a string that matches one of the edge targets registered with add_conditional_edges.
When writing tests for a LangGraph workflow, which of the following best validates that a human-approval interrupt works correctly?
Testing interrupts requires actually running the graph to the pause point, then resuming with a value and asserting that downstream nodes ran — compile-time checks alone can't catch runtime flow errors.