AI Agents — A Graph, Not a Model
Without a Stop Condition It Is Not a Product
In one line
An agent without an ending condition is not a product. And that condition is set by a person, not by the model.
Why this is needed — the recursion limit is a safety net, not a design
LangGraph has a recursion_limit. If you exceed that number, it throws an exception. The moment you lean on it, two things follow: the user sees an error, and the cost spent until then is billed as it is.
The limit is a net for catching bugs, not a way to stop. The way to stop has to be inside the graph.
Three stopping conditions
The combination used in practice is usually these three.
| Condition | When | If you omit it |
|---|---|---|
| Success | You got what you wanted | It keeps looping even after getting the answer |
| Attempt limit | You have tried N times | It retries forever |
| Give-up path | You reached the limit | It dies with an exception or makes something up |
The third is the one most often left out. If you set only the limit and do not decide what comes after, the moment you reach the limit there is nowhere to go and an exception is raised. Giving up is also a path.
def after_lookup(state):
if state.get("answer"):
return END # 성공
if state.get("tries", 0) < MAX_TRIES:
return "lookup" # 다시
return "fallback" # 포기 — 이 줄이 자주 빠진다
Do not make things up when you do not know
The give-up path does more than stop. It says it does not know.
If a lookup comes back empty-handed and you hand it to the model with "answer this", the model makes up an answer. This is the most common route to hallucination, and the cause is not the model but the graph that passed the empty result along as it was.
In the field
When you get a report that the token cost came out several times what was expected, where to look is settled: the path that loops and its limit. If no path is left in the log, you cannot even check that, and you end up rebuilding the whole thing. Limits and records go together.