CCAR-F · Agentic Architecture
The agentic loop: keep going while stop_reason is tool_use
An agent is a loop: you send Claude a request, Claude asks to use a tool, your code runs it, you return the result and it starts over. The exam question is almost always the same: when does it continue and when does it end?
The cycle
The agentic loop has four steps:
- send the request with the full history (the API is stateless: Claude only sees what is in
messages); - check the stop_reason of the response;
- if it is
"tool_use", run every requested tool and append the results to the history; - if it is
"end_turn", Claude is done and the loop ends.
stop_reason is the API’s structured signal. The response text never decides.
How the history is built
The order is always the same: a user message, an assistant message with the tool_use block, and another user message with the tool_result.
- Each
tool_resultcarries thetool_use_idof the call it answers. Without the assistant message before it, the API can’t find which call it belongs to. - If Claude requested three tools in one response, three
tool_resultblocks go together in a single user message. Leaving one unanswered is an error. - If the result is printed to a log but not appended to the history, Claude never sees it and asks again: that is how loops that call
get_orderforever are born. - A tool failure doesn’t end the loop: it comes back as a
tool_resultwithis_error: trueand a clear description, and Claude decides whether to retry, use another tool or explain the limitation to the user.
Other stop_reason values
"max_tokens" means the response was cut off by the length limit, not that the task is finished. Handle it separately: raise the limit or ask Claude to continue. Treating “anything that isn’t tool_use” as the end delivers truncated answers.
Model or fixed script
In model-driven decision-making, Claude chooses which tool to call and when to stop based on what it finds. A fixed script that runs the same five calls for every query wastes time and doesn’t adapt. The exception is steps with strict requirements (verifying identity, approving a payment): those are guaranteed in code, as lesson 1 showed.
The usual traps
- Reading the text to decide: looking for phrases like “done” or “I’ll now…” is interpreting natural language, which is ambiguous and fragile. One response can contain text and a
tool_use; withstop_reason: "tool_use", that text is interim commentary. - Treating the absence of text as the end: it says nothing either.
- An iteration cap as the main control: it cuts long tasks short and doesn’t fix the cause. A cap is only a safety net against runaway loops, and it’s worth logging the runs that hit it so you can investigate.
- Forcing
tool_choice: "any"to “keep it working”: it takes away Claude’s ability to finish with text.
If the response says "end_turn" but the text announces a lookup that never happened, end_turn wins: the loop ends and you investigate the prompt.
In the exam
If the scenario describes a loop that ends too early, never ends or repeats the same call, look for the option that makes stop_reason the control and appends results to the history with their tool_use_id. Rule out parsing text, caps as the fix and minimum iteration counts.
Quick question
A practice exam question on this domain. It counts towards your progress.
A payroll company is building an agent that helps small businesses pay their contractors. It can call send_payment, which moves money from the client's account to a contractor's bank account. Payments are usually batched at the end of each month, when most contractor invoices fall due.
The requirement says that a payment must never be sent to an account that has not been verified. An internal verification service returns "verified" or "not verified" for each account and responds in under 50 ms.
The product manager wants the feature to launch in three weeks, and the team has two backend developers available for it.
Which design best meets the requirement?