Notes

Agent 核心能力 ①:Tool Use(工具调用)

摘要:Chatbot 只能“说”,Agent 必须能“做”。所谓 Tool Use,就是把 LLM 的意图(要做什么)变成可执行的动作(调用函数 / API / 文件系统 / 浏览器),再把执行结果反馈给模型,让它继续决策。

Agent = LLM + Planning + Memory + Tools。本章先把 Tools 这条链路打通。


1. Tool Use 在系统里的位置

一个最小的 Agent 循环通常长这样:

  1. 用户提问
  2. LLM 选择:直接回答 or 请求调用工具(tool call)
  3. 你的程序执行工具(真实世界动作)
  4. 把工具结果回传给 LLM
  5. 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.namefunction.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 成本、补丁粒度、修改可靠性
cd ..