Tool 是怎么工作的
用「问 BTC 价格」这个真实例子讲一遍,最后对照到 Berth 的代码。
模型本身只会读文字、写文字,不能上网,也不会执行代码。
所谓
tool,就是你提前告诉模型「有这些工具可用」。模型需要时写一张申请单,
你的程序照着去执行,再把结果当作新的一段文字交回给模型。
打个比方:餐厅
服务员 = 模型
很会说话,但进不了后厨。手里有一份菜单(tool 清单),会写点单。
点单 = tool call
「hl__get_market,coin=BTC」,写在纸上递出去。
后厨 = 你的代码
真正干活:发 HTTP 请求、查数据库、下单……做完把菜端回来。
服务员不会自己炒菜。模型说「我要调
tool」,只是一段格式固定的文字;真正执行的永远是程序。
一次完整的来回
你的程序(agent 运行时)
模型(LLM)
-
程序
把三样东西一起发给模型:系统提示词、聊天记录(含「现在 btc
的价格是多少?」)、tool 清单(每个 tool
的名字、用途说明、参数格式)。
-
模型
读完判断:「这要实时数据,我自己不知道。」于是不直接回答,而是输出一条
tool call:
{ "tool": "hl__get_market", "input": { "coin": "BTC" } }
然后停下来等结果。
-
程序
收到这条 tool call,校验参数格式,找到对应函数去执行。这里就是向
Hyperliquid 发
POST /info 请求,拿回标记价、资金费率、盘口等数据。
-
程序
把执行结果(一段 JSON)作为「tool
结果」消息追加进聊天记录,再把整个对话发给模型一次。
-
模型
这次看到数据了,用自然语言写出回答:「BTC 标记价格
79,377……」。如果还缺信息,它可以回到第 2 步再申请别的 tool。
tool 清单里写了什么
每个 tool 给模型的就是一张「说明书」,三要素:
{
"name": "hl__get_market",
"description": "读取某个 Hyperliquid 市场的实时行情……", // 模型靠这句话决定用不用它
"input_schema": { // 参数格式(JSON Schema)
"coin": "string,必填,比如 BTC",
"marketType": "perp | spot,默认 perp",
"bookDepth": "可选,盘口精度"
}
}
示意写法,不是 Berth 的原文。真实定义在
contexts/bot/src/domain/tools/hl/hlMarkets.ts,用 zod 写
schema,框架会自动转成 JSON Schema 发给模型。
说明书写得好不好,直接决定模型会不会选对 tool。模型看不到你的代码,只看得到名字、描述和参数格式。
新人最该记住的几件事
模型从不亲手执行
它只「申请」,执行权、网络、密钥都在程序手里。所以安全检查放在程序这边。
tool 结果就是普通文本
对模型来说,结果和用户的话一样是输入。网页内容可能夹带「忽略之前的指令」这类陷阱,Berth
会把它包在 untrusted 标记里,并告诉模型这些只是数据。
一次回答可调多次 tool
先查价格,再查 K 线……每次都是「申请 → 执行 → 喂回」。Berth 给每次 Run
设了 tool 调用次数上限,防止无限循环。
数字要来自 tool
模型很会「编得像真的」。Berth 的系统提示词要求:所有数字必须从 tool
结果原样抄,不许自己算或估。
用不用 tool 是模型自己判断的
程序只提供菜单。想引导它,就改描述和系统提示词,比如「实时行情一律走
Hyperliquid tools」。
tool 越多越难选
菜单太长,模型容易挑错,也更费 token。Berth
有「deferred」机制:不常用的 tool 先不放进清单,需要时用
tool_search 再加载。
对照到 Berth 代码
| 环节 |
在哪 |
| tool 说明书(名字、参数 schema) |
contexts/bot/src/domain/tools/hl/hlToolPack.ts、hlMarkets.ts
|
| 系统提示词(何时用哪个 tool) |
apps/bot/src/owner/systemPrompt.ts |
| 收到 tool call → 分派执行 |
apps/bot/src/owner/thinkRuntime.ts 的
executeHlReadTool
|
| 执行逻辑(读哪些数据、怎么整理) |
contexts/bot/src/application/hl/HlReadService.ts |
| 真正发网络请求 |
SDK HttpTransport 的
fetch(),外面套一层缓存(apps/bot/src/platform/hlInfo.ts)
|
| 「请求 → 执行 → 喂回」这个循环本身 |
交给框架(AI SDK)驱动,Berth 只在执行前后挂钩子,比如
beforeToolCall 做次数限制
|
一句话总结:tool = 模型写申请,程序去执行,结果再喂回给模型。