AI 工具调用
AI 的限制
AI 在嵌入式系统中有许多用途,但输出可能包含不准确、偏见或安全问题。
本指南假设您已经查看了我们的嵌入向量指南和 AI 文本助手指南。
工具调用允许 AI 模型的输出调用外部函数或 API。工具调用的典型用途是从基于云的 LLM 访问云 API;但在嵌入式系统中,我们也可以使用它与系统状态和外设进行交互。这有许多用途,包括嵌入式系统的语音用户界面 (VUI) 控制。
让我们扩展基于问答的 AI 助手,使其在看到特殊标记时调用外部工具。 这使您的 AI 能够:
- 通过网络摄像头查看(
{vision}) - 打开/关闭 LED(
{light_on}和{light_off}) - 运行 shell 命令(
{time})

信息
本快速指南适用于所有 SL16xx 开发板。虽然推理性能可能有所不同,但所有 Astra SL 系列处理器的步骤都相同。
硬件设置
- Synaptics Astra SL1680 开发板
- USB 网络摄像头(可选)
- 由
vision.py访问,它使用 NPU 加速在帧上运行图像分类 - 返回文本描述,例如:"我看到一只猫。"
- 由
- GPIO 引脚上的 LED(可选)
- 连接到 GPIO[36](开发板上的物理引脚 33)高电平(
{light_on})或低电平({light_off}) - 通过类似"开灯"或"关灯"的短语进行语音控制
- 连接到 GPIO[36](开发板上的物理引脚 33)高电平(

运行演示
- 运行助手
python3 -m assistant.toolcall - 询问"你能看到什么?"
- 系统在
qa_pairs.json中识别匹配项("我看到 {vision}) - 它发现
{vision},运行python3 path/to/vision.py,并用脚本输出替换{vision}。
- 系统在
- 询问"打开灯"
- 匹配问答
"打开灯" ->"{light_on}"` - 您的代码执行 GPIO 命令将 LED 引脚设置为高电平。
- 匹配问答
- 询问"现在几点了?"
- 返回
{date}=> 调用date=> 输出系统时间。
- 返回
工作原理
- 嵌入向量和相似度:我们将每个"问题+答案"对嵌入到向量空间中。当用户提问时,我们计算问题的嵌入向量,将其与存储的嵌入向量进行比较,并找到最高的余弦相似度。
- 响应构建:我们从
qa_pairs.json中检索最佳匹配的"答案"。 - 标记替换:在打印最终答案之前,我们查找任何占位符,如
{light_on}。如果存在,我们从tools.json执行相应的命令,并用命令的输出替换标记。
数据文件
1. data/qa_pairs.json
我们不仅在 answer 字段中存储静态文本,还嵌入"工具标记"。例如:
[
{
"question": "现在几点了?",
"answer": "{time}"
},
{
"question": "你能看到什么?",
"answer": "我看到 {vision}"
},
{
"question": "打开灯",
"answer": "{light_on}"
},
{
"question": "关闭灯",
"answer": "{light_off}"
},
]
这里,"{vision}" 代表对网络摄像头图像运行 NPU 加速的图像分类,而 "{light_on}" 调用 GPIO 脚本来打开 LED。
2. data/tools.json
此文件将每个标记映射到我们希望系统运行的命令:
[
{
"token": "{time}",
"command": "date"
},
{
"token": "{vision}",
"command": "python3 assistant/tools/vision.py"
},
{
"token": "{light_on}",
"command": "echo 'light on' & python assistant/tools/gpio.py 484 out 1"
},
{
"token": "{light_off}",
"command": "echo 'light off' & python assistant/tools/gpio.py 484 out 0"
}
]
请随意自定义路径和参数以匹配您的开发板设置。
关键代码概念
以下是在选择的答案中出现标记时如何调用工具的基本代码片段:
import json
import subprocess
def run_command(command):
"""运行 shell 命令并返回其输出作为字符串。"""
try:
return subprocess.check_output(command, shell=True).decode().strip()
except Exception as e:
return f"[错误: {e}]"
def replace_tool_tokens(answer, tools):
"""用外部命令输出替换答案中的占位符。"""
for tool in tools:
if tool["token"] in answer:
# 运行相应的命令并注入结果
result = run_command(tool["command"])
answer = answer.replace(tool["token"], result)
return answer
在您的主助手循环中:
# 加载问答对并预计算嵌入向量等(未完全显示)
with open("qa_pairs.json") as f:
qa_pairs = json.load(f)
with open("tools.json") as f:
tools = json.load(f)
while True:
query = input("问我任何问题(或输入 'exit'):")
if query.lower() == "exit":
break
# 1. 通过余弦相似度找到最佳匹配答案(伪代码)
best_answer = find_best_match(query, qa_pairs)
# 2. 用命令输出替换任何工具标记
final_answer = replace_tool_tokens(best_answer, tools)
print(f"答案:{final_answer}\n")
结果是一个可以与物理环境交互(打开/关闭灯)并动态收集信息(运行视觉分析、打印当前时间)的助手,所有这些都通过在其文本答案中返回简短的标记来实现。
自定义工具和命令
要添加新功能,只需在 qa_pairs.json 中添加更多标记,并在 tools.json 中定义如何处理它们。例如,如果您有红外发射器或伺服电机,创建相应的标记(如 {raise servo})并将其链接到您的硬件脚本。
结论
通过将工具调用与基于嵌入向量的问题匹配配对,我们现在有了一个实用的 AI 助手,它可以:
- 回答来自精选知识集的问题,
- 动态运行系统命令或脚本以从外部系统获取答案,
- 与真实世界的硬件(如网络摄像头和 GPIO 驱动的 LED)集成。
这种架构是模块化的,让您能够以最少的代码更改插入新的硬件工具、脚本或 API。