feat(vertexai/genai): constrained decoding (#9731)
Expose FunctionCallingMode, which lets the user configure
how the model issues function calls.
By setting the new field `Model.ToolConfig`, the user can select whether
the model can call any provided function, only those in a provided list,
or no functions.
Regenerating also brought along a few other new types and values,
some of which required configuration.
diff --git a/vertexai/genai/aiplatformpb_veneer.gen.go b/vertexai/genai/aiplatformpb_veneer.gen.go
index a887908..63a1e8a 100644
--- a/vertexai/genai/aiplatformpb_veneer.gen.go
+++ b/vertexai/genai/aiplatformpb_veneer.gen.go
@@ -24,13 +24,11 @@
"cloud.google.com/go/vertexai/internal/support"
)
-// Blob contains raw media bytes.
-//
-// Text should not be sent as raw bytes, use the 'text' field.
+// Blob contains binary data like images. Use [Text] for text.
type Blob struct {
// Required. The IANA standard MIME type of the source data.
MIMEType string
- // Required. Raw bytes for media formats.
+ // Required. Raw bytes.
Data []byte
}
@@ -64,12 +62,19 @@
BlockedReasonSafety BlockedReason = 1
// BlockedReasonOther means candidates blocked due to other reason.
BlockedReasonOther BlockedReason = 2
+ // BlockedReasonBlocklist means candidates blocked due to the terms which are included from the
+ // terminology blocklist.
+ BlockedReasonBlocklist BlockedReason = 3
+ // BlockedReasonProhibitedContent means candidates blocked due to prohibited content.
+ BlockedReasonProhibitedContent BlockedReason = 4
)
var namesForBlockedReason = map[BlockedReason]string{
- BlockedReasonUnspecified: "BlockedReasonUnspecified",
- BlockedReasonSafety: "BlockedReasonSafety",
- BlockedReasonOther: "BlockedReasonOther",
+ BlockedReasonUnspecified: "BlockedReasonUnspecified",
+ BlockedReasonSafety: "BlockedReasonSafety",
+ BlockedReasonOther: "BlockedReasonOther",
+ BlockedReasonBlocklist: "BlockedReasonBlocklist",
+ BlockedReasonProhibitedContent: "BlockedReasonProhibitedContent",
}
func (v BlockedReason) String() string {
@@ -371,6 +376,69 @@
}
}
+// FunctionCallingConfig holds configuration for function calling.
+type FunctionCallingConfig struct {
+ // Optional. Function calling mode.
+ Mode FunctionCallingMode
+ // Optional. Function names to call. Only set when the Mode is ANY. Function
+ // names should match [FunctionDeclaration.name]. With mode set to ANY, model
+ // will predict a function call from the set of function names provided.
+ AllowedFunctionNames []string
+}
+
+func (v *FunctionCallingConfig) toProto() *pb.FunctionCallingConfig {
+ if v == nil {
+ return nil
+ }
+ return &pb.FunctionCallingConfig{
+ Mode: pb.FunctionCallingConfig_Mode(v.Mode),
+ AllowedFunctionNames: v.AllowedFunctionNames,
+ }
+}
+
+func (FunctionCallingConfig) fromProto(p *pb.FunctionCallingConfig) *FunctionCallingConfig {
+ if p == nil {
+ return nil
+ }
+ return &FunctionCallingConfig{
+ Mode: FunctionCallingMode(p.Mode),
+ AllowedFunctionNames: p.AllowedFunctionNames,
+ }
+}
+
+// FunctionCallingMode is function calling mode.
+type FunctionCallingMode int32
+
+const (
+ // FunctionCallingUnspecified means unspecified function calling mode. This value should not be used.
+ FunctionCallingUnspecified FunctionCallingMode = 0
+ // FunctionCallingAuto means default model behavior, model decides to predict either a function call
+ // or a natural language repspose.
+ FunctionCallingAuto FunctionCallingMode = 1
+ // FunctionCallingAny means model is constrained to always predicting a function call only.
+ // If "allowed_function_names" are set, the predicted function call will be
+ // limited to any one of "allowed_function_names", else the predicted
+ // function call will be any one of the provided "function_declarations".
+ FunctionCallingAny FunctionCallingMode = 2
+ // FunctionCallingNone means model will not predict any function call. Model behavior is same as when
+ // not passing any function declarations.
+ FunctionCallingNone FunctionCallingMode = 3
+)
+
+var namesForFunctionCallingMode = map[FunctionCallingMode]string{
+ FunctionCallingUnspecified: "FunctionCallingUnspecified",
+ FunctionCallingAuto: "FunctionCallingAuto",
+ FunctionCallingAny: "FunctionCallingAny",
+ FunctionCallingNone: "FunctionCallingNone",
+}
+
+func (v FunctionCallingMode) String() string {
+ if n, ok := namesForFunctionCallingMode[v]; ok {
+ return n
+ }
+ return fmt.Sprintf("FunctionCallingMode(%d)", v)
+}
+
// FunctionDeclaration is structured representation of a function declaration as defined by the
// [OpenAPI 3.0 specification](https://spec.openapis.org/oas/v3.0.3). Included
// in this declaration are the function name and parameters. This
@@ -379,8 +447,8 @@
type FunctionDeclaration struct {
// Required. The name of the function to call.
// Must start with a letter or an underscore.
- // Must be a-z, A-Z, 0-9, or contain underscores and dashes, with a maximum
- // length of 64.
+ // Must be a-z, A-Z, 0-9, or contain underscores, dots and dashes, with a
+ // maximum length of 64.
Name string
// Optional. Description and purpose of the function.
// Model uses it to decide how and whether to call the function.
@@ -389,8 +457,10 @@
// format. Reflects the Open API 3.03 Parameter Object. string Key: the name
// of the parameter. Parameter names are case sensitive. Schema Value: the
// Schema defining the type used for the parameter. For function with no
- // parameters, this can be left unset. Example with 1 required and 1 optional
- // parameter: type: OBJECT properties:
+ // parameters, this can be left unset. Parameter names must start with a
+ // letter or an underscore and must only contain chars a-z, A-Z, 0-9, or
+ // underscores with a maximum length of 64. Example with 1 required and 1
+ // optional parameter: type: OBJECT properties:
//
// param1:
// type: STRING
@@ -400,6 +470,10 @@
// required:
// - param1
Parameters *Schema
+ // Optional. Describes the output from this function in JSON Schema format.
+ // Reflects the Open API 3.03 Response Object. The Schema defines the type
+ // used for the response value of the function.
+ Response *Schema
}
func (v *FunctionDeclaration) toProto() *pb.FunctionDeclaration {
@@ -410,6 +484,7 @@
Name: v.Name,
Description: v.Description,
Parameters: v.Parameters.toProto(),
+ Response: v.Response.toProto(),
}
}
@@ -421,6 +496,7 @@
Name: p.Name,
Description: p.Description,
Parameters: (Schema{}).fromProto(p.Parameters),
+ Response: (Schema{}).fromProto(p.Response),
}
}
@@ -504,6 +580,18 @@
MaxOutputTokens *int32
// Optional. Stop sequences.
StopSequences []string
+ // Optional. Positive penalties.
+ PresencePenalty *float32
+ // Optional. Frequency penalties.
+ FrequencyPenalty *float32
+ // Optional. Output response mimetype of the generated candidate text.
+ // Supported mimetype:
+ // - `text/plain`: (default) Text output.
+ // - `application/json`: JSON response in the candidates.
+ // The model needs to be prompted to output the appropriate response type,
+ // otherwise the behavior is undefined.
+ // This is a preview feature.
+ ResponseMIMEType string
}
func (v *GenerationConfig) toProto() *pb.GenerationConfig {
@@ -511,12 +599,15 @@
return nil
}
return &pb.GenerationConfig{
- Temperature: v.Temperature,
- TopP: v.TopP,
- TopK: int32pToFloat32p(v.TopK),
- CandidateCount: v.CandidateCount,
- MaxOutputTokens: v.MaxOutputTokens,
- StopSequences: v.StopSequences,
+ Temperature: v.Temperature,
+ TopP: v.TopP,
+ TopK: int32pToFloat32p(v.TopK),
+ CandidateCount: v.CandidateCount,
+ MaxOutputTokens: v.MaxOutputTokens,
+ StopSequences: v.StopSequences,
+ PresencePenalty: v.PresencePenalty,
+ FrequencyPenalty: v.FrequencyPenalty,
+ ResponseMimeType: v.ResponseMIMEType,
}
}
@@ -525,15 +616,43 @@
return nil
}
return &GenerationConfig{
- Temperature: p.Temperature,
- TopP: p.TopP,
- TopK: float32pToInt32p(p.TopK),
- CandidateCount: p.CandidateCount,
- MaxOutputTokens: p.MaxOutputTokens,
- StopSequences: p.StopSequences,
+ Temperature: p.Temperature,
+ TopP: p.TopP,
+ TopK: float32pToInt32p(p.TopK),
+ CandidateCount: p.CandidateCount,
+ MaxOutputTokens: p.MaxOutputTokens,
+ StopSequences: p.StopSequences,
+ PresencePenalty: p.PresencePenalty,
+ FrequencyPenalty: p.FrequencyPenalty,
+ ResponseMIMEType: p.ResponseMimeType,
}
}
+// HarmBlockMethod determines how harm blocking is done.
+type HarmBlockMethod int32
+
+const (
+ // HarmBlockMethodUnspecified means the harm block method is unspecified.
+ HarmBlockMethodUnspecified HarmBlockMethod = 0
+ // HarmBlockMethodSeverity means the harm block method uses both probability and severity scores.
+ HarmBlockMethodSeverity HarmBlockMethod = 1
+ // HarmBlockMethodProbability means the harm block method uses the probability score.
+ HarmBlockMethodProbability HarmBlockMethod = 2
+)
+
+var namesForHarmBlockMethod = map[HarmBlockMethod]string{
+ HarmBlockMethodUnspecified: "HarmBlockMethodUnspecified",
+ HarmBlockMethodSeverity: "HarmBlockMethodSeverity",
+ HarmBlockMethodProbability: "HarmBlockMethodProbability",
+}
+
+func (v HarmBlockMethod) String() string {
+ if n, ok := namesForHarmBlockMethod[v]; ok {
+ return n
+ }
+ return fmt.Sprintf("HarmBlockMethod(%d)", v)
+}
+
// HarmBlockThreshold specifies probability based thresholds levels for blocking.
type HarmBlockThreshold int32
@@ -627,7 +746,7 @@
return fmt.Sprintf("HarmProbability(%d)", v)
}
-// HarmSeverity is harm severity levels.
+// HarmSeverity specifies harm severity levels.
type HarmSeverity int32
const (
@@ -741,6 +860,9 @@
Category HarmCategory
// Required. The harm block threshold.
Threshold HarmBlockThreshold
+ // Optional. Specify if the threshold is used for probability or severity
+ // score. If not specified, the threshold is used for probability score.
+ Method HarmBlockMethod
}
func (v *SafetySetting) toProto() *pb.SafetySetting {
@@ -750,6 +872,7 @@
return &pb.SafetySetting{
Category: pb.HarmCategory(v.Category),
Threshold: pb.SafetySetting_HarmBlockThreshold(v.Threshold),
+ Method: pb.SafetySetting_HarmBlockMethod(v.Method),
}
}
@@ -760,6 +883,7 @@
return &SafetySetting{
Category: HarmCategory(p.Category),
Threshold: HarmBlockThreshold(p.Threshold),
+ Method: HarmBlockMethod(p.Method),
}
}
@@ -773,23 +897,49 @@
// Optional. The format of the data.
// Supported formats:
//
- // for NUMBER type: float, double
- // for INTEGER type: int32, int64
+ // for NUMBER type: "float", "double"
+ // for INTEGER type: "int32", "int64"
+ // for STRING type: "email", "byte", etc
Format string
+ // Optional. The title of the Schema.
+ Title string
// Optional. The description of the data.
Description string
// Optional. Indicates if the value may be null.
Nullable bool
- // Optional. Schema of the elements of Type.ARRAY.
+ // Optional. SCHEMA FIELDS FOR TYPE ARRAY
+ // Schema of the elements of Type.ARRAY.
Items *Schema
+ // Optional. Minimum number of the elements for Type.ARRAY.
+ MinItems int64
+ // Optional. Maximum number of the elements for Type.ARRAY.
+ MaxItems int64
// Optional. Possible values of the element of Type.STRING with enum format.
// For example we can define an Enum Direction as :
// {type:STRING, format:enum, enum:["EAST", NORTH", "SOUTH", "WEST"]}
Enum []string
- // Optional. Properties of Type.OBJECT.
+ // Optional. SCHEMA FIELDS FOR TYPE OBJECT
+ // Properties of Type.OBJECT.
Properties map[string]*Schema
// Optional. Required properties of Type.OBJECT.
Required []string
+ // Optional. Minimum number of the properties for Type.OBJECT.
+ MinProperties int64
+ // Optional. Maximum number of the properties for Type.OBJECT.
+ MaxProperties int64
+ // Optional. SCHEMA FIELDS FOR TYPE INTEGER and NUMBER
+ // Minimum value of the Type.INTEGER and Type.NUMBER
+ Minimum float64
+ // Optional. Maximum value of the Type.INTEGER and Type.NUMBER
+ Maximum float64
+ // Optional. SCHEMA FIELDS FOR TYPE STRING
+ // Minimum length of the Type.STRING
+ MinLength int64
+ // Optional. Maximum length of the Type.STRING
+ MaxLength int64
+ // Optional. Pattern of the Type.STRING to restrict a string to a regular
+ // expression.
+ Pattern string
}
func (v *Schema) toProto() *pb.Schema {
@@ -797,14 +947,24 @@
return nil
}
return &pb.Schema{
- Type: pb.Type(v.Type),
- Format: v.Format,
- Description: v.Description,
- Nullable: v.Nullable,
- Items: v.Items.toProto(),
- Enum: v.Enum,
- Properties: support.TransformMapValues(v.Properties, (*Schema).toProto),
- Required: v.Required,
+ Type: pb.Type(v.Type),
+ Format: v.Format,
+ Title: v.Title,
+ Description: v.Description,
+ Nullable: v.Nullable,
+ Items: v.Items.toProto(),
+ MinItems: v.MinItems,
+ MaxItems: v.MaxItems,
+ Enum: v.Enum,
+ Properties: support.TransformMapValues(v.Properties, (*Schema).toProto),
+ Required: v.Required,
+ MinProperties: v.MinProperties,
+ MaxProperties: v.MaxProperties,
+ Minimum: v.Minimum,
+ Maximum: v.Maximum,
+ MinLength: v.MinLength,
+ MaxLength: v.MaxLength,
+ Pattern: v.Pattern,
}
}
@@ -813,14 +973,24 @@
return nil
}
return &Schema{
- Type: Type(p.Type),
- Format: p.Format,
- Description: p.Description,
- Nullable: p.Nullable,
- Items: (Schema{}).fromProto(p.Items),
- Enum: p.Enum,
- Properties: support.TransformMapValues(p.Properties, (Schema{}).fromProto),
- Required: p.Required,
+ Type: Type(p.Type),
+ Format: p.Format,
+ Title: p.Title,
+ Description: p.Description,
+ Nullable: p.Nullable,
+ Items: (Schema{}).fromProto(p.Items),
+ MinItems: p.MinItems,
+ MaxItems: p.MaxItems,
+ Enum: p.Enum,
+ Properties: support.TransformMapValues(p.Properties, (Schema{}).fromProto),
+ Required: p.Required,
+ MinProperties: p.MinProperties,
+ MaxProperties: p.MaxProperties,
+ Minimum: p.Minimum,
+ Maximum: p.Maximum,
+ MinLength: p.MinLength,
+ MaxLength: p.MaxLength,
+ Pattern: p.Pattern,
}
}
@@ -861,6 +1031,30 @@
}
}
+// ToolConfig configures tools.
+type ToolConfig struct {
+ // Optional. Function calling config.
+ FunctionCallingConfig *FunctionCallingConfig
+}
+
+func (v *ToolConfig) toProto() *pb.ToolConfig {
+ if v == nil {
+ return nil
+ }
+ return &pb.ToolConfig{
+ FunctionCallingConfig: v.FunctionCallingConfig.toProto(),
+ }
+}
+
+func (ToolConfig) fromProto(p *pb.ToolConfig) *ToolConfig {
+ if p == nil {
+ return nil
+ }
+ return &ToolConfig{
+ FunctionCallingConfig: (FunctionCallingConfig{}).fromProto(p.FunctionCallingConfig),
+ }
+}
+
// Type contains the list of OpenAPI data types as defined by
// https://swagger.io/docs/specification/data-models/data-types/
type Type int32
diff --git a/vertexai/genai/client.go b/vertexai/genai/client.go
index a0f3872..de18690 100644
--- a/vertexai/genai/client.go
+++ b/vertexai/genai/client.go
@@ -95,6 +95,7 @@
GenerationConfig
SafetySettings []*SafetySetting
Tools []*Tool
+ ToolConfig *ToolConfig // configuration for tools
}
const defaultMaxOutputTokens = 2048
@@ -145,6 +146,7 @@
Contents: support.TransformSlice(contents, (*Content).toProto),
SafetySettings: support.TransformSlice(m.SafetySettings, (*SafetySetting).toProto),
Tools: support.TransformSlice(m.Tools, (*Tool).toProto),
+ ToolConfig: m.ToolConfig.toProto(),
GenerationConfig: m.GenerationConfig.toProto(),
}
}
diff --git a/vertexai/genai/client_test.go b/vertexai/genai/client_test.go
index 17b06d5..d0e5f7d 100644
--- a/vertexai/genai/client_test.go
+++ b/vertexai/genai/client_test.go
@@ -234,32 +234,52 @@
model := client.GenerativeModel(*modelName)
model.SetTemperature(0)
model.Tools = []*Tool{weatherTool}
- session := model.StartChat()
- res, err := session.SendMessage(ctx, Text("What is the weather like in New York?"))
- if err != nil {
- t.Fatal(err)
- }
- part := res.Candidates[0].Content.Parts[0]
- funcall, ok := part.(FunctionCall)
- if !ok {
- t.Fatalf("want FunctionCall, got %T", part)
- }
- if g, w := funcall.Name, weatherTool.FunctionDeclarations[0].Name; g != w {
- t.Errorf("FunctionCall.Name: got %q, want %q", g, w)
- }
- if g, c := funcall.Args["location"], "New York"; !strings.Contains(g.(string), c) {
- t.Errorf(`FunctionCall.Args["location"]: got %q, want string containing %q`, g, c)
- }
- res, err = session.SendMessage(ctx, FunctionResponse{
- Name: weatherTool.FunctionDeclarations[0].Name,
- Response: map[string]any{
- "weather_there": "cold",
- },
+ t.Run("funcall", func(t *testing.T) {
+ session := model.StartChat()
+ res, err := session.SendMessage(ctx, Text("What is the weather like in New York?"))
+ if err != nil {
+ t.Fatal(err)
+ }
+ part := res.Candidates[0].Content.Parts[0]
+ funcall, ok := part.(FunctionCall)
+ if !ok {
+ t.Fatalf("want FunctionCall, got %T", part)
+ }
+ if g, w := funcall.Name, weatherTool.FunctionDeclarations[0].Name; g != w {
+ t.Errorf("FunctionCall.Name: got %q, want %q", g, w)
+ }
+ if g, c := funcall.Args["location"], "New York"; !strings.Contains(g.(string), c) {
+ t.Errorf(`FunctionCall.Args["location"]: got %q, want string containing %q`, g, c)
+ }
+ res, err = session.SendMessage(ctx, FunctionResponse{
+ Name: weatherTool.FunctionDeclarations[0].Name,
+ Response: map[string]any{
+ "weather_there": "cold",
+ },
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+ checkMatch(t, responseString(res), "(it's|it is|weather) .*cold")
})
- if err != nil {
- t.Fatal(err)
- }
- checkMatch(t, responseString(res), "(it's|it is|weather) .*cold")
+ t.Run("funcall-none", func(t *testing.T) {
+ model.ToolConfig = &ToolConfig{
+ FunctionCallingConfig: &FunctionCallingConfig{
+ Mode: FunctionCallingNone, // never return a FunctionCall part
+ },
+ }
+ session := model.StartChat()
+ res, err := session.SendMessage(ctx, Text("What is the weather like in New York?"))
+ if err != nil {
+ t.Fatal(err)
+ }
+ // We should not find a FunctionCall part.
+ for _, p := range res.Candidates[0].Content.Parts {
+ if _, ok := p.(FunctionCall); ok {
+ t.Fatal("saw FunctionCall")
+ }
+ }
+ })
})
}
diff --git a/vertexai/genai/config.yaml b/vertexai/genai/config.yaml
index f223835..dedbe68 100644
--- a/vertexai/genai/config.yaml
+++ b/vertexai/genai/config.yaml
@@ -18,6 +18,12 @@
valueNames:
SafetySetting_HARM_BLOCK_THRESHOLD_UNSPECIFIED: HarmBlockUnspecified
+ SafetySetting_HarmBlockMethod:
+ name: HarmBlockMethod
+ protoPrefix: SafetySetting_
+ veneerPrefix: HarmBlockMethod
+ doc: 'determines how harm blocking is done.'
+
SafetyRating_HarmProbability:
name: HarmProbability
protoPrefix: SafetyRating_
@@ -50,7 +56,8 @@
fields:
MimeType:
name: MIMEType
- docVerb: contains
+ doc: 'contains binary data like images. Use [Text] for text.'
+ removeOtherDoc: true
FileData:
fields:
@@ -63,11 +70,23 @@
FunctionResponse:
+ FunctionCallingConfig:
+ doc: 'holds configuration for function calling.'
+
+ FunctionCallingConfig_Mode:
+ name: FunctionCallingMode
+ protoPrefix: FunctionCallingConfig
+ veneerPrefix: FunctionCalling
+ valueNames:
+ FunctionCallingConfig_MODE_UNSPECIFIED: FunctionCallingUnspecified
+
GenerationConfig:
fields:
TopK:
type: '*int32'
convertToFrom: int32pToFloat32p, float32pToInt32p
+ ResponseMimeType:
+ name: ResponseMIMEType
SafetyRating:
docVerb: 'is the'
@@ -105,10 +124,16 @@
GoogleSearchRetrieval:
omit: true
+ ToolConfig:
+ doc: 'configures tools.'
+
Schema:
fields:
Example:
omit: true
+ Default:
+ # TODO(jba): protoveneer should treat a *structpb.Value as an any
+ omit: true
CitationMetadata:
FunctionDeclaration:
diff --git a/vertexai/genai/example_test.go b/vertexai/genai/example_test.go
index c549f3b..229c7e7 100644
--- a/vertexai/genai/example_test.go
+++ b/vertexai/genai/example_test.go
@@ -135,6 +135,143 @@
printResponse(res)
}
+func ExampleTool() {
+ ctx := context.Background()
+ client, err := genai.NewClient(ctx, projectID, location)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer client.Close()
+
+ currentWeather := func(city string) string {
+ switch city {
+ case "New York, NY":
+ return "cold"
+ case "Miami, FL":
+ return "warm"
+ default:
+ return "unknown"
+ }
+ }
+
+ // To use functions / tools, we have to first define a schema that describes
+ // the function to the model. The schema is similar to OpenAPI 3.0.
+ //
+ // In this example, we create a single function that provides the model with
+ // a weather forecast in a given location.
+ schema := &genai.Schema{
+ Type: genai.TypeObject,
+ Properties: map[string]*genai.Schema{
+ "location": {
+ Type: genai.TypeString,
+ Description: "The city and state, e.g. San Francisco, CA",
+ },
+ "unit": {
+ Type: genai.TypeString,
+ Enum: []string{"celsius", "fahrenheit"},
+ },
+ },
+ Required: []string{"location"},
+ }
+
+ weatherTool := &genai.Tool{
+ FunctionDeclarations: []*genai.FunctionDeclaration{{
+ Name: "CurrentWeather",
+ Description: "Get the current weather in a given location",
+ Parameters: schema,
+ }},
+ }
+
+ model := client.GenerativeModel("gemini-1.0-pro")
+
+ // Before initiating a conversation, we tell the model which tools it has
+ // at its disposal.
+ model.Tools = []*genai.Tool{weatherTool}
+
+ // For using tools, the chat mode is useful because it provides the required
+ // chat context. A model needs to have tools supplied to it in the chat
+ // history so it can use them in subsequent conversations.
+ //
+ // The flow of message expected here is:
+ //
+ // 1. We send a question to the model
+ // 2. The model recognizes that it needs to use a tool to answer the question,
+ // an returns a FunctionCall response asking to use the CurrentWeather
+ // tool.
+ // 3. We send a FunctionResponse message, simulating the return value of
+ // CurrentWeather for the model's query.
+ // 4. The model provides its text answer in response to this message.
+ session := model.StartChat()
+
+ res, err := session.SendMessage(ctx, genai.Text("What is the weather like in New York?"))
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ part := res.Candidates[0].Content.Parts[0]
+ funcall, ok := part.(genai.FunctionCall)
+ if !ok {
+ log.Fatalf("expected FunctionCall: %v", part)
+ }
+
+ if funcall.Name != "CurrentWeather" {
+ log.Fatalf("expected CurrentWeather: %v", funcall.Name)
+ }
+
+ // Expect the model to pass a proper string "location" argument to the tool.
+ locArg, ok := funcall.Args["location"].(string)
+ if !ok {
+ log.Fatalf("expected string: %v", funcall.Args["location"])
+ }
+
+ weatherData := currentWeather(locArg)
+ res, err = session.SendMessage(ctx, genai.FunctionResponse{
+ Name: weatherTool.FunctionDeclarations[0].Name,
+ Response: map[string]any{
+ "weather": weatherData,
+ },
+ })
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ printResponse(res)
+}
+
+func ExampleToolConifg() {
+ // This example shows how to affect how the model uses the tools provided to it.
+ // By setting the ToolConfig, you can disable function calling.
+
+ // Assume we have created a Model and have set its Tools field with some functions.
+ // See the Example for Tool for details.
+ var model *genai.GenerativeModel
+
+ // By default, the model will use the functions in its responses if it thinks they are
+ // relevant, by returning FunctionCall parts.
+ // Here we set the model's ToolConfig to disable function calling completely.
+ model.ToolConfig = &genai.ToolConfig{
+ FunctionCallingConfig: &genai.FunctionCallingConfig{
+ Mode: genai.FunctionCallingNone,
+ },
+ }
+
+ // Subsequent calls to ChatSession.SendMessage will not result in FunctionCall responses.
+ session := model.StartChat()
+ res, err := session.SendMessage(context.Background(), genai.Text("What is the weather like in New York?"))
+ if err != nil {
+ log.Fatal(err)
+ }
+ for _, part := range res.Candidates[0].Content.Parts {
+ if _, ok := part.(genai.FunctionCall); ok {
+ log.Fatal("did not expect FunctionCall")
+ }
+ }
+
+ // It is also possible to force a function call by using FunctionCallingAny
+ // instead of FunctionCallingNone. See the documentation for FunctionCallingMode
+ // for details.
+}
+
func printResponse(resp *genai.GenerateContentResponse) {
for _, cand := range resp.Candidates {
for _, part := range cand.Content.Parts {