A tool call is a model-generated request to invoke an external function or API. It specifies a tool name and arguments; it does not execute anything. The application receives the call, runs the tool, and returns the result to the model. This boundary lets an LLM use current information, perform precise calculations, or take actions it cannot perform through text generation alone. section 3.2 section 3.1
A minimal implementation has four parts:
- Define the tool with a name, a clear description, and a parameter schema. Implement the corresponding function separately. section 3.2.1
- Send the user request and tool definition to the model. Inspect its response: it may answer directly or return one or more tool calls. section 3.2.1
- For each call, parse its arguments, dispatch to the named function, and record the result as a tool message linked to the call ID. Send the updated messages back to the model for an answer. section 3.2.1
- For an agent, repeat the decision–execution–observation cycle until the model has enough information to stop. section 1.3.2
Calculator call
A question about South Korea’s capital can receive a direct answer. For “What is 1234 × 5678?”, the model instead requests calculator with operator="multiply", first_number=1234, and second_number=5678. Python executes the function; a tool message carries 7006652 back to the model, which formats the final answer. The call is a request for computation, not the computation itself. section 3.2.1
Reliable calls begin with unambiguous schemas: state when a tool is useful, distinguish required inputs, constrain valid values, and avoid contradictory parameters. Keep identifiers already known to the application in code rather than asking the model to reproduce them. A malformed call or tool failure still needs handling by the executor; a structured call alone does not make the external action succeed. section 3.2.3 section 3.2.1
Tool calling also supports a ReAct-style loop without parsing fragile free-form instructions such as Action: search["query"]. Tool definitions and execution can remain local, or an MCP server can expose a Python function for clients to discover and invoke. section 4.1.2 section 3.4.4
Listing 3.5 Feeding tool results back to the LLM
ai_message = response_with_tool.choices[0].message
messages.append({ #1
"role": "assistant", #1
"content": ai_message.content, #1
"tool_calls": ai_message.tool_calls #1
})
if ai_message.tool_calls:
for tool_call in ai_message.tool_calls:
function_name = tool_call.function.name #2
function_args = json.loads(tool_call.function.arguments) #2
if function_name == "calculator":
result = calculator(**function_args) #2
messages.append({ #3
"role": "tool", #3
"tool_call_id": tool_call.id, #3
"content": str(result) #3
})
final_response = completion(
model='gpt-5-mini',
messages=messages
)
print("Messages: ", messages)
print("Final Answer:", final_response.choices[0].message.content)
The message-handling listing shows the crucial handoff: preserve the assistant’s call, execute it, attach a tool result using tool_call_id, and request the final response. section 3.2.1












