Session 5· 13· 20 min

Execute Tool & Return Result

What you'll learn
  • Call a local Python function with the model-provided arguments
  • Send the result back as a tool message
  • Get a final natural-language answer from the model

The full three-step dance

Call 1
user + tools
tool_calls
from the model
Run function
your code
Call 2
+ tool message
Final answer
plain text
13_execute_single_tool_and_return.py
# 1. First call — model returns tool_calls
first = client.chat.completions.create(model=model, messages=messages, tools=tools)
assistant_msg = first.choices[0].message
messages.append(assistant_msg)                                  ①

# 2. Run the function locally
call = assistant_msg.tool_calls[0]
args = json.loads(call.function.arguments)
result = cancel_ticket(**args)                                   ②

# 3. Send the result back as a tool message
messages.append({                                                ③
    "role": "tool",                                              ④
    "tool_call_id": call.id,                                     ⑤
    "content": json.dumps(result),                               ⑥
})

# 4. Second call — model turns the result into a human reply
second = client.chat.completions.create(model=model, messages=messages, tools=tools)
print(second.choices[0].message.content)
Crucial: append the assistant message (which contains tool_calls) to history before the tool result.
Unpack the args dict straight into your Python function with **args.
Tool result is a NEW message appended to history.
Role is literally "tool" — this is a special role just for tool results.
tool_call_id must match the id on the tool_call — it links the result back to the request.
content must be a JSON string, so json.dumps() the result dict.
$ python 13_execute_single_tool_and_return.py
Why two API calls?
The first call decides WHICH tool to use. The second call interprets the tool's result into a human-friendly answer. This pattern is at the heart of every agent.
Code Check
What goes into the "content" field of the tool message?
Knowledge Check
Why must tool_call_id match the id from the tool_call?
Recap — what you just learned
  • Three steps: get tool_calls → run function → send tool message → call API again
  • Append the assistant tool_call message to history BEFORE the tool result
  • tool_call_id links the result to the request
  • content is a JSON string, not a dict
Next up: 14 — Tool-Call Loop