硬件准备
环境搭建
硬件连接
按照下图进行硬件连接:

- 使用 Type-C 数据线连接AIbox和电脑。
设备开发
开机
完成硬件连接的工作后,电脑设备管理器的端口列表中出现包含 Quectel USB 字样的 COM 口,表示开机成功。

烧录固件包
参考此章节,烧录对应型号固件包至开发板。
脚本导入与运行
-
参考此章节,将源码目录下 src 文件夹中的所有文件导入到模组文件系统,如下图所示:

-
参考此章节,执行主程序文件 _main.py。
-
参考此章节,停止程序运行。
业务调试
程序启动
执行 _main.py 脚本后,程序开始运行。
注册小智
如果小智没有被注册,那么无法进行正常交互,程序启动时OTA会返回注册设备所用的验证码,然后到小智 AI 聊天机器人控制台进行设备注册,注册完成后再次运行脚本就可以顺利交互了

激活小智#
下图所示状态为待唤醒状态,开发板会出现红灯闪烁,需要语音“小智,小智”来唤醒小智AI进行语音对话。

唤醒后会出现连接服务器相关的数据或者是连接失败的提示,当出现连接失败时,请检查网络是否正常。

当系统长时间未进行对话或未接收到命令时会自动断开连接,等待下次唤醒。

软件框架
框架设计图

业务系统启动流程

代码讲解
AI 唤醒&人声检测
AI 初始化
初始化 AI 对象以及其他硬件驱动。
AI 对话中断逻辑
在唤醒AI之后启动该人声音频检测与上传的线程,self.start_vad()用于启动录音功能,当有人声时会通过websocket发送“开始监听”的标志位start,然后执行self.__protocol.abort()结束当前的语音从而实现打断AI说话。
音频管理
统一管理设备的音频输入输出、编解码、语音识别相关功能(关键词识别 KWS 和语音活动检测 VAD),并提供回调接口供上层应用使用。
LCD屏显
通过会话总线sys_bus来控制LCD的表情显示
MCP管理
基于 MCP 协议的消息构造与发送功能,涵盖了初始化、工具列表查询、工具调用响应以及设备通知等场景。所有消息均遵循 JSON-RPC 2.0 格式,并通过 send_mcp 方法统一发送,确保了代码的模块化和一致性。
class WebSocketClient(object):
def send_mcp(self, payload, session_id=""):
"""
发送标准MCP消息,payload为JSON-RPC 2.0格式字典
"""
with self.__resp_helper:
self.send(
JsonMessage(
{
"session_id": session_id,
"type": "mcp",
"payload": payload
}
).to_bytes()
)
def mcp_initialize(self, capabilities=None, session_id="", req_id=1):
"""
发送MCP initialize响应
"""
payload = {
"jsonrpc": "2.0",
"id": req_id,
"result": {
"protocolVersion": "2025-9-03",
"capabilities": {
"tools":{},
"notifications": {}
},
"serverInfo": {
"name": 'xiaozhi-mqtt-client',
"version": "1.0.0"
}
}
}
self.send_mcp(payload, session_id)
def mcp_tools_list(self, cursor="", session_id="", req_id=2):
"""
发送MCP tools/list响应请求
"""
payload = {
"jsonrpc": "2.0",
"id": req_id,
"result": {
"tools": [
{
"name": "self.setvolume_down()",
"description": "只通过调用setvolume_down方法来控制音量变小,接收到回应后会播报当前音量大小",
"inputSchema": {}
},
{
"name": "self.setvolume_up()",
"description": "只通过调用setvolume_up方法来控制音量变大,接收到回应后会播报当前音量大小",
"inputSchema": {}
},
{
"name": "self.setvolume_close()",
"description": "只通过调用setvolume_close方法来静音,接收到回应后会播报当前音量大小",
"inputSchema": {}
},
],
}
}
self.send_mcp(payload, session_id)
def mcp_tools_call(self, session_id="", req_id="", error=None, tool_name=""):
"""
发送MCP tools/call响应
:param error: 如果为None则返回成功响应,否则返回错误响应(字典,包含code和message)
"""
if error is None:
if tool_name == "self.setvolume_down()":
payload = {
"jsonrpc": "2.0",
"id": req_id,
"result": {
"content": [
{ "type": "text", "text": "音量已调小 "}
],
"isError": False
}
}
elif tool_name == "self.setvolume_up()":
payload = {
"jsonrpc": "2.0",
"id": req_id,
"result": {
"content": [
{ "type": "text", "text": "音量已调大" }
],
"isError": False
}
}
elif tool_name == "self.setvolume_close()":
payload = {
"jsonrpc": "2.0",
"id": req_id,
"result": {
"content": [
{ "type": "text", "text": "已静音" }
],
"isError": False
}
}
else:
payload = {
"jsonrpc": "2.0",
"id": req_id,
"error": {
"code": error.get("code", -32601),
"message": error.get("message", "Unknown error")
}
self.send_mcp(payload, session_id)
def mcp_notify(self, method, params, session_id=""):
"""
设备主动发送MCP通知
"""
payload = {
"jsonrpc": "2.0",
"method": "notifications/state_changed",
"params": {
"newState": "idle",
"oldState": "connecting"
}
}
self.send_mcp(payload, session_id)