Agent 核心能力 ①:Tool Use(工具调用)
摘要:Chatbot 只能“说”,Agent 必须能“做”。所谓 Tool Use,就是把 LLM 的意图(要做什么)变成可执行的动作(调用函数 / API / 文件系统 / 浏览器),再把执行结果反馈给模型,让它继续决策。
Agent = LLM + Planning + Memory + Tools。本章先把 Tools 这条链路打通。
1. Tool Use 在系统里的位置
一个最小的 Agent 循环通常长这样:
- 用户提问
- LLM 选择:直接回答 or 请求调用工具(tool call)
- 你的程序执行工具(真实世界动作)
- 把工具结果回传给 LLM
- LLM 基于结果输出最终答复(或继续调用下一个工具)
关键点:LLM 不会真的执行代码。真正的副作用(读写文件、发请求、改 DB)都发生在你的程序里。
2. Tools Schema:你要给模型什么信息
以 OpenAI 兼容协议为例,工具通常以 tools 数组声明,每个工具包含:
name:工具名(唯一、稳定、尽量短)description:给模型看的说明(决定它会不会用、怎么用)parameters:JSON Schema(决定参数结构稳定性)
示例(读文件):
{
"type": "function",
"function": {
"name": "read_file",
"description": "读取本地文件内容,用于理解代码或文档",
"parameters": {
"type": "object",
"properties": {
"path": {
"type": "string",
"description": "相对路径或绝对路径,例如 content/notes/ai/roadmap.md"
}
},
"required": ["path"]
}
}
}
工程经验:
- description 要“可操作”,不要抽象(例如“读取文件内容(必要时分段)”比“读取文件”更好)
- 参数 schema 要“紧”,该必填必填、枚举就枚举(越松越容易产生垃圾参数)
3. Tool Call 的闭环:从模型到代码再回模型
当模型决定使用工具,它会返回 tool_calls(或类似结构),此时:
assistant.content可能为空- 你要解析出
function.name和function.arguments
伪代码(语言无关):
while (true) {
const resp = await llm(messages, tools)
const msg = resp.choices[0].message
if (!msg.tool_calls?.length) {
// 没有工具调用:直接结束
return msg.content
}
// 逐个执行工具
for (const call of msg.tool_calls) {
const { name, arguments: argsJson } = call.function
const args = JSON.parse(argsJson)
const result = await runTool(name, args)
messages.push(msg) // 把 tool_calls 这条 assistant 消息也放进历史
messages.push({
role: "tool",
tool_call_id: call.id,
name,
content: JSON.stringify(result)
})
}
}
为什么要把 tool 的结果也放进 messages? 因为模型是无状态的;你不把结果给它,它就不知道你执行了什么。
4. 常见坑与护栏(必须做)
4.1 参数不可信:必须校验
模型生成的参数只是“建议”,不是事实。
- 路径必须做白名单/沙箱
- URL 必须做 allowlist
- 数值范围必须校验
4.2 工具要可观测:记录 trace
至少记录:
- tool name / args / result(可脱敏)
- latency
- token usage
否则你很难 debug:到底是模型不行,还是工具不行。
4.3 工具结果要“给模型看得懂”
工具输出不要塞一坨原始数据(尤其是大 JSON)。建议:
- 做摘要(summary)
- 给出关键字段
- 给出可选的
raw(必要时再取)
4.4 多工具调用与循环
模型可能:
- 一次请求多个工具
- 或不断重复同一个工具(陷入循环)
护栏:
- 设置
max_tool_calls/max_steps - 对重复调用做去重或阈值限制
5. 从 Tool Use 到 Mini Cursor
Tool Use 的终极练习是:让模型能够 读代码 -> 理解 -> 修改文件 -> 再读 -> 自检。
下一篇我们做一个 CLI 版 Mini Cursor:
- 提供
read_file/write_file/list_dir/search等工具 - 用一个简单的 agent loop 驱动
- 重点解决:token 成本、补丁粒度、修改可靠性