Tool Confirmation 与安全认证:在 Agent 行动前增加安全阀

让 Agent 自动帮用户做事是方便,但有些操作有风险——删除数据、转账、发邮件。在这些操作执行前加上用户确认,就叫 Tool Confirmation。

Tool Confirmation:让用户确认后再执行

使用场景

  • 删除操作(delete、drop)
  • 财务操作(转账、付款)
  • 信息泄露风险操作(发送邮件、发布内容)
  • 高成本操作(调用付费 API)

实现方式

ADK Go 的 Tool 支持 Confirmation 字段:

type deleteTool struct{}

func (deleteTool) Name() string          { return "delete_file" }
func (deleteTool) Description() string   { return "Delete a file from the system" }
func (deleteTool) InputSchema() string   { return `{"type":"object","properties":{"path":{"type":"string"}}}` }

func (t deleteTool) Confirmation(ctx context.Context, input string) (bool, error) {
    var args struct {
        Path string `json:"path"`
    }
    json.Unmarshal([]byte(input), &args)

    fmt.Printf("⚠️ 确认:要删除文件 %s 吗?(y/N) ", args.Path)
    var confirm string
    fmt.Scan(&confirm)
    return confirm == "y" || confirm == "Y", nil
}

func (t deleteTool) Call(ctx context.Context, input string) (string, error) {
    // 实际删除逻辑
}

Confirmation() 返回 true 才执行 Call(),返回 false 则跳过。

Web 模式下的确认

CLI 模式下 fmt.Scan 可以工作,但 Web 模式下不行。更通用的方式是返回一个确认 UI 的提示:

func (t deleteTool) Confirmation(ctx context.Context, input string) (bool, error) {
    return false, tool.ErrConfirmationRequired  // 告诉 Agent 需要用户确认
}

ADK Go 会把 ErrConfirmationRequired 转换成 Web 界面的确认弹窗。


API Key 管理

场景:多个 Tool 用不同的 Key

一个 Agent 挂了多个 Tool,每个 Tool 用不同的 API Key:

type weatherTool struct{ apiKey string }
type stockTool struct{ apiKey string }

func main() {
    weatherTool := newWeatherTool(os.Getenv("WEATHER_API_KEY"))
    stockTool := newStockTool(os.Getenv("STOCK_API_KEY"))

    agent, _ := llmagent.New(llmagent.Config{
        Tools: []tool.Tool{weatherTool, stockTool},
    })
}

Key 不写入代码

通过环境变量或 Secret Manager 注入,不要硬编码:

type toolWithKey struct {
    apiKey string
}

func newToolWithKey() *toolWithKey {
    return &toolWithKey{
        apiKey: os.Getenv("MY_TOOL_API_KEY"),  // 从环境变量读取
    }
}

OAuth 认证

如果 Tool 需要访问用户授权的资源(如 Google Calendar、GitHub):

import "google.golang.org/adk/auth"

oauthTool, err := auth.NewOAuthTool(ctx,
    auth.WithConfig(auth.OAuthConfig{
        ClientID:     os.Getenv("OAUTH_CLIENT_ID"),
        ClientSecret: os.Getenv("OAUTH_CLIENT_SECRET"),
        AuthURL:      "https://accounts.google.com/o/oauth2/auth",
        TokenURL:     "https://oauth2.googleapis.com/token",
        Scopes:       []string{"https://www.googleapis.com/auth/calendar.readonly"},
    }),
)

最小权限原则

每个 Tool 用的 Key,应该只有执行这个 Tool 所需的最小权限:

ToolKey 权限
天气查询只读天气 API
日历读取只读日历
邮件发送只发邮件
文件删除只操作指定目录

常见问题

Q:Confirmation 回调卡住不动 A:在 Web 模式下不要用 fmt.Scan,改用 ErrConfirmationRequired 返回错误,让框架处理 UI 确认。

Q:Tool 报错 permission denied,但 Key 是对的 A:确认 Key 有对应 API 的权限。不同 API 的 Key 权限是分开的。

Q:OAuth token 过期了怎么办 A:实现 token refresh 逻辑,或使用框架内置的 token 自动刷新。


小结

模块 3 完成。学习了:

  • Function Tool 编写基础
  • Function Tool 性能优化
  • MCP Server 接入
  • OpenAPI Tool
  • Tool Confirmation 与安全认证

接下来进入模块 4:记忆与上下文——Agent 是如何记住对话历史、管理状态的。

OpenAPI Tool | Session 管理 →


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