← 懂一点

工具调用与 Function Calling——Agent 如何“动手”

2026-07-21

本文是专栏《从零看懂 AI Agent》第 4 篇。回到目录与导读。上一篇:ReAct 循环

一个容易被忽略的事实

大模型本身只会做一件事:根据输入的文字,生成后面的文字。它不会真的联网,不会真的发邮件,不会真的读你的硬盘。

那 Agent 是怎么"动手"的?答案有点反直觉:

模型不亲自动手,它只是"说"出想调用哪个工具、传什么参数;真正动手的是外面那段程序。

模型负责"点菜",厨房(你的程序)负责"做菜"。这个"点菜"的机制,就叫 Function Calling(函数调用),也叫工具调用(Tool Calling)。

三步搞懂 Function Calling

第一步:告诉模型"你有哪些工具可用"

在每次请求时,除了用户的问题,你还会附上一份工具清单,每个工具用结构化的方式描述清楚。比如查天气这个工具:

{
  "name": "get_weather",
  "description": "查询某个城市今天的天气",
  "parameters": {
    "city": { "type": "string", "description": "城市名,比如 北京" }
  }
}

这段东西相当于给模型看的"工具说明书":工具叫什么、干什么用、需要哪些参数description 写得好不好,直接决定模型能不能在对的时机选对工具——这是实战里很吃经验的一环。

第二步:模型输出一个"调用请求"(而不是执行它)

当模型判断需要天气信息时,它不会假装自己查到了,而是输出一段结构化的调用请求:

{
  "tool_call": {
    "name": "get_weather",
    "arguments": { "city": "北京" }
  }
}

注意:这一步模型只是表达意图——"我想调用 get_weather,参数是北京"。它并没有、也不可能真的查到天气。球现在踢给了你的程序。

第三步:你的程序执行工具,把结果喂回去

你的程序(也就是第 2 篇说的调度器)收到这个请求后:

  1. 解析出"哦,要调 get_weather,city=北京";
  2. 真正地去调用天气 API,拿到 {"temp": 32, "desc": "多云"}
  3. 把这个结果作为一条新消息,塞回对话历史,再交给模型。

模型这才"看到"了真实天气,继续它的推理。是不是很眼熟?这正是上一篇 ReAct里的 Action(模型发出调用)→ Observation(程序返回结果) 那两步的底层实现。

完整走一遍

把三步串起来,一次带工具的对话是这样流动的:

你 → 模型:北京今天多少度?(附:工具清单[get_weather])

模型 → 你:我要调用 get_weather(city="北京")   ← 只是意图,没真查

你的程序:真的调用天气 API → 得到 32℃

你 → 模型:get_weather 的结果是 {temp:32, desc:多云}

模型 → 你:北京今天 32℃,多云。              ← 拿到真实数据才作答

关键就一句:模型和真实世界之间,永远隔着你的程序这层"中介"。 模型说想做什么,程序决定要不要做、怎么做、结果给不给它看。这层中介也正是安全和可控的关键——第 8 篇讲护栏时会回到这里。

为什么这套设计很重要

现实中的几个坑

Function Calling 听起来干净利落,实战里有几个常见麻烦:

最后这个坑,正是催生 MCP 协议的背景。过去每接一个新工具都要手写一套对接代码,又碎又难维护。下一篇就讲这个正在成为行业标准的解决方案。

小结

下一篇,我们看看 MCP——一个让 Agent 接工具不再靠"手搓"的通用协议。

继续阅读:MCP 协议——给 Agent 装上"USB-C"接口