共计 1557 个字符,预计需要花费 4 分钟才能阅读完成。
背景痛点
现在的智能音箱虽然能完成一些基础任务,比如控制家电、播放音乐,但遇到稍微复杂点的对话就露怯了。上周我问小爱 ” 推荐几本适合程序员读的科幻小说 ”,它直接给我跳转到音乐播放界面——这种尴尬场景相信大家都遇到过。

传统语音助手的局限主要体现在:
- 只能识别固定句式,稍微换个说法就听不懂
- 缺乏上下文记忆,多轮对话容易断片
- 知识库更新慢,问 2023 年的新政策可能答不上来
技术架构
整个系统的数据流向是这样的:
flowchart LR
小爱音响 -->| 语音指令 | 小米服务器 -->|OAuth2.0| 我们的服务端 -->|gRPC|ChatGPT
ChatGPT-->|JSON| 服务端 -->| 音频流 | 小米服务器 -->| 播报 | 小爱音响
我们对比了三种通信协议在本地测试环境的表现:
| 协议类型 | 平均延迟 | 断线重连耗时 |
|---|---|---|
| REST | 320ms | 需重新建立会话 |
| WebSocket | 210ms | 自动恢复 |
| gRPC | 150ms | 瞬时恢复 |
核心实现
OAuth2.0 鉴权
小米开放平台用的是设备码授权模式,Python 实现示例:
def get_xiaomi_token():
try:
response = requests.post(
'https://api.xiaomi.com/oauth2/device',
data={
'client_id': YOUR_CLIENT_ID,
'code': device_code # 从扫码页面获取
},
timeout=5
)
response.raise_for_status()
return response.json()['access_token']
except requests.exceptions.RequestException as e:
logger.error(f"Token 获取失败: {e}")
time.sleep(3) # 指数退避重试
return get_xiaomi_token()
音频实时转码
用 FFmpeg 处理小爱传来的 PCM 流(记得先安装 libav):
ffmpeg -f s16le -ar 16k -ac 1 -i input.pcm \
-ar 16000 -ac 1 -c:a pcm_s16le output.wav
避坑指南
设备 ID 冲突
当用户重置音箱后,可能会遇到 ” 设备已绑定 ” 错误。解决方案是在数据库存两份映射:
CREATE TABLE device_bindings (mi_did VARCHAR(32) PRIMARY KEY,
gpt_session_id VARCHAR(64),
previous_did VARCHAR(32) # 记录旧设备 ID
);
VAD 参数调优
建议这样配置 WebRTC 的 VAD 检测器:
import webrtcvad
vad = webrtcvad.Vad(2) # 适中敏感度
frame_ms = 30 # 每帧 30ms
性能优化
上下文缓存
用 Redis 存最近 5 轮对话,键值设计示例:
redis_key = f"ctx:{user_id}:{device_id[-4:]}"
redis_client.expire(redis_key, 300) # 5 分钟过期
指令模板
对 ” 打开客厅灯 ” 这类高频指令,可以提前生成回复音频存入 MinIO:
if "打开" in query and "灯" in query:
cached_audio = minio_client.get_object('templates', 'turn_on_light.wav')
return cached_audio.read()
本地测试技巧
- 安装 ngrok:
brew install ngrok - 配置隧道:
ngrok http 8000 --host-header=rewrite - 把生成的外网 URL 填到小米开发者后台
这套方案在我们智能家居项目中,将平均响应时间从 2.1 秒压到了 1.3 秒。最惊喜的是用户开始主动和音箱聊编程问题——这大概就是技术带来的小确幸吧。
正文完
