Agentic Engineering

Loops, tools, and context — the craft of building software around models that act.

Agentic Engineering / The Agent Loop
Topics · 05

The Agent Loop

The core architecture of every agent: a stateless model called in a loop. Each turn, the harness assembles everything seen so far into one request, the model replies with either a tool call or a final answer, the harness executes the call and appends the result, and the cycle repeats until the model declares completion or hits a budget. All agent engineering is tuning some part of this cycle — what gets assembled, what actions exist, how errors feed back, and when to stop. A working agent loop is under a hundred lines of code; the craft is in making those hundred lines reliable over long tasks, where small per-step error rates compound.

Prerequisites: none — this is the first topic. Mental Models is assumed. Feeds problems: Reliability over long horizons, Cost and latency at scale.

Practitioner

Strip away every framework and an agent is this:

messages = [task]
while True:
    response = model(system_prompt, tools, messages)
    messages.append(response)
    if response.is_final_answer or budget_exhausted():
        break
    for call in response.tool_calls:
        messages.append(execute(call))

Everything else in this hub is a refinement of one of these lines. Walk through a real iteration to see the moving parts. The task is “fix the failing test in this repo.” Turn one: the model sees the system prompt, the tool definitions, and the task; it calls run_tests. The harness runs the tests and appends the failure output. Turn two: the model reads the failure, calls read_file on the implicated source. Turn three: it calls edit_file with a fix. Turn four: it calls run_tests again, sees green, and answers “done — the bug was an off-by-one in the date comparison.” Four turns, one growing transcript, no memory anywhere except that transcript.

The design decisions that matter, in the order they’ll bite you:

Termination. Let the model end the loop by answering instead of calling a tool — but never trust that alone. Cap turns, tokens, and wall-clock time, because the signature failure is the doom loop: the model re-trying a failing action with small variations, forever. A stuck agent that stops at turn 30 with a partial result beats one that burns $40 discovering nothing. Decide what “budget exhausted” returns to the caller: best effort so far plus what remains, not a bare timeout error.

Errors are context, not exceptions. When a tool call fails, resist the reflex to have the harness retry silently or crash. Append the failure to the transcript and let the model see it — models are good at reacting to “permission denied” or “file not found: did you mean config.yaml?” by trying something else. The division of labor: the harness retries mechanical transients (network blips, rate limits); the model handles semantic failures (wrong path, bad query). A useful slogan: the model can only recover from what it can see.

Verify at the boundaries. Compounding error is the loop’s fundamental enemy, and the fix is structural: end every autonomous stretch at a checkpoint something can verify. In code, that’s running tests or the compiler — cheap, objective oracles. Elsewhere it’s schema validation, a second model reviewing the output, or a human gate before anything irreversible. When you design an agent task, design its verification first; a task with no checkable boundary is a task you’ll be debugging on vibes.

The workflow escape hatch. Before building any loop, ask whether you need one. If the steps are the same every run — extract, transform, summarize, file — write a workflow: fixed code, model inside each step. It will be faster, cheaper, more testable, and more reliable than an agent, because it removes the model’s opportunity to choose wrongly. Reach for the loop when the steps genuinely can’t be known in advance. The dial goes up later much more easily than a misarchitected agent comes back down.

Keep the harness boring. State lives in the transcript; the harness should be a plain, inspectable program — assemble, call, execute, append. Cleverness in the harness (mutating history, injecting hints mid-task, hidden retries) makes trajectories lie to you, and the trajectory is your only debugging instrument. When something goes wrong, you will read the transcript top to bottom like a detective reads a witness statement; protect its integrity.

Expert pointers

The frontier is models trained end-to-end on agentic tasks with reinforcement learning — they plan, self-correct, and interleave thinking with tool calls natively, which keeps moving behavior from the harness into the model (the “build for the model six months from now” thesis playing out). Live arguments: how much structure to impose (explicit plan-then-execute stages vs. letting the model drive), whether long-running agents need durable-execution engines like temporal workflow systems or just good checkpointing, and how far single-loop agents scale before multi-agent decomposition genuinely wins.

Misconceptions

  • “An agent is a special kind of model.” It’s an ordinary model in a loop you write. The same model is a chatbot without the loop and an agent with it — the capability lives in the combination.
  • “More turns means more capable.” Each turn multiplies error probability and cost. Long autonomy is something you earn with verification structure, not something you grant by raising the turn cap.
  • “The harness should shield the model from errors.” Backwards, mostly. Tool failures are information, and the model is often the best-placed component to act on them. Shield it only from mechanical noise.

Check yourself

  1. Your agent succeeds at 95% of individual steps. Roughly what’s the end-to-end success rate on a 30-step task — and which two design changes from this topic raise it most?
  2. A tool call fails with “path not found.” Argue for showing this to the model rather than having the harness retry — then name a failure type where the harness should handle it silently.
  3. A teammate proposes an agent for turning support tickets into a weekly report — same four steps every week. What do you build instead, and why?
  4. Why does a doom loop happen at all, given the model can see its own failed attempts in the transcript?

Apply it

Build the loop above for real — no framework, ~60 lines in any language with an LLM API. Give it exactly two tools: list_files(dir) and read_file(path). Task: “find which file defines function X and explain what it does” against a small repo. Print the full transcript as it runs. Read the trajectory end to end and mark every point where the model’s next move depended on what a tool returned. Keep this agent — the Apply-its in later topics extend it, and it can seed your capstone.