The Tool-Use Loop
Model requests a tool, your code runs it, the result goes back, model answers.
Tool use is a small loop between the model and your code.
- You send the user message plus the tool definitions.
- The model replies asking to call a tool with specific arguments.
- Your code runs the tool and returns the result as a new message.
- The model uses the result to answer (or calls another tool).
Example
let messages = [{ role: 'user', content: 'Weather in Tokyo?' }];
let res = await chat({ messages, tools });
if (res.tool_call) {
const args = JSON.parse(res.tool_call.arguments);
const result = await getWeather(args.city); // run the real function
messages.push(res.message); // model's tool request
messages.push({ role: 'tool', name: 'get_weather', content: JSON.stringify(result) });
res = await chat({ messages, tools }); // model now answers
}
console.log(res.message.content);When to use it
- A booking agent runs the tool loop repeatedly, calling availability-check and then confirm-booking functions in sequence until the task is complete.
- A code assistant loops through tool calls — search, read-file, run-tests — until all tests pass before returning a final summary to the user.
- An expense processor calls parse-receipt, then lookup-budget, then record-expense in successive loop turns to handle a full reimbursement flow.
More examples
Tool loop with auto-dispatch
Runs the tool loop until the model stops requesting tools and returns a final text answer.
from openai import OpenAI
import json
client = OpenAI()
def get_weather(city): return f'{city}: 22°C sunny'
def get_population(city): return f'{city} population: 3.7 million'
TOOL_FNS = {'get_weather': get_weather, 'get_population': get_population}
tools = [
{'type':'function','function':{'name':'get_weather','description':'Weather for a city.','parameters':{'type':'object','properties':{'city':{'type':'string'}},'required':['city']}}},
{'type':'function','function':{'name':'get_population','description':'Population of a city.','parameters':{'type':'object','properties':{'city':{'type':'string'}},'required':['city']}}},
]
messages = [{'role':'user','content':'What is the weather and population of Tokyo?'}]
while True:
r = client.chat.completions.create(model='gpt-4o-mini', messages=messages, tools=tools)
msg = r.choices[0].message
messages.append(msg)
if not msg.tool_calls:
print(msg.content)
break
for tc in msg.tool_calls:
fn_result = TOOL_FNS[tc.function.name](**json.loads(tc.function.arguments))
messages.append({'role':'tool','tool_call_id':tc.id,'content':fn_result})Limit loop iterations as a safety cap
Caps the loop at MAX_TURNS iterations to prevent infinite loops when a model keeps requesting tools.
from openai import OpenAI
import json
client = OpenAI()
MAX_TURNS = 5
def lookup(key): return f'Value for {key}: 42'
tool = {'type':'function','function':{'name':'lookup','description':'Lookup a key.','parameters':{'type':'object','properties':{'key':{'type':'string'}},'required':['key']}}}
messages = [{'role':'user','content':'What is the value of alpha?'}]
for turn in range(MAX_TURNS):
r = client.chat.completions.create(model='gpt-4o-mini', messages=messages, tools=[tool])
msg = r.choices[0].message
messages.append(msg)
if not msg.tool_calls:
print('Final:', msg.content)
break
for tc in msg.tool_calls:
result = lookup(**json.loads(tc.function.arguments))
messages.append({'role':'tool','tool_call_id':tc.id,'content':result})
else:
print('Max turns reached')Parallel tool calls in one turn
Handles the case where the model requests multiple tools in the same turn by processing all tool_calls before the next generation.
from openai import OpenAI
import json
client = OpenAI()
def get_weather(city): return f'{city}: 18°C'
def get_time(city): return f'{city} local time: 14:35'
FNS = {'get_weather': get_weather, 'get_time': get_time}
tools = [
{'type':'function','function':{'name':'get_weather','description':'Weather.','parameters':{'type':'object','properties':{'city':{'type':'string'}},'required':['city']}}},
{'type':'function','function':{'name':'get_time','description':'Local time.','parameters':{'type':'object','properties':{'city':{'type':'string'}},'required':['city']}}},
]
messages = [{'role':'user','content':'What is the weather and local time in London?'}]
r = client.chat.completions.create(model='gpt-4o-mini', messages=messages, tools=tools)
msg = r.choices[0].message
messages.append(msg)
for tc in msg.tool_calls:
result = FNS[tc.function.name](**json.loads(tc.function.arguments))
messages.append({'role':'tool','tool_call_id':tc.id,'content':result})
final = client.chat.completions.create(model='gpt-4o-mini', messages=messages)
print(final.choices[0].message.content)
Discussion