You know a tool (or skill): the model asks, your program runs it, and you send the result back as data.
One question → one run → one result is not always enough. Summarizing a file needs the file first, then another model call. That repeat is the tool-call loop — the loop in the agent recipe.
Why one call is not enough
A chatbot often does one model call per user question (with history).
An agent may need several model calls for one user question:
- First call: “I need
read_file.” - Your program reads the file and adds the result to history.
- Second call: model sees the file text and writes the summary.
Without the loop, you stop after step 1 — the person never gets the summary.
The loop
Your program owns the loop. The model only answers each call.
Repeat:
- Call the model — send history, and the list of tools / skills it may use
- Read the reply
- If it is a final answer (normal assistant text, no tool call) → show it and stop
- If it asks for a tool / skill → run it, append the tool call and the result to history, go back to step 1
- Your limits — also stop if you hit a max number of steps, a timeout, or an error you will not retry
┌─────────────────────┐
│ call the model │
└─────────┬───────────┘
│
┌──────────┴──────────┐
│ │
▼ ▼
final answer tool / skill call
│ │
│ ▼
│ your code runs it
│ │
│ ▼
│ add result to history
│ │
│ └──▶ call again
▼
doneCompanies use different field names for “why this reply stopped” (finish_reason, stop_reason, and so on). The job is the same: either the model is done talking, or it is waiting on a tool result from you.
Worked example: read, then summarize
Person asks: “Summarize notes.txt in one sentence.”
Round 1 — model needs the file
History so far:
{
"messages": [
{
"role": "user",
"content": "Summarize notes.txt in one sentence."
}
]
}
Model reply (tool call — shape idea):
{
"type": "tool_call",
"tool": "read_file",
"inputs": {
"path": "notes.txt"
}
}
Your program runs read_file. Result:
{
"tool": "read_file",
"result": "Milk, eggs, buy cat food. Dentist Tuesday 3pm."
}
Round 2 — model can answer
You call again with richer history: the original question, the tool call, and the tool result (exact roles/fields vary by company; the jobs stay):
{
"messages": [
{
"role": "user",
"content": "Summarize notes.txt in one sentence."
},
{
"role": "assistant",
"content": "tool call: read_file path=notes.txt"
},
{
"role": "user",
"content": "tool result: Milk, eggs, buy cat food. Dentist Tuesday 3pm."
}
]
}
Model reply (final answer):
{
"type": "final",
"content": "The notes list groceries and a Tuesday dentist appointment."
}
Your program shows that text and stops. Two model calls, one user question — that is the loop.
Who owns what
| Piece | Owner |
|---|---|
| Decide “need a tool?” / “done?” | The model (each call) |
| Run the tool / skill | Your program |
| Keep history across rounds | Your program |
| Hard stop (max steps, timeout, refuse a dangerous tool) | Your program |
The model cannot enforce your budget. If you never set a max step count, a buggy or stubborn model can ask for tools forever. Always give the loop a ceiling.
What to put back into history
Each round must leave the model enough context to continue:
| You should keep | Why |
|---|---|
| The person’s original question | The goal |
| Earlier assistant text (if any) | What was already said |
| Each tool call | What was requested |
| Each tool result (or error) | What actually happened |
Treat a tool error like a result: send it back. The model can retry another path or tell the person it failed. Silent failure breaks the loop.
One picture to keep
| Word | Meaning |
|---|---|
| Tool-call loop | Call model → maybe run tool/skill → add result to history → call again |
| Final answer | A reply meant for the person — no pending tool call |
| Step limit | Your max rounds so the loop cannot run forever |
See it in Code
The Code panel runs the loop on “summarize notes.txt”: declare read_file, then a for / while in your program until a final answer or max steps. Same explicit loop in Python, Java, Go, and TypeScript.
You can run an agent with one tool this way. Some SDKs can run this loop for you — that comes next. Then: when many tools / skills are available, and how the model picks among them.