DocumentationTools
Build
Tools
Describe your functions to the model. It decides when to call one, your code runs it and returns the result.
On this page
The full round trip
You describe the function
Its name, what it does and its parameters, in JSON Schema.
The model requests the call
Instead of text, it returns tool_calls with the arguments.
Your code runs it
The model runs nothing itself. You stay in control of what happens.
The model answers
With the result sent back in a tool message, it writes its answer.
Example
A function that says whether an invoice is paid. The response shown is from the first call, when the model asks for the function.
import json
tools = [
{
"type": "function",
"function": {
"name": "invoice_status",
"description": "Payment status of an invoice.",
"parameters": {
"type": "object",
"properties": {"number": {"type": "string"}},
"required": ["number"],
},
},
}
]
messages = [
{
"role": "user",
"content": "Has invoice 2026-114 been paid?",
}
]
first = client.chat.completions.create(
model="flash", messages=messages, tools=tools
)
call = first.choices[0].message.tool_calls[0]
args = json.loads(call.function.arguments)
# Run the function, then return its result with the call id.
result = {
"number": args["number"],
"status": "paid",
"paid_on": "2026-10-02",
}
messages.append(first.choices[0].message)
messages.append(
{
"role": "tool",
"tool_call_id": call.id,
"content": json.dumps(result),
}
)
final = client.chat.completions.create(
model="flash", messages=messages, tools=tools
)
print(final.choices[0].message.content)const tools = [
{
type: "function",
function: {
name: "invoice_status",
description: "Payment status of an invoice.",
parameters: {
type: "object",
properties: { number: { type: "string" } },
required: ["number"],
},
},
},
]
const messages = [
{ role: "user", content: "Has invoice 2026-114 been paid?" },
]
const first = await client.chat.completions.create({
model: "flash",
messages,
tools,
})
const call = first.choices[0].message.tool_calls[0]
const args = JSON.parse(call.function.arguments)
// Run the function, then return its result with the call id.
const result = {
number: args.number,
status: "paid",
paid_on: "2026-10-02",
}
messages.push(first.choices[0].message)
messages.push({
role: "tool",
tool_call_id: call.id,
content: JSON.stringify(result),
})
const final = await client.chat.completions.create({
model: "flash",
messages,
tools,
})
console.log(final.choices[0].message.content)import type {
ChatCompletionMessageParam,
ChatCompletionTool,
} from "openai/resources"
const tools: ChatCompletionTool[] = [
{
type: "function",
function: {
name: "invoice_status",
description: "Payment status of an invoice.",
parameters: {
type: "object",
properties: { number: { type: "string" } },
required: ["number"],
},
},
},
]
const messages: ChatCompletionMessageParam[] = [
{ role: "user", content: "Has invoice 2026-114 been paid?" },
]
const first = await client.chat.completions.create({
model: "flash",
messages,
tools,
})
const call = first.choices[0].message.tool_calls?.[0]
if (call?.type !== "function")
throw new Error("no function call")
const args = JSON.parse(call.function.arguments) as {
number: string
}
// Run the function, then return its result with the call id.
const result = {
number: args.number,
status: "paid",
paid_on: "2026-10-02",
}
messages.push(first.choices[0].message)
messages.push({
role: "tool",
tool_call_id: call.id,
content: JSON.stringify(result),
})
const final = await client.chat.completions.create({
model: "flash",
messages,
tools,
})
console.log(final.choices[0].message.content)Response
{
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_7f3a",
"type": "function",
"function": { "name": "invoice_status", "arguments": "{\"number\": \"2026-114\"}" }
}
]
}Good to know
- An empty tool list is removed along with tool_choice, as if you had sent none.
- parallel_tool_calls lets the model request several functions at once.
- Check the arguments before acting. The model can be wrong, your code decides.