[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"academy-blogs-en-1-1-all-golang-ai-ep172-function-calling-all--*":3,"academy-blog-translations-f50hc0gm73i8673":88},{"data":4,"page":74,"perPage":74,"totalItems":74,"totalPages":74},[5],{"alt":6,"collectionId":7,"collectionName":8,"content":9,"cover_image":10,"cover_image_path":11,"cover_image_s_url":12,"created":13,"created_by":14,"expand":15,"id":82,"keywords":83,"locale":53,"published_at":84,"scheduled_at":69,"school_blog":78,"short_description":85,"status":76,"title":86,"updated":87,"updated_by":14,"slug":79,"views":81},"Cover image for Golang The Series EP.172 titled Function Calling: Teaching AI to Invoke Go Functions","sclblg987654321","school_blog_translations","\u003Cp>Welcome to EP.172! In our previous episode, we laid the groundwork for AI Agents and the ReAct reasoning loop. Today, we are getting our hands dirty with the absolute core foundation of building autonomous agents: \u003Cstrong>Function Calling\u003C\u002Fstrong> (also known as Tool Calling).\u003C\u002Fp>\u003Cp>Function Calling is the mechanism that empowers AI models (LLMs) to interact with the outside world. Instead of simply replying with conversational text, the AI analyzes the user's prompt and outputs a structured JSON payload containing a \u003Cem>\"Function Name\"\u003C\u002Fem> and its \u003Cem>\"Arguments\"\u003C\u002Fem>. Our Go backend catches this, executes the actual function, and feeds the real-world data back to the AI!\u003C\u002Fp>\u003Ch2>The Function Calling Workflow\u003C\u002Fh2>\u003Cp>Plaintext\u003C\u002Fp>\u003Cpre>\u003Ccode>[1. User Request] ──&gt; \"Can you check the stock for SKU-1024?\"\n        │\n        ▼\n[2. Go App Call LLM]  &lt;--- Sends the prompt + Tool Definition (JSON Schema)\n        │\n        ▼\n[3. LLM Processing]   &lt;--- AI selects 'GetStockQuantity' and extracts the SKU\n        │\n        ▼\n[4. LLM Response]     &lt;--- Returns Tool Calls (Name: \"GetStockQuantity\", Args: {\"sku\": \"SKU-1024\"})\n        │\n        ▼\n[5. Go App Execution] &lt;--- Go parses the tool name -&gt; Executes GetStockQuantity(\"SKU-1024\")\n        │\n        ▼\n[6. Return Result]    &lt;--- Sends the result (e.g., \"150 items\") back to the LLM\n        │\n        ▼\n[7. Final AI Answer]  ──&gt; \"There are currently 150 units of SKU-1024 in stock.\"\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch2>Registering the Tool Schema in Go\u003C\u002Fh2>\u003Cp>To let the AI know what our Go functions can do, we need to define a JSON Schema for each tool. We have to tell the AI:\u003C\u002Fp>\u003Cul>\u003Cli>\u003Cp>\u003Cstrong>Name:\u003C\u002Fstrong> The identifier of the function.\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cstrong>Description:\u003C\u002Fstrong> What the function does (this is crucial, as the AI uses this to decide \u003Cem>when\u003C\u002Fem> to use it).\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cstrong>Parameters:\u003C\u002Fstrong> The expected arguments, their data types, and which ones are \u003Ccode>Required\u003C\u002Fcode>.\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Ch2>Writing the Go Code for Function Calling\u003C\u002Fh2>\u003Cp>To make things easy to digest, let's break the code down into 4 logical steps.\u003C\u002Fp>\u003Ch3>Part 1: The Native Go Function\u003C\u002Fh3>\u003Cp>First, let's write our standard business logic. Imagine this is a function that checks warehouse inventory.\u003C\u002Fp>\u003Cp>Go\u003C\u002Fp>\u003Cpre>\u003Ccode>package main\n\nimport (\n\t\"context\"\n\t\"encoding\u002Fjson\"\n\t\"fmt\"\n\t\"log\"\n\n\t\"github.com\u002Fsashabaranov\u002Fgo-openai\"\n\t\"github.com\u002Fsashabaranov\u002Fgo-openai\u002Fjsonschema\"\n)\n\n\u002F\u002F --- 1. Define the native Go function ---\n\n\u002F\u002F GetStockQuantity simulates a database query to get stock count\nfunc GetStockQuantity(sku string) (int, error) {\n\t\u002F\u002F In a real app, you would query your database here\n\tstocks := map[string]int{\n\t\t\"SKU-1024\": 150,\n\t\t\"SKU-2048\": 0,\n\t\t\"SKU-9999\": 42,\n\t}\n\tqty, exists := stocks[sku]\n\tif !exists {\n\t\treturn 0, fmt.Errorf(\"item SKU %s not found in the system\", sku)\n\t}\n\treturn qty, nil\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch3>Part 2: Defining the Schema and Calling the AI\u003C\u002Fh3>\u003Cp>Next, we create an \u003Ccode>openai.Tool\u003C\u002Fcode> to describe our function to the AI, and we send it along with the user's prompt.\u003C\u002Fp>\u003Cp>Go\u003C\u002Fp>\u003Cpre>\u003Ccode>func main() {\n\tclient := openai.NewClient(\"YOUR_OPENAI_API_KEY\")\n\n\t\u002F\u002F --- 2. Create the Tool Definition to register with the AI ---\n\tstockTool := openai.Tool{\n\t\tType: openai.ToolTypeFunction,\n\t\tFunction: &amp;openai.FunctionDefinition{\n\t\t\tName:        \"GetStockQuantity\",\n\t\t\tDescription: \"Fetch the current inventory stock quantity using the item's SKU\",\n\t\t\tParameters: jsonschema.Definition{\n\t\t\t\tType: jsonschema.Object,\n\t\t\t\tProperties: map[string]jsonschema.Definition{\n\t\t\t\t\t\"sku\": {\n\t\t\t\t\t\tType:        jsonschema.String,\n\t\t\t\t\t\tDescription: \"The item SKU, e.g., SKU-1024\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tRequired: []string{\"sku\"}, \u002F\u002F Tell AI it MUST provide this\n\t\t\t},\n\t\t},\n\t}\n\n\tuserQuery := \"Can you tell me how many units of SKU-1024 we have left?\"\n\tfmt.Printf(\"👤 User: %s\\n\\n\", userQuery)\n\n\tmessages := []openai.ChatCompletionMessage{\n\t\t{Role: openai.ChatMessageRoleUser, Content: userQuery},\n\t}\n\n\t\u002F\u002F --- 3. Send the initial request along with our Tools ---\n\tresp, err := client.CreateChatCompletion(\n\t\tcontext.Background(),\n\t\topenai.ChatCompletionRequest{\n\t\t\tModel:    openai.GPT4oMini,\n\t\t\tMessages: messages,\n\t\t\tTools:    []openai.Tool{stockTool},\n\t\t},\n\t)\n\tif err != nil {\n\t\tlog.Fatalf(\"API Error: %v\", err)\n\t}\n\n\tmsg := resp.Choices[0].Message\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch3>Part 3: Catching the AI's Decision and Executing Code\u003C\u002Fh3>\u003Cp>When the AI replies, we check if it decided to use a tool. If it did, we parse the arguments it generated, map them to a Go struct, and run our native function.\u003C\u002Fp>\u003Cp>Go\u003C\u002Fp>\u003Cpre>\u003Ccode>\t\u002F\u002F --- 4. Check if the AI decided to call a tool ---\n\tif len(msg.ToolCalls) &gt; 0 {\n\t\ttoolCall := msg.ToolCalls[0]\n\t\tfmt.Printf(\"🤖 AI decided to use Tool: %s\\n\", toolCall.Function.Name)\n\t\tfmt.Printf(\"📦 Arguments parsed by AI: %s\\n\", toolCall.Function.Arguments)\n\n\t\t\u002F\u002F Parse the JSON arguments generated by the AI\n\t\tvar args struct {\n\t\t\tSKU string `json:\"sku\"`\n\t\t}\n\t\tif err := json.Unmarshal([]byte(toolCall.Function.Arguments), &amp;args); err != nil {\n\t\t\tlog.Fatalf(\"Failed to parse tool arguments: %v\", err)\n\t\t}\n\n\t\t\u002F\u002F --- 5. Execute the actual Go function ---\n\t\tvar toolResult string\n\t\tif toolCall.Function.Name == \"GetStockQuantity\" {\n\t\t\tqty, err := GetStockQuantity(args.SKU)\n\t\t\tif err != nil {\n\t\t\t\ttoolResult = fmt.Sprintf(`{\"error\": \"%s\"}`, err.Error())\n\t\t\t} else {\n\t\t\t\t\u002F\u002F Wrap the result in JSON to send back\n\t\t\t\ttoolResult = fmt.Sprintf(`{\"sku\": \"%s\", \"quantity\": %d}`, args.SKU, qty)\n\t\t\t}\n\t\t}\n\n\t\tfmt.Printf(\"⚙️ Result from Go Execution: %s\\n\\n\", toolResult)\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch3>Part 4: Sending the Result Back for the Final Answer\u003C\u002Fh3>\u003Cp>This is the final, crucial step. We must append the AI's \"thought process\" (the Assistant message) and the result of our Go execution (the Tool message) back into the history, then hit the API one last time so the AI can summarize the answer for the user.\u003C\u002Fp>\u003Cp>Go\u003C\u002Fp>\u003Cpre>\u003Ccode>\t\t\u002F\u002F --- 6. Send the tool execution result back to the AI ---\n\t\tmessages = append(messages, msg) \u002F\u002F Keep the AI's context\u002Fdecision in history\n\t\tmessages = append(messages, openai.ChatCompletionMessage{\n\t\t\tRole:       openai.ChatMessageRoleTool, \u002F\u002F Mark this as a Tool response\n\t\t\tContent:    toolResult,\n\t\t\tToolCallID: toolCall.ID, \u002F\u002F MUST match the ID the AI originally sent\n\t\t})\n\n\t\tfinalResp, err := client.CreateChatCompletion(\n\t\t\tcontext.Background(),\n\t\t\topenai.ChatCompletionRequest{\n\t\t\t\tModel:    openai.GPT4oMini,\n\t\t\t\tMessages: messages,\n\t\t\t},\n\t\t)\n\t\tif err != nil {\n\t\t\tlog.Fatalf(\"API Error on Final Response: %v\", err)\n\t\t}\n\n\t\t\u002F\u002F 7. Get the final human-readable answer!\n\t\tfmt.Printf(\"🤖 Final AI Answer: %s\\n\", finalResp.Choices[0].Message.Content)\n\n\t} else {\n\t\t\u002F\u002F If the AI didn't need a tool and answered directly\n\t\tfmt.Printf(\"🤖 Standard AI Answer: %s\\n\", msg.Content)\n\t}\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch2>Security Guardrails &amp; Best Practices\u003C\u002Fh2>\u003Cul>\u003Cli>\u003Cp>\u003Cstrong>Never Trust AI Arguments Blindly:\u003C\u002Fstrong> Always treat the arguments generated by the AI (e.g., \u003Ccode>args.SKU\u003C\u002Fcode>) as untrusted user input. Validate and sanitize them in Go before executing Database queries or making external API calls to prevent things like SQL Injection or unauthorized actions.\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cstrong>Type Safety Handling:\u003C\u002Fstrong> LLMs can occasionally hallucinate types (e.g., passing a string \u003Ccode>\"1024\"\u003C\u002Fcode> instead of an integer \u003Ccode>1024\u003C\u002Fcode>). Using \u003Ccode>json.Unmarshal\u003C\u002Fcode> into a strictly typed Go struct ensures that your application catches these type mismatches safely before they reach your business logic.\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Ch2>🎯 Daily Mission\u003C\u002Fh2>\u003Cp>Try running the code above in your local project and watch the console to see the Tool Calls in action.\u003C\u002Fp>\u003Cp>\u003Cstrong>Challenge for you:\u003C\u002Fstrong> Imagine you have a second tool called \u003Ccode>CalculateDiscount(customerTier string, totalAmount float64)\u003C\u002Fcode>. How would you structure the routing in Go (\u003Ccode>switch \u003C\u002Fcode>\u003Ca rel=\"noopener noreferrer\" href=\"http:\u002F\u002FtoolCall.Function.Name\">\u003Ccode>toolCall.Function.Name\u003C\u002Fcode>\u003C\u002Fa>) to handle 10 or 20 different tools cleanly without writing a massive, ugly \u003Ccode>if-else\u003C\u002Fcode> chain? (Hint: Think about using a Map of function pointers!).\u003C\u002Fp>\u003Ch2>❓ Frequently Asked Questions (FAQ)\u003C\u002Fh2>\u003Ch3>Can I pass multiple tools to the AI at the same time?\u003C\u002Fh3>\u003Cp>Absolutely. You just append multiple schemas into the \u003Ccode>[]openai.Tool{}\u003C\u002Fcode> slice. The AI is smart enough to read their descriptions and pick the right one based on the user's prompt. It can even call multiple tools simultaneously (Parallel Tool Calling).\u003C\u002Fp>\u003Ch3>What happens if the AI generates bad arguments or invalid JSON?\u003C\u002Fh3>\u003Cp>If \u003Ccode>json.Unmarshal\u003C\u002Fcode> fails in Go, catch the error, wrap it in a string (e.g., \u003Cem>\"Invalid parameter type, expected integer\"\u003C\u002Fem>), and send it right back to the AI as a Tool Message. The AI will read the error, realize its mistake, and usually correct itself on the next loop!\u003C\u002Fp>\u003Ch3>Why do we have to \u003Ccode>append(messages, msg)\u003C\u002Fcode> back to the array?\u003C\u002Fh3>\u003Cp>It is a strict requirement from the OpenAI API. If a tool was called, the conversation history must include the exact Assistant message containing the \u003Ccode>ToolCalls\u003C\u002Fcode> intent, immediately followed by the \u003Ccode>Tool\u003C\u002Fcode> message containing the result. This maintains the AI's working memory.\u003C\u002Fp>\u003Cdiv data-type=\"horizontalRule\">\u003Chr>\u003C\u002Fdiv>\u003Ch2>Summary\u003C\u002Fh2>\u003Cp>In this episode, we walked through the \u003Cstrong>Function Calling mechanics step-by-step\u003C\u002Fstrong>—from defining JSON schemas, catching tool calls, executing native Go code, to feeding the results back to the LLM. This is the ultimate bridge that connects a trapped AI to the real world.\u003C\u002Fp>\u003Cp>\u003Cstrong>Next up (EP.173): \u003C\u002Fstrong>Now that we have mastered Function Calling in Go, we are going to build one of the most powerful and practical enterprise agents: \u003Cstrong>The Database Agent (Text-to-SQL).\u003C\u002Fstrong> We will teach the AI to read your database schema, convert natural language into SQL queries, execute them safely, and summarize the data. Don't miss it, Gophers!\u003C\u002Fp>\u003Cp>\u003Cstrong>Follow Superdev Academy on all platforms:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cul>\u003Cli>\u003Cp>\u003Cstrong>🔵 Facebook: \u003C\u002Fstrong>\u003Ca target=\"_blank\" rel=\"noopener\" class=\"ng-star-inserted\" href=\"https:\u002F\u002Fwww.facebook.com\u002Fsuperdev.academy.th\">\u003Cstrong>Superdev Academy Thailand\u003C\u002Fstrong>\u003C\u002Fa>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cstrong>🎬 YouTube: \u003C\u002Fstrong>\u003Ca target=\"_blank\" rel=\"noopener\" class=\"ng-star-inserted\" href=\"https:\u002F\u002Fwww.youtube.com\u002F@SuperdevAcademy\">\u003Cstrong>Superdev Academy Channel\u003C\u002Fstrong>\u003C\u002Fa>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cstrong>📸 Instagram: \u003C\u002Fstrong>\u003Ca target=\"_blank\" rel=\"noopener\" class=\"ng-star-inserted\" href=\"https:\u002F\u002Fwww.instagram.com\u002Fsuperdevacademy\u002F\">\u003Cstrong>@superdevacademy\u003C\u002Fstrong>\u003C\u002Fa>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cstrong>🎬 TikTok: \u003C\u002Fstrong>\u003Ca target=\"_blank\" rel=\"noopener\" class=\"ng-star-inserted\" href=\"https:\u002F\u002Fwww.tiktok.com\u002F@superdevacademy?lang=th-TH\">\u003Cstrong>@superdevacademy\u003C\u002Fstrong>\u003C\u002Fa>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cstrong>🌐 Website: \u003C\u002Fstrong>\u003Ca rel=\"noopener noreferrer\" href=\"https:\u002F\u002Fsuperdevacademy.com\">\u003Cstrong>superdevacademy.com\u003C\u002Fstrong>\u003C\u002Fa>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003C\u002Fp>","64aaov7tl0mv_rn8rpdqije_p4ga84w8km.webp","https:\u002F\u002Ftwsme-r2.tumwebsme.com\u002Fsclblg987654321\u002Fjpru9ygi36xd6n3\u002F64aaov7tl0mv_rn8rpdqije_p4ga84w8km.webp","https:\u002F\u002Ftwsme-r2.tumwebsme.com\u002Fsclblg987654321\u002Fjpru9ygi36xd6n3\u002Fs\u002F64aaov7tl0mv_rn8rpdqije_p4ga84w8km.webp","2026-08-21 01:59:37.050Z","76qprkevbgfdps8",{"keywords":16,"locale":47,"school_blog":57},[17,24,28,32,37,42],{"collectionId":18,"collectionName":19,"created":20,"created_by":14,"id":21,"name":22,"updated":23,"updated_by":14},"sclkey987654321","school_keywords","2026-05-11 04:12:12.008Z","bficy78v6muc3cs","Golang AI","2026-06-07 06:49:11.153Z",{"collectionId":18,"collectionName":19,"created":25,"created_by":14,"id":26,"name":27,"updated":25,"updated_by":14},"2026-08-21 01:41:25.146Z","p69rz9y2xg4vcfy","Function Calling Go",{"collectionId":18,"collectionName":19,"created":29,"created_by":14,"id":30,"name":31,"updated":29,"updated_by":14},"2026-08-21 01:41:27.963Z","c0yy6kh8niv0wyk","Go OpenAI API",{"collectionId":18,"collectionName":19,"created":33,"created_by":14,"id":34,"name":35,"updated":36,"updated_by":14},"2026-04-08 03:42:08.603Z","ts3een5rqiteigt","Build AI Agent","2026-06-07 06:49:03.292Z",{"collectionId":18,"collectionName":19,"created":38,"created_by":14,"id":39,"name":40,"updated":41,"updated_by":14},"2026-05-13 04:25:50.416Z","czsyl2b7o6m4b5x","SuperDev Academy","2026-06-07 06:49:15.072Z",{"collectionId":18,"collectionName":19,"created":43,"created_by":14,"id":44,"name":45,"updated":46,"updated_by":14},"2026-03-04 08:44:11.146Z","gms2qr4xg6qv65e","Superdev Academy","2026-06-07 06:46:28.624Z",{"code":48,"collectionId":49,"collectionName":50,"created":51,"flag":52,"id":53,"is_default":54,"label":55,"updated":56},"en","pbc_1989393366","locales","2026-01-22 11:00:02.726Z","twemoji:flag-united-states","qv9c1llfov2d88z",false,"English","2026-04-10 15:42:46.825Z",{"category":58,"collectionId":59,"collectionName":60,"created":61,"expand":62,"id":78,"slug":79,"updated":80,"views":81},"wqxt7ag2gn7xcmk","pbc_2105096300","school_blogs","2026-08-21 01:36:40.044Z",{"category":63},{"blogIds":64,"collectionId":65,"collectionName":66,"created":67,"created_by":14,"id":58,"image":68,"image_alt":69,"image_path":70,"image_s_url":71,"label":72,"name":73,"priority":74,"publish_at":75,"scheduled_at":69,"status":76,"updated":77,"updated_by":14},[],"sclcatblg987654321","school_category_blogs","2026-03-04 08:33:53.210Z","59ty92ns80w_15oc1implw_bj2o4tjgh4.webp","","https:\u002F\u002Ftwsme-r2.tumwebsme.com\u002Fsclcatblg987654321\u002Fwqxt7ag2gn7xcmk\u002F59ty92ns80w_15oc1implw_bj2o4tjgh4.webp","https:\u002F\u002Ftwsme-r2.tumwebsme.com\u002Fsclcatblg987654321\u002Fwqxt7ag2gn7xcmk\u002Fs\u002F59ty92ns80w_15oc1implw_bj2o4tjgh4.webp",{"en":73,"th":73},"Golang The Series",1,"2026-03-16 04:39:38.440Z","published","2026-08-18 14:48:36.739Z","f50hc0gm73i8673","golang-ai-ep172-function-calling","2026-08-25 05:14:14.493Z",111,"jpru9ygi36xd6n3",[21,26,30,34,39,44],"2026-08-26 03:00:00.000Z","Learn how to implement Function Calling in Go step-by-step. Teach your AI (LLM) to interact with external systems, databases, and APIs by executing real Go functions.","Golang The Series EP.172: Function Calling (Teach AI to Invoke Go Functions)","2026-08-26 03:00:00.314Z",{"th":79,"en":79}]