Insights·2026-08-23

stop_reason — skip it and you will use a truncated answer

The fourth agent anti-pattern on Anthropic's certification exam is using the model's response the moment it arrives. An LLM cannot execute tools; it only tells you "call this tool with these values," and your code is what actually calls it. So when a response arrives you check stop_reason first. If it is tool_use, run the tool, feed the result back, and go around again; if it is end_turn, exit. The third case is the problem: a response that stopped because it ran out of tokens still reads plausibly, so without checking stop_reason you take a truncated answer for a finished one.

stop_reason을 안 보면 잘린 답을 완성된 답으로 쓴다 — 명령과 단계를 담은 요약 도식

Why loops, and why now — a 1966 proof

Before the anti-pattern, why this became a problem now.

In the early days of computing, programming languages were multiplying and people argued over whose language could do more. In 1966 Corrado Böhm and Giuseppe Jacopini ended the argument with a proof: any computation needs only three things. Executing statements in sequence, branching on a condition, and looping.

Map that onto AI today and the picture sharpens. Firing off a prompt and getting an answer is sequence. Branching on a condition is something many people already do. But the loop was missing — feeding the answer back in, getting another, feeding it back again.

Part of why agents feel different is that models got better, but structurally it is the moment that third piece got filled in. And the new mistake that appeared the moment loops did is this anti-pattern.

A misconception to clear first — an LLM cannot execute tools

A diagram showing that the model only tells you which tool to call, while your own code actually calls it and feeds the result back to the model.

We say "the AI searched the web" or "the AI read the file" all the time, and taken literally that is not true.

An LLM cannot do anything except predict the next word probabilistically. Hand it a tool and it still cannot run it. All it can do is tell you, very intelligently, "call this tool with these values."

Your code is what actually calls it. Hitting the search API, opening the file, taking the result and handing it back to the model — all of that is on your side.

This distinction matters because it is where the fact that a model has several reasons to stop comes from. Stopping because it finished, stopping to ask for a tool, and stopping because it hit a length cap are three different events that all look like "a response arrived."

stop_reason — three branches

So when a response arrives you do not start with the body; you look at a field called stop_reason. Why the model stopped is written there.

stop_reasonWhat it meansWhat your code does
tool_useStopped to ask for a tool callRun the tool, append the result, loop once more
end_turnStopped because it finishedExit the loop and use the answer
max_tokensCut off at the length capNot a finished answer — re-request or fail

What the loop looks like

In code it is short. Call the model inside a while loop, branch on stop_reason, and on tool_use continue for another pass.

The line worth noticing is that running the tool sits outside the model call. The model decides what to call; your code does the calling.

agent-loop.py
while True:
    resp = client.messages.create(
        model="claude-opus-5",
        messages=messages,
        tools=tools,
    )

    # Look at why it stopped before using the answer
    if resp.stop_reason == "tool_use":
        result = run_tool(resp)          # your code runs the tool
        messages.append(result)          # feed it back, go around again
        continue

    if resp.stop_reason == "max_tokens":
        raise RuntimeError("truncated — do not treat this as a finished answer")

    break                                # end_turn: exit

The third case is the dangerous one — a truncated answer does not look truncated

A comparison showing that a missed tool_use stops the agent visibly, while a max_tokens-truncated answer looks fine and fails silently.

Miss tool_use and the agent simply stops doing anything, so you notice fast. The problem is max_tokens.

When the model stops because it ran out of tokens, a response still comes back — and as prose it reads fine. Cut off mid-way, the last sentence just ends awkwardly; no marker saying "truncated here" arrives with the body.

So without checking stop_reason you take it for a finished answer and use it. You asked for ten items, got six, and the six flow straight into the next step. This is where things go wrong quietly.

There is a version of this for people who do not write code. If a long table or list from a chatbot ends half-way, that is probably the length cap rather than the limit of what the model knew. Type "continue" and the rest comes out.

After the loop exits — where the human belongs

Exiting on end_turn is also where a human belongs.

The talk says to check confidence at that point. If the result looks good, keep it; if not, escalate. You define the end of the automation not as "fully automatic" but as "automatic plus a handoff condition."

Without that condition, the agent produces an answer even when it is unsure — because it fills the gap plausibly instead of stopping to say it does not know.

One thing to try today

If you write code, check whether you look at stop_reason where you receive the model's response. If not, add the max_tokens branch first. That one line turns a quiet failure into a loud one.

If you do not write code, think back to answers that ended half-way recently. That was probably a length cap rather than the model's limit. Next time, type "keep going" first.

The next post is the last one: why a million-token window does not mean you should fill it.