- You describe the available functions (their schema) and send a normal request with
tools=. - The model replies not with text but with a
tool_callsarray — what to call and with which arguments. - You run the function yourself and send a second request, appending the model’s reply and the function result to the history.
- The model returns the final text.
Complete Python example
Let’s use the classicget_weather(city). In real life it would hit a weather service; here it returns a stub so the flow stays clear.
Gotchas
The model can ask for several calls at once
The model can ask for several calls at once
A single reply’s
message.tool_calls is an array and may hold more than one
call — the weather in two cities, say. Loop over it and add a separate
role="tool" message with its own tool_call_id for every tool_call.
Leave even one call unanswered and the next request will fail.Assistant reply first, then the function result
Assistant reply first, then the function result
The order in
messages is strict: append the assistant’s own reply (the
message object carrying tool_calls) first, and only after it the
role="tool" messages with the results. Send a result without the preceding
assistant reply and the API rejects the history as inconsistent.Arguments arrive as a string, not an object
Arguments arrive as a string, not an object
tool_call.function.arguments is a JSON string, not a ready-made dict. Parse
it before use with json.loads(...). Indexing the raw string by key will raise.What’s next
- Quickstart — sign-up, key, and first request
- Errors and response codes — what to do when a request fails