adk-go-tool
1. tool 与 Toolsets 的接口:是什么?有什么用?
在 google.golang.org/adk/tool 包下,工具体系被拆分成了两个维度的抽象。
Tool:能力原子
Tool 代表的是一个单一的具体能力(例如:查天气、读文件、执行 SQL)。 在底层逻辑中,一个可执行的工具通常包含两部分核心:
- 定义 (Declaration):大模型能看懂的元数据,包含名称、描述和严格的入参 Schema(映射为底层模型的 Function Declaration)。
- 执行 (Run):Go 语言侧的真实执行回调,接收大模型吐出的参数,执行业务逻辑并返回结果。
作用:作为大模型 Function Calling 的直接执行实体。
Toolsets:动态能力容器
这是 adk-go 设计得非常漂亮的一个接口:
type Toolset interface {
// Name 返回工具集的名称
Name() string
// Tools 根据当前的只读上下文,动态返回一组可用的 Tool
Tools(ctx agent.ReadonlyContext) ([]Tool, error)
}作用:它不仅仅是一个数组切片,而是一个动态能力工厂。通过传入的 agent.ReadonlyContext,Toolset 可以在运行时决定要暴露出哪些工具。这为多租户、权限隔离和上下文感知的工具注入提供了基础。
2. tool 与 Toolsets 的区别
如果你对这两者还觉得模糊,可以这样理解:
- 粒度不同:
Tool是一把特定的扳手,Toolsets是一个包含扳手、螺丝刀的工具箱。 - 静态 vs 动态:
Tool的能力一旦定义通常是静态的。而Toolsets是动态的,同一个Toolset,管理员调用时会返回 10 个Tool(包含增删改查),普通访客调用时,Tools(ctx)方法可能只返回 1 个Tool(只能查)。 - 策略层拦截:在 adk-go 中,很多高级策略是挂载在
Toolset级别的。例如:tool.FilterToolset(ts, predicate):按条件动态过滤掉不安全的工具。tool.WithConfirmation(ts, requireConfirmation, ...):为整个工具集注入 HITL(人工确认)拦截。调用敏感工具前,会自动挂起等待授权。
3. tool 何时使用,如何使用
何时使用?
- 打破信息孤岛:当需要实时数据(如查数据库、调第三方 API)时。
- 控制 Agent 流程:比如 adk-go 内置的
exitlooptool,允许 Agent 主动决定何时退出循环。 - 多智能体协作 (A2A):通过内置的
agenttool,将另一个子 Agent 包装成一个 Tool 交给主 Agent 调用。
如何使用?
adk-go 提供了极其简便的封装:functiontool。你可以将任何普通的 Go 函数一键包装为大模型工具。
import (
"context"
"fmt"
"google.golang.org/adk/tool/functiontool"
"google.golang.org/adk/agent/llmagent"
)
// 1. 定义一个原生的 Go 函数
func getWeather(ctx context.Context, city string) (string, error) {
// 实际业务逻辑:调用气象 API
return fmt.Sprintf("【%s】今天天气晴朗", city), nil
}
// 2. 用 functiontool 包装
weatherTool, err := functiontool.New(
getWeather,
"get_weather",
"根据城市名称获取当地当前的天气预报",
)
// 3. 传给 Agent 配置
agent, err := llmagent.New(llmagent.Config{
Name: "Assistant",
Model: myModel,
Instruction: "你是一个贴心助手,遇到天气问题请调用工具。",
Tools: []tool.Tool{weatherTool},
})4. 如何自定义 tool 与 Toolsets
自定义 Tool
虽然 functiontool 能覆盖 80% 的场景,但如果你的工具需要极其复杂的嵌套 JSON Schema 控制,或者需要自定义校验逻辑,你需要自己实现实现了相关接口的自定义结构体,手动组装 genai.FunctionDeclaration 并暴露 Run 方法。
自定义 Toolsets(看人下菜碟的功能定制)
这是将 Agent 推向实际业务必须掌握的能力。
假设你的“天气机器人”对外上线了,普通访客只能查天气,而“VIP付费用户”还可以直接通过对话预定机票。这种根据用户身份动态暴露工具的能力,就是靠自定义 Toolset 实现的:
// 1. 定义一个用于 VIP 鉴权的专属工具集
type WeatherVIPToolset struct {}
func (ts *WeatherVIPToolset) Name() string {
return "vip_weather_and_flight_tools"
}
func (ts *WeatherVIPToolset) Tools(ctx agent.ReadonlyContext) ([]tool.Tool, error) {
// 假设你能从上下文中(如 Session metadata)取到当前用户的角色信息
userRole, ok := ctx.Session().CustomMetadata()["role"]
// 所有人都有的基础能力:看天气
tools := []tool.Tool{weatherTool}
// 只有 VIP 角色,才把它暴露出订机票的 Tool
if ok && userRole == "vip" {
tools = append(tools, bookFlightTool) // 敏感或增值工具
}
return tools, nil
}将这个 WeatherVIPToolset 注册到你的 Runner 或 Agent 中,你的机器人就拥有了“看人下菜碟”的高级能力!
5. 进阶接入:RAG、Skill 与 MCP
在 v1.1.0 的语境下,Tool 是连接高级架构的桥梁。
接入 RAG (Retrieval-Augmented Generation)
在 adk-go 中,RAG 本质上就是一个信息召回类的 Tool。
- 私有化接入:将连接 Milvus、Pinecone 或是 Elasticsearch 的检索代码,封装为一个
SearchKnowledgeBase函数,用functiontool包装进去。 - Google 原生接入:如果你用的是 Vertex AI 的原生 RAG,可以直接通过
ragCorpora配置或原生的 Retriever 接口集成,底层依然会被转译为 Tool 给到模型。
接入 Skill (技能化)
Skill 往往代表一组具有强业务属性的连贯动作。在 adk-go 最佳实践中,Skill 通常不单写成一个 Tool,而是写成一个专精子 Agent,并通过 agenttool 接入。 例如,你需要一个 "财务分析 Skill":
- 编写一个专注计算和查账的
FinanceAgent。 - 使用
agenttool.New(FinanceAgent, config)将其包装为 Tool。 - 挂载给
MainAgent。当用户提问时,主干 Agent 就会调用这个 "Skill"。
接入 MCP (Model Context Protocol)
MCP 是当前大模型圈解决本地资源与远程 LLM 连接的标准化协议。adk-go 迅速跟进并原生支持了 MCP 的对接! 你可以通过 adk-go 的 mcptoolset,将现成的数百种开箱即用的 MCP Server(如读取本地文件、GitHub、SQLite)一键暴露给你的 Go Agent。
import (
"google.golang.org/adk/tool/mcptoolset"
// 假设需要某个底层的 mcp transport 包
)
// 1. 定义连接到某个运行中的 MCP Server
endpoint := "http://localhost:8080/mcp/my-server"
transport := &mcp.StreamableClientTransport{Endpoint: endpoint}
// 2. 利用 mcptoolset 生成动态工具集
mcpTS, err := mcptoolset.New(mcptoolset.Config{
Transport: transport,
})
if err != nil {
log.Fatal(err)
}
// 3. 将其注册进 Agent 系统中
// 现在,MCP Server 提供的所有工具(可能几十个),都已经变成 Agent 可以调用的原生 Tool 了!总结: 在 adk-go 的架构里,Tool 负责具体的动作,而 Toolsets 负责动作的动态管理与风控。从直接写 Go 函数,到封装子 Agent 形成 Skill,再到接入标准化的 MCP Server,这套 Tool 体系给了开发者极大的拓展自由。不要试图把所有的业务逻辑塞进 Prompt 里——用好 Tool,才是让大模型真正在生产环境落地的核心解法。