Loop Engineering for AI Agents: Five Parts, Four Shapes and a LangGraph Build
Loop engineering for AI agents: five parts, four common shapes, a verify-and-retry research agent in LangGraph, guards against failure, and when not to loop.
This article is published in English.
Sources: Loop Engineering with Agents
Every AI agent already runs in a loop, and hardly anyone designs that loop on purpose. That gap separates an agent that quietly finishes the job from one that burns a budget overnight while convinced it is making progress. The practice of closing the gap has a name: loop engineering.
Structurally there is little to it. At each turn the agent thinks about what to do, performs an action such as a tool call or a search, looks at what came back and thinks again. That cycle of reasoning, acting and observing sits underneath tools like Claude Code and Cursor. For some time the skill in demand was prompt engineering, phrasing one request as well as possible. Models that can act, search and read their own output raised a larger question: what chooses the agent's next move, and what tells it to stop?
Loop engineering is the habit of answering that on purpose. The designer picks the goal, the checks and the stopping point, then builds a compact system that states the objective a single time and lets the agent keep iterating until the job is finished. Responsibility moves away from instructing the agent step by step and toward constructing whatever issues the instructions.
This is a strong idea, and it is also where the hard part starts. Sloppy loops burn tokens, never end, or persuade themselves that they are advancing. Good ones are economical, halt at the right moment and deliver output that can be relied on. A smarter prompt does not close that distance. A better loop does.
The examples below use LangGraph because it makes a loop's structure easy to see, but nothing here is tied to one framework. The same ideas apply with another agent framework or plain hand-written code. Frameworks change, and the concepts stay.
The five parts of an agentic loop
Before deciding when a loop is appropriate, it helps to know what one is made of. Nearly every agentic loop has five parts.
- A trigger. Some event gets things moving, such as a person typing go, a scheduler firing, a ticket arriving or a pull request being opened. Absent a trigger, the agent idles.
- A checkable goal. The loop must know what finished looks like, preferably in a form a machine can confirm. Improve the app invites an endless run. Get every test passing, or return an answer whose claims all cite sources, supplies a genuine finish line.
- Tools. The agent has to be able to act and also to observe the outcome, running code and reading the error, or searching the web and reading the results. If the environment never answers back, the agent is only guessing.
- State. This is the running picture of the job: attempts so far, findings, how many rounds have passed. It is the trickiest part of loop design, since oversized state buries the useful signal under noise.
- Stop rules. They define how the loop ends, and there are three doors. Success means the goal was reached. Giving up means the attempt budget was spent. Hand-off means the loop ran into something risky or unclear and passed it to a person instead of guessing.
The rest of the discussion, covering when to loop, when not to and how, traces back to these five.
When a loop pays off
A loop earns its place when a single pass through the model is not enough, and the task really needs the agent to try, check and try again. Four signals point that way.
- Results can be verified. This matters most. When an outcome can be checked automatically, because tests pass or fail, a response does or does not cite real sources, or a JSON payload is valid or broken, the loop can use that check to home in on correct. Verification works as the steering wheel, and a loop without it only spends money.
- The first try is often wrong yet repairable. Code, research drafts and messy-data cleanup get better with repetition. The agent makes something, notices the defects and fixes them.
- Nobody knows how many steps it will take. A problem of one kind may need two steps today and seven tomorrow. A fixed pipeline cannot flex like that, whereas a loop that continues until the goal is reached can.
- Nobody is watching. Handling tickets overnight, or retrying a flaky integration until it succeeds, calls for a system that chooses its own next action and does not wait for a prompt.
One fitting case is a research agent that audits its own findings. It drafts a reply, tests whether sources support each claim, and goes back to dig into the weak ones. It keeps cycling until the reply stands up or a limit is hit. All four signals are present, and this is the agent built further down.
Common shapes of loops
Most agentic loops are variations on a few shapes. Recognizing them helps identify which one a problem wants before anything is wired together.
Generate and verify, sometimes called reflection. One stage creates an output and a second inspects it, and the pair repeats until the inspection passes. The steering signal is binary: the check approves or states what is wrong. It fits situations where correctness can be tested, like code that has to pass tests or research whose claims need support. This is the shape constructed later.
+-----------+ +-----------+
-->| Generate |----->| Verify |----- pass -----> [ done ]
+-----------+ +-----+-----+
^ |
+------- fail ------+
Pick it when an objective test of correctness exists and the agent should keep repairing until the test passes. A SQL-writing agent that runs its query and loops until the statement executes and returns plausible rows is the classic example.
Evaluator and optimizer, also called generate and score. A scorer rates each attempt in place of a yes or no, and the loop pushes toward the highest score and not merely toward correct. It helps when no clean pass or fail exists but a notion of better can still be measured, as in tuning a prompt, refining ad copy or ranking results.
+-----------+ +-----------+
-->| Generate |----->| Score |--- good enough --> [ done ]
+-----------+ +-----+-----+
^ |
+-- improve --------+
(use the score)
Pick it when quality sits on a scale yet can still be given a number. Drafting a product tagline, with a scorer rating clarity and punch while the loop polishes the best candidate, shows the idea.
Plan, execute, replan. A planner outlines the steps and executors perform them, and whenever a step reveals something unexpected the loop returns to revise the plan. The loop surrounds the plan rather than one output, so it suits open-ended, multi-step work like research or a software project.
+-----------+ +-----------+
-->| Plan |----->| Execute |-- all steps done --> [ done ]
+-----------+ +-----+-----+
^ |
+-- replan ---------+
(hit a surprise)
Choose it when the task has many steps and not all are knowable up front. Migrating a service to a new framework works: plan the steps, start executing and replan the moment one step uncovers an unexpected dependency.
Scheduled or monitoring loop. In place of iterating toward a goal during one run, this variant wakes on a timer or an event to watch and respond, for instance triaging new tickets, sweeping for broken builds or retrying an unreliable job. It spans time and does not live inside a single task.
+-----------+ +-----------+ +-----------+
-->| Wait |---->| Check |---->| Act |---+
| (timer / | +-----------+ +-----------+ |
| trigger) | |
+-----------+ <-------------------------------------+
(no fixed end — keeps watching over time)
Pick it when no single finish line exists and the aim is continuous watching and reacting, like an inbox checked every few minutes or a nightly sweep for stale pull requests.
These shapes are not mutually exclusive. Real systems often nest them, for example a scheduled loop that runs a generate and verify pass on each wake. The most common shape, generate and verify, is the one built from end to end next.
Building a loop with LangGraph
The agent to build is a researcher that distrusts its own first draft. Given a question, it collects information, writes an answer, and then fact-checks each claim against actual sources. A claim lacking support is sent back for more research. The cycle continues until the full answer holds, or until a retry cap is reached, whereupon the agent returns its best version and marks what is still uncertain. In short, it answers and then convinces itself the answer is right before handing it over.
That self-checking behavior is exactly the generate and verify loop, so it makes a clean first build.
LangGraph is a good match because it describes an agent as a graph. Nodes are boxes that do work, and edges are arrows that decide what runs next. Edges are allowed to point backward, which is what permits a loop. A simple linear chain cannot repeat itself, but a graph can.
The researcher has three jobs, hence three nodes. The first two divide the work between a maker and a checker, a doer and a critic kept separate, a pattern common in loops.
+------------------+
START ----------> | Research | <-------------+
| (draft / revise) | |
+--------+---------+ |
| |
v | needs work
+------------------+ | (+ feedback)
| Verify | |
| (check claims) | |
+--------+---------+ |
| |
v |
+-----------+ needs work |
| Decide |-------------------+
| (router) |
+-----+-----+
| verified / out of tries
v
[ END ]
- Research collects material and drafts an answer.
- Verify reviews the draft and tests whether each claim is backed up.
- Decide is a tiny router that reads the verdict and picks what follows: finish, or go back and research the weak spots.
The example runs on Python 3.12. Three packages are needed:
pip install langgraph==1.2.6 langchain-openai==1.3.3 pydantic==2.13.4
langgraphis the graph and loop engine, withStateGraph,STARTandEND.langchain-openaiwraps the OpenAI chat model asChatOpenAI.pydanticdefines the structured verdict that the verifier returns.
An OpenAI API key must also be present in the environment before running it:
export OPENAI_API_KEY="your-key-here"
from typing import TypedDict, Literal
from langgraph.graph import StateGraph, START, END
from langchain_openai import ChatOpenAI
from pydantic import BaseModel, Field
# A model client on OpenAI's Responses API, with the built-in web-search tool
# bound on — so the model can search the web itself, no extra package needed.
# "gpt-5" is a reasoning model; swap it for any current model you have access to.
llm = ChatOpenAI(model="gpt-5", use_responses_api=True)
searcher = llm.bind_tools([{"type": "web_search"}])
MAX_ITERATIONS = 3 # a stop rule, decided up front
# STATE — the shared memory passed between every node
class ResearchState(TypedDict):
question: str # what we're answering
draft: str # the current best answer
verdict: str # "verified" or "needs_work"
feedback: str # what the verifier said to fix
iterations: int # how many times we've looped
# The verifier returns a typed result, so the router gets a clean
# "verified" / "needs_work" to branch on instead of parsing prose.
class Verdict(BaseModel):
status: str = Field(description='"verified" or "needs_work"')
feedback: str = Field(description="claims lacking support, if any")
# NODE 1 — the maker: search the web, then draft (or revise) the answer.
def research(state: ResearchState) -> dict:
prompt = "Search the web, then answer the question. Back every claim with a source.\n"
if state.get("feedback"):
prompt += f"A reviewer flagged these gaps — fix them:\n{state['feedback']}\n"
prompt += f"\nQuestion: {state['question']}"
draft = searcher.invoke(prompt).text
return {"draft": draft, "iterations": state["iterations"] + 1}
# NODE 2 — the checker: search for evidence, then critique the draft.
def verify(state: ResearchState) -> dict:
evidence = searcher.invoke(
f"Search the web for evidence to fact-check claims about: {state['question']}"
).text
checker = llm.with_structured_output(Verdict)
result = checker.invoke(
"You are a fact-checker. Using the evidence below, reply 'verified' "
"only if every claim in the answer is supported; otherwise 'needs_work' "
"and list the unsupported claims as feedback.\n\n"
f"Evidence:\n{evidence}\n\nAnswer:\n{state['draft']}"
)
return {"verdict": result.status, "feedback": result.feedback}
# ROUTER — the heart of the loop. Reads the verdict, picks the next step.
def decide(state: ResearchState) -> Literal["research", "__end__"]:
if state["verdict"] == "verified":
return "__end__" # success: goal met
if state["iterations"] >= MAX_ITERATIONS:
return "__end__" # surrender: out of tries
return "research" # loop back and fix the gaps
# WIRE IT UP
graph = StateGraph(ResearchState)
graph.add_node("research", research)
graph.add_node("verify", verify)
graph.add_edge(START, "research") # trigger
graph.add_edge("research", "verify") # always verify a fresh draft
graph.add_conditional_edges("verify", decide, {
"research": "research", # the backward arrow = the loop
"__end__": END,
})
agent = graph.compile()
result = agent.invoke({
"question": "What were the main causes of the 2008 financial crisis?",
"draft": "", "verdict": "", "feedback": "", "iterations": 0,
})
print(result["draft"])
Two details stand out. One: both nodes reach the live web via OpenAI's built-in web_search tool, attached with bind_tools. The research node searches before drafting so that its claims rest on actual results. The verify node searches a second time to test the draft against fresh evidence instead of the model's memory, and that second search is what hands the loop an objective signal. Two: verify relies on with_structured_output, which forces a typed verdict plus feedback instead of prose, so the router can branch dependably without parsing free text.
The five loop parts map cleanly onto the code:
- Trigger: calling
invoke(...)with a question begins a run. - Checkable goal:
verifyrules eitherverifiedorneeds_work. - Tools: both nodes use built-in web search,
researchto write andverifyto check. - State: the
ResearchStatedictionary moves the draft, the feedback and the iteration count between nodes. - Stop rules: the
deciderouter ends the run on success or on reachingMAX_ITERATIONS.
The last point is the whole game, because the router is where loop engineering actually lives. One line, stop if verified, stop after three tries, otherwise go back, separates an agent that reliably improves its answer from one that runs up the bill indefinitely.
The example has two exits. Production loops tend to add a third, a hand-off to a human. Meeting something risky or unclear, the agent is better off neither guessing nor stopping quietly, but halting and escalating with all it has collected. In the router this is merely one more branch: when confidence is low or the action is sensitive, an escalate route ends the loop and presents the draft, the open questions and the attempts made. Recognizing when not to decide belongs to good loop design.
Failure modes and their guards
Once a loop runs by itself, a short list of predictable failures shows up, and each has a standard guard.
- The endless loop. The agent never concludes it is finished and keeps going until something breaks or the money is gone. The guard is a hard iteration cap, such as
MAX_ITERATIONSabove, an exit that does not rely on the agent's own opinion. - Token burn. Every pass resends a growing heap of context, and cost rises unnoticed. Keep state lean by carrying forward just what the next step requires, the current draft and the specific feedback, and never the complete history.
- Imaginary progress. The agent announces success it did not achieve, such as claiming a fix that never happened. Do not let it mark its own work on the point that matters. A separate verification step with an objective test, tests that actually run or sources that actually exist, makes done mean done.
- Repeating one mistake. The loop retries the same failing action and receives the same failure. Pass the earlier failure into the next attempt so the approach changes, which is why
researchreceives the verifier'sfeedback. - Unaccountable actions. Over long runs it gets hard to say what happened and why. Record each step: what the agent saw, decided and did. Observability stops being optional once a loop touches anything important, and tools like LangSmith exist to trace such runs.
- Full autonomy from the start. A loop acting unsupervised on day one has not yet earned trust. Phase it in: first a report-only mode that says what it would do, next assisted changes that a person approves, and finally unattended operation, each stage earned before the next.
When not to build a loop
Loops are strong, so they get over-applied easily. In these situations something simpler is better.
- A single pass suffices. Summarizing a document, translating text, answering a factual question and classifying an email are one-shot jobs. A loop around them only adds cost, delay and new ways to fail. If a straight sequence of steps works, use the straight sequence.
- Success is unrecognizable. When the goal is subjective or fuzzy, or only a human can judge it, the loop has nothing to steer by and will end arbitrarily or spin without end. A goal that cannot be verified makes a slot machine, not a loop.
- Errors are expensive or permanent. A loop that emails, moves money or deletes data on every iteration can do real harm quickly. Keep a person in the approval path, or do not loop on the consequential action.
- Speed and cost outrank autonomy. Each iteration means extra calls, tokens and time. In a high-volume, thin-margin or latency-sensitive feature, a predictable single call often beats a clever but costly loop.
A rule of thumb: if the conditions for success and for giving up cannot be written down, the loop is not ready to be built.
A checklist before looping
Loop engineering relocates the payoff. Writing a flawless prompt matters less than designing the system that directs the agent, meaning its trigger, goal, tools, state and stop rules. Even so, a loop is one tool among others and never a default. Five questions are worth asking first:
- Can success be checked automatically? If not, skip the loop, because it would have nothing to steer by.
- Does the task get better with repetition? If one pass is enough, keep things simple.
- What does done mean, exactly? Put the success condition in writing before coding.
- When should it quit? Set a hard limit so the loop cannot run forever.
- Can the actions safely repeat? If an iteration might do real damage, add a human checkpoint or do not loop on that step.
With honest answers to all five, the result can be a reliable loop and not merely a showy one. A modest first project works best: one research-and-verify round as built above, with the stop rules nailed down before anything grows.
A final point: a loop does more than speed work up. It amplifies whatever judgment went into it, repeating good decisions and bad ones alike at machine speed. The aim, then, is not to set one up and leave. The discipline is staying close enough to keep understanding what the loop does after it starts running alone, so that its designer remains its engineer and not merely the person who presses start.