Skip to content

工具调用:Agent 把意图变成动作的接口

今天先记住

工具调用(Tool Calling)不是让模型“知道更多工具名字”,而是给 Agent 一组可控接口:模型负责判断要不要用、用哪个、填什么参数;系统负责真正执行、返回结果、限制权限。

它在大地图里的位置

继续看这条 Agent 主线:

txt
用户目标
  -> 上下文 / 记忆
  -> 规划 / 决策
  -> 工具调用 / 外部系统
  -> 执行 / 观察结果
  -> 评估 / 修正
  -> 最终输出

前三课讲了 Agent 不是只聊天,而是推进状态;昨天讲了最小闭环。今天放大闭环里的“行动”入口:工具调用。没有工具,Agent 只能建议;有了工具,它才可能读文件、查数据库、跑命令、发请求、更新任务状态。

它到底是什么

工具调用可以理解成一份“模型能申请执行的函数清单”。每个工具至少要有三样东西:名字、用途说明、参数结构。

模型看到用户目标后,不是直接编造结果,而是输出一个结构化请求,比如:

json
{
  "tool": "read_file",
  "arguments": {
    "path": "docs/ai-agent/2026-07-13.md"
  }
}

真正读文件的不是模型,而是宿主程序。宿主程序执行后,把结果再喂回模型,模型再决定下一步。这一点很关键:工具调用把“想做什么”和“实际执行”分开了。

为什么 Agent 里会用到它

Agent 要处理真实任务,就必须碰外部状态。比如写每日课程时,只靠模型记忆不够,它要读已有文章,判断下一主题,写入文件,运行构建,再看 Git 状态。

工具调用的价值不是抽象地“增强能力”,而是把每个动作变成可审计的状态转移:读到了什么、写了哪个文件、命令返回码是多少、是否允许继续提交。这样失败时才能定位在具体动作上,而不是只剩一句“任务没完成”。

怎么判断它有没有用

如果任务只需要生成一段文本,工具调用可能是多余的。

如果答案依赖当前外部状态,比如文件内容、最新提交、日历、库存、构建结果,就应该让模型通过工具拿真实数据。

如果动作会改变外部世界,比如发消息、改配置、提交代码,就必须把工具权限拆细:读工具可以自动用,写工具要有范围限制,高风险工具要确认或禁止。

如果模型需要填复杂参数,就要让 schema 足够明确。参数含糊时,模型更容易把“删除哪个文件”“发给谁”“改哪条记录”猜错。

最近冒出来的词

这几天可以留意一个讨论点:MCP vs tool calls。

MCP(Model Context Protocol)不是 tool calling 的替代品,更像把工具发现、连接和调用方式标准化的一层协议;tool calling 则是模型和宿主程序之间发起具体函数请求的机制。2026-07-14 Nango Blog 有一篇文章专门比较二者在生产集成里的取舍。

它和今天主题的关系很直接:先理解 tool calling 是“单个动作接口”,再理解 MCP 是“让很多外部工具以统一方式接进来”的连接层。

来源提示:Nango Blog,2026-07-14,https://nango.dev/blog/mcp-vs-tool-calls-for-ai-agents/

一个小例子

txt
Input:
生成并发布 2026-07-14 的 AI Agent Daily lesson。

Process:
1. read_file:读取写作框架和已有课程。
2. list_files:确认 ai-agent 目录下最新一课是 2026-07-13。
3. write_file:写入 docs/ai-agent/2026-07-14.md。
4. run_command:执行 npm run docs:build。
5. git_status:确认只提交本次课程文件。

Output:
状态从“缺少 2026-07-14 课程”变成“课程文件存在、构建通过、相关提交可推送”。

这个例子里,模型不是直接说“我发布好了”,而是通过工具一步步拿证据。你判断系统靠不靠谱,就看它有没有把关键动作暴露成可检查的工具结果。

常见误区

  1. 以为工具越多越好。工具越多,选择错误和权限风险也越多。
  2. 以为模型会天然按工具说明做对。工具说明、参数 schema、返回格式都要工程上约束。
  3. 以为工具成功等于任务成功。一次写文件成功,不代表构建通过,更不代表发布完成。
  4. 以为所有工具都能自动执行。读、写、发消息、付款、删数据,风险等级完全不同。

今天自测

  1. 为什么工具调用要把“模型决策”和“宿主程序执行”分开?
  2. 一个会写文件的工具,至少应该限制哪些参数或路径?
  3. MCP 和 tool calling 的关系,能不能用“一层连接协议”和“单次函数请求”解释清楚?