Function Tool 编写基础:让 Agent 调用自定义逻辑

Tool 是 Agent 真正做事的能力。ADK Go 内置了 Google Search 等工具,但真实业务往往需要自定义逻辑——查数据库、调内部 API、做特定计算。这篇讲如何写一个自定义 Function Tool。

Function Tool 的本质

Function Tool 是一个实现了 tool.Tool 接口的 Go struct。Agent 通过这个接口调用 Tool,Tool 返回结果给 Agent。

type Tool interface {
    Name() string
    Description() string
    InputSchema() string
    Call(context.Context, string) (string, error)
}

四个方法:

方法作用返回示例
Name()工具名称get_weather
Description()描述,Model 据此判断何时调用"Get weather for a city"
InputSchema()输入参数 JSON Schema{"type":"object","properties":{"city":{"type":"string"}}}
Call()实际执行逻辑返回天气字符串

最小可用的 Function Tool

场景:查询书籍信息

一个查书的功能,传入书名,返回作者和价格:

package main

import (
    "context"
    "encoding/json"
    "fmt"
)

type bookTool struct{}

func (bookTool) Name() string {
    return "get_book_info"
}

func (bookTool) Description() string {
    return "Get author and price information for a book by its title"
}

func (bookTool) InputSchema() string {
    return `{
        "type": "object",
        "properties": {
            "title": {
                "type": "string",
                "description": "The title of the book"
            }
        },
        "required": ["title"]
    }`
}

func (bookTool) Call(ctx context.Context, input string) (string, error) {
    var args struct {
        Title string `json:"title"`
    }
    if err := json.Unmarshal([]byte(input), &args); err != nil {
        return "", fmt.Errorf("invalid input: %w", err)
    }

    // 模拟数据库查询
    books := map[string]struct{ Author string; Price float64 }{
        "Go 编程":         {Author: "张三", Price: 59.00},
        "Go 高并发":        {Author: "李四", Price: 79.00},
        "Go 进阶":         {Author: "王五", Price: 99.00},
    }

    book, ok := books[args.Title]
    if !ok {
        return fmt.Sprintf("Book '%s' not found", args.Title), nil
    }

    return fmt.Sprintf("《%s》作者:%s,价格:%.2f元", args.Title, book.Author, book.Price), nil
}

注册到 Agent

myAgent, err := llmagent.New(llmagent.Config{
    Name:        "book_assistant",
    Model:       model,
    Instruction: "你是书城助手,帮助用户查询书籍信息。",
    Tools: []tool.Tool{
        bookTool{},   // 注册自定义 Tool
    },
})

使用 Tool

用户问:“Go 编程这本书的作者是谁?”

Agent 自动识别需要调用 get_book_info,解析参数,调用 Call() 方法,返回结果。


参数解析:InputSchema 的写法

InputSchema() 返回一个 JSON Schema,描述输入参数的结构。ADK Go 用这个 Schema 做参数验证,也会把它传给 Model,让 Model 知道怎么构造调用参数。

简单参数

{
    "type": "object",
    "properties": {
        "city": {
            "type": "string",
            "description": "城市名称"
        }
    }
}

多参数

{
    "type": "object",
    "properties": {
        "city": {"type": "string"},
        "date": {"type": "string"}
    },
    "required": ["city"]
}

required 数组声明哪些参数是必填的。

枚举参数

{
    "type": "object",
    "properties": {
        "currency": {
            "type": "string",
            "enum": ["CNY", "USD", "EUR"]
        }
    }
}

错误处理

返回错误 vs 返回错误消息

// 方式 1:返回错误(Agent 会看到错误)
func (t myTool) Call(ctx context.Context, input string) (string, error) {
    return "", fmt.Errorf("network error: %w", err)
}

// 方式 2:返回错误消息(Agent 会把消息当结果)
func (t myTool) Call(ctx context.Context, input string) (string, error) {
    return "API 暂时不可用,请稍后再试", nil
}

建议:可预期的错误(如网络超时)返回错误消息;不可预期的(如编程 Bug)返回 error。

超时处理

给 Tool 加超时,避免慢操作卡住整个 Agent:

func (bookTool) Call(ctx context.Context, input string) (string, error) {
    ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
    defer cancel()

    done := make(chan string, 1)
    errCh := make(chan error, 1)

    go func() {
        // 实际查询逻辑
        result := doQuery()
        done <- result
    }()

    select {
    case result := <-done:
        return result, nil
    case <-ctx.Done():
        return "", fmt.Errorf("query timeout")
    }
}

常见问题

Q:Tool 被调用了但 Model 没识别到 A:检查 Description() 是否描述清楚了这个 Tool 什么情况下应该被调用。Model 根据 Description 决定是否调用。

Q:参数解析失败 A:检查 InputSchema() 返回的 JSON Schema 是否和实际传入的参数匹配。Schema 写错会导致 ADK Go 参数验证失败。

Q:Tool 长时间不返回 A:实现超时逻辑,给 Tool 加截止时间,防止慢操作卡住 Agent。


下一步

一个 Tool 写好了,接下来了解如何对 Tool 做性能优化——超时控制、并发处理——让 Agent 更健壮。

API Key 与 Model 选择 | Function Tool 性能优化 →


想跟着学更多 Go ADK 实战?关注「全栈之巅-梦兽编程」公众号,每周更新 Go / AI 编程实战干货。