XiaoO WebSocket API 文档
20260713
1. 概述
本文档描述了通过 WebSocket 与服务端进行实时通信的 API。该 API 允许客户端建立持久连接,进行双向通信,主要用于语音识别、文本合成、聊天、IoT、MCP网关,以及私有网关协议调用第三方服务等,通过个性化大模型提示词可满足任意对话场景需求。
该协议兼容小智 AI WebSocket 报文协议。已有小智生态设备进入配网模式后,将 OTA Endpoint 配置为本平台 OTA 地址即可接入本平台服务,并在 Web 管理端激活设备。
本平台理论上支持小智所有版本的固件,因为协议是兼容的,不过未经测试的版本可能存在不稳定的情况,测试过的稳定版本如下(不断增加中):
- V1.5.6
- V1.6.6
1.1 平台开放能力
- 实时音频编解码、降噪、压缩
- 实时语音识别(Realtime ASR)
- 实时声音活动检测(Realtime VAD)
- 多Agent多模态大模型整合
- 实时语音合成(Realtime TTS)
- 用户意图识别引擎(Intent Engine)
- 用户情绪识别引擎(Emotion Engine)
- 开放MCP网关(整合MCP Tools、Resources、Prompts生态能力)
- 支持MCP服务器自定义接入
- 支持终端多MCP服务器调用
- 私有网关协议,可插拔式对接自有系统(如:歌曲库、知识库等)、第三方平台
- 物联网(IoT),通过MCP和私有网关协议控制设备
- 架构灵活,扩展性强,以上能力模块皆可根据需要进行个性化组合
1.2 接入平台的应用形态
只要实现了本通信协议,任何载体都可接入,如:小程序、App、智能体硬件等。
2. 连接信息
- WebSocket Chat URL:
wss://server.xiao-o.cn/v1/chat - WebSocket Realtime Chat URL:
wss://server.xiao-o.cn/v1/realtime_chat - OTA URL: https://api.xiao-o.cn/api/v1/ota
- Web 管理端 URL: https://webui.xiao-o.cn
- 协议版本: 1.0.0
3. 认证
方式一:HTTP Headers
在建立 WebSocket 连接时,需要在 HTTP 请求头中包含以下认证信息:
Authorization: Bearer {your_access_token}
Client-Id: {device_unique_id}
Device-Id: {device_mac_address}
字段说明:
Authorization: 设备访问令牌,格式必须是Bearer <device_token>。Client-Id: 设备 UUID,对应设备注册/OTA 信息中的uuid。Device-Id: 设备 MAC 地址。
当服务端配置 server.enable_auth = true 时,/v1/chat 和 /v1/realtime_chat 都会校验以上信息,并要求设备已激活、令牌未过期且已绑定用户。/v1/vision 可不要求 Client-Id,但 WebSocket 入口要求 Client-Id。
连接示例
浏览器原生 WebSocket API 不支持设置自定义 HTTP Header,因此下面示例使用 Node.js ws 客户端;浏览器接入需要通过后端代理、原生 App 容器或其它可设置 Header 的 WebSocket 客户端实现鉴权。
import WebSocket from 'ws';
const socket = new WebSocket('wss://your-server-domain.com/v1/chat', {
headers: {
Authorization: 'Bearer your_device_token',
'Client-Id': 'device_uuid',
'Device-Id': 'AA:BB:CC:DD:EE:FF'
}
});
4. 消息格式
所有消息均使用 JSON 格式,分为文本消息和二进制消息两种类型:
文本json消息格式,完整参数详见各API
{
"type": "message_type",
...
}
二进制消息
用于传输音频数据,采用 Opus 编码格式。
5. API清单
连接初始化
握手
例:
{
"type": "hello",
"version": 1,
"transport": "websocket",
"features": {
"mcp": true
},
"audio_params": {
"format": "opus",
"sample_rate": 16000,
"channels": 1,
"frame_duration": 60
}
}
说明:
features.mcp = true时,服务端会把当前 WebSocket 连接复用为设备侧 MCP Server 通道,并在握手阶段向客户端发送 MCP JSON-RPC 初始化请求;客户端需要支持type: "mcp"消息。- 客户端上报的
audio_params目前用于协议表达,服务端会以服务端配置的音频参数返回hello,客户端应以服务端返回值为准。
语音识别请求
开始监听
握手成功后,客户端开始向服务端发送二进制音频流。
mode: auto,自动循环监听模式。mode: manual,手动监听模式。
例:
{
"type": "listen",
"mode": "auto", // 可选值:`auto`, `manual`, `realtime`
"state": "start",
"session_id": "xxx" // hello握手成功后,服务端返回的
}
接下来客户端发送二进制音频数据(Opus 编码)
说明:listen start 必须在服务端返回 hello 后发送;普通 /v1/chat 链路会忽略握手前的 listen start。
停止监听
例:
{
"type": "listen",
"mode": "auto",
"state": "stop",
"session_id": "xxx"
}
唤醒词检测
例:
{
"session_id": "xxx",
"type": "listen",
"state": "detect",
"text": "你好小明"
}
中断说话
reason值可为其他。
例:
{
"session_id": "xxx",
"type": "abort",
"reason": "wake_word_detected"
}
IOT
发送当前设备的物联网相关信息:
Descriptors(描述设备功能、属性等)。States(设备状态的实时更新)。
例:
{
"session_id": "xxx",
"type": "iot",
"update": true,
"descriptors": [
{
"name": "Speaker",
"description": "扬声器",
"methods": {
"SetVolume": {
"description": "设置音量",
"parameters": {
"volume": {
"description": "音量0-100之间的整数",
"type": "number"
}
}
}
},
"properties": {
"volume": {
"description": "当前音量值",
"type": "number"
}
}
},
{ ... }
]
}
或
{
"session_id": "xxx",
"type": "iot",
"update": true,
"states": [
{
"name": "Speaker",
"state": {
"volume": 30
}
},
{
"name": "Screen",
"state": {
"brightness": 75,
"theme": "dark"
}
},
{
"name": "Battery",
"state": {
"charging": false,
"level": 84
}
},
{ ... }
]
}
MCP
当客户端在 hello.features.mcp 中声明支持 MCP 后,服务端和客户端通过 type: "mcp" 文本消息传递 JSON-RPC 2.0 payload。
服务端会主动发送 initialize、tools/list 和 tools/call 等请求;客户端需要把 JSON-RPC 响应放回 payload 字段。
例:
{
"session_id": "xxx",
"type": "mcp",
"payload": {
"jsonrpc": "2.0",
"id": "request-id",
"result": {
"tools": []
}
}
}
OTA
发送当前设备信息
例:
{
"application": {
"compile_time": "Mar 31 2025T16:48:23Z",
"elf_sha256": "bd3ac81a0f6dd726143e93b027a6630684d82cbba681ae0359e212375a516f31",
"idf_version": "v5.4-dirty",
"name": "xiaozhi",
"version": "1.5.5"
},
"board": {
"channel": 3,
"ip": "192.168.101.232",
"mac": "b4:3a:45:a6:41:a4",
"name": "bread-compact-wifi",
"rssi": -31,
"ssid": "客厅",
"type": "bread-compact-wifi"
},
"chip_info": {
"cores": 2,
"features": 18,
"model": 9,
"revision": 2
},
"chip_model_name": "esp32s3",
"flash_size": 16777216,
"language": "zh-CN",
"mac_address": "b4:3a:45:a6:41:a4",
"minimum_free_heap_size": 8298820,
"ota": {
"label": "ota_0"
},
"partition_table": [
{
"address": 36864,
"label": "nvs",
"size": 16384,
"subtype": 2,
"type": 1
},
{
"address": 53248,
"label": "otadata",
"size": 8192,
"subtype": 0,
"type": 1
},
{
"address": 61440,
"label": "phy_init",
"size": 4096,
"subtype": 1,
"type": 1
},
{
"address": 65536,
"label": "model",
"size": 983040,
"subtype": 130,
"type": 1
},
{
"address": 1048576,
"label": "ota_0",
"size": 6291456,
"subtype": 16,
"type": 0
},
{
"address": 7340032,
"label": "ota_1",
"size": 6291456,
"subtype": 17,
"type": 0
}
],
"uuid": "2dc1510b-4fdb-43ce-b8f1-074309f954bc",
"version": 2
}
(语音识别实时状态更新):
Hello
例:
{
"type": "hello",
"version": 1,
"transport": "websocket",
"session_id": "xxx",
"audio_params": {
"format": "opus",
"sample_rate": 16000,
"channels": 1,
"frame_duration": 60
}
}
STT
表示服务器端识别到了用户语音。(例如语音转文本结果)。
设备可能将此文本显示到屏幕上,后续再进入回答等流程。
例:
{
"type": "stt",
"session_id": "xxx",
"text": "..."
}
LLM
服务器指示设备调整表情动画 / UI 表达。
例:
{
"type": "llm",
"session_id": "xxx",
"emotion": "happy",
"text": "😀"
}
TTS
服务器准备下发 TTS 音频,客户端进入 "speaking" 播放状态。
state: stop,表示本次 TTS 结束。state: sentence_start,让设备在界面上显示当前要播放或朗读的文本片段。state: sentence_end, 停止朗读文本显示。
例:
{
"type": "tts",
"session_id": "xxx",
"state": "start", // 可选值:"start", "stop", "sentence_start"
"text": "😀"
}
IOT
服务器向设备发送物联网的动作指令,设备解析并执行(如打开灯、设置温度等)。
例:
{
"type": "iot",
"session_id": "xxx",
"commands": [ ... ]
}
MCP
服务端发给客户端的 MCP 消息同样使用 payload 包装原始 JSON-RPC 请求。
例:
{
"type": "mcp",
"session_id": "xxx",
"payload": {
"jsonrpc": "2.0",
"id": "request-id",
"method": "tools/call",
"params": {
"name": "tool_name",
"arguments": {}
}
}
}
音频数据:二进制帧
- 当服务器发送音频二进制帧(Opus 编码)时,客户端解码并播放。
- 若客户端正在处于 "listening" (录音)状态,收到的音频帧会被忽略或清空以防冲突。
6. 音频编解码
- 客户端发送录音数据
- 音频输入经过可能的回声消除、降噪或音量增益后,通过 Opus 编码打包为二进制帧发送给服务器。
- 如果客户端每次编码生成的二进制帧大小为 N 字节,则会通过 WebSocket 的 binary 消息发送这块数据。
- 客户端播放收到的音频
- 收到服务器的二进制帧时,同样认定是 Opus 数据。
- 设备端会进行解码,然后交由音频输出接口播放。
- 如果服务器的音频采样率与设备不一致,会在解码后再进行重采样。
7. 常见状态流转
以下简述设备端关键状态流转,与 WebSocket 消息对应:
用户触发或唤醒后,设备调用
OpenAudioChannel() → 建立 WebSocket 连接 → 发送 "type":"hello"。
成功建立连接后,若继续执行
SendStartListening(...),则进入录音状态。此时设备会持续编码麦克风数据并发送到服务器。
收到服务器 TTS Start 消息 (
{"type":"tts","state":"start"}) → 停止录音并播放接收到的音频。
服务器 TTS Stop (
{"type":"tts","state":"stop"}) → 音频播放结束。若未继续进入自动监听,则返回 Idle;如果配置了自动循环,则再度进入 Listening。
调用
SendAbortSpeaking(...) 或 CloseAudioChannel() → 中断会话 → 关闭 WebSocket → 状态回到 Idle。
8. 错误处理
- 连接失败
如果
Connect(url)返回失败或在等待服务器 "hello" 消息时超时,触发on_network_error_()回调。设备会提示"无法连接到服务"或类似错误信息。 - 服务器断开
如果 WebSocket 异常断开,回调
OnDisconnected():- 设备回调
on_audio_channel_closed_() - 切换到 Idle 或其他重试逻辑。
- 设备回调
9. 其它注意事项
- 鉴权
设备通过设置
Authorization: Bearer <token>提供鉴权,服务器端需验证是否有效。如果令牌过期或无效,服务器可拒绝握手或在后续断开。
- 会话控制
服务端返回
hello后会分配session_id。后续客户端消息建议带上该值;当前服务端主要依赖连接内会话状态处理消息,MCP、STT、TTS、LLM 等服务端下发消息会携带session_id。 - 音频负载
代码里默认使用 Opus 格式,并设置
sample_rate = 16000,单声道。帧时长由OPUS_FRAME_DURATION_MS控制,一般为 60ms。可根据带宽或性能做适当调整。 - IoT 指令
"type":"iot"的消息用户端代码对接thing_manager执行具体命令,因设备定制而不同。服务器端需确保下发格式与客户端保持一致。 - 错误或异常 JSON
当 JSON 中缺少必要字段,例如
{"type": ...},客户端会记录错误日志(ESP_LOGE(TAG, "Missing message type, data: %s", data);),不会执行任何业务。
10. 连接状态管理
- 客户端可定期发送 WebSocket ping 消息以保持连接活跃
- 当前服务端外层 WebSocket 会话上下文超时时间为 30 分钟;是否配置更短的空闲断开时间取决于部署层、反向代理或网关
- 客户端断开连接后,应采用指数退避算法进行重连
11. 附录
音频规格
- 采样率: 16kHz
- 通道数: 单声道
- 编码格式: Opus
- 帧大小: 960 (60ms)
实现建议
- 确保适当处理网络波动和连接中断
- 实现音频缓冲以平滑播放
- 在较差的网络条件下使用较低的比特率
问题反馈、技术支持、合作联系
Email: xiao-o_service@odsio.com