跳到主要内容 ESP32 小智 AI 机器人语音对话系统搭建与云端部署 | 极客日志
C AI 算法
ESP32 小智 AI 机器人语音对话系统搭建与云端部署 详细介绍基于 ESP32-S3 构建语音对话机器人的完整流程。内容涵盖硬件选型(I2S 麦克风、显示屏)、开发环境搭建(ESP-IDF、VSCode)、本地语音唤醒(ESP-SR WakeNet)、流式音频传输(WebSocket)以及云端服务部署(SenseVoice 语音识别 + DeepSeek/Qwen 大模型)。通过代码示例展示设备端录音上传与云端回复接收的实现逻辑,适合希望从零开始制作 AI 语音助手的开发者参考。
协议工匠 发布于 2026/4/5 更新于 2026/4/13 0 浏览ESP32 小智 AI 机器人语音对话系统搭建与云端部署
1. 基础原理
ESP32 架构及其在 AI 领域的应用
ESP32 是一款集成 Wi-Fi 和蓝牙的双核微控制器,具有较高的主频和丰富的外设接口,适合物联网和嵌入式 AI 应用。特别是新版的 ESP32-S3 芯片,不仅运行频率高达 240MHz,还内置了向量加速指令并支持高速 PSRAM,从而可以在一定程度上加速神经网络推理。在 AI 领域,ESP32 常用于边缘设备,执行一些轻量级的本地 AI 任务(如语音关键词检测、简单的图像识别等),或充当连接云端 AI 服务的桥梁。由于资源有限,ESP32 无法独立运行大型深度学习模型,但它可以负责前端的数据采集和初步处理(如音频处理),然后将数据传输给云端或本地服务器上的强大 AI 模型进行复杂计算,再将结果返回设备。
语音唤醒模块(ESP-SR)的工作原理 乐鑫官方提供了 ESP-SR (Speech Recognition) 语音识别框架,包含唤醒词引擎(WakeNet)、命令词识别(MultiNet)等组件。其中唤醒词 功能用于在设备待机时持续监听音频流,当检测到特定的唤醒词时触发设备进入对话/识别状态。例如,我们可以将'小智小智'设定为唤醒词。当 ESP32 运行 WakeNet 模型时,它会不断从麦克风录制音频并计算梅尔频谱倒谱系数(MFCC)等特征,然后通过一个针对 ESP32-S3 优化的神经网络算法对特征进行分类。一旦检测到训练好的关键词序列,WakeNet 就输出唤醒信号,唤醒设备进入语音交互状态。这种本地唤醒机制即使在有环境噪声的情况下也能保持较高的准确率。ESP-SR 默认提供了一些开箱即用的唤醒词模型,开发者也可以定制自己的唤醒词模型。工作流程是:麦克风采集到的模拟音频经前端处理(降噪、增益等),送入 WakeNet 模型进行关键词检测。如果未检测到唤醒词,设备保持低功耗待机;一旦检测到唤醒词,设备即进入后续的语音识别或对话流程。同时,为了节省运算资源,ESP32 在唤醒后通常会暂停 WakeNet,以便释放 CPU 处理后续音频;待对话完成后再重新启用 WakeNet 监听下一个唤醒词。
流式对话的概念及 WebSocket/UDP 传输机制 所谓流式对话 ,是指机器人在唤醒后能够实时地接收和发送数据,与用户进行连续的对话交流,而非一次性等待用户说完整句子再回复。要实现流式对话,ESP32 需要将用户的语音数据边录制边发送到云端的语音识别/大模型服务,并且及时接收对方返回的回复数据。这通常涉及到稳定高效的网络传输机制。常用的方式有两种:
WebSocket 通信: WebSocket 是基于 TCP 的全双工长连接协议,非常适合实时数据交换。一旦建立连接,服务器和客户端(ESP32)都可以随时发送数据而不需要重复握手。在本项目中,可在 ESP32 启动时就建立一个通向服务器的 WebSocket 长连接。ESP32 检测到唤醒词后,立即通过该 WebSocket 流式发送音频数据到服务器。服务器一边接收音频流一边进行语音识别,并将部分结果或最终结果通过同一连接发回给 ESP32。得益于 WebSocket 保持的长连接,数据可以持续、快速地往返,实现即时的对话体验。
UDP 传输: UDP 是基于数据报的传输协议,开销小、延迟低,但不保证可靠送达。在一些对实时性要求极高且可以容忍少量数据丢失的场景,可以考虑使用 UDP 将音频帧连续地发送到服务器。不过 UDP 没有内建重发、排序机制,需要应用层自行处理丢包重传或顺序问题。因此,对于初学者项目来说,UDP 方案实现难度略高,而且在局域网环境下 WebSocket 已经可以提供足够低的延迟和可靠性。所以通常推荐使用 WebSocket 实现流式语音对话。
总结来说,本项目将利用 ESP32-S3 的本地语音唤醒能力,让设备在检测到'小智'唤醒词后,开始录音并流式发送音频到云端,通过 WebSocket 与服务器上的大语言模型保持对话数据的实时交互。当云端返回文本应答后,ESP32 可将其显示在屏幕上(或语音播报),从而完成一次人机对话循环。
2. 硬件准备 要制作一个语音对话机器人,我们需要准备以下硬件组件,并确保它们兼容且正确连接:
ESP32-S3 开发板(带有 PSRAM) – 核心控制器,大脑所在。建议选择 ESP32-S3 系列开发板,因其具备 AI 加速指令集和高速 PSRAM,可支持语音唤醒等 AI 功能。常见选项包括官方的 ESP32-S3-DevKitC-1(WROVER 模块带 8MB PSRAM)、或多合一的语音开发板如 ESP32-S3-Korvo 系列和 ESP32-S3-BOX 等。这些板子自带麦克风阵列、音频编解码等硬件,方便语音应用开发。
麦克风 – 用于采集用户语音。强烈推荐使用 I2S 接口的数字麦克风(MEMS 麦克风),例如 INMP441 模块。数字麦克风可以直接将音频数据以数字信号传给 ESP32,抗干扰能力强,音质更好。避免使用模拟麦克风加 ADC 的方法,因为 ESP32 自带的 ADC 精度有限且噪声较大,模拟方案音质往往不佳。常用的 I2S 麦克风模块有 INMP441、ICS-43434 等,它们需要连接 ESP32 的 I2S 接口引脚(WS, SCK, SD 等)以及电源。
扬声器和音频放大器(可选) – 用于语音播报机器人回复。如果希望机器人能'说话',需要一个小型扬声器(如 4Ω 3W)的输出方案。ESP32 可以通过内置 DAC 输出模拟音频,但驱动扬声器需要功率放大器。常用方案是使用 I2S 数字功放模块(如 MAX98357A)将 ESP32 的 I2S 音频输出转换为扬声器驱动信号。该模块接收 ESP32 的 I2S 数据和时钟,输出功率音频信号,直接驱动小喇叭。如果暂时不需要语音输出,也可以先不接扬声器,后续通过串口日志或屏幕查看机器人回复的文本。
显示屏(OLED/LCD,可选) – 用于显示对话内容或机器人表情。一个小型显示屏可以显著增强人机交互体验。初学者可以选用 I2C 接口的单色 OLED(如 0.96 寸 128×64 OLED)或 SPI 接口的彩色 LCD(如 1.3 寸 240×240 TFT)。这些屏幕可以用来显示用户说的内容和机器人生成的回复文字,或显示一些图标、头像来提示当前状态(正在听/在想/在说等)。显示屏通过 I2C 或 SPI 接口连接到 ESP32 的对应引脚,并需要供电。后续可以使用图形库(如 LVGL)或驱动库来控制显示内容。
其他配件: 若使用独立的开发板和模块,还需要若干面包板和连接线方便搭建原型、电源线和 USB 数据线等。如果选用的是类似 ESP32-S3-BOX 这类集成度高的设备,许多组件(屏幕、麦克风、扬声器)已经内置,无需额外连接。
选购建议: 如果希望尽量减少硬件连接的麻烦,可以选择类似 ESP32-S3-BOX 或 ESP32-S3-Korvo 这样的开发套件,它们集成了语音所需的大部分硬件,开箱即可使用唤醒词和语音功能。例如,ESP32-S3-BOX 自带触摸屏、双麦克风和扬声器,只需刷入程序即可成为一个简单语音助手。不过这类套件价格相对较高。对于学习和制作原型来说,使用普通的 ESP32-S3 开发板加上外接麦克风和屏幕也是常用方案,性价比更高。在购买麦克风模块时,要确认其引脚定义与 ESP32 兼容(一般接 3.3V、GND、WS、SCK、SD),并注意麦克风的指向性、灵敏度等参数,以满足您的应用(如近场对话一般使用全指向麦克风,远场则考虑阵列降噪技术)。扬声器方面,小功率扬声器即可满足语音提示功能;若追求更大音量,可考虑使用有源音箱或更高功率的放大器,但要注意供电能力。显示屏选型取决于需求和预算,初期可以使用廉价的 0.96 寸 OLED 显示文字,后期可升级为彩屏显示头像或图形界面。
总之,在硬件搭建阶段,请按照各模块的规格说明正确连接电路,并确保供电稳定(ESP32 开发板通常通过 USB 供电,确保电脑 USB 口或电源适配器有足够的电流供应)。完成硬件连接后,我们就可以着手软件环境的搭建与代码编写了。
3. 软件环境搭建 在开始编程之前,需要搭建好 ESP32 的开发环境,以及准备云端大模型所需的工具库。
安装 ESP-IDF 开发框架 ESP-IDF(Espressif IoT Development Framework)是乐鑫官方的底层开发框架。我们将使用 ESP-IDF 来编写 C/C++ 代码控制 ESP32。请根据您的操作系统安装相应版本的 ESP-IDF。建议使用最新版(如 v5.x),以便支持 ESP32-S3 和 ESP-SR 库。安装方法如下:
Windows 用户: 可以使用乐鑫提供的安装包,其中集成了 IDF、编译工具链和 Python 环境等。一键安装后,运行 ESP-IDF 提供的命令行快捷方式进入开发环境。
Linux/Mac 用户: 可通过 git 克隆 ESP-IDF 仓库,然后运行 install.sh 脚本安装所需工具链和 Python 包。安装完成后,运行 export.sh 脚本配置环境变量。
详细步骤可参考乐鑫官方文档,但总的来说,安装完成后在命令行执行 idf.py --version 能看到版本信息即表示环境就绪。接下来创建一个 ESP-IDF 项目或者使用官方示例作为起点。
配置 VSCode/Cursor 开发环境 为了提高开发效率,我们推荐使用 VSCode 作为主要的代码编辑器,并安装乐鑫官方的 ESP-IDF VSCode 插件。该插件可以方便地菜单配置项目信息、一键编译烧录、监视串口输出等。您可以在 VSCode 的扩展商店搜索'Espressif IDF'并安装,然后按照插件指引配置 ESP-IDF 安装路径和 Python 环境。除此之外,您也可以尝试使用最近流行的 Cursor 代码编辑器。Cursor 本质上是 VSCode 的一个改进版本,内置了 GPT-4、Claude 2 等大型语言模型作为编程助手。使用 Cursor,您可以在编写代码时得到 AI 对代码的提示、自动补全和错误检查等智能帮助。这对初学者调试语音项目这样的复杂工程非常有益。例如,当您不知道某个 ESP-IDF 函数如何使用时,可以直接在 Cursor 中询问 AI 获取帮助。当然,使用 Cursor 并非必需,如果您习惯纯 VSCode 或其他编辑器也完全可以。
安装所需库和工具 本项目除了 ESP-IDF 自带的组件外,还可能需要用到一些专门的软件库,特别是在云端服务器部分,以实现语音识别和大语言模型对话功能。在开发电脑或服务器上,建议准备好以下工具:
SenseVoice 语音识别模型及 API: 这是阿里巴巴达摩院开源的一个多语言语音理解模型,支持语音转文本 (ASR)、语言识别、情感识别等功能。相较于其他开源方案,SenseVoice 在中文等多语言识别上精度很高,据称训练了超 40 万小时语音数据,效果优于 OpenAI 的 Whisper 模型。我们可以使用开源社区提供的 SenseVoice 推理代码或封装好的 API 服务。例如,GitHub 上的项目 SenseVoice-API 提供了基于 ONNXRuntime 的轻量级封装和 FastAPI 接口,方便我们将 SenseVoice 部署成一个本地服务。请按照该项目说明安装所需依赖(如 Python 及 onnxruntime)并下载模型文件,然后启动服务用于将音频流转成文本。
DeepSeek / Qwen 大语言模型: 为了让机器人更智能地对答,我们需要接入一个强大的大语言模型 (LLM)。DeepSeek 是国内开源的一个系列大模型,基于强化学习技术训练,性能媲美一些商业模型。他们提供了多种版本,包括体积较小的蒸馏模型(如基于 Qwen-7B 的 DeepSeek-R1 Distill)以及更大的 Qwen-32B/72B 模型。其中 Qwen (通义千问) 是阿里巴巴开源的大模型系列,7B 和 14B 版本已开源,而 72B 参数的模型则在阿里云上提供服务。您可以根据自身算力选择使用哪种模型:如果本地有高性能 GPU,可以尝试部署 7B 左右参数的模型运行;如果没有,则可以考虑通过在线 API 调用这些模型的推理服务。阿里云提供了 DashScope API 接口来调用通义千问模型,只需注册获取 API Key 即可使用。无论本地部署还是云端 API,请先安装好相应的 Python 库:如 Hugging Face Transformers(用于加载 DeepSeek/Qwen 模型)或者官方提供的 SDK(如 DashScope SDK)。
其他工具: 音频处理库(如 pyaudio 或 soundfile)可能用于服务器录音或读取文件;用于 WebSocket 通信的库(如 websockets for Python 或 Node.js 的 socket 库)如果您计划实现实时流式传输;以及 HTTP 客户端工具(如 requests)用于调用 RESTful API 等。如果打算使用 Node.js 作为服务器,也需要准备好 Node.js 环境以及相关依赖(如用于 WebSocket 的 ws 库,用于调用 AI 服务的 SDK 等)。
配置好以上软件环境后,整个开发流程将会是:使用 VSCode/ESP-IDF 在本地编写并烧录 ESP32 端代码,同时使用 Python/Node 等在电脑上编写服务器端代码并运行 AI 模型服务。接下来,我们就进入代码实现部分,看看如何让各部分协同工作。
4. 代码实现 在这一部分,我们将编写 ESP32 端的主要代码,实现以下功能:唤醒词检测 、音频采集并上传 、接收并处理云端返回的文本 。代码将基于 ESP-IDF 编写,语言为 C/C++。由于完整代码较长,这里拆分讲解关键步骤,并提供简化的代码示例。
4.1 初始化语音唤醒功能 首先,我们需要初始化 ESP-SR 提供的唤醒词引擎,使能麦克风采集和关键词检测。假设我们使用 ESP32-S3 和官方 ESP-SR 库,初始化主要包括:配置 AFE(声学前端)参数、启用 WakeNet 模型、设置唤醒回调等。伪代码示例如下:
#include "esp_sr_iface.h"
#include "esp_sr_models.h"
afe_config_t afe_config = AFE_CONFIG_DEFAULT ();
afe_config.wakenet_init = true ;
afe_config.voice_communication_init = false ;
afe_config.wakenet_model_name = "wn9_xiaozhi" ;
afe_config.wakenet_mode = DET_MODE_1CH;
sr_handle_t sr_handle = sr_handle_init (&afe_config);
if (!sr_handle) {
printf ("ESP-SR 初始化失败\n" );
return ;
}
esp_err_t ret = sr_wakenet_init (sr_handle);
if (ret == ESP_OK) {
printf ("唤醒词引擎加载成功\n" );
}
sr_set_wakenet_cb (sr_handle, on_wakeup_detected);
使用 AFE_CONFIG_DEFAULT() 宏获取默认的音频前端配置结构,然后根据需要调整参数。我们启用了 wakenet_init 来打开唤醒词检测,而将 voice_communication_init 置为 false,因为这两者不能同时为 true(通话模式用于双工通话情景,不在本项目范围)。wakenet_model_name 指定要加载的唤醒词模型的名字(例如这里假设我们有名为 'xiaozhi' 的模型,实际上需要先把模型文件烧录进 SPIFFS 或 Flash)。wakenet_mode 设为单通道检测,如果有双麦克风可以用相应的双通道模式以提升远场性能。
使用 sr_handle_init 初始化语音识别句柄,然后调用 sr_wakenet_init 加载唤醒词模型。如果返回 ESP_OK 则表示模型加载成功,可以开始检测。
通过 sr_set_wakenet_cb 注册一个回调函数 on_wakeup_detected,当 WakeNet 在音频流中检测到目标关键词时,这个回调就会被调用。在回调函数中我们可以进行接下来的处理(例如开始录音等)。
需要注意提前将所需的唤醒词模型文件添加到工程中(通常 ESP-SR 提供了一些预训练模型,可以在菜单配置中选中,如 'Hi 乐鑫' 等;如果要自定义唤醒词,则需要使用乐鑫提供的工具训练模型,然后集成)。
4.2 处理语音输入并上传至大模型 当唤醒词被检测到时,ESP32 应该切换到对用户语音指令的录制和传输流程。典型做法是在回调中通知主程序开始录音。可以创建一个 音频采集任务 ,持续从 I2S 麦克风读取音频数据,直到检测到一段静音 (表示用户说话结束)或达到最大录音时长,然后通过网络将音频发送出去。
音频采集: ESP32 IDF 提供 I2S 驱动来读取麦克风数据。麦克风模块通常以固定采样率输出,比如 16kHz 16 位音频。我们可以设置 I2S DMA,每次读取一定帧数的数据到内存缓冲区。为了简单,我们假设每次读取 BUFFER_SIZE 大小的数据块,并将其暂存。如果需要判断何时用户说话结束,可以实现一个简单的静音检测 (VAD):连续几百毫秒检测音量,如果音量低于阈值则认为用户讲话结束。
流式上传(推荐): 边录音边通过网络发送数据段。利用前文建立的 WebSocket 连接,将每个缓冲区的数据通过 esp_websocket_client_send_bin() 发给服务器。这样服务器可同步识别,不需等全部录完。这种方法实现对话响应更快。
后端上传(简单): 先本地录完整句话,存成 PCM 或 WAV 格式,然后通过一次 HTTP POST 请求将音频文件发送给服务器,等待服务器返回结果。在初期调试时此方法更直观,但交互上会有一点延迟。
#define SAMPLE_RATE 16000
#define BYTES_PER_SAMPLE 2
#define BUFFER_SIZE 512
bool recording = false ;
void on_wakeup_detected () {
printf ("唤醒词检测到!开始录音...\n" );
recording = true ;
disable_wakenet (sr_handle);
}
void audio_record_task (void *arg) {
char mic_buffer[BUFFER_SIZE];
size_t bytes_read = 0 ;
int silence_count = 0 ;
const int silence_threshold = 5 ;
while (true ) {
i2s_read (I2S_NUM_0, mic_buffer, BUFFER_SIZE, &bytes_read, portMAX_DELAY);
if (!recording) {
continue ;
}
if (bytes_read > 0 ) {
esp_websocket_client_send_bin (ws_client, mic_buffer, bytes_read, portMAX_DELAY);
}
bool is_silence = check_silence (mic_buffer, bytes_read);
if (is_silence) {
silence_count++;
} else {
silence_count = 0 ;
}
if (silence_count > silence_threshold) {
esp_websocket_client_send_text (ws_client, "<END>" , 5 , portMAX_DELAY);
recording = false ;
enable_wakenet (sr_handle);
printf ("录音结束,等待回复...\n" );
}
}
}
上述代码中,audio_record_task 会一直运行:平时 recording 标志为 false 时读入的数据直接丢弃(或可缓冲覆盖);当唤醒发生时回调将 recording 置为 true,于是任务开始真正处理音频数据。
通过 i2s_read 从 I2S 采集 BUFFER_SIZE 字节音频,每采集到一块,就用 esp_websocket_client_send_bin 发送二进制数据帧给服务器。这里假定已在别处初始化了 WebSocket 客户端 ws_client 并连接到服务器地址(例如 ws://<服务器 IP>:<端口>)。ESP-IDF 的 WebSocket 客户端是线程安全的,可直接从任务中调用发送函数。
check_silence 是用户定义的函数,用于检查缓冲中是否绝大部分样本都接近零(可设定一个幅值阈值)。如果连续检测到若干帧静音,我们就认为用户停止了讲话。这时通过发送一条特殊的文本帧 <END> 通知服务器音频流结束,然后把 recording 置回 false,表示本轮录音完成。还调用 enable_wakenet 恢复唤醒词检测,让设备准备接受下一次唤醒。
注意: 上述实现相对简单,实际应用中可能需要更健壮的 VAD 算法来准确判断讲话结束。另外,为了防止用户长时间讲话导致数据过多,可以设置最大录制时长,到点后强制结束。本示例省略了错误处理和资源管理(例如在结束录音后可能需要关闭 I2S 或重置缓冲等)。
4.3 与云端模型的交互并返回文本 当 ESP32 将语音数据发送到服务器后,接下来就轮到服务器端进行处理:把音频转成文本,交给大模型生成回复,再将回复发送回来。因此 ESP32 需要能接收服务器的响应数据。在流式方案中,服务器可能通过 WebSocket 发回 文本回复;在简单 HTTP 方案中,则是 ESP32 主动请求获取结果。我们这里以 WebSocket 双工通信为例说明。
ESP-IDF 的 WebSocket 客户端支持接收服务器推送的消息。可以注册回调或在循环中使用 esp_websocket_client_receive 来获取数据。在本例中,我们假定服务器最终发送回来的内容是纯文本的对话回复(或者为了简便,也可以让服务器直接返回语音合成后的 MP3 URL 等,但初期我们用文本即可)。ESP32 收到文本后,需要在本地加以处理,如在串口打印或者显示在屏幕上,或者通过 TTS 播放出来。
char recv_buf[256 ];
for (;;) {
int32_t rlen = esp_websocket_client_receive (ws_client, recv_buf, sizeof (recv_buf) - 1 , portMAX_DELAY);
if (rlen > 0 ) {
recv_buf[rlen] = 0 ;
if (strcmp (recv_buf, "<ACK>" ) == 0 ) {
continue ;
}
printf ("云端回复:%s\n" , recv_buf);
display_text_on_screen (recv_buf);
}
}
这个循环会一直等待 WebSocket 的消息。esp_websocket_client_receive 阻塞等待服务器发送的数据。收到后,我们检查内容:如果是预定义的控制消息(例如这里假设服务器可能发 <ACK> 表示收到结束标志),那么不做处理;否则将其作为正常回复文本处理。通过串口打印出回复,并调用一个假定的 display_text_on_screen 函数在 OLED 上显示该文字。实际实现中,您需要用相应的屏幕驱动 API 将文字绘制出来(如使用 SSD1306 驱动或 LVGL 库)。
如果您希望机器人语音回答,可以在 ESP32 上集成一个简单的本地 TTS (ESP-SR 框架本身带有简易的中文语音合成功能)或让服务器直接返回合成后的语音(例如 MP3 文件 URL 或音频流)。初始阶段为了专注核心,我们先不处理 TTS。
至此,ESP32 端的主要代码逻辑已经完整:等待唤醒→录音上传→接收回复→输出结果→循环等待下一次唤醒。接下来,我们看看云端服务器该如何部署大模型来配合工作。
5. 云端部署 云端(或本地 PC 服务器)在整个系统中承担了重型 AI 计算 的任务,包括语音识别和对话生成。根据硬件条件和需求,您可以选择自建服务器 或使用云服务 。本节将介绍如何连接大语言模型,以及如何搭建服务器端程序来实现智能对话。
连接大语言模型 (DeepSeek/Qwen 等) 大语言模型的选择取决于您的资源。对于中文对话,比较好的开源选择有阿里巴巴的通义千问系列 (Qwen) 和衍生的 DeepSeek 模型。如果有足够算力,您可以在服务器上直接运行开源模型实例。例如,使用 Hugging Face Transformers 加载 DeepSeek-R1 Distill (基于 Qwen-7B) 模型,然后在本地执行推理。伪代码如下:
from transformers import AutoModelForCausalLM, AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("deepseek-ai/DeepSeek-R1-Distill-Qwen-7B" )
model = AutoModelForCausalLM.from_pretrained("deepseek-ai/DeepSeek-R1-Distill-Qwen-7B" , device_map="auto" )
user_text = input ()
input_ids = tokenizer.encode(user_text, return_tensors="pt" )
output_ids = model.generate(input_ids, max_length=200 )
response_text = tokenizer.decode(output_ids[0 ], skip_special_tokens=True )
上述代码会生成 response_text 作为回复。但需要注意,这对 7B 模型至少需要十几 GB 显存或使用 CPU 耗时较长,因此如果硬件有限,不妨考虑调用在线 API 服务。
另一种便利的方法是使用模型提供方的云 API :例如阿里云的通义千问提供了 DashScope API,可以直接通过 HTTP 请求获得回复,无需本地运行模型。您只需在阿里云申请 API Key,然后按照文档构造请求(通常是一个包含会话历史的 JSON)。以下是使用 DashScope SDK 的伪代码:
from dashscope import Completion
Completion.api_key = "<你的通义 API Key>"
response = Completion.create(prompt=user_text, model="qwen-plus" )
answer_text = response.completions[0 ].text
利用在线大模型服务的优势是省去了部署模型的麻烦,而且一般响应速度快、效果好。不过要考虑到接口的使用费用或调用频率限制。
无论采用哪种方式获取对话回复,都应该注意实现上下文管理 :即让模型记住之前的对话历史,从而实现连贯的多轮对话。这可以通过每次调用 API 时在 prompt 中附带前文对话,或使用模型的对话模式接口来实现。在 DeepSeek/通义这样的模型中,一般支持多轮对话,只需将历史问答拼接即可(或在 API 参数中传递 conversation_id 等)。
调用语音识别 API 在让大模型理解用户意图之前,我们需要将音频转成文字。这里我们使用之前准备好的 SenseVoice 模型服务。假设您已在服务器上运行了 SenseVoice 的 API(例如本地 FastAPI 服务,端点 URL 为 /asr),ESP32 发送的音频通过 WebSocket 或 HTTP 转发给该服务进行识别。
如果采用我们上节的 WebSocket 方案,服务器可以在收到 ESP32 的音频帧后,将其拼接或直接送入语音识别引擎进行流式识别 。阿里的 SenseVoice 支持长语音转写 和多语言 ,可以逐步输出转写结果。简化流程如下:
服务器收到音频数据帧,缓存至音频缓冲区。
如果检测到结束标志 <END>,则将缓冲区音频送入 ASR 引擎。
获取到完整的转写文本 user_text。
调用大模型生成 answer_text。
通过 WebSocket 将 answer_text 发回 ESP32。
在实现中,可将步骤 1-4 集成在服务器的一个事件循环或多线程处理里。您也可以选择不等音频结束就边识别边生成 ,但那会复杂许多(需要分段、多段上下文管理,这里不深入)。
服务器端搭建 AI 服务 您可以用任意擅长的语言编写服务器。例如,用 Python 的 websockets 库搭建 WebSocket 服务,收到二进制音频后调用 Python 接口处理。这需要加载 SenseVoice 模型和大模型,可能耗时,建议在服务器启动时就加载好模型到内存,避免每次请求重复初始化。以下是服务器伪代码框架(Python):
import asyncio, websockets
from sensevoice import ASRModel
from your_llm_api import LLMAPI
asr_model = ASRModel.load("SenseVoiceSmall" )
llm_api = LLMAPI(api_key="..." )
async def handle_client (websocket, path ):
print ("客户端已连接" )
audio_bytes = b""
async for message in websocket:
if isinstance (message, bytes ):
audio_bytes += message
elif message == "<END>" :
user_text = asr_model.transcribe(audio_bytes)
print ("识别结果:" , user_text)
answer = llm_api.ask(user_text)
await websocket.send(answer)
audio_bytes = b""
else :
await websocket.send("<ACK>" )
这个简化的服务器逻辑中,我们使用 async for 来持续监听来自某个客户端 (ESP32) 的消息。如果收到的是二进制数据,则累加到 audio_bytes 缓冲。如果收到文本 <END> 则表示一段语音结束,遂调用 ASR 将整个音频转为文字,然后把文字传给大模型接口获得回复,最后通过 websocket.send 将回复发回客户端。然后清空缓冲等待下一轮交流。这里还示范了收/发 <ACK> 之类的控制信息的处理。实际应用中,应考虑异常处理(如网络中断)、识别超时等情况。
通过上述服务器的配合,我们的 ESP32 语音机器人基本功能就完成了:当你对着麦克风说'小智小智'(假定这是唤醒词),ESP32 检测到后开始录音,并把你的话通过网络发送出去;服务器将你的语音识别为文字,再由大模型生成回答'好的,我在呢'(示例),服务器将回答发送回 ESP32;ESP32 接收到后在屏幕上显示出来,并通过扬声器播报出来。整个过程接近实时,并且可以多次轮询,实现连续对话。
6. 优化与扩展 在基本功能实现后,我们可以对'小智'机器人进行多方面的优化和扩展,以提升体验和性能:
(1) 提升本地计算能力: 虽然 ESP32 性能有限,但我们可以通过一些技巧优化运行效率。例如,使用缓存 机制:针对用户经常询问的问题,可以在 ESP32 端缓存上一次的回答,若短时间内再次询问相同问题,可以直接回复缓存结果而不必每次都请求云端,从而降低延迟和流量。另外,尽量利用好 ESP32-S3 的硬件加速功能,如采用定点运算或使用 ESP-DSP 库优化音频处理。对于云端的大模型,可以考虑模型蒸馏或量化 来加快推理速度。例如将原本大的模型压缩为更小的参数,这也是 DeepSeek 提供蒸馏模型的思路。量化后的模型(如 INT8/INT4)在 GPU 甚至 CPU 上的推理速度会有明显提升,使对话响应更快。同时可在服务器端对相似的问答进行缓存,减少重复计算。
(2) 增强离线功能: 目前我们的机器人主要依赖云端 AI,但是我们可以赋予它一定的脱机能力 。首先,ESP32 上的 MultiNet 命令词识别 模块可以识别一些常用指令词离线运行。我们可以预先定义一组本地指令(例如:'播放音乐'、'停止'、'音量大一点'等)并训练相应模型烧录进 ESP32。这使得即使断网,机器人也能执行简单指令控制。此外,可以加入简单的本地问答库或规则,例如对于固定的问题(天气、时间)在 ESP32 存储预设答案,这样在无网络时也能回答部分问题。更高级的,可以在 ESP32 上运行一个超小型的语言模型(例如基于 Edge Impulse 或 GPT2-tiny 等),用于应对非常简短的对话。不过由于设备限制,这类模型智能性有限,主要作为备份。在应用中,可以设置策略:优先调用云端 AI,若不可用则退而求其次使用本地能力应答。
(3) 显示屏交互扩展: 为了让'小智'更生动,我们可以充分利用 OLED/LCD 显示屏来丰富人机界面。例如,在屏幕上显示对话文字的同时,可以加入表情或头像 来指示机器人状态:听的时候显示'耳朵'图标,思考时显示'加载中'动画,说话时显示'嘴巴'或表情变化等。如果使用的是彩色屏幕,可以绘制一个卡通头像,小智在不同状态下的表情(睁眼/闭眼/说话)变化,从而使机器人更具亲和力。技术实现上,可以预先加载几张位图或者使用简单的绘图指令组合出表情。在 ESP-IDF 中可以结合 LVGL 图形库实现精美的 UI 界面,包括文本、图像和动画效果。触摸屏设备还可以扩展触控功能,例如加一个'对话历史'查看或功能菜单。除了屏幕,您还可以增添LED 指示灯 (比如 RGB LED 显示不同颜色代表正在录音或思考)或者蜂鸣器音效提示用户进行交互提示。
(4) 语音合成输出: 虽然本教程侧重文字输出,但让机器人'开口说话'无疑会提供更直观的互动。在 ESP32 上实现文本转语音 (TTS) 有几种方案:可以利用 ESP-SR 自带的简易 TTS 模块生成中文语音;或者占用稍多资源,集成一个轻量级的 TTS 引擎(如科大讯飞离线 TTS SDK,不过对 Flash 和 RAM 要求较高);再或者走云端,由服务器把回复文本经过 TTS 合成后,以音频文件发送给 ESP32 播放。最后一种方式对 ESP32 压力最小,只需接收和播放音频即可。在具体实现时,可以在服务器端调用诸如阿里云易音识别、微软 Azure TTS 等云服务,将回答文本转为语音,然后 ESP32 通过 HTTP 获取 MP3 文件,使用集成的音频解码器播放。若追求本地纯离线,也可考虑安装一个小型 MP3 解码库,将服务器传来的 MP3 数据用 ESP32 解码输出至扬声器(ESP32 有足够能力播放中等码率的 MP3)。语音合成的声音可以自定义,让小智有独特的音色。
(5) 其他扩展创意: 小智机器人可以结合更多传感器和功能模块,实现丰富的玩法。例如,加入摄像头模块 (ESP32-S3 支持连接摄像头),配合云端的视觉识别,实现看图对话或人脸识别后的个性化对话;或者集成舵机 作为'头部',让机器人朝向发声方向转动;添加触摸传感器 或按钮,让用户可以用触摸来激活对话等。此外,如果追求更强的 AI 本地能力,可以关注乐鑫新推出的 ESP32-P4 等更高性能芯片或者结合 Edge AI 加速器来运行部分模型。对于软件层面,也可以将当前方案与其他开源框架集成,例如接入 Home Assistant 平台,实现家居语音控制;或使用 LangChain 框架设计机器人的对话流程和工具调用能力,让小智不仅能聊天,还能帮忙查询资料、控制设备。
通过以上优化,小智 AI 机器人将变得更加实用和智能:在联网时,它是一个功能全面的语音助手,能聊天、查信息、控制家电;离线时,它仍具备基本的指令识别和交流能力。不仅如此,借助 ESP32 的开源生态,您可以不断为小智添加新功能。在实践过程中,请充分利用社区资源:参考官方示例、查看类似项目源码,这将有助于您更深入地理解实现细节并排除开发中的困难。
微信扫一扫,关注极客日志 微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
相关免费在线工具 加密/解密文本 使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
RSA密钥对生成器 生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
Mermaid 预览与可视化编辑 基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
Markdown 转 HTML 将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML 转 Markdown 互为补充。 在线工具,Markdown 转 HTML在线工具,online