前言
小智 AI 聊天机器人是最近一个很火的开源项目,它借助LLM大模型以及TTS等AI的能力,通过自然语言来与其对话实现交互。它可以回答任何问题、播放音乐、背诵古诗,颇有未来AI机器人的雏形。
因为最近工作上的需要对其进行了研究,因此有了本篇文章。本文不会过多的讲解源码,而是通过图解各个架构和数据流的方式,带大家搞懂它的工作原理。我相信只要搞懂了工作原理,再来看源码就会简单很多,废话不多说,马上进入正题。
源码: https://github.com/78/xiaozhi-esp32 ,本文章基于源码 v1.7.6 版本。
系统架构
本小节展示小智 AI 各种架构图,包括:
整体系统架构分层图
展示系统从用户交互到物理硬件的完整分层结构

👤 用户交互层
- 位置: 最顶层,直接面向用户
- 作用: 处理用户的输入输出操作
- 组件:
- 语音输入:接收用户的语音指令
- 触摸交互:处理屏幕触摸操作
- 视觉反馈:通过显示屏向用户展示信息
- 音频输出:播放AI回复和系统提示音
🧠 应用层
- 位置: 核心控制层
- 作用: 系统的大脑,统一调度和管理
- 组件:
- Application主控制器:单例模式,负责整个系统的生命周期管理
- 状态管理器:管理9个不同的设备状态转换
- 事件系统:基于FreeRTOS事件组,处理系统内各种事件
- 任务调度器:管理后台任务的执行
⚙️ 服务层
- 位置: 业务逻辑层,分为四个子模块
- 作用: 提供具体的功能服务
- 音频服务:
- 音频处理器:支持AFE噪声抑制和直通模式
- 唤醒词检测:ESP-SR或ESP Wake Word两种方案
- OPUS编解码器:实现音频的压缩和解压
- 音频队列:管理音频数据的缓冲
- 网络服务:
- 协议管理器:支持WebSocket和MQTT两种协议
- 网络栈:WiFi和4G网络自动切换
- 会话管理:维护连接状态和会话信息
- MCP服务:
- MCP服务器:实现JSON-RPC 2.0协议
- 工具注册表:管理设备能力发现
- 属性验证器:确保参数类型和范围正确
- 传统IoT服务:
- Thing管理器:兼容旧版IoT协议
- 设备控制:处理状态同步
🏗️ 硬件抽象层
- 位置: 连接服务层和驱动层的桥梁
- 作用: 屏蔽硬件差异,提供统一接口
- 开发板继承体系:
- Board基类:定义通用接口
- WifiBoard:WiFi网络开发板
- Ml307Board:4G网络开发板
- DualNetworkBoard:双网络开发板
- 硬件抽象接口:
- 音频编解码接口:统一音频硬件操作
- 显示接口:支持LCD和OLED显示
- LED接口:控制各种LED设备
- 摄像头接口:视觉输入支持
- 电源接口:电池和充电管理
🔌 驱动层
- 位置: 直接操作硬件的最底层软件
- 作用: 提供硬件设备的具体驱动实现
- 音频编解码器: ES8311、ES8374、ES8388等不同芯片驱动
- 显示驱动: LCD、OLED、触摸屏驱动
- 网络驱动: WiFi、4G、以太网驱动
- 外设驱动: I2C、SPI、GPIO、UART、ADC等总线和接口驱动
⚡ 物理硬件层
- 位置: 最底层,实际的物理硬件
- 作用: 提供计算和输入输出能力
- ESP32芯片系列: 支持ESP32、ESP32-S3、ESP32-C3、ESP32-C6、ESP32-P4
- 物理组件: 麦克风、扬声器、显示屏、触摸面板、摄像头、LED、传感器、电源管理
🌍 外部系统
- 位置: 系统外部的云服务和应用
- 作用: 提供AI能力和设备管理
- AI云服务: 语音识别和对话生成
- MCP客户端: 设备控制应用
- OTA服务器: 固件更新服务
- 配置服务器: 设备激活和配置
📦 开发板实例层
- 位置: 具体的硬件产品实现
- 作用: 将抽象架构映射到具体硬件
- 支持70+开发板: M5Stack Core S3、ESP32-S3-BOX、LILYGO T-Circle-S3等
连接关系分析
核心组件关系图
展示系统核心组件之间的依赖关系和职责分工

🎯 核心单例组件(红色边框)
- Application: 系统主控制器,协调所有其他组件
- McpServer: 设备控制服务,提供MCP协议支持
- ThingManager: IoT设备管理,处理传统IoT协议
- Board: 硬件抽象基类,代表具体的开发板实例
⚙️ 服务组件(绿色边框)
- AudioProcessor: 音频处理服务,包含AFE和直通模式
- WakeWord: 唤醒词检测服务,支持多种检测算法
- Protocol: 网络协议服务,支持WebSocket和MQTT
- Display: 显示管理服务,控制屏幕输出
- AudioCodec: 音频编解码服务,处理音频硬件
🔧 工具组件(紫色边框)
- BackgroundTask: 后台任务管理,处理异步操作
- OTA: 固件升级服务,支持远程更新
- Settings: 配置管理服务,处理系统配置
- SystemInfo: 系统信息服务,提供设备信息
依赖关系分析
硬件抽象层继承体系
展示硬件抽象层的面向对象设计和继承关系

Board基类(抽象类)
- 作用: 定义所有开发板的通用接口
- 核心方法:
- GetBoardType(): 返回开发板类型标识
- GetAudioCodec(): 获取音频编解码器实例
- GetDisplay(): 获取显示器实例
- GetLed(): 获取LED控制实例
- CreateHttp/WebSocket/Mqtt(): 创建网络协议实例
- StartNetwork(): 启动网络功能
- SetPowerSaveMode(): 电源管理
- 保护成员: uuid_字符串,每个设备的唯一标识
WifiBoard类
- 继承: Board基类
- 特化: 专门处理WiFi网络的开发板
- 新增功能:
- ResetWifiConfiguration(): 重置WiFi配置
- EnterWifiConfigMode(): 进入WiFi配置模式
- 重写方法: 网络相关方法针对WiFi优化
Ml307Board类
- 继承: Board基类
- 特化: 专门处理4G网络的开发板
- 新增功能:
- InitializeMl307(): 初始化ML307 4G模块
- 重写方法: 网络相关方法针对4G优化
DualNetworkBoard类
- 继承: 同时继承WifiBoard和Ml307Board(多重继承)
- 特化: 支持WiFi和4G双网络的开发板
- 新增功能:
- SwitchToWifi(): 切换到WiFi网络
- SwitchToCellular(): 切换到4G网络
- GetActiveNetwork(): 获取当前活跃网络类型
具体开发板实现
- ESP32S3Box: WiFi开发板,带TouchScreen LCD
- M5StackCoreS3: WiFi开发板,带圆形LED灯带
- LilygoTCircleS3: WiFi开发板,圆形显示屏
- SensecapWatcher: WiFi开发板,带摄像头功能
设计模式分析
服务层架构详图
详细展示四个核心服务的内部架构和数据流

🎵 音频服务架构
- 数据流: 音频输入 → 音频处理 → 唤醒词检测 → OPUS编码 → 队列系统
- 处理器选择:
- AfeAudioProcessor: 带噪声抑制和回声消除
- NoAudioProcessor: 直通模式,不做处理
- 唤醒词方案:
- AfeWakeWord: 基于ESP-SR的唤醒检测
- EspWakeWord: 基于ESP Wake Word的检测
- NoWakeWord: 无唤醒功能的模式
- 编码标准: OPUS格式,60ms帧时长
- 队列管理: 生产者-消费者模式的音频缓冲
🌐 网络服务架构
- 协议支持: WebSocket(实时双向通信)和MQTT(IoT消息传输)
- 二进制协议: BinaryProtocol2/3版本支持
- 网络栈: 自动WiFi/4G切换能力
- 传输层: TCP/WebSocket over WiFi, ML307模块 over 4G
⚙️ MCP服务架构
- 核心: McpServer单例服务
- 工具管理:
- 通用工具集: 音量、LED、GPIO、电机控制
- 自定义工具: 开发板特定功能
- 属性系统: 类型验证和范围检查
- 协议处理: JSON-RPC 2.0请求解析和响应生成
- 执行引擎: 回调函数调用和硬件控制
📱 显示服务架构
- 显示类型:
- LcdDisplay: TFT/IPS彩色屏幕
- OledDisplay: OLED单色/彩色屏幕
- EsplogDisplay: 串口日志显示(调试用)
- 渲染引擎: LVGL图形库
- 字体系统: 多语言字体支持
- 主题系统: 暗色/亮色模式切换
- 资源管理: 图片和音频资源加载
服务间协作
并发架构与任务管理
展示FreeRTOS下的任务管理和并发控制机制

⚡ FreeRTOS内核
- 任务调度器: 优先级抢占式调度,确保高优先级任务及时执行
- 内存管理器: 堆栈管理,防止栈溢出
- 事件组: 任务间事件同步机制
- 队列: 任务间数据传递通道
- 定时器: 周期性任务触发机制
🔄 应用任务分配
- 主任务: Application::Start(),优先级高,系统控制中心
- 音频任务: OPUS编解码,优先级实时,保证音频流畅
- 网络任务: 协议处理,优先级中,处理网络通信
- 显示任务: LVGL渲染,优先级中,界面更新
- 后台任务: BackgroundTask,优先级低,处理非紧急任务
- 唤醒词任务: 实时检测,优先级高,快速响应用户
- MCP任务: 工具执行,优先级中,设备控制
📚 任务栈分配
- 内存分配原则: 根据任务需求分配合适大小的栈空间
- 音频任务栈: 8KB,需要音频缓冲区
- 网络任务栈: 6KB,协议处理缓冲
- 显示任务栈: 4KB,GUI渲染缓冲
- 后台任务栈: 28KB,最大的栈空间用于复杂操作
- 其他任务: 3-4KB,满足基本功能需求
🔄 同步机制
- 应用事件组:
- SCHEDULE_EVENT: 调度事件
- SEND_AUDIO_EVENT: 音频发送事件
- CHECK_VERSION_EVENT: 版本检查事件
- 互斥锁保护:
- 音频互斥锁: 保护编解码器访问
- 显示互斥锁: LVGL线程安全
- MCP互斥锁: 工具执行保护
- 信号量同步: 网络连接状态同步
并发控制策略
配置管理架构
展示从配置源到运行时的完整配置管理流程

⚙️ 配置源
- 用户配置: 通过menuconfig选择70+开发板类型和功能选项
- SDK默认配置: 针对不同ESP32芯片的优化配置
- 开发板配置: 每个开发板的硬件参数和引脚定义
- 组件配置: 外部依赖库的版本和配置要求
🔄 配置处理
- Kconfig解析器: 处理menuconfig的用户选择
- 开发板选择器: 根据选择激活对应的开发板配置
- 依赖解析器: 检查组件版本兼容性
- 配置验证器: 检测配置冲突和不一致
🏗️ 编译时配置
- CMake配置: 确定构建目标和编译选项
- 编译器标志: 设置优化级别和特殊编译选项
- 链接选项: 确定内存布局和分区方案
- 分区表: 定义Flash存储的分区结构
⚡ 运行时配置
- Settings管理器: 持久化用户设置和系统配置
- 设备激活: 从云端获取设备特定配置
- WiFi凭据: 网络连接配置
- 用户偏好: 语言、音量等个性化设置
配置流程分析
数据流程图
数据流程图可以帮我们梳理整理数据流的走向,理解整个系统是如何运作的。
接下来从如下层面介绍数据流:
整体系统架构数据流
展示从用户输入到系统响应的完整数据传输路径

🎤 音频采集路径
- 起点: 用户语音 → 麦克风物理采集
- 硬件转换: 麦克风 → 音频编解码器(ES8311/ES8374/ES8388)
- 数据格式: 模拟音频信号 → PCM数字音频数据(24kHz/16bit)
- 处理层级: 音频编解码器 → 音频处理器(AFE噪声抑制/直通模式)
🗣️ 唤醒词检测路径
- 检测输入: 降噪后的音频数据
- 检测引擎: ESP-SR 或 ESP Wake Word 算法
- 触发机制: 检测到"你好,小智"关键词 → 生成唤醒事件
- 状态切换: 唤醒事件 → Application主控制器 → 设备状态转换
📦 音频编码传输路径
- 编码流程: 录音数据 → OPUS编码器 → 60ms帧时长的数据包
- 缓冲管理: OPUS数据包 → 音频队列(MAX_AUDIO_PACKETS_IN_QUEUE 限制)
- 协议封装: 音频队列 → 协议层(WebSocket/MQTT)
- 网络传输: 二进制协议格式 → 网络栈(WiFi/4G)→ AI服务器
🤖 AI处理响应路径
- 服务器处理: AI服务器接收音频 → 语音识别 → 对话生成
- 双路返回:
- 音频响应: OPUS音频流 → 网络栈 → 协议层 → OPUS解码器 → 音频编解码器 → 扬声器
- 控制消息: JSON消息 → 协议层 → Application → 显示屏更新/MCP设备控制
🔄 状态管理路径
- 状态控制: Application → 设备状态机(9个状态)
- 事件驱动: 设备状态 → FreeRTOS事件组 → 后台任务调度
- 任务分配: 事件组 → 后台任务(4096*7栈空间)
⚙️ MCP设备控制路径
- 工具发现: MCP服务器 → 工具发现(JSON-RPC 2.0)
- 属性验证: 设备能力 → 属性验证器(类型检查&范围限制)
- 设备操作: 验证通过 → 设备控制(音量/LED/GPIO/电机)
关键设计特点
音频数据流详细流程
按时间顺序展示音频处理的完整生命周期

阶段一: 音频采集阶段
- T1: 用户开始说话,产生声波信号
- T2: 麦克风采集声波并转换为电信号
- T3: 音频编解码器将模拟信号转换为PCM数字信号(24kHz/16bit采样率)
- T4: 音频处理器对原始音频流进行降噪处理
- T5: 唤醒词检测器分析降噪后音频,识别"你好,小智"关键词
- T6: 检测成功后向Application发送唤醒事件
阶段二: 录音与传输阶段
- T7: Application接收唤醒事件,状态切换为kListening(监听模式)
- T8: Application指示音频处理器开始正式录音
- T9: 音频处理器将PCM音频块传递给OPUS编码器
- T10: OPUS编码器将音频压缩为60ms帧长的数据包
- T11: 压缩后的数据包放入音频队列进行缓冲管理
- T12: 协议层从队列取出数据,封装为AudioStreamPacket
- T13: 通过二进制协议(BinaryProtocol2/3)向AI服务器传输
阶段三: 响应与播放阶段
- T14: AI服务器处理音频,返回OPUS音频流和JSON控制消息
- T15: 协议层分离音频数据和控制消息
- T16: 音频数据传递给OPUS解码器,控制消息传递给Application
- T17: OPUS解码器将压缩音频解码为PCM数据
- T18: PCM数据传递给音频编解码器转换为模拟信号
- T19: Application状态切换为kSpeaking(播放模式)
- T20: 扬声器播放AI响应语音给用户
时序特点分析
网络协议栈数据流
展示网络数据从应用层到物理层的完整传输路径

🎵 应用数据层
- 音频数据: OPUS格式,60ms帧时长,适合实时传输
- JSON消息: 控制指令和状态信息,使用文本格式便于调试
- MCP消息: JSON-RPC 2.0格式,用于设备控制和能力发现
📦 协议处理层
- 二进制协议: BinaryProtocol2/3版本,提供高效的数据封装
- 协议路由器: 智能选择最适合的传输协议
- WebSocket协议:
- 主要协议选择
- 实时双向通信能力
- 低延迟特性适合语音交互
- MQTT协议:
- 备用协议选择
- IoT标准协议,适合设备管理
- 支持主题订阅和发布模式
🔌 传输层
- TCP Socket: 提供可靠的端到端传输
- 连接管理: 处理连接建立、维护和断开
- 流控制: 防止网络拥塞和数据丢失
📡 网络接口层
- 网络接口路由: 智能选择可用的网络接口
- WiFi协议栈:
- 802.11 b/g/n标准支持
- 适合室内高带宽场景
- 4G蜂窝网络:
- ML307模块支持
- 适合移动和偏远地区
- 双网络切换:
- 自动故障转移机制
- 无缝网络切换能力
📡 物理层
- WiFi天线: 2.4GHz频段,支持多种天线类型
- 4G天线: 支持多频段LTE网络
- 信号传输: 电磁波信号在空中传播
🌍 服务器端
- 互联网路由: 通过运营商网络到达服务器
- 负载均衡器: 分发请求到多个服务器实例
- AI服务器集群: 处理语音识别和对话生成
网络特性分析
MCP协议数据流
详细展示设备控制协议的完整工作流程

🎛️ 设备能力注册阶段
- 能力定义: 设备端定义可控制的硬件能力(音量、LED、GPIO、电机)
- MCP服务器: 作为设备端的协议服务器,管理所有可用工具
- 工具注册: 通过AddCommonTools()方法注册标准设备控制工具
🔧 工具类型定义
- 音量控制工具:
- 属性: level (0-100范围的整数)
- 功能: 调节系统音量大小
- LED控制工具:
- 属性: color (颜色值), brightness (亮度值)
- 功能: 控制LED灯带/矩阵的颜色和亮度
- GPIO控制工具:
- 属性: pin (引脚号), state (高低电平状态)
- 功能: 控制通用输入输出引脚
- 电机控制工具:
- 属性: angle (角度), speed (速度)
- 功能: 控制舵机或步进电机
✅ 属性验证系统
- 类型检查: 验证参数类型(Boolean/Integer/String)
- 范围检查: 检查数值参数的min_value和max_value限制
- 默认值处理: 为可选参数提供合理的默认值
- Property类: 统一的属性管理数据结构
📋 JSON-RPC 2.0协议处理
- 协议标准: 遵循JSON-RPC 2.0规范,确保互操作性
- 工具发现:
- 请求类型: tools/list
- 响应内容: 返回所有可用工具及其属性定义
- 工具执行:
- 请求类型: tools/call
- 请求内容: 工具名称和参数
- 响应内容: 执行结果和状态信息
🌐 网络传输层
- 协议承载: MCP消息通过WebSocket或MQTT协议传输
- 双向通信: 支持客户端向设备发送命令,设备向客户端报告状态
- 连接管理: 维护与AI服务器的稳定连接
🤖 服务器端处理
- MCP客户端: 服务器端的MCP协议实现
- 工具目录: 缓存和管理所有已连接设备的能力
- 智能控制: AI决策引擎分析用户意图,选择合适的设备操作
⚡ 设备端执行
- 回调执行: 使用std::function<ReturnValue>实现工具调用
- 硬件操作: 直接控制物理设备(GPIO、PWM、I2C等)
- 结果返回: 将操作结果封装为ReturnValue返回给服务器
MCP协议优势
设备状态机流转图
展示设备在不同工作模式下的状态转换逻辑

🔄 启动相关状态
- Unknown: 系统刚启动的未知状态
- Starting: 系统初始化阶段
- 成功路径: → Idle(网络已配置)
- 配置路径: → WifiConfiguring(需要WiFi配置)
- 失败路径: → FatalError(初始化失败)
📶 网络配置状态
- WifiConfiguring: WiFi配置模式
- 成功路径: → Idle(配置成功)
- 失败路径: → FatalError(配置失败)
- Connecting: 网络重连状态
- 成功路径: → Idle(重连成功)
- 失败路径: → FatalError(连接失败)
🎙️ 核心工作状态
- Idle: 主要工作状态,等待用户交互
- 触发路径:
- → Listening(检测到唤醒词)
- → Connecting(网络中断)
- → Activating(需要设备激活)
- → Upgrading(发现新版本)
- → AudioTesting(音频测试模式)
- 触发路径:
- Listening: 录音状态,OPUS编码传输
- 转换路径:
- → Speaking(收到AI响应)
- → Idle(录音超时或手动停止)
- → FatalError(音频处理失败)
- 转换路径:
- Speaking: 播放状态,OPUS解码播放
- 转换路径:
- → Idle(播放完成)
- → Listening(被唤醒词中断)
- → FatalError(播放失败)
- 转换路径:
🔧 维护相关状态
- Activating: 设备激活状态
- 成功路径: → Idle(激活成功)
- 失败路径: → FatalError(激活失败)
- Upgrading: 固件升级状态
- 成功路径: → Starting(升级完成重启)
- 失败路径: → FatalError(升级失败)
- AudioTesting: 音频测试模式
- 成功路径: → Idle(测试完成)
- 失败路径: → FatalError(测试失败)
⚠️ 错误处理状态
- FatalError: 致命错误状态
- 恢复路径:
- → Starting(手动重启)
- → [*](系统重启)
- 恢复路径:
状态机特性分析
内存管理数据流
展示ESP32有限内存下的高效内存管理策略

💾 系统内存总览
- 总内存容量: 约300KB RAM(ESP32系列芯片)
- 分配策略: 静态分配 + 动态分配混合模式
- 内存区域: 栈内存、堆内存、静态内存三大区域
📚 栈内存分配
- 主任务栈: 默认栈大小,处理系统主要控制逻辑
- 后台任务栈: 4096*7 = 28KB,最大的栈分配,处理复杂后台操作
- 音频任务栈: 专用于音频处理,需要实时性保证
- 网络任务栈: 专用于网络协议处理和数据传输
🗄️ 堆内存分配
- 音频缓冲区:
- OPUS帧缓冲:60ms * MAX_PACKETS个数据包
- PCM缓冲区:录音和播放的原始音频数据
- AFE处理缓冲区:降噪算法所需的工作内存
- 网络缓冲区: WebSocket和MQTT协议的数据缓冲
- JSON缓冲区: cJSON对象的动态内存分配
- 显示缓冲区: LVGL图形库的帧缓冲区
🏗️ 静态内存
- 全局变量: 系统配置和状态变量
- 静态变量: 各模块的静态数据存储
- 常量数据: 字体、图片等资源数据
总结
相信看完本文章,再搭配源码,将能非常快速的上手整个项目,并基于此进行二次开发。
如果觉得本文写得不错,麻烦给个点赞、收藏、转发,我是 Leon_Chenl,下篇文章见~


