导航栏:首页 / AI教程目录 / AI创客项目开发教程目录 / 第1篇 基础知识篇 / AID101-1-3-01 – AI大模型工具调用基础
本节内容简介
本节将详细讲解如何通过 AI 大语言模型的 Tool Calls(工具调用)功能,让 ESP32 开发板根据用户的自然语言指令控制ESP32 S3开发板的板载 LED 。通过本节课程,您将理解 Tool Calls(工具调用) 的核心概念、工作流程,以及如何在 ESP32 上实现 AI 驱动的硬件控制。
Tool Calls(工具调用)详解
什么是 Tool Calls(工具调用)(工具调用)?
Tool Calls(工具调用)是现代大语言模型的一项重要功能,它让 AI 不仅能“说话”,主动调用预定义的工具,为我们“办事”。在物联网(IoT)场景中,Tool Calls(工具调用) 能让 AI 模型理解用户指令(如用 ESP32 控制 LED、继电器或读取传感器读数等),并生成结构化的控制命令,由 ESP32 执行操作,实现设备控制目的。
在前几章的课程中,我们学习了通过 System Role、User Role 和 Assistant Role 与 AI 进行文本对话。但这种方式有一个明显的局限:AI 只能”说”,不能”做”。比如,当用户说”打开LED”时,AI 无法真正控制 LED 的开关。Tool Calls(工具调用) 正是为了解决这个问题而诞生的。
🔁 Tool Calls(工具调用)整体流程概览

注意:对于本章教程来说,“工具调用”中所提到的“工具”这一概念指的是ESP32程序中的可以执行任务的函数。基于这个原因,在后续的讲解中,如果您在看到工具的时候,请马上联想到某个ESP32程序中的函数。
整个工具调用过程分为三个阶段:
- 请求阶段:ESP32 向 AI 平台发送包含“用户指令 + 可用工具列表(可用函数列表)”的请求。
- 分析响应阶段:AI 收到 ESP32 发来的请求后,对请求内容进分析。然后AI将分析结果返回 ESP32,告知ESP32“要调哪个函数、传什么参数”
- 执行阶段:ESP32 根据AI的指令来调用工具函数。
注意:以上过程中,实际执行函数的是ESP32,而不是AI模型。AI模型仅仅起到将我们的自然语言指令(比如“打开LED”)转化为要求ESP32执行哪个函数的指令。而AI模型,并不实际参与实际的函数执行。这一点非常关键,需要牢牢记住,否则后续学习会产生困扰。
第一阶段:ESP32 如何构建一个工具调用请求?
ESP32 本身不能直接“理解”我们的自然语言指令,但ESP32可以把我们的自然语言指令,以及其它重要信息组装成一个标准 JSON 请求包,并且将这个JSON请求信息发送给类似阿里云百炼、OpenAI 或其他支持 Tool Calls(工具调用) 的 AI 平台。
注意:并不是所以的AI模型都支持“工具调用”调用功能,您在选择用什么模型来处理工具调用请求的时候,一定要确定该模型具备“工具调用”处理能力,再使用它处理工具调用请求。
📦 标准 工具调用 JSON 请求包含 4 个关键部分:
标准 工具调用 JSON 请求包含以下 4 个关键部分。
1. 指定模型
"model": "qwen-flash"告诉AI平台:“请用这个叫做qwen-flash的模型来处理工具调用”。
2. 提供对话上下文(messages)
"messages": [
{
"role": "system",
"content": "你是一个智能家居助手,可以帮助用户控制设备。"
},
{
"role": "user",
"content": "打开LED"
}
]system role:设定 AI 的角色。在这里个实例中,Ai的角色是一个智能家居助手,可以帮助用户控制设备。user role:用户的原始指令。在这里个实例中,用户要求ESP32打开LED。
3. 声明可用工具(tools)
"tools": [
{
"type": "function",
"function": {
"name": "controlLEDOnOFF",
"description": "控制LED的打开或关闭",
"parameters": {
"type": "object",
"properties": {
"action": {
"type": "string",
"description": "LED控制动作",
"enum": ["on", "off"]
}
},
"required": ["action"]
}
}
}
]这段内容较为复杂,下面我将逐字段、按层级顺序详细解释您提到的 tools 数组中这个 JSON 对象的每一个组成部分,尤其重点剖析 "function" 内部各字段的作用和设计意义。从而让您清晰理解:这个 JSON 到底在“告诉 AI 什么”?为什么这样写?
首先我们来整体看一下这个 JSON 到底在“告诉 AI 什么”?
| 字段 | 告诉 AI 的内容 |
|---|---|
name | “AI 模型可以让ESP32执行一个叫 controlLEDOnOFF 的工具函数” |
description | “这个叫 controlLEDOnOFF 的工具函数是用来控制LED开关” |
parameters | “parameters 用于完整定义调用 controlLEDOnOFF 所需的参数类型和取值范围。” |
parameters.type | AI 模型必须在返回的响应中提供一个JSON格式的数据,该JSON数据包含运行 controlLEDOnOFF 工具函数所需的参数 |
parameters.properties | properties 列出了controlLEDOnOFF 函数允许传入的参数及其各自的类型和取值规则。 |
parameters.properties.action | 这里告知AI模型可通过名为 action 的字段来提供一个controlLEDOnOFF 函数参数。 |
parameters.properties.action.type | 这个action字段所传递的参数类型必须是字符串类型的 |
parameters.properties.action.enum | “action 字段所传递的参数只能是 'on' 或 'off'这两个值中的一个,不能是其它任何内容!” |
required | “action 字段是必须在AI模型相应信息里提供的,不能省略” |
✅ 最终效果:如果用户想要ESP32打开LED,那么它无论说“开灯”、“把 LED 打开”、“点亮”或其他类似表达,AI 都会标准化输出:
{
"name": "controlLEDOnOFF",
"arguments": {
"action": "on"
}
}ESP32 只需解析以上这个结构化数据,即可得知要运行的函数名称是controlLEDOnOFF并且在运行时使用参数on。
通过这种严格约束 + 语义描述的方式,Tool Calls(工具调用) 实现了 “自然语言输入” → “可靠机器指令” 的转换,极大简化了智能硬件的开发流程。
小结:
下面我们把以上示例中 Tool Calls 工具调用的完整 Json包写在下面,供您参考:
{
"model": "Qwen/Qwen3-VL-8B-Instruct",
"messages": [
{
"role": "system",
"content": "你是一个智能家居助手,可以帮助用户控制设备"
},
{
"role": "user",
"content": "打开LED"
}
],
"tools": [
{
"type": "function",
"function": {
"name": "controlLEDOnOFF",
"description": "控制LED的打开或关闭",
"parameters": {
"type": "object",
"properties": {
"action": {
"type": "string",
"description": "LED控制动作",
"enum": ["on", "off"]
}
},
"required": ["action"]
}
}
}
],
"tool_choice": "auto",
"temperature": 0.1
}细心的朋友可能已经发现了,在上面这个Tool Calls(工具调用)请求Json包中,还有两个字段:
"tool_choice": "auto",
"temperature": 0.1他们是可选字段,作用如下:
"tool_choice": "auto", // 让 AI 自己决定是否调用工具
"temperature": 0.1 // 降低AI响应内容的随机性,确保AI输出稳定可靠第二阶段:AI 平台如何分析并响应?
当 AI 平台收到上述请求后,会进行以下智能分析:
🔍 分析过程:
- 理解用户意图
- 输入:“打开LED” → 语义解析为“需要开启某个照明设备”。
- 匹配可用工具
- 查看
tools列表,发现有一个叫controlLEDOnOFF的函数,描述是“控制LED开关”。 - 判断:该工具能完成用户需求。
- 查看
- 生成合法参数
- 根据
parameters中的enum: ["on", "off"],确定只能选"on"。 - 不会生成
"open"、"start"等非法值(因为被parameters中的enum限制了只能使用"on", "off")。
- 根据
- 决定输出形式
- 因为
tool_choice是"auto",且匹配成功,所以不返回文字,而是返回一个工具调用指令。
- 因为
第三阶段:ESP32 如何处理 AI 的响应并执行相应操作?
在前两步中,我们已经完成了指令的发送和AI平台的分析。现在,让我们来看看ESP32是如何接收并处理AI返回的指令的。
当AI平台完成分析后,它会向ESP32返回一个结构化的响应。为了便于大家理解,以下是一个简化版本的AI响应,实际AI平台的响应内容要更加丰富和复杂,但是考虑到我们这个教程文章面向初学者,所以先省略掉一部分内容,而只是将最重要的部分摘出来进行讲解:
{
"choices": [
{
"finish_reason": "tool_calls",
"index": 0,
"message": {
"role": "assistant",
"content": "",
"tool_calls": [
{
"function": {
"name": "controlLEDOnOFF",
"arguments": "{\"action\": \"on\"}"
}
}
]
}
}
]
}ESP32收到这个响应后,会按照以下步骤进行处理:
首先,ESP32会检查响应中的finish_reason字段。当这个字段的值为"tool_calls"时,ESP32就知道AI已经生成了一个工具调用指令,而不是普通的文本回复。
接着,ESP32会从tool_calls数组中提取关键信息。在这个例子中,ESP32会找到第一个(也是唯一一个)工具调用,并从中获取两个重要信息:
- 函数名称:通过
function.name字段,ESP32得知需要调用名为controlLEDOnOFF的函数 - 函数参数:通过
function.arguments字段,ESP32获得一个JSON格式的字符串{"action": "on"}
然后,ESP32会对参数字符串进行解析,将其转换为可操作的数据结构。通过解析,ESP32能够提取出具体的参数值:action的值为"on"。
最后,ESP32会根据这些信息执行相应的硬件操作。在这个例子中,由于action的值是"on",ESP32就会执行打开LED的操作。如果action的值是"off",则会执行关闭LED的操作。
通过这种方式,ESP32成功地将AI生成的结构化指令转化为实际的硬件控制动作,实现了”让AI控制物理设备”的目标。
补充说明:完整响应中的其他重要字段
在前面的讲解中,我们聚焦于ESP32如何从AI响应中提取关键的函数调用信息(如函数名和参数),并据此控制硬件。然而,实际从阿里云百炼平台返回的完整JSON响应还包含许多其他字段,这些字段虽然不直接影响LED的开关动作,但对于构建健壮、可维护和可调试的系统非常有价值。下面我们列出实际从阿里云百炼平台返回的完整JSON响应并且对以上讲解中没有涉及的内容进行补充说明,帮助你更全面地理解整个通信过程。
{
"choices": [
{
"finish_reason": "tool_calls",
"index": 0,
"message": {
"content": "",
"role": "assistant",
"tool_calls": [
{
"function": {
"arguments": "{\"action\": \"on\"}",
"name": "controlLEDOnOFF"
},
"id": "call_79fb27a337534b0fa58147",
"index": 0,
"type": "function"
}
]
}
}
],
"created": 1776425906,
"id": "chatcmpl-7fc1186d-a768-95c1-845c-5f9d32e89951",
"model": "qwen-flash",
"object": "chat.completion",
"usage": {
"completion_tokens": 21,
"prompt_tokens": 177,
"prompt_tokens_details": {
"cached_tokens": 0
},
"total_tokens": 198
}
}tool_calls中的元数据字段
在每个工具调用对象中,除了function.name和function.arguments之外,还有几个辅助字段:id:例如"call_79fb27a337534b0fa58147",这是该次工具调用的唯一标识符。如果你的应用需要追踪某个工具调用,这个ID可以帮助你将请求与响应准确匹配。index:表示该工具调用在列表中的位置(从0开始)。当AI一次生成多个工具调用时(例如同时打开灯和调节风扇),你可以通过index来按顺序处理它们。type:明确指出这是一个"function"类型的工具调用,未来如果平台支持其他类型,这个字段将有助于区分处理逻辑。
- 顶层响应元信息
响应的顶层包含一些描述整个AI生成过程的元数据:id:如"chatcmpl-7fc1186d-a768-95c1-845c-5f9d32e89951",这是本次聊天完成(chat completion)的唯一ID,可用于日志记录或问题排查。created:时间戳(Unix格式),表示响应生成的时间。这对于调试延迟问题或分析系统性能很有帮助。model:指明所使用的AI模型(这里是"qwen-flash")。这个字段可以用于确认当前生效的模型。object:固定为"chat.completion",表明这是一个标准的聊天完成响应,符合OpenAI兼容的API规范。
usage字段:用量统计
这部分提供了本次请求的资源消耗详情:prompt_tokens:输入提示(包括系统指令、用户消息和工具定义)消耗的token数量(177个)。completion_tokens:AI生成的响应(即工具调用部分)消耗的token数量(21个)。total_tokens:总token数(198 = 177 + 21)。
usage字段,你可以估算服务成本,并优化提示词以减少不必要的token消耗(例如精简工具描述)。finish_reason的更多可能值
虽然本例中finish_reason是"tool_calls",但实际应用中它还可能是:"stop":AI正常结束回复(无工具调用)。"length":响应达到最大长度限制。"content_filter":内容被安全过滤器拦截。
finish_reason的值,以确保只在预期情况下处理工具调用,避免因异常终止导致解析错误。
实践建议
尽管初学者教程可以简化响应结构,但在实际项目中,建议你的ESP32固件至少做以下增强:
- 监控
usage:设置token用量告警,防止意外高额费用。 - 处理多种
finish_reason:增加错误处理分支,提升系统鲁棒性。
通过理解这些额外字段,你不仅能正确控制LED,还能构建一个生产级的、可监控、可扩展的AIoT(人工智能物联网)应用。
✅ 总结
Tool Calls(工具调用) 让 ESP32 项目具备了“听懂人话”的能力,而你作为开发者,只需:
- 告诉 AI 你能做什么(通过
tools定义), - 执行 AI 下达的指令(解析
tool_calls并操作 GPIO)。
这大大降低了自然语言交互的开发门槛,让你专注于硬件控制,而不是复杂的语言理解。
现在,当你看到示例程序中的 JSON 构造、HTTP 请求、响应解析代码时,就能清楚知道:每一行都是在实现这个“AI 指令 → 设备动作”的桥梁。