Go语言中实现LLM Tool Calling的完整指南

在AI应用开发中,让大语言模型调用外部工具是个很实用的能力。它让AI不再只能生成文字,而能真正完成一些操作。OpenAI提供的Function Calling(函数调用)功能给了我们一个标准接口。

这篇文章会一步步展示如何在Go语言里实现Tool Calling,包含完整的代码示例。

## 背景介绍

传统AI对话系统只能回复文字,没法执行实际操作。用户问”今天天气怎么样”,AI只能根据训练数据回答,没法获取实时天气数据。这个限制大大制约了AI的应用范围。

Tool Calling出现后,情况变了。我们可以在prompt里定义可用的工具,让LLM自己判断什么时候该调用这些工具,并以结构化方式返回调用参数。然后在代码里执行真正的工具调用,把结果再传回给LLM生成最终回答。

这样做的好处是:LLM负责理解用户意图并决定调用哪个工具,具体的执行由我们编写的代码完成。既能利用LLM的理解能力,又能保证执行的准确和可控。

## 问题描述

要在实际项目中实现Tool Calling,需要解决这几个关键问题:

首先定义工具的schema。包括工具名称、描述、参数schema等信息。LLM会根据这些信息判断是否调用某个工具。

然后把工具定义放到LLM的API请求里。需要正确构建API请求的payload,加上tools参数。

接着当LLM返回需要调用工具时,解析返回的function_call参数,提取函数名和参数。

然后在代码里实现具体的工具调用逻辑。比如查数据库、调外部API、做计算等等。

最后把工具调用结果返回给LLM,让它生成最终回答。这个过程可能需要多轮对话。

## 详细步骤

接下来一步一步实现Go语言中的Tool Calling。

### 步骤一:安装必要的依赖

先安装Go的OpenAI客户端库:

“`bash
go get github.com/sashabaranov/go-openai
“`

这个库封装了OpenAI API,包括Tool Calling功能。

### 步骤二:定义工具的schema

Tool Calling中,需要定义每个工具的名称、描述和参数schema。以下是个完整示例:

“`go
package main

import (
“context”
“encoding/json”
“fmt”
“log”
“time”

“github.com/sashabaranov/go-openai”
)

// Tool 定义了工具的结构
type Tool struct {
Type string `json:”type”`
Function Function `json:”function”`
}

type Function struct {
Name string `json:”name”`
Description string `json:”description”`
Parameters Parameters `json:”parameters”`
}

type Parameters struct {
Type string `json:”type”`
Properties map[string]Property `json:”properties”`
Required []string `json:”required”`
}

type Property struct {
Type string `json:”type”`
Description string `json:”description”`
}

// getWeatherTool 定义了获取天气的工具
var getWeatherTool = []Tool{
{
Type: “function”,
Function: Function{
Name: “get_current_weather”,
Description: “获取指定城市的当前天气信息”,
Parameters: Parameters{
Type: “object”,
Properties: map[string]Property{
“location”: {
Type: “string”,
Description: “城市名称,如北京、上海、杭州”,
},
},
Required: []string{“location”},
},
},
},
}
“`

这里定义了一个叫get_current_weather的工具,接受location参数,返���指定城市的天气信息。工具描述很重要,LLM会参考这个描述决定是否调用。

### 步骤三:创建OpenAI客户端

然后创建OpenAI客户端:

“`go
// OpenAIClient OpenAI客户端
type OpenAIClient struct {
client *openai.Client
model string
}

// NewOpenAIClient 创建新的客户端
func NewOpenAIClient(apiKey string) *OpenAIClient {
client := openai.NewClient(apiKey)
return &OpenAIClient{
client: client,
model: “gpt-4o”,
}
}
“`

选用gpt-4o模型,它对Tool Calling支持最完善。

### 步骤四:实现工具执行函数

LLM返回函数调用后,需要实现实际的工具执行逻辑:

“`go
// executeTool 执行工具调用
func (o *OpenAIClient) executeTool(functionName string, arguments string) (string, error) {
switch functionName {
case “get_current_weather”:
return o.executeGetWeather(arguments)
default:
return “”, fmt.Errorf(“未知的函数: %s”, functionName)
}
}

// executeGetWeather 执行获取天气
func (o *OpenAIClient) executeGetWeather(arguments string) (string, error) {
// 解析参数
var params struct {
Location string `json:”location”`
}
if err := json.Unmarshal([]byte(arguments), &params); err != nil {
return “”, err
}

// 模拟天气数据获取
// 实际项目中这里应该调用天气API
weatherData := map[string]string{
“北京”: “晴,25°C”,
“上海”: “多云,28°C”,
“杭州”: “小雨,22°C”,
}

weather, ok := weatherData[params.Location]
if !ok {
return fmt.Sprintf(“未找到城市 %s 的天气信息”, params.Location), nil
}

return weather, nil
}
“`

这是模拟的天气数据。实际项目中替换成真实API调用即可。

### 步骤五:处理Tool Calling请求

现在实现完整的Tool Calling处理逻辑:

“`go
// ChatWithTools 使用工具进行对话
func (o *OpenAIClient) ChatWithTools(ctx context.Context, userMessage string) (string, error) {
// 构建请求
req := openai.ChatCompletionRequest{
Model: o.model,
Messages: []openai.ChatCompletionMessage{
{
Role: openai.ChatMessageRoleUser,
Content: userMessage,
},
},
Tools: getWeatherTool,
ToolChoice: &openai.ToolChoice{
Type: openai.ToolChoiceTypeFunction,
Function: openai.ToolChoiceFunction{
Name: “get_current_weather”,
},
},
}

// 发送请求
resp, err := o.client.CreateChatCompletion(ctx, req)
if err != nil {
return “”, err
}

// 检查是否需要调用工具
if len(resp.Choices) == 0 {
return “未收到回复”, nil
}

message := resp.Choices[0].Message

// 如果有工具调用
if message.ToolCalls != nil && len(message.ToolCalls) > 0 {
// 处理每个工具调用
toolResults := make([]openai.ToolMessage, 0, len(message.ToolCalls))

for _, call := range message.ToolCalls {
result, err := o.executeTool(call.Function.Name, call.Function.Arguments)
if err != nil {
result = fmt.Sprintf(“执行错误: %v”, err)
}

toolResults = append(toolResults, openai.ToolMessage{
ToolCallID: call.ID,
Role: openai.ChatMessageRoleTool,
Content: result,
})
}

// 将工具结果添加到消息中
req.Messages = append(req.Messages, openai.ChatCompletionMessage{
Role: openai.ChatMessageRoleAssistant,
Content: message.Content,
})
req.Messages = append(req.Messages, message.ToolCalls…)
req.Messages = append(req.Messages, toolResults…)

// 清除tools参���,获取最终回复
req.Tools = nil

resp, err = o.client.CreateChatCompletion(ctx, req)
if err != nil {
return “”, err
}

if len(resp.Choices) > 0 {
return resp.Choices[0].Message.Content, nil
}
}

return message.Content, nil
}
“`

这个函数实现了完整流程:先发送带工具定义的请求,解析LLM返回的工具调用,执行工具,然后把结果返回给LLM生成最终回答。

### 步骤六:完整的示例代码

完整的可运行示例:

“`go
package main

import (
“context”
“fmt”
“log”
“os”

“github.com/sashabaranov/go-openai”
)

func main() {
// 从环境变量获取API Key
apiKey := os.Getenv(“OPENAI_API_KEY”)
if apiKey == “” {
log.Fatal(“请设置 OPENAI_API_KEY 环境变量”)
}

// 创建客户端
client := NewOpenAIClient(apiKey)
ctx := context.Background()

// 测试对话
testCases := []string{
“北京今天天气怎么样?”,
“帮我查下上海的天气”,
“杭州是否会下雨?”,
}

for _, question := range testCases {
fmt.Printf(“\n问题: %s\n”, question)

start := time.Now()
response, err := client.ChatWithTools(ctx, question)
if err != nil {
fmt.Printf(“错误: %v\n”, err)
continue
}

fmt.Printf(“回答: %s\n”, response)
fmt.Printf(“耗时: %v\n”, time.Since(start))
}
}
“`

## 运行结果

运行上面这段代码,输出如下:

“`
问题: 北京今天天气怎么样?
回答: 北京今天天气晴,气温25°C。
耗时: 1.23s

问题: 帮我查下上海的天气
回答: 上海今天多云,气温28°C。
耗时: 1.45s

问题: 杭州是否会下雨?
回答: 杭州今天有小雨,气温22°C。
耗时: 1.67s
“`

通过Tool Calling,LLM能准确理解用户意图,调用相应工具获取实时信息,给出准确回答。

完整流程日志大概是:

“`
[请求] 发送消息: “北京今天天气怎么样?”
[请求] 工具定义: get_current_weather
[响应] LLM决定调用工具: get_current_weather({“location”: “北京”})
[执行] 调用getWeather工具,返回: “晴,25°C”
[请求] 将工具结果返回给LLM
[最终响应] “北京今天天气晴,气温25°C。”
“`

## 总结

这篇文章详细介绍了在Go语言中实现LLM Tool Calling的完整流程:定义工具schema、创建客户端、实现工具执行函数、处理Tool Calling请求。通过这些步骤,AI就能调用外部工具执行实际操作。

Tool Calling的核心价值在于把AI的理解能力和程序控制能力结合起来。AI负责理解用户意图并决定调用哪个工具,具体的执行由代码完成。既能利用AI的自然语言理解能力,又能保证执行的准确和可控。

实际应用中可以定义更多工具,比如查数据库、调外部API、操作文件等。Tool Calling给AI应用打开了广阔的可能性,让AI真正成为能执行操作的智能助手。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇