Skip to content

The loop

Read · 1 of 3

Everything comes together

You have every piece: messages, tools, tool results. The agent loop just repeats them:

1. Send the messages. 2. Add the reply to the messages. 3. If stop_reason is end_turn, the model is done. 4. Otherwise run every tool_use, send the results back as a user message, and go to 1.

That's it. Every agent you've heard of (coding agents, research agents, customer-support agents) is this loop with better tools, better prompts and more safety checks.

Read this lesson as text

Twenty lines that turn a model into an agent.

Everything comes together

You have every piece: messages, tools, tool results. The agent loop just repeats them:

1. Send the messages. 2. Add the reply to the messages. 3. If stop_reason is end_turn, the model is done. 4. Otherwise run every tool_use, send the results back as a user message, and go to 1.

That's it. Every agent you've heard of (coding agents, research agents, customer-support agents) is this loop with better tools, better prompts and more safety checks.

Watch an agent think

def calculator(op, a, b):
    return a * b if op == "mul" else a + b

client = Client(calc_brain)
messages = [{"role": "user", "content": "What is 2 + 3 * 4?"}]
while True:
    reply = client.messages.create(model="stand-in", max_tokens=500, messages=messages)
    messages.append({"role": "assistant", "content": reply.content})
    if reply.stop_reason == "end_turn":
        break
    outputs = []
    for block in reply.content:
        if block.type == "tool_use":
            value = calculator(**block.input)
            print("tool:", block.input["op"], block.input["a"], block.input["b"], "->", value)
            outputs.append({"type": "tool_result", "tool_use_id": block.id, "content": str(value)})
    messages.append({"role": "user", "content": outputs})
print(reply.content[0].text)
  1. Line 5: The goal: a question that needs two calculations, in the right order.
  2. Line 7: Call 1. The model decides to multiply first (3 × 4), so it replies with a tool_use.
  3. Line 8: The reply joins the conversation, tool request and all.
  4. Line 9: `tool_use`, not `end_turn`: the model is waiting for us.
  5. Line 14: Our code does the maths. The model never runs anything itself.
  6. Line 15: We log each tool call. Logs are how you'll debug agents.
  7. Line 17: The result goes back, tagged with the tool_use id it answers.
  8. Line 7: Call 2. Now the model knows 3 × 4 = 12, so it asks to add 2.
  9. Line 15: Second tool call.
  10. Line 7: Call 3. With both results in hand, the model answers. No tool this time.
  11. Line 10: `end_turn`: the loop stops.
  12. Line 18: Three model calls, two tools, one answer.

How many calls?

def calculator(op, a, b):
    return a * b if op == "mul" else a + b

client = Client(calc_brain)
messages = [{"role": "user", "content": "What is 1 + 5 * 6?"}]
while True:
    reply = client.messages.create(model="stand-in", max_tokens=500, messages=messages)
    messages.append({"role": "assistant", "content": reply.content})
    if reply.stop_reason == "end_turn":
        break
    outputs = []
    for block in reply.content:
        if block.type == "tool_use":
            value = calculator(**block.input)
            pass
            outputs.append({"type": "tool_result", "tool_use_id": block.id, "content": str(value)})
    messages.append({"role": "user", "content": outputs})
print(client.calls)

Same loop, new question, and now it prints how many times the model was called. What does it print?

  • 2
  • 3
  • 4
Show the answer

3 One call asks for the multiplication, one asks for the addition, and one gives the answer. Every tool round costs a model call, which is why agents are slower and pricier than a single chat reply.