ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Go 实现 Function Calling 工具调用:从工具定义到参数解析保姆级教程

Go 实现 Function Calling 工具调用:从工具定义到参数解析保姆级教程

Go 实现 Function Calling 工具调用:从工具定义到参数解析保姆级教程

系列第 1 篇 · Go + Function Calling 写 AI Agent。本文只讲一件事:工具怎么定义、怎么注册给大模型、参数怎么解析。

目录

  • Go 实现 Function Calling 工具调用:从工具定义到参数解析保姆级教程
    • 一个工具需要四样东西
    • 怎么注册给大模型
    • 参数解析:最容易踩的坑
    • Params 的 JSON Schema 怎么写
    • 一句话总结

一个工具需要四样东西

很多 Go 教程把 Function Calling 讲得云里雾里,其实在 Go 里落地,一个工具就是一个结构体:

// tools/tool.gotypeToolDefstruct{Namestring// 工具名,模型靠它点名Descriptionstring// 工具说明,模型靠它决定什么时候用Params openai.FunctionParameters// JSON Schema,告诉模型传什么参数Fnfunc(ctx context.Context,argsmap[string]any)(string,error)// 真正干活的函数}

小提醒:这里的openai和shared都来自OpenAI 官方 Go SDK,不是什么厂商私有库——任何兼容 OpenAI 接口的服务都能用。四个导入一个都不能少:

import("context""encoding/json""github.com/openai/openai-go/v3""github.com/openai/openai-go/v3/shared")

就这四样:名字、描述、参数格式、执行函数。缺一不可,后面的无数坑都源于对这四个字段理解不深。

怎么注册给大模型

光有结构体模型不认识,得把它翻译成 OpenAI API 能懂的格式:

func(t*ToolDef)ToChatParam()openai.ChatCompletionToolUnionParam{returnopenai.ChatCompletionToolUnionParam{OfFunction:&openai.ChatCompletionFunctionToolParam{Function:shared.FunctionDefinitionParam{Name:t.Name,Description:openai.String(t.Description),Parameters:t.Params,},},}}

注册后,把它塞进请求的Tools字段,模型就知道"我有这些工具可以调用"。

参数解析:最容易踩的坑

模型决定调用工具后,会把参数用JSON 字符串传回来,长这样:

"{\"sql\":\"select * from users\"}"

注意:它是字符串,不是对象。里面的引号是转义的。所以必须先json.Unmarshal成 Go 的 map,才能取值:

func(t*ToolDef)Call(ctx context.Context,argsJSONstring)(string,error){varargsmap[string]anyiferr:=json.Unmarshal([]byte(argsJSON),&args);err!=nil{return"",err}returnt.Fn(ctx,args)}

很多人卡在这里,直接把argsJSON当对象用,结果永远nil。记住这一句:模型给你的是字符串,先反序列化,再干活。

Params 的 JSON Schema 怎么写

Params字段告诉模型该传什么参数,格式是固定的三段:

Params:openai.FunctionParameters{"type":"object","properties":map[string]any{"sql":map[string]any{"type":"string","description":"要执行的 SQL 语句",},},"required":[]string{"sql"},}
  • type: “object” —— 外层永远是对象
  • properties—— 里面有哪些字段
  • required—— 哪些字段必填

哪怕工具不要参数,这三个键也要存在,内容填空就行。这是很多教程漏讲的细节。

一句话总结

Function Calling 的落地就是:定义结构体 → 翻译成 API 格式 → 反序列化模型传来的 JSON 参数 → 执行真正的函数。把这四步走通,你就已经会写 80% 的工具调用代码了。

下一篇讲:怎么把这些工具串成一个 Agent 主循环——那才是 Agent 真正的骨架。

系列导航:第 1 篇(本文)· [第 2 篇:Go 手写 Agent 主循环] · [第 3 篇:SQL 安全四道锁]

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进