Function tool example
Let's look at an end-to-end tool calling flow for a get_horoscope function that gets a daily horoscope for an astrological sign.
Complete tool calling example
javascript
import OpenAI from "openai";
import { toResponseInputItems } from "openai/lib/responses/ResponseInputItems";
const openai = new OpenAI();
// 1. Define a list of callable tools for the model
/** @type {OpenAI.Responses.Tool[]} */
const tools = [
{
type: "function",
name: "get_horoscope",
description: "Get today's horoscope for an astrological sign.",
parameters: {
type: "object",
properties: {
sign: {
type: "string",
description: "An astrological sign like Taurus or Aquarius",
},
},
required: ["sign"],
additionalProperties: false,
},
strict: true,
},
];
function getHoroscope(sign) {
return `${sign}: Next Tuesday you will befriend a baby otter.`;
}
// Create a running input list we will add to over time
/** @type {OpenAI.Responses.ResponseInput} */
let input = [
{ role: "user", content: "What is my horoscope? I am an Aquarius." },
];
// 2. Prompt the model with tools defined
let response = await openai.responses.create({
model: "gpt-6-astra",
tools,
input,
});
// Preserve model output for the next turn
input.push(...toResponseInputItems(response.output));
for (const item of response.output) {
if (item.type !== "function_call") continue;
if (item.name === "get_horoscope") {
// 3. Execute the function logic for get_horoscope
const { sign } = JSON.parse(item.arguments);
const horoscope = getHoroscope(sign);
// 4. Provide function call results to the model
input.push({
type: "function_call_output",
call_id: item.call_id,
output: horoscope,
});
}
}
console.log("Final input:");
console.log(JSON.stringify(input, null, 2));
response = await openai.responses.create({
model: "gpt-6-astra",
instructions: "Respond only with a horoscope generated by a tool.",
tools,
input,
});
// 5. The model should be able to give a response!
console.log("Final output:");
console.log(response.output_text);python
from openai import OpenAI
import json
client = OpenAI()
# 1. Define a list of callable tools for the model
tools = [
{
"type": "function",
"name": "get_horoscope",
"description": "Get today's horoscope for an astrological sign.",
"parameters": {
"type": "object",
"properties": {
"sign": {
"type": "string",
"description": "An astrological sign like Taurus or Aquarius",
},
},
"required": ["sign"],
},
},
]
def get_horoscope(sign):
return f"{sign}: Next Tuesday you will befriend a baby otter."
# Create a running input list we will add to over time
input_list = [{"role": "user", "content": "What is my horoscope? I am an Aquarius."}]
# 2. Prompt the model with tools defined
response = client.responses.create(
model="gpt-6-astra",
tools=tools,
input=input_list,
)
# Save function call outputs for subsequent requests
input_list += response.output
for item in response.output:
if item.type == "function_call":
if item.name == "get_horoscope":
# 3. Execute the function logic for get_horoscope
sign = json.loads(item.arguments)["sign"]
horoscope = get_horoscope(sign)
# 4. Provide function call results to the model
input_list.append(
{
"type": "function_call_output",
"call_id": item.call_id,
"output": horoscope,
}
)
print("Final input:")
print(input_list)
response = client.responses.create(
model="gpt-6-astra",
instructions="Respond only with a horoscope generated by a tool.",
tools=tools,
input=input_list,
)
# 5. The model should be able to give a response!
print("Final output:")
print(response.model_dump_json(indent=2))
print("\n" + response.output_text)go
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
)
func main() {
client := openai.NewClient()
tool := horoscopeResponseTool()
response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
Input: responses.ResponseNewParamsInputUnion{OfString: openai.String("What is my horoscope? I am an Aquarius.")},
Tools: []responses.ToolUnionParam{tool},
})
if err != nil {
panic(err)
}
var functionOutput responses.ResponseInputItemUnionParam
for _, output := range response.Output {
if output.Type != "function_call" {
continue
}
call := output.AsFunctionCall()
if call.Name != "get_horoscope" {
continue
}
var arguments struct {
Sign string `json:"sign"`
}
if err := json.Unmarshal([]byte(call.Arguments), &arguments); err != nil {
panic(err)
}
functionOutput = responses.ResponseInputItemParamOfFunctionCallOutput(getHoroscope(arguments.Sign))
functionOutput.OfFunctionCallOutput.CallID = openai.String(call.CallID)
}
if functionOutput.OfFunctionCallOutput == nil {
panic("the model did not call get_horoscope")
}
response, err = client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
PreviousResponseID: openai.String(response.ID),
Instructions: openai.String("Respond only with a horoscope generated by a tool."),
Input: responses.ResponseNewParamsInputUnion{OfInputItemList: responses.ResponseInputParam{functionOutput}},
Tools: []responses.ToolUnionParam{tool},
})
if err != nil {
panic(err)
}
fmt.Println(response.OutputText())
}
func horoscopeResponseTool() responses.ToolUnionParam {
parameters := map[string]any{
"type": "object",
"properties": map[string]any{
"sign": map[string]any{"type": "string", "description": "An astrological sign like Taurus or Aquarius"},
},
"required": []string{"sign"},
"additionalProperties": false,
}
tool := responses.ToolParamOfFunction("get_horoscope", parameters, true)
tool.OfFunction.Description = openai.String("Get today's horoscope for an astrological sign.")
return tool
}
func getHoroscope(sign string) string {
return fmt.Sprintf("%s: Next Tuesday you will befriend a baby otter.", sign)
}java
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.JsonValue;
import com.openai.models.responses.FunctionTool;
import com.openai.models.responses.ResponseCreateParams;
import com.openai.models.responses.ResponseInputItem;
import java.util.List;
import java.util.Map;
FunctionTool horoscope =
FunctionTool.builder()
.name("get_horoscope")
.description("Get today's horoscope for an astrological sign.")
.parameters(
FunctionTool.Parameters.builder()
.putAdditionalProperty("type", JsonValue.from("object"))
.putAdditionalProperty(
"properties",
JsonValue.from(
Map.of(
"sign",
Map.of(
"type", "string",
"description",
"An astrological sign like Taurus or Aquarius"))))
.putAdditionalProperty("required", JsonValue.from(List.of("sign")))
.putAdditionalProperty("additionalProperties", JsonValue.from(false))
.build())
.strict(true)
.build();
var firstResponse =
client
.responses()
.create(
ResponseCreateParams.builder()
.model("gpt-6-astra")
.input("What is my horoscope? I am an Aquarius.")
.addTool(horoscope)
.build());
var functionCall =
firstResponse.output().stream()
.flatMap(item -> item.functionCall().stream())
.filter(call -> call.name().equals("get_horoscope"))
.findFirst()
.orElseThrow(() -> new IllegalStateException("The model did not call get_horoscope"));
record HoroscopeArguments(String sign) {}
String sign = functionCall.arguments(HoroscopeArguments.class).sign();
ResponseCreateParams followUp =
ResponseCreateParams.builder()
.model("gpt-6-astra")
.instructions("Respond only with a horoscope generated by a tool.")
.previousResponseId(firstResponse.id())
.inputOfResponse(
List.of(
ResponseInputItem.ofFunctionCallOutput(
ResponseInputItem.FunctionCallOutput.builder()
.callId(functionCall.callId())
.output(sign + ": Embrace an unexpected opportunity today.")
.build())))
.addTool(horoscope)
.build();
client.responses().create(followUp).output().stream()
.flatMap(item -> item.message().stream())
.flatMap(message -> message.content().stream())
.flatMap(content -> content.outputText().stream())
.forEach(text -> System.out.println(text.text()));ruby
require "json"
require "openai"
client = OpenAI::Client.new
tools = [{
type: :function,
name: "get_horoscope",
description: "Get today's horoscope for an astrological sign.",
parameters: {
type: :object,
properties: {sign: {type: :string}},
required: ["sign"],
additionalProperties: false
},
strict: true
}]
first_response = client.responses.create(
model: "gpt-6-astra",
input: "What is my horoscope? I am an Aquarius.",
tools: tools
)
function_call = first_response.output.find do |item|
item.is_a?(OpenAI::Models::Responses::ResponseFunctionToolCall) &&
item.name == "get_horoscope"
end
unless function_call.is_a?(OpenAI::Models::Responses::ResponseFunctionToolCall)
raise "The model did not call get_horoscope"
end
arguments = JSON.parse(function_call.arguments, symbolize_names: true)
sign = arguments.fetch(:sign)
response = client.responses.create(
model: "gpt-6-astra",
previous_response_id: first_response.id,
input: [{
type: :function_call_output,
call_id: function_call.call_id,
output: "#{sign}: Embrace an unexpected opportunity today."
}],
tools: tools
)
puts(response.output_text)Note that for reasoning models like GPT-5 or o4-mini, any reasoning items returned in model responses with tool calls must also be passed back with tool call outputs.