一、先做一件事:让它"等"你说话
烧录 demo01_ai_voice(要联网、要密钥)。上电后屏幕顶部出现青绿色状态条,旁边写着"准备就绪 / 按键开始说话"。
先别急着按。做三件事:
- 盯着那条状态条,记住它的颜色和文字;
- 看看屏幕上有两张卡片:"我说"(空白)和**"助手回答"**(空白);
- 然后按住 BOOT 键说一句话(比如"今天天气怎么样"),松开。
看:状态条会依次变色——红(正在录音)→ 黄(正在识别)→ 橙(正在思考)→ 回到青绿(准备就绪)。"我说"卡片出现你说的字,"助手回答"卡片出现它回答的话。
为什么说它"会等"?因为它待机时什么都不干,就等你按。这就是一台真 AI 设备的样子。
二、状态机:一块板子穿五件"马甲"
现在,把整台助手看成一个穿马甲的后台小剧组:板子是舞台,演员每次上场只演一个角色,演完就退场换下一场。这叫状态机(State Machine)。
这块板子一共五件马甲:
| 状态(马甲) | 状态条 | 它在干什么 | 谁能让它"让位" | 我看到的 |
|---|---|---|---|---|
| 待机 READY | 青绿 · 准备就绪 / "按键开始说话" | 安静等你,什么都不做 | 按下 BOOT → 变"录音" | 两张卡片都是空 |
| 录音 RECORDING | 红 · 正在录音 + 进度条(3 秒填满) | 麦克风采 16kHz/16bit/单声道 PCM,存内存 | 松开 BOOT 或录满 3 秒 → 变"识别" | 卡片还是空,进度条在涨 |
| 识别 RECOGNIZING | 黄 · 正在识别 / "请稍候" | 把 PCM 转 base64 寄给百度,换回文字 | 收到文字 → 变"思考";失败 → 变"错误" | "我说"出现你说的字 |
| 思考 THINKING | 橙 · 正在思考 / "请稍候" | 把文字 + system 提示词寄给火山豆包,换回答 | 收到回答 → 悄悄变回"待机";失败 → 变"错误" | "助手回答"出现 AI 回答 |
| 错误 ERROR | 红 · 发生错误 | 亮出红字,停住等你 | 按 BOOT → 回到"待机" | 下方出现红字 |
⚠️ 比喻的边界:状态机不是"心情"、不是"人格"——板子不会"高兴了才干活"。它必须也只能处于一个状态,换状态是被事件触发的(按键、计时、云端回信),不是它自己决定的。而且状态有限且有数——就这五件,你数得清。最关键的一点:它每一刻只穿一件马甲,绝不会"一边待机一边又在思考"。
三、一次完整对话:环形链路图
把五件马甲串起来,就是一条环形数据流:
待机 —— 按下 ——> 录音 —— 松开/录满3秒 ——> 识别 —— 成功 ——> 思考 —— 成功 ——> 回到待机
|失败 |失败
+------> 错误 ——按BOOT——> 回到待机
(彩色箭头版见教案.md 第四节;你只要能顺着箭头说一遍就算懂了。)
看懂的标准:能指着每一环说出——它现在在干嘛、寄给谁、收到什么才换下一件、失败了往哪走。
四、一句话讲清:两段"寄包裹"
这台助手做两趟"寄包裹":
第一趟(识别):你说话 → 板子把声音数字(PCM)包成 base64 → 寄给百度 → 百度猜出文字 → "我说"卡片亮出来。
第二趟(思考):板子把文字 + 一段 system 提示词 → 寄给火山豆包 → 豆包按提示词的口吻回答 → "助手回答"卡片亮出来。
system 提示词就一行(程序里写的),意思是:"你是一个运行在 ESP32-S3 上的语音助手,用简洁的中文回答,不超过 50 个字。"这一句指挥了大模型干两件事:
| 提示词里的指令 | 它"指挥"了什么 | 没写会怎样 |
|---|---|---|
| 用中文(Simplified Chinese) | 规定输出语言 | 可能答英文 |
| 限 50 字(limit to 50 characters) | 规定回答长度 | 可能长篇大论 |
这就是第 26 课的观点:提示词能"指挥"口吻和长度。 把这行改成"一位数学老师",它口吻就变了。
五、改一个条件验证:看它怎么"扛"住意外
状态机强在出错不乱。动手拆一拆:
| 我改了什么 | 我猜会怎样 | 实际/推论 |
|---|---|---|
| 说话不到 1 秒就松手 | 可能识别出乱码 | 报"录音时间至少一秒"——太短,它宁可不认也不硬猜 |
| 按住 BOOT 3 秒不放 | 一直录下去 | 到 3 秒自动停,自动进"正在识别"——有硬上限 |
| 拔掉 WiFi 再按 BOOT | 识别失败 | 报"百度识别连接失败/超时"进错误态——但没网永远救不回 |
| 说一句英语 | 可能识别成中文 | dev_pid=1537 只认中文普通话,英文常变成乱码/空 |
| 改提示词让"≤50 字"变"≤10 字" | 回答更短 | 回答真的短了——提示词能"指挥"长度 |
| 一次说一整段书 | 识别可能不全 | 最多只能录 3 秒,太长要分次说 |
结论:状态机把"意外"变成了"规则"——每个失败都有明确去处,每段录音都有上限,每次识别都有门槛。它永远知道"出错往哪走",所以不会卡死。
六、一个藏在代码里的小聪明:录音时屏幕只画进度条
你发现了吗——录音时屏幕几乎不动,只有进度条在涨。为什么不画整个屏幕?
程序里写了句注释:"录音中只更新进度条这一小块(整屏 fillScreen 太慢会阻塞音频采集)。" 意思是:麦克风每毫秒都在往里灌声音数字,如果一边"画整屏"一边"听声音",画画会抢走太多时间,声音就漏采了(会卡顿、断句)。
所以它只重新画"进度条"这一小块,把时间和 CPU 留给录音。
这告诉你的道理:做真实设备时,"好看"和"干正事"打架,先保干正事。 为了把声音录完整,宁可让画面"朴素"一点。
七、自己做一遍 + 过关检查
动手实验
- 看状态条:按 BOOT 说一句话,全程盯住状态条,把每一次变色和对应的卡片内容填进一张表。
- 录太短:按下又马上松开,看红字"录音时间至少一秒"。
- 按住 3 秒:不松手,看它自己停、自己进"正在识别"。
过关检查(对着这张表打勾)
- 我能说出 5 种状态的中文名(待机 / 录音 / 识别 / 思考 / 错误)。
- 按下 BOOT 进"录音",松开或满 3 秒进"识别",成功进"思考",成功回待机。
- 识别失败、模型超时,都进"错误",按 BOOT 回到待机。
- 我能说出 system 提示词"指挥"了大模型哪两件事(语言 + 长度)。
- 我能解释"为什么录音时只画进度条、不画整屏"。
自己想通一个开放问题
这一课助手回答是显示在屏幕上的。如果要让板子开口把回答念出来,应该接第几课的哪一棒?(提示:第 25 课文字转语音。)
八、创意方向
| 想做什么 | 描述给 AI 的效果 | 会观察到 |
|---|---|---|
| 换个人设的助手 | 把提示词里的"voice assistant"改成"一位聪明数学老师" | 换口吻,更容易帮你解题 |
| 把回答"念"出来 | 在思考→回待机之间接上第 25 课 textToSpeech | 回答从屏幕上到你耳朵里——这才是完整的语音助手 |
| 加唤醒词 | 待机再拆成"未唤醒/已唤醒",听到"你好小助"才进录音 | 更像真音箱、更省电,代价是多了个状态 |
| 会记事的助手 | 把多轮问答存数组,下轮再喂给大模型 | 它就"记得你们刚才聊的"——多轮对话雏形 |
| 会认生的助手 | 识别置信度太低时显示"我不太确定" | 比答错更友好 |
别忘了保密:密钥(百度/火山的 key)只放你自己配置里,绝不写进课件、截图,也不出现在任何公开分享里。公开仓库只留 config.example.h 模板。
下一课:第 29 课,板子要陪你下五子棋了——第五章 AI 感知与对话收官,第六章游戏开发开始。