Agentic loop (1): anatomy of the cycle

An LLM is stateless: an agent is what you get when you put it in a loop with a goal, tools, observations and a stop condition. Part 1 of 3: the minimal loop (with pseudocode and a diagram), the components, schema-typed tool calling and termination.

AICybersecurityR&DAIAgenticAutonomous AgentsLLMTool CallingContext EngineeringArchitectureCybersecurity
Diagram of the agentic loop: from the initial goal the model decides, acts with a tool call, the harness executes in the environment, the result feeds back into the context, and the cycle repeats until the task is solved or the budget is exhausted; the end_turn branch produces the final answer
The minimal agent cycle: from a goal, decide, act, execute, observe, repeat. State lives in the context; termination and security live in the harness.

A 3-part series. How AI agents really work: (1) anatomy of the cycle · (2) context, patterns and multi-agent (from 8 July) · (3) security and governance (from 10 July). This is part 1.

An LLM is not an agent

A language model, on its own, is a stateless function: it takes a sequence of tokens and produces another. It does not “do” anything, remembers nothing between calls, observes no world. An agent is what you get by placing that model inside a loop that, starting from a goal, lets it invoke tools, observe their results and decide the next step, until the task is solved. In one sentence: the loop is the agent. The model is only the decision organ inside it.

This distinction moves attention from the wrong place (the prompt, the model) to the right one: the harness, the code that keeps the model in the loop, executes its requests, manages context and errors, and enforces policy. That is where an agentic system becomes reliable, governable and secure, or fails to.

The minimal loop

The loop starts from a goal (plus the system prompt): it is the only “human” input. From there on the agent proceeds on its own. Stripped to the bone:

messages = [system_prompt, user_goal]     # the goal enters the context

for step in range(MAX_STEPS):
    # 1. DECIDE: the model picks the next action
    reply = llm(messages, tools=TOOLS, temperature=0)
    messages.append(reply)

    # 2. TERMINATE? the model signals it is done
    if reply.stop_reason == "end_turn":
        return reply.text                 # final answer
    if reply.stop_reason != "tool_use":
        raise UnexpectedStop(reply.stop_reason)   # e.g. max_tokens, refusal

    # 3. ACT + EXECUTE: the harness runs the requested tool calls
    results = []
    for call in reply.tool_calls:
        try:
            args = validate(call.arguments, SCHEMA[call.name])   # no unvalidated input
            results.append(tool_result(call.id, execute(call.name, args)))  # side effect in the environment
        except ValidationError as e:
            results.append(error_result(call, e))   # the error feeds back into the context, the model self-corrects

    # 4. OBSERVE: the result feeds back into the context
    messages.append(tool_results(results))

raise BudgetExceeded("no solution within MAX_STEPS")

Each iteration the model emits either a final answer or one or more tool calls. The harness runs the calls, feeds the outcomes back into the context, and the loop starts again. The crucial point: the model is stateless, all the run’s state lives in messages. There is no magic “memory”: there is only what, at each turn, gets serialized into the context, starting from the initial goal.

The components, one by one

  • Goal: the task to solve, the only external input that starts the cycle.
  • System prompt / policy: role, constraints, tool descriptions, stop criteria. It is the behavioural contract, not a suggestion.
  • Tool schema: name, description and parameters (JSON Schema) of each tool. It is the interface the model sees; the quality of this description matters as much as the model.
  • Context (messages): the model’s only memory within the run. It grows at every step.
  • The model: it decides, it does not execute. It produces text and structured action requests.
  • The harness / executor: it executes the tool calls, validates arguments, handles errors and timeouts, enforces policy, traces everything. Security lives here.
  • The termination condition: without it, the loop is potentially infinite.

Tool calling, in detail

Tool calling is how the model moves from “saying” to “doing”. The model calls nothing: it emits a structure (a tool name plus schema-conforming arguments) that the harness interprets and executes. Three technical points separate a toy from a serious system:

  • Argument validation. Models hallucinate parameters: an out-of-range integer, a missing field, an arbitrary path. Arguments must be validated against the schema before execution. If they fail, you do not execute: you feed the error back into the context as an observation, and the model self-corrects on the next turn. The error message is part of the control loop.
  • Parallel calls. In a single step the model can emit multiple independent tool calls, runnable in parallel (fan-out). This cuts the number of iterations, hence latency and cost.
  • Deterministic and non-deterministic tools. A SQL query is deterministic; another LLM used as a tool (a sub-agent, a classifier) is not. A sub-agent, in particular, is in effect a nested loop inside the loop.

Termination: knowing when to stop

A loop without a good stop condition is an elegant way to burn budget. The typical conditions, in AND/OR:

  • end_turn: the model explicitly signals it is finished (final answer).
  • Budget: a maximum number of steps, tokens or time.
  • No-progress / anti-loop: detect that the agent oscillates (repeats the same action, alternates between two states) and stop. This is an essential defence: a naive reactive loop can spin forever.
  • Human handoff: the agent yields control when it hits a decision outside its mandate.

A concrete example. In Claude Code, the /goal <condition> command fuses goal and termination: you give the agent a completion condition (for example /goal all tests in test/auth pass and the lint step is clean) and the agent keeps going, turn after turn, on its own, until a lightweight evaluator model (Haiku by default) confirms the condition holds; then it stops. It is exactly the loop of this article, with the stop condition made explicit and checked by a second model. Not to be confused with /loop, which repeats a command at time intervals: a different purpose (polling, status checks, recurring tasks), not a goal to reach.

This is the skeleton. But an agent that must last more than a few steps immediately hits the limit of the context, and an agent that touches real data or actions hits security. Those are the subjects of the next two parts.


Part 2 (context, patterns and multi-agent) arrives on 8 July, part 3 (security and governance) on 10 July.

Need support?Under attack?Service Status
Need support?Under attack?Service Status