Skip to main content
The model decides which of your registered tools to invoke and generates typed arguments for it. You execute the tool and hand the result back, and the model continues. Use it whenever the model needs to act on the world: call an API, query a database, run a calculation, fetch a document. Tool calling is a per-model capability. Check the capability listing on the model’s page before sending tools. A model that does not list tool calling refuses the request with 400 hosted_capability_not_supported.

Minimal code

What one turn actually looks like

One tool turnrepeat until tool_calls is absentMessages you hold01 SendThe model sees every tool description you registered.user02 Getfinish_reason is tool_calls; arguments arrive as a JSON string.user03 PushThen one tool message per call, each with its tool_call_id.user, assistant, tool04 SendThe model now answers, or asks for another tool.user, assistant, tool, …Your messages, plus toolsAn assistant message with tool_callsPush the whole assistant message backThe grown array, same callFinal answerThe turn with no tool_calls is the one you show the user.Dropping the assistant turn at step 03 breaks the state: the tool result then has nothing to attach to.
One tool turnrepeat until tool_calls is absentMessages you hold01 SendThe model sees every tool description you registered.user02 Getfinish_reason is tool_calls; arguments arrive as a JSON string.user03 PushThen one tool message per call, each with its tool_call_id.user, assistant, tool04 SendThe model now answers, or asks for another tool.user, assistant, tool, …Your messages, plus toolsAn assistant message with tool_callsPush the whole assistant message backThe grown array, same callFinal answerThe turn with no tool_calls is the one you show the user.Dropping the assistant turn at step 03 breaks the state: the tool result then has nothing to attach to.

What to tune

Common mistakes

  • Dropping the assistant turn. Push the whole assistant message, tool_calls and all, before you push any tool result. Without it the tool message has nothing to attach to.
  • Returning a non-string tool result. The content on a tool-role message must be a string. Always serialize it.
  • A vague description. Write it as though the model has never seen your API: what the tool does, what each argument means, what a good input looks like. This is the single biggest lever on whether a tool gets called at all.
  • No turn limit. Bound the loop. Ten turns covers almost every pattern, and an unbounded loop can spend real money.
  • Trusting the arguments. The model can invent a field or omit a required one. Validate with Pydantic or Zod before you execute.

Next steps

Structured output

When you want JSON back without a tool loop.

Streaming

Stream the assistant turn as it arrives.

Chat completions

The full request contract.