go/function_calling.go (126 lines of code) (raw):
package examples
import (
"context"
"encoding/json"
"fmt"
"log"
"os"
"google.golang.org/genai"
)
// Arithmetic functions.
func add(a, b float64) float64 {
return a + b
}
func subtract(a, b float64) float64 {
return a - b
}
func multiply(a, b float64) float64 {
return a * b
}
func divide(a, b float64) float64 {
return a / b
}
// ArithmeticArgs represents the expected arguments for our arithmetic operations.
type ArithmeticArgs struct {
FirstParam float64 `json:"firstParam"`
SecondParam float64 `json:"secondParam"`
}
// createArithmeticToolDeclaration creates a function declaration with the given name and description.
// The parameters schema includes "firstParam" and "secondParam" as required numbers.
func createArithmeticToolDeclaration(name, description string) *genai.FunctionDeclaration {
paramSchema := &genai.Schema{
Type: genai.TypeObject,
Description: "The result of the arithmetic operation.",
Properties: map[string]*genai.Schema{
"firstParam": {
Type: genai.TypeNumber,
Description: "The first parameter which can be an integer or a floating point number.",
},
"secondParam": {
Type: genai.TypeNumber,
Description: "The second parameter which can be an integer or a floating point number.",
},
},
Required: []string{"firstParam", "secondParam"},
}
return &genai.FunctionDeclaration{
Name: name,
Description: description,
Parameters: paramSchema,
}
}
func FunctionCalling() error {
// [START function_calling]
ctx := context.Background()
client, err := genai.NewClient(ctx, &genai.ClientConfig{
APIKey: os.Getenv("GEMINI_API_KEY"),
Backend: genai.BackendGeminiAPI,
})
if err != nil {
log.Fatal(err)
}
modelName := "gemini-2.0-flash"
// Create the function declarations for arithmetic operations.
addDeclaration := createArithmeticToolDeclaration("addNumbers", "Return the result of adding two numbers.")
subtractDeclaration := createArithmeticToolDeclaration("subtractNumbers", "Return the result of subtracting the second number from the first.")
multiplyDeclaration := createArithmeticToolDeclaration("multiplyNumbers", "Return the product of two numbers.")
divideDeclaration := createArithmeticToolDeclaration("divideNumbers", "Return the quotient of dividing the first number by the second.")
// Group the function declarations as a tool.
tools := []*genai.Tool{
{
FunctionDeclarations: []*genai.FunctionDeclaration{
addDeclaration,
subtractDeclaration,
multiplyDeclaration,
divideDeclaration,
},
},
}
// Create the content prompt.
contents := []*genai.Content{
genai.NewContentFromText(
"I have 57 cats, each owns 44 mittens, how many mittens is that in total?", genai.RoleUser,
),
}
// Set up the generate content configuration with function calling enabled.
config := &genai.GenerateContentConfig{
Tools: tools,
ToolConfig: &genai.ToolConfig{
FunctionCallingConfig: &genai.FunctionCallingConfig{
// The mode equivalent to FunctionCallingConfigMode.ANY in JS.
Mode: genai.FunctionCallingConfigModeAny,
},
},
}
genContentResp, err := client.Models.GenerateContent(ctx, modelName, contents, config)
if err != nil {
log.Fatal(err)
}
// Assume the response includes a list of function calls.
if len(genContentResp.FunctionCalls()) == 0 {
log.Println("No function call returned from the AI.")
return nil
}
functionCall := genContentResp.FunctionCalls()[0]
log.Printf("Function call: %+v\n", functionCall)
// Marshal the Args map into JSON bytes.
argsMap, err := json.Marshal(functionCall.Args)
if err != nil {
log.Fatal(err)
}
// Unmarshal the JSON bytes into the ArithmeticArgs struct.
var args ArithmeticArgs
if err := json.Unmarshal(argsMap, &args); err != nil {
log.Fatal(err)
}
// Map the function name to the actual arithmetic function.
var result float64
switch functionCall.Name {
case "addNumbers":
result = add(args.FirstParam, args.SecondParam)
case "subtractNumbers":
result = subtract(args.FirstParam, args.SecondParam)
case "multiplyNumbers":
result = multiply(args.FirstParam, args.SecondParam)
case "divideNumbers":
result = divide(args.FirstParam, args.SecondParam)
default:
return fmt.Errorf("unimplemented function: %s", functionCall.Name)
}
log.Printf("Function result: %v\n", result)
// Prepare the final result message as content.
resultContents := []*genai.Content{
genai.NewContentFromText("The final result is " + fmt.Sprintf("%v", result), genai.RoleUser),
}
// Use GenerateContent to send the final result.
finalResponse, err := client.Models.GenerateContent(ctx, modelName, resultContents, &genai.GenerateContentConfig{})
if err != nil {
log.Fatal(err)
}
printResponse(finalResponse)
// [END function_calling]
return err
}