a, err := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{ Name: "BookRecommender", Description: "An agent that can recommend books", Instruction: `You are an expert book recommender. Based on the user's request, use the "search_book" tool to find relevant books. Finally, present the results to the user.`, Model: NewChatModel(), ToolsConfig: adk.ToolsConfig{ ToolsNodeConfig: compose.ToolsNodeConfig{ Tools: []tool.BaseTool{NewBookRecommender()}, }, }, }) if err != nil { log.Fatal(fmt.Errorf("failed to create chatmodel: %w", err)) }
finish_reason:tool_calls usage:&{242 {0} 34276} ====== message: tool: {"Books":["God's blessing on this wonderful world!"]} tool_call_id:call_soznhv9d tool_call_name:search_book ====== message: assistant: I found a book that matches your preferences:"God's blessing on this wonderful world!".Itisafictionbookwithnopagelimitandhasaminimumratingof4.0. finish_reason:stop usage:&{300 {0} 39339} ======
// Names of the tools that will make agent return directly when the tool is called. // When multiple tools are called and more than one tool is in the return directly list, only the first one will be returned. ReturnDirectly map[string]bool }
type AskForClarificationInput struct { Question string`json:"question" jsonschema:"description=The specific question you want to ask the user to get the missing information"` }
funcNewAskForClarificationTool() tool.InvokableTool { t, err := utils.InferOptionableTool( "ask_for_clarification", "Call this tool when the user's request is ambiguous or lacks the necessary information to proceed. Use it to ask a follow-up question to get the details you need, such as the book's genre, before you can use other tools effectively.", func(ctx context.Context, input *AskForClarificationInput, opts ...tool.Option) (output string, err error) { o := tool.GetImplSpecificOptions[askForClarificationOptions](nil, opts...) if o.NewInput == nil { return"", compose.NewInterruptAndRerunErr(input.Question) } return *o.NewInput, nil }) if err != nil { log.Fatal(err) } return t }
name: BookRecommender path: [{BookRecommender}] tool name: ask_for_clarification arguments: {"question":"Could you please specify the genre you're interested in, such as fiction, sci-fi, mystery, biography, or business?"}
name: BookRecommender path: [{BookRecommender}] action: interrupted interrupt snapshot: { "Info": { "State": { "Messages": [ { "role": "system", "content": "You are an expert book recommender. Based on the user's request, use the \"search_book\" tool to find relevant books. Finally, present the results to the user." }, { "role": "user", "content": "recommend a book to me" }, { "role": "assistant", "content": "", "tool_calls": [ { "index": 0, "id": "call_e7uebdb7", "type": "function", "function": { "name": "ask_for_clarification", "arguments": "{\"question\":\"Could you please specify the genre you're interested in, such as fiction, sci-fi, mystery, biography, or business?\"}" } } ], "response_meta": { "finish_reason": "tool_calls", "usage": { "prompt_tokens": 346, "prompt_token_details": { "cached_tokens": 0 }, "completion_tokens": 47, "total_tokens": 393 } } } ], "ReturnDirectlyToolCallID": "", "ToolGenActions": {}, "AgentName": "BookRecommender", "AgentToolInterruptData": {} }, "BeforeNodes": null, "AfterNodes": null, "RerunNodes": [ "ToolNode" ], "RerunNodesExtra": { "ToolNode": { "ToolCalls": [ { "index": 0, "id": "call_e7uebdb7", "type": "function", "function": { "name": "ask_for_clarification", "arguments": "{\"question\":\"Could you please specify the genre you're interested in, such as fiction, sci-fi, mystery, biography, or business?\"}" } } ], "ExecutedTools": {}, "RerunTools": [ "call_e7uebdb7" ], "RerunExtraMap": { "call_e7uebdb7": "Could you please specify the genre you're interested in, such as fiction, sci-fi, mystery, biography, or business?" } } }, "SubGraphs": {} }, "Data": "/4p/AwEBCmNoZWNrcG9pbnQB/4AAAQcBCENoYW5uZWxzAf+CAAEGSW5wdXRzAf+EAAEFU3RhdGUBEAABDlNraXBQcmVIYW5kbGVyAf+GAAEKUmVydW5Ob2RlcwH/iAABFlRvb2xzTm9kZUV4ZWN1dGVkVG9vbHMB/4wAAQlTdWJHcmFwaHMB/44AAAAq/4EEAQEabWFwW3N0cmluZ11jb21wb3NlLmNoYW5uZWwB/4IAAQwBEAAAJ/+DBAEBF21hcFtzdHJpbmddaW50ZXJmYWNlIHt9Af+EAAEMARAAAB//hQQBAQ9tYXBbc3RyaW5nXWJvb2wB/4YAAQwBAgAAFv+HAgEBCFtdc3RyaW5nAf+IAAEMAAAt/4sEAQEcbWFwW3N0cmluZ11tYXBbc3RyaW5nXXN0cmluZwH/jAABDAH/igAADv+JBAEC/4oAAQwBDAAAL/+NBAEBHm1hcFtzdHJpbmddKmNvbXBvc2UuY2hlY2twb2ludAH/jgABDAH/gAAASv+AAQMJQ2hhdE1vZGVsFF9laW5vX3ByZWdlbF9jaGFubmVs/48DAQENcHJlZ2VsQ2hhbm5lbAH/kAABAQEGVmFsdWVzAf+EAAAA/97/kAMBAAAIVG9vbE5vZGUUX2Vpbm9fcHJlZ2VsX2NoYW5uZWz/kAMBAAADZW5kFF9laW5vX3ByZWdlbF9jaGFubmVs/5ADAQAAAQABFV9laW5vX2Fka19yZWFjdF9zdGF0Zf+RAwEBBVN0YXRlAf+SAAEFAQhNZXNzYWdlcwH/ugABGFJldHVybkRpcmVjdGx5VG9vbENhbGxJRAEMAAEOVG9vbEdlbkFjdGlvbnMB/8IAAQlBZ2VudE5hbWUBDAABFkFnZW50VG9vbEludGVycnVwdERhdGEB/9AAAAAg/7kCAQERW10qc2NoZW1hLk1lc3NhZ2UB/7oAAf+UAAD/mf+TAwEC/5QAAQoBBFJvbGUBDAABB0NvbnRlbnQBDAABDE11bHRpQ29udGVudAH/oAABBE5hbWUBDAABCVRvb2xDYWxscwH/pgABClRvb2xDYWxsSUQBDAABCFRvb2xOYW1lAQwAAQxSZXNwb25zZU1ldGEB/6gAARBSZWFzb25pbmdDb250ZW50AQwAAQVFeHRyYQH/hAAAACf/nwIBARhbXXNjaGVtYS5DaGF0TWVzc2FnZVBhcnQB/6AAAf+WAABm/5UDAQEPQ2hhdE1lc3NhZ2VQYXJ0Af+WAAEGAQRUeXBlAQwAAQRUZXh0AQwAAQhJbWFnZVVSTAH/mAABCEF1ZGlvVVJMAf+aAAEIVmlkZW9VUkwB/5wAAQdGaWxlVVJMAf+eAAAAVP+XAwEBE0NoYXRNZXNzYWdlSW1hZ2VVUkwB/5gAAQUBA1VSTAEMAAEDVVJJAQwAAQZEZXRhaWwBDAABCE1JTUVUeXBlAQwAAQVFeHRyYQH/hAAAAEn/mQMBARNDaGF0TWVzc2FnZUF1ZGlvVVJMAf+aAAEEAQNVUkwBDAABA1VSSQEMAAEITUlNRVR5cGUBDAABBUV4dHJhAf+EAAAASf+bAwEBE0NoYXRNZXNzYWdlVmlkZW9VUkwB/5wAAQQBA1VSTAEMAAEDVVJJAQwAAQhNSU1FVHlwZQEMAAEFRXh0cmEB/4QAAABR/50DAQESQ2hhdE1lc3NhZ2VGaWxlVVJMAf+eAAEFAQNVUkwBDAABA1VSSQEMAAEITUlNRVR5cGUBDAABBE5hbWUBDAABBUV4dHJhAf+EAAAAIP+lAgEBEVtdc2NoZW1hLlRvb2xDYWxsAf+mAAH/ogAASf+hAwEBCFRvb2xDYWxsAf+iAAEFAQVJbmRleAEEAAECSUQBDAABBFR5cGUBDAABCEZ1bmN0aW9uAf+kAAEFRXh0cmEB/4QAAAAx/6MDAQEMRnVuY3Rpb25DYWxsAf+kAAECAQROYW1lAQwAAQlBcmd1bWVudHMBDAAAAET/pwMBAQxSZXNwb25zZU1ldGEB/6gAAQMBDEZpbmlzaFJlYXNvbgEMAAEFVXNhZ2UB/6oAAQhMb2dQcm9icwH/rgAAAGb/qQMBAQpUb2tlblVzYWdlAf+qAAEEAQxQcm9tcHRUb2tlbnMBBAABElByb21wdFRva2VuRGV0YWlscwH/rAABEENvbXBsZXRpb25Ub2tlbnMBBAABC1RvdGFsVG9rZW5zAQQAAAAx/6sDAQESUHJvbXB0VG9rZW5EZXRhaWxzAf+sAAEBAQxDYWNoZWRUb2tlbnMBBAAAACP/rQMBAQhMb2dQcm9icwH/rgABAQEHQ29udGVudAH/uAAAAB//twIBARBbXXNjaGVtYS5Mb2dQcm9iAf+4AAH/sAAAR/+vAwEBB0xvZ1Byb2IB/7AAAQQBBVRva2VuAQwAAQdMb2dQcm9iAQgAAQVCeXRlcwH/sgABC1RvcExvZ1Byb2JzAf+2AAAAFf+xAgEBB1tdaW50NjQB/7IAAQQAACL/tQIBARNbXXNjaGVtYS5Ub3BMb2dQcm9iAf+2AAH/tAAAOf+zAwEBClRvcExvZ1Byb2IB/7QAAQMBBVRva2VuAQwAAQdMb2dQcm9iAQgAAQVCeXRlcwH/sgAAACz/wQQBARttYXBbc3RyaW5nXSphZGsuQWdlbnRBY3Rpb24B/8IAAQwB/7wAAFD/uwMBAv+8AAEEAQRFeGl0AQIAAQtJbnRlcnJ1cHRlZAH/vgABD1RyYW5zZmVyVG9BZ2VudAH/wAABEEN1c3RvbWl6ZWRBY3Rpb24BEAAAACT/vQMBAQ1JbnRlcnJ1cHRJbmZvAf++AAEBAQREYXRhARAAAAA1/78DAQEVVHJhbnNmZXJUb0FnZW50QWN0aW9uAf/AAAEBAQ1EZXN0QWdlbnROYW1lAQwAAAA3/88EAQEmbWFwW3N0cmluZ10qYWRrLmFnZW50VG9vbEludGVycnVwdEluZm8B/9AAAQwB/8QAACT/wwMBAv/EAAECAQlMYXN0RXZlbnQB/8YAAQREYXRhAQoAAABT/8UDAQEKQWdlbnRFdmVudAH/xgABBQEJQWdlbnROYW1lAQwAAQdSdW5QYXRoAf/KAAEGT3V0cHV0Af/MAAEGQWN0aW9uAf+8AAEDRXJyARAAAAAc/8kCAQENW11hZGsuUnVuU3RlcAH/ygAB/8gAABP/xwUBAQdSdW5TdGVwAf/IAAAAQf/LAwEBC0FnZW50T3V0cHV0Af/MAAECAQ1NZXNzYWdlT3V0cHV0Af/OAAEQQ3VzdG9taXplZE91dHB1dAEQAAAACv/NBQEC/9IAAABD/9MDAQE3U3RyZWFtUmVhZGVyWypnaXRodWIuY29tL2Nsb3Vkd2Vnby9laW5vL3NjaGVtYS5NZXNzYWdlXQH/1AAAAP4B4v+S/gHBAQMBBnN5c3RlbQH/nVlvdSBhcmUgYW4gZXhwZXJ0IGJvb2sgcmVjb21tZW5kZXIuIEJhc2VkIG9uIHRoZSB1c2VyJ3MgcmVxdWVzdCwgdXNlIHRoZSAic2VhcmNoX2Jvb2siIHRvb2wgdG8gZmluZCByZWxldmFudCBib29rcy4gRmluYWxseSwgcHJlc2VudCB0aGUgcmVzdWx0cyB0byB0aGUgdXNlci4AAQR1c2VyARZyZWNvbW1lbmQgYSBib29rIHRvIG1lAAEJYXNzaXN0YW50BAECDWNhbGxfZTd1ZWJkYjcBCGZ1bmN0aW9uAQEVYXNrX2Zvcl9jbGFyaWZpY2F0aW9uAf+BeyJxdWVzdGlvbiI6IkNvdWxkIHlvdSBwbGVhc2Ugc3BlY2lmeSB0aGUgZ2VucmUgeW91J3JlIGludGVyZXN0ZWQgaW4sIHN1Y2ggYXMgZmljdGlvbiwgc2NpLWZpLCBteXN0ZXJ5LCBiaW9ncmFwaHksIG9yIGJ1c2luZXNzPyJ9AAADAQp0b29sX2NhbGxzAQH+ArQBAAFeAf4DEgAAAAIAAQ9Cb29rUmVjb21tZW5kZXIBAAABAAEBCFRvb2xOb2RlAQEIVG9vbE5vZGUAAQAA" }
name: BookRecommender path: [{BookRecommender}] tool response: {"Books":["God's blessing on this wonderful world!"]}
name: BookRecommender path: [{BookRecommender}] answer: I found a book that matches your criteria. Here isone suggestion: "God's blessing on this wonderful world!" from the fiction genre.
Would you like me tosearchfor more options or provide some additional information?
a, err := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{ Name: "BookRecommender", Description: "An agent that can recommend books", Instruction: `You are an expert book recommender. Based on the user's request, use the "search_book" tool to find relevant books. Finally, present the results to the user.`, Model: NewChatModel(), ToolsConfig: adk.ToolsConfig{ ToolsNodeConfig: compose.ToolsNodeConfig{ Tools: []tool.BaseTool{NewBookRecommender(), NewAskForClarificationTool()}, }, }, }) if err != nil { log.Fatal(fmt.Errorf("failed to create chatmodel: %w", err)) }
type AskForClarificationInput struct { Question string`json:"question" jsonschema:"description=The specific question you want to ask the user to get the missing information"` }
funcNewAskForClarificationTool() tool.InvokableTool { t, err := utils.InferOptionableTool( "ask_for_clarification", "Call this tool when the user's request is ambiguous or lacks the necessary information to proceed. Use it to ask a follow-up question to get the details you need, such as the book's genre, before you can use other tools effectively.", func(ctx context.Context, input *AskForClarificationInput, opts ...tool.Option) (output string, err error) { o := tool.GetImplSpecificOptions[askForClarificationOptions](nil, opts...) if o.NewInput == nil { return"", compose.NewInterruptAndRerunErr(input.Question) } return *o.NewInput, nil }) if err != nil { log.Fatal(err) } return t }
type BookSearchInput struct { Genre string`json:"genre" jsonschema:"description=Preferred book genre,enum=fiction,enum=sci-fi,enum=mystery,enum=biography,enum=business"` MaxPages int`json:"max_pages" jsonschema:"description=Maximum page length (0 for no limit)"` MinRating int`json:"min_rating" jsonschema:"description=Minimum user rating (0-5 scale)"` }
type BookSearchOutput struct { Books []string }
funcNewBookRecommender() tool.InvokableTool { bookSearchTool, err := utils.InferTool("search_book", "Search books based on user preferences", func(ctx context.Context, input *BookSearchInput) (output *BookSearchOutput, err error) { // search code // ... return &BookSearchOutput{Books: []string{"God's blessing on this wonderful world!"}}, nil }) if err != nil { log.Fatalf("failed to create search book tool: %v", err) } return bookSearchTool }
/* * Copyright 2025 CloudWeGo Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */
funcmain() { ctx := context.Background() a := internal.NewBookRecommendAgent() runner := adk.NewRunner(ctx, adk.RunnerConfig{ EnableStreaming: true, // you can disable streaming here Agent: a, CheckPointStore: internal.NewInMemoryStore(), }) iter := runner.Query(ctx, "recommend a book to me", adk.WithCheckPointID("1")) for { event, ok := iter.Next() if !ok { break } if event.Err != nil { log.Fatal(event.Err) }