Skip to content

Commit

Permalink
reviewer comments
Browse files Browse the repository at this point in the history
  • Loading branch information
jba committed Apr 15, 2024
1 parent 6b887f8 commit dfcdc5d
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 2 deletions.
2 changes: 1 addition & 1 deletion vertexai/genai/client.go
Expand Up @@ -95,7 +95,7 @@ type GenerativeModel struct {
GenerationConfig
SafetySettings []*SafetySetting
Tools []*Tool
ToolConfig *ToolConfig
ToolConfig *ToolConfig // configuration for tools
}

const defaultMaxOutputTokens = 2048
Expand Down
2 changes: 1 addition & 1 deletion vertexai/genai/client_test.go
Expand Up @@ -234,7 +234,7 @@ func TestLive(t *testing.T) {
model := client.GenerativeModel(*modelName)
model.SetTemperature(0)
model.Tools = []*Tool{weatherTool}
t.Run("funcall-auto", func(t *testing.T) {
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 {
Expand Down
137 changes: 137 additions & 0 deletions vertexai/genai/example_test.go
Expand Up @@ -135,6 +135,143 @@ func ExampleChatSession() {
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 {
Expand Down

0 comments on commit dfcdc5d

Please sign in to comment.