# Loops: Retry, Refine and Reflect — LangGraph Agents & Multi-Agent Systems

Source: https://www.geekswithgeeks.com/en/langgraph-agents/f-loop

> Return to an earlier node until a condition is met, with a cap.

## Cycles are the point of agents

Unlike a chain, a graph may contain **cycles**: an edge that sends control back to an earlier node. This enables patterns such as **retry until valid**, **write → critique → revise**, and **agent ↔ tools** loops. Every loop needs a **termination rule** in the router (quality is good enough, a goal is met) and a **hard cap** on attempts stored in state, because a model may never be satisfied. Keep a history of attempts in a reducer-backed list for debugging, and decide what to do when the cap is hit (return the best attempt, escalate to a human, or raise an error).

## A write-and-check loop, run

I ran this offline with langgraph 1.2.12 and langchain-core 1.6.6 in a Python virtual environment. No API key or model is needed because plain Python functions stand in for the model, so the output is repeatable. The first draft is too short, so the router sends control back to `write`; the second passes and the graph ends after 2 attempts. The `attempts >= 3` clause is the safety cap.

```python
import operator
from typing import Annotated, TypedDict
from langgraph.graph import StateGraph, START, END

class State(TypedDict):
    draft: str
    attempts: int
    history: Annotated[list, operator.add]

def write(state):
    n = state["attempts"] + 1
    draft = "short" if n == 1 else "a good, complete answer"
    return {"draft": draft, "attempts": n, "history": [f"attempt {n}: {draft}"]}

def route(state):
    ok = len(state["draft"]) >= 10
    return "done" if ok or state["attempts"] >= 3 else "retry"   # always cap the loop

g = StateGraph(State)
g.add_node("write", write)
g.add_edge(START, "write")
g.add_conditional_edges("write", route, {"done": END, "retry": "write"})
out = g.compile().invoke({"draft": "", "attempts": 0, "history": []})
print(out["history"])
print("attempts:", out["attempts"])

```

Output:

```
['attempt 1: short', 'attempt 2: a good, complete answer']
attempts: 2
```

**Quiz:** What must every loop in a graph have?

- [ ] A bigger model
- [ ] An unlimited retry count
- [ ] No state
- [x] A termination rule and a hard cap on iterations

*Answer:* A termination rule and a hard cap on iterations. Caps prevent infinite loops and runaway cost.
