Skip to content

Commit d205e88

Browse files
elibenjba
andauthored
genai/test: add example for Tool / FunctionCall (#71)
Co-authored-by: Jonathan Amsterdam <[email protected]>
1 parent 9267665 commit d205e88

File tree

2 files changed

+105
-2
lines changed

2 files changed

+105
-2
lines changed

genai/content.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ const (
2525
roleModel = "model"
2626
)
2727

28-
// A Part is either a Text or a Blob.
28+
// A Part is either a Text, a Blob or a FunctionResponse.
2929
type Part interface {
3030
toPart() *pb.Part
3131
}

genai/example_test.go

+104-1
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ func ExampleEmbeddingModel_EmbedContent() {
189189
res, err := em.EmbedContent(ctx, genai.Text("cheddar cheese"))
190190

191191
if err != nil {
192-
panic(err)
192+
log.Fatal(err)
193193
}
194194
fmt.Println(res.Embedding.Values)
195195
}
@@ -258,6 +258,109 @@ func ExampleClient_ListModels() {
258258
}
259259
}
260260

261+
func ExampleTool() {
262+
ctx := context.Background()
263+
client, err := genai.NewClient(ctx, option.WithAPIKey(os.Getenv("GEMINI_API_KEY")))
264+
if err != nil {
265+
log.Fatal(err)
266+
}
267+
defer client.Close()
268+
269+
currentWeather := func(city string) string {
270+
switch city {
271+
case "New York, NY":
272+
return "cold"
273+
case "Miami, FL":
274+
return "warm"
275+
default:
276+
return "unknown"
277+
}
278+
}
279+
280+
// To use functions / tools, we have to first define a schema that describes
281+
// the function to the model. The schema is similar to OpenAPI 3.0.
282+
//
283+
// In this example, we create a single function that provides the model with
284+
// a weather forecast in a given location.
285+
schema := &genai.Schema{
286+
Type: genai.TypeObject,
287+
Properties: map[string]*genai.Schema{
288+
"location": {
289+
Type: genai.TypeString,
290+
Description: "The city and state, e.g. San Francisco, CA",
291+
},
292+
"unit": {
293+
Type: genai.TypeString,
294+
Enum: []string{"celsius", "fahrenheit"},
295+
},
296+
},
297+
Required: []string{"location"},
298+
}
299+
300+
weatherTool := &genai.Tool{
301+
FunctionDeclarations: []*genai.FunctionDeclaration{{
302+
Name: "CurrentWeather",
303+
Description: "Get the current weather in a given location",
304+
Parameters: schema,
305+
}},
306+
}
307+
308+
model := client.GenerativeModel("gemini-1.0-pro")
309+
310+
// Before initiating a conversation, we tell the model which tools it has
311+
// at its disposal.
312+
model.Tools = []*genai.Tool{weatherTool}
313+
314+
// For using tools, the chat mode is useful because it provides the required
315+
// chat context. A model needs to have tools supplied to it in the chat
316+
// history so it can use them in subsequent conversations.
317+
//
318+
// The flow of message expected here is:
319+
//
320+
// 1. We send a question to the model
321+
// 2. The model recognizes that it needs to use a tool to answer the question,
322+
// an returns a FunctionCall response asking to use the CurrentWeather
323+
// tool.
324+
// 3. We send a FunctionResponse message, simulating the return value of
325+
// CurrentWeather for the model's query.
326+
// 4. The model provides its text answer in response to this message.
327+
session := model.StartChat()
328+
329+
res, err := session.SendMessage(ctx, genai.Text("What is the weather like in New York?"))
330+
if err != nil {
331+
log.Fatal(err)
332+
}
333+
334+
part := res.Candidates[0].Content.Parts[0]
335+
funcall, ok := part.(genai.FunctionCall)
336+
if !ok {
337+
log.Fatalf("expected FunctionCall: %v", part)
338+
}
339+
340+
if funcall.Name != "CurrentWeather" {
341+
log.Fatalf("expected CurrentWeather: %v", funcall.Name)
342+
}
343+
344+
// Expect the model to pass a proper string "location" argument to the tool.
345+
locArg, ok := funcall.Args["location"].(string)
346+
if !ok {
347+
log.Fatalf("expected string: %v", funcall.Args["location"])
348+
}
349+
350+
weatherData := currentWeather(locArg)
351+
res, err = session.SendMessage(ctx, genai.FunctionResponse{
352+
Name: weatherTool.FunctionDeclarations[0].Name,
353+
Response: map[string]any{
354+
"weather": weatherData,
355+
},
356+
})
357+
if err != nil {
358+
log.Fatal(err)
359+
}
360+
361+
printResponse(res)
362+
}
363+
261364
func printResponse(resp *genai.GenerateContentResponse) {
262365
for _, cand := range resp.Candidates {
263366
if cand.Content != nil {

0 commit comments

Comments
 (0)