Course Content
LangGraph Agents
7 sections · 49 lessons
How do you implement a loop (reflection / critique-revise / retry) safely without infinite cycles?
What you need to know
Python
1from typing import TypedDict2from langgraph.graph import StateGraph, START, END34class State(TypedDict):5 draft: str6 approved: bool7 revisions: int8 feedback: str910def write(state: State) -> dict:11 return {"draft": f"draft v{state['revisions'] + 1}", "revisions": state["revisions"] + 1}1213def critique(state: State) -> dict:14 ok = state["revisions"] >= 2 # stand-in for an LLM critic15 return {"approved": ok, "feedback": "" if ok else "add a source for the figure"}1617def should_continue(state: State) -> str:18 if state["approved"] or state["revisions"] >= 3:19 return "finalise"20 return "write"2122builder = StateGraph(State)23builder.add_node("write", write)24builder.add_node("critique", critique)25builder.add_node("finalise", lambda s: {})26builder.add_edge(START, "write")27builder.add_edge("write", "critique")28builder.add_conditional_edges("critique", should_continue, ["write", "finalise"])29builder.add_edge("finalise", END)30graph = builder.compile()31print(graph.invoke({"draft": "", "approved": False, "revisions": 0, "feedback": ""},32 {"recursion_limit": 20}))The guards
- Semantic exit —
approvedfrom a structured critic. - Budget —
revisions >= 3, incremented by a node, stored in state. - Backstop —
recursion_limitin the config. Each super-step counts as one step. When exceeded, the run raisesGraphRecursionError. In LangGraph 1.x the default is no longer 25 but a very large number, so a missing exit can burn money for a long time unless you set it.
Useful extras
- No-progress detection — stop if the new draft or the critic's feedback repeats the last one.
RemainingSteps— a managed state value (remaining_steps: RemainingSteps) that tells a node how many steps are left before the limit, so it can finish gracefully.- Best-so-far — keep the highest-scoring draft in state and return it when the budget ends.
A real-life example
A research agent writes market summaries and retries searches when evidence is thin. One night a news API returned the same empty result for a new company name, and the agent looped "rewrite query, search, grade: insufficient" 900 times before anyone noticed, costing about Rs 18,000. The fix had three parts: search_attempts in state with an exit at 3, a check that stops if the rewritten query equals a previous one, and recursion_limit: 40 in every run's config. The next empty-result case ended after three attempts with "I could not find reliable sources for this company".
Follow-up questions to expect
- "Why keep the counter in state and not a Python variable?" — State is checkpointed. After a resume or on another server, a local variable resets to zero and the loop runs forever.
- "How do you choose the budget?" — From evals: measure how often attempt 2, 3 and 4 improve the score. Most gains come early.
- "Is
GraphRecursionErrora good way to stop?" — No. It is a crash. Design a normal exit; the limit is only a safety net.