Date: 2026-09-18
评估与排序修订:phase-4-eval-and-roadmap.md(对照 Phase 1–4 代码缺口 + 家长端提前)。
输入(历史):phase-1-review.md·phase-2-review.md·phase-3-review.md· Capability Spec v1.0
粒度:架构与项目管理。不是 Coding Plan。
Phase 4 已实施(设备播放列表 + 后评估)。**下一编码阶段:Phase 7a 家长任务下发**(施工单phase-7a-plan.md)。先 Dispatch,再 History;**不做计量 UI**。
语言包 / 离线词表仍见 Phase 6 / 6b / 7b。7a 双语场景只存并传递language_pair,不换 MultiNet。
产品代际 / 多硬件版本(原 Phase V)改到最后:现网只有一款色宁设备,不挡演示。
原则:每完成一个 Phase → Completion Review → Architecture 更新 → Roadmap Review → 下一份 Phase Plan。
禁止把本文当成锁死到 Phase 9 的施工图。后面 Phase 只保证目标、边界与 对应的 Spec 能力 ID。
Capability Spec 把系统分成三层:
Application 以后才无限扩展(教育 / 益智 / 陪伴 / 助手)
Task Runtime 尽快稳定,权威在 Server
Device Capability 语义已冻结:播 / 听 / VAD / speak 出声 / wait / loop / 指示 / 抢占
因此路线图不再按「再做 10 个 App」排列,而按:
1. 把已声明、固件尚未具备的原子能力补齐(只允许因此 OTA)
2. 把 Task Runtime 做成可归档、可查询
3. 把评估 / 调度 / 资源放到 Server
4. 用倒背 / 口算 / 接龙反证:新 App 零固件增量
原 V1.1「Phase 2 = type=task + Java 表 + 跟读 + 评分」仍然拆开。Spec 额外要求:
loop(同一音频 N 次)在设备;branch(答对了吗) 只在 Server,且 仅 Task 声明为流内评估时才走进业务(倒背/接龙);跟读默认不走apps.json 不是离线业务引擎record_clip v1 = 听流 + Server 归档;本地 WAV 上传是 v1.1| 编号 | 一句话 | Spec 主要验证 / 交付 |
|---|---|---|
| Phase 1 | 薄 App Runtime | 已完成:D15 设备 loop、D4 Mode 策略雏形、翻译走 Server |
| Freeze | Capability Spec v1.0 | 文档冻结;不编码 |
| Phase 2 | 用复读+跟读钉死事件与采集 | 已完成(见 phase-2-review.md):D1、D6、D7 v1、D8 v1 文本;另提前 D13 目录 /{app}/{task}/lessons |
| Phase 3 | TaskInstance 持久化 | 已完成(见 phase-3-review.md):三表 + PUT/GET;GET 现为 server secret |
| Phase 4 | 跟读:清单循环 + 后评估 | 已完成(见 phase-4-eval-and-roadmap.md):设备本地播→听→下一句;metrics 不指挥喇叭 |
| Phase 7a | 家长任务下发 + 执行记录 | 下一编码:场景+参数;立即 vs 计划;本地全表、RTC 只写下一次。泛听≠跟读。History 后做、无 metrics |
| Phase 5 | Server Scheduler 补救扫描 | 权威表已并入 7a-B;本阶段剩「设备已开机、云端到点再推一把」 |
| Phase 6 | App / 资源 + 在线 Locale | D13 fetch;phrase pack;翻译/双语的 language_pair |
| Phase 4b | 倒背 / 口算 / 接龙 | 流内评估 + 及时 speak;排在家长能看见跟读之后 |
| Phase 6b | 离线 Locale(可选 OTA) | MultiNet/唤醒词表按 locale;**仅 ESP-SR 已有模型的语种(先 zh/en)** |
| Phase 7b | 家长完整能力 | 语言对、PAUSE、长按退出、听原声完善 |
| Phase 8 | 开发者 App 平台 | Manifest 只能调已冻结 Skill |
| Phase 9 | Subscription / Marketplace | 账号,不改音频 |
| Phase V | 产品代际 + 端云兼容 | 最后做。 小智 AI 1 / 1-1 / 2;就这一款硬件时不开工 |
Phase 1 薄 App Runtime ✅
↓
Capability Spec v1.0 ✅ 文档
↓
Phase 2 钉死 D1 事件 + D6/D7/D8v1 采集 ✅
↓
Phase 3 TaskInstance 持久化 ✅
↓
Phase 4 跟读清单循环 + 后评估 ✅ 设备执行列表;Server 只评估
↓
Phase 7a 家长任务下发 ← 下一编码
│ 7a-A 固件:计划全表 + RTC 只写最近一次;开机到点也执行
│ 7a-B 云端任务表 + 场景 catalog + SYNC_SCHEDULE / 立即 START
│ 7a-C 小程序:场景参数 + 立即 / 周期
│ 7a-D 历史(文本+可选录音;无 metrics)
├─────────────┐
↓ ↓
Phase 5 到点补推 Phase 6 资源 + 在线 Locale
│
↓
Phase 4b 倒背/口算/接龙(inline;禁止改跟读后评估模型)
↓
Phase 6b 离线 Locale(zh/en)
Phase 7b 家长完整(语言对 / PAUSE / 听原声)
↓
Phase 8 开发者平台
↓
Phase 9 订阅
↓
Phase V 代际/兼容 最后;第二款硬件或摄像头 SKU 前才必须
必须串行: 1 → Freeze → 2 → 3 → 4 → 7a-A 固件(全表+下一次闹钟) → 7a-B 云端 → 7a-C 小程序。7a-D 历史不挡宣称 Dispatch Done。
7a 不依赖 4b / 6 / V。SD 已有 unit01 即可选课。家长任务数量 不是 10;ALARM_MAX_NUM 不准当上限。语言对可存 params,phrase pack 仍 Phase 6。
Phase 4b 依赖 4 的听窗/Instance,也依赖家长能看见结果(否则新 App 同样「只有喇叭」)。禁止为此改 C++。评估时机见下文「评估时机」表。
Phase V 不挡 7a / 4b / 5。 现网一款硬件;摄像头立项前再做握手字段。
Phase 6: 目录树与 ensure_app 已在 Phase 2 提前落地。本阶段做清单 / DOWNLOAD / resource_id,并做 在线 Locale。不要重做 mkdir。
Phase 6b: 仅当需要「没网也用德语/英语喊切换」时才 OTA 离线词表。德语等 没有 官方 MultiNet 的语种,离线入口保持 zh 或 en。
明确后置、不挡冻结宣称:
| Spec 能力 | 最早 Phase |
|---|---|
D11 wait 一等 Skill |
4b 前可仍用 Server 延时;需要「播完停 800ms 再听」且不想云端睡时再下固件 |
| D14 TASK_PAUSE/RESUME | 5 或 7b 家长控制需要时 |
| D8 v1.1 本地文件上传 | 会议纪要 / 律师询问产品化时;7a 不依赖 |
| D9 长按退出 Task | 可与口令退出并存;正式绑定放 7b |
D10 indicate 逻辑态 |
有空再做;禁止塞进 DeviceState 迁移表 |
新 WS type=command |
仅当 detect 前缀不够表达步进;**不加新语义** |
| 在线 Locale / 语言对 | Phase 6(phrase pack + pair);控制台 Phase 7b |
| 摄像头 / 新传感器 Skill | Phase V 之后;新 SKU = 小智 AI 2,禁止混进 1 的固件包 |
| 产品代际 hello 字段 | Phase V,最后做;现网一款硬件不挡 7a |
Objective
不是做一个新 App。用 已有 复读机 + 跟读 Demo,把 Spec 里尚未落地的三块钉进 Runtime:
audio.completed/stopped(D1)、非 Chat 的 listen/句边界(D6/D7)、跟读归档 v1(D8)。
完成事实: 见 phase-2-review.md。跟读改为 SD 一句一 MP3;订阅 App 可 mkdir 不烧录。
Why Now
Spec §20:这三项不补齐就不能宣称 Device 已冻结。跟读 Mode 已在线,继续堆倒背/口算只会在没有事件的底座上复制 Demo。
Dependencies
Phase 1 执行器、SHADOWING/PLAY_AUDIO 分流、Opus 听流、report、设备 repeat loop(D15,本阶段 不改)。
Scope
逻辑事件(运输:[skill_event],对应 Spec AUDIO_COMPLETED/STOPPED);TaskSession 文件;跟读 turn = prompt + asr + 可选 WAV;pytest。Mode 名代码里可仍叫 SHADOWING,文档对齐 Spec FOLLOW_READ。
Out of Scope
评分(S4)、Java 表、type=task、倒背/口算/接龙产品、SD 范读必修、wait Skill、TASK_PAUSE、record_clip 本地文件、apps.json 下发、新 DeviceState、MultiNet 加业务口令。
Client
复读结束上报完成/停止事件;不改 Opus;不把跟读句子表写进固件。
Server
Session + 跟读记轮次 + 吃事件后回 chat;ASR/LLM/翻译仍在 Server。
Protocol
不增加命令种类。 只把已声明的 Event 用现有 listen/detect 文本运过去。语义见 Spec §4–5。
Database
无新表。归档走现有 ai_agent_chat_audio(D8 v1)。
API
无新 REST。
Data Flow
见 phase-2-plan.md。跟读下一步由 Server 步进(D16),不是设备 loop。
State Machine
DeviceState 不动。InteractionMode:PLAY_AUDIO / SHADOWING(FOLLOW_READ) / 回 CHAT。
Acceptance Criteria
Spec §22 四条纪律 + 本文 Phase 2 验收:完成事件单次回聊、跟读 JSON 轮次完整、Chat/离线复读/翻译不回归。
Risks
回声当跟读;事件与 [app_task]chat 双招呼。
Regression Risks
复读双播、离线「切换模式」连云、Chat barge_in。
详细施工:phase-2-plan.md。
Objective
中层 Task Runtime 可查询:Session JSON → ai_task_instance / ai_task_step / ai_task_event。不新增 Device Capability。
完成事实: 见 phase-3-review.md。GET 走 server secret(非计划中的 oauth2)。未建空 score 列。跟读 prompt_text 仍是 SD 路径。
Why Now
Phase 2 字段已稳定,建表不会空。评估和调度需要主键。
Dependencies
Phase 2 TaskSession schema;D8 v1 report 管道。固件保持 Phase 2 bin。
Scope
manager-api 最小 DDL;TaskSession.save() upsert;只读 GET。Agent ≠ App。JSON 文件双写保留。
Out of Scope
评分算法、对象存储、家长 UI、新 WS type、设备缓存 instance_id、改 SD 布局。
6–10.
Client 零改动。Server Python 上报 + Java CRUD。协议不加新命令种类。音频挂 step 尽力而为。
14–15.
与 chat_history 双写但表分开;旧固件无 instance_id 必须兼容(id 只在云端)。
详细施工:phase-3-plan.md。验收:phase-3-test.md。
Objective
仅跟读这一类:预定 MP3 序列 + 定时录音。分析全部后置、定量、允许失败。设备不宣读对错。
完成事实: 见 phase-4-eval-and-roadmap.md。步进在**设备播放列表**(一次 JSON 下发),不是逐句 MCP;后评估仍在 Server。
Why Now
跟读/打卡录音的价值在归档与事后看指标。若把云端比对绑在句间,喇叭会卡。
Dependencies
Phase 3 Instance;Phase 2 duration_ms 听窗。原文来自 txt 契约,**不能**用 prompt_text 路径。
Scope(已落地)
设备:listen_ratio × 墙钟播放时长;清单结束 playlist_completed。
Server:ASR 不进 LLM;metrics[{method,value}];本地 wav + 同名 txt。无 passed、无当场 TTS 分数。
Out of Scope
倒背/接龙的及时反馈(4b);家长 UI(**7a**);S8 再播同一句;音素;租户。
Client
有 diff(播放列表 / 听窗)。禁止再改回「每句 MCP」。
Acceptance
说错/不说/API 挂了仍播下一句。语音回归已按锁定路径验收。
详细施工(历史):phase-4-plan.md(其中「固件零 diff / Server 时钟」已被代码修正,以评估报告为准)。
产品:选场景填参数;可立即执行(临时,最高优先)或存为周期计划。设备存全表,RTC 只写最近一次。先下发,后看记录;无计量 UI。对外 泛听(旧称复读机)/ 跟读。
详细见phase-4-eval-and-roadmap.md§5.2。施工单:phase-7a-plan.md。
Objective
家长按场景创建任务(泛听/跟读:课文、遍数、结束后关机或回对话;双语:中英/中法/中日…;对话可带时长)。立即下发马上跑;计划任务到点跑。软关机后从本地表挑下一最近时刻写入唯一硬件闹钟。History:跟读句文本+录音;对话类聊天。不展示相似度。
Why Now
把计划 1:1 塞进 ALARM_MAX_NUM=10 撑不住「每小时整点聊 10 分钟」这类周期。DS3231 本来就只编程下一次。现网唯一 pending 会被覆盖;已开机到点不执行;课文写死。
Dependencies
Phase 1 START_APP_TASK / 软关机 / Alarm1;Phase 3 Instance;Phase 4 播放列表。不依赖 4b/6/V。
Scope
7a-A 本地 schedule 全表 + recompute_next_alarm;7a-B ai_parent_task + SYNC_SCHEDULE + 立即 START;7a-C 场景表单;7a-D 历史。
Out of Scope
metrics;课文 DOWNLOAD;倒背口算;新 WS type;改锁定热路径;用 10 限制条数。
Device
允许 OTA:计划文件、只写 Alarm1、duration 墙钟、on_complete。禁止新 DeviceState。课文不进固件。
Acceptance(Dispatch)
立即跟读可打断计划;≥15 条计划含 hourly 全量在设备、芯片只有最近一次;软关机唤醒进正确场景;结束后重算下一闹钟。History 不挡 Dispatch Done。
2026-09-18: 现网只有一款硬件。本阶段 不挡 7a / 5 / 4b。摄像头 SKU 或第二款板子立项前再开工。
现状结论(2026-09-02 核对代码,仍成立):**没有「小智 AI 1 / 1-1 / 2」代际,也没有兼容矩阵。**
施工单以后写phase-v-plan.md。
Objective
把三套独立的编号钉死,并在连接时对上:
产品代际(小智 AI 1 / 1-1 / 2)≠ 固件 semver(OTA 包)≠ 协议/能力集(Server 决定开哪些业务)。
Server 对过旧设备降级或引导 OTA;对过新设备拒绝未知能力,而不是 silently 当聊天。
Why Now
不加摄像头也可以出 1-1(跟读/Task Runtime 已是大功能面)。不加代际字段,OTA 只能按板型比 2.2.6 vs 1.0.0 两个对不上的数字,Server 无法判断「这台有没有相机 MCP、能不能跑 cap.v1.1 的跟读听窗」。
Dependencies
现网已有:OTA 上报 application.version + board.type;WS hello version(帧格式 1/2/3)+ features.mcp|aec;MQTT snlp/v1 + header "1.0";manager-api Liquibase 日期 changeset。
不依赖 Phase 4 完成。摄像头硬件不在本阶段。
编号模型(冻结语义,实现可后写)
product.generation 1 / 2 / 3 硬件族。1=现网音箱;2=加摄像头(或其它新传感器)
product.revision 0 / 1 / 2 同代硬件上的软件大改。对外:小智 AI 1、小智 AI 1-1、小智 AI 2
firmware.semver 1.4.2 每一次可 OTA 的 bin;只升这个数字去升包
capability.set cap.v1 / v1.1 与 Spec 修订对齐(播/听/跟读听窗/…);新 App 不加 cap 号
protocol.ws 1 已有 hello.version,只为二进制帧;禁止拿它当产品代际
protocol.mqtt snlp/v1 topic 大改才升 v2;header.version 只升破坏性字段
server.release 2026.09.x 或 semver xiaozhi-server + manager-api 同发
api.rest /xiaozhi/v1/ 破坏性 REST 才 /v2/;旧路径保留到兼容窗结束
对外称呼:
| 对外 | generation | revision | 含义 |
|---|---|---|---|
| 小智 AI 1 | 1 | 0 | 现网:无摄像头,当前能力面 |
| 小智 AI 1-1 | 1 | 1 | 同一块硬件,能力集或业务面大改(例如 Task Runtime 成为默认) |
| 小智 AI 2 | 2 | 0 | 新硬件(摄像头等);固件包与 1.x 分轨,禁止烧到对方板上 |
| 层 | 现在有什么 | 缺什么 |
|---|---|---|
| 终端产品号 | system.h 里 APP_FIRMWARE_VERSION "1.0.0" 几乎不 bump;CMake PROJECT_VER "2.2.6" 是上游仓库号;User-Agent 是 BOARD_NAME/esp_app.version |
没有 product.generation/revision;1 和 1-1 无法区分 |
| WS 握手 | hello:version=1 + features.{mcp,aec} + 音频参数 |
不报固件、不报代际、不报 cap_set;Server 不拒不匹配 |
| OTA | 按 板型 比 semver,新则给下载 URL | 不按产品代际分轨;不检查 Server 最低 cap;1.0.0 vs 2.2.6 两套数字并存 |
| MQTT snlp | topic v1、header "1.0" 写死 |
无协商;无能力位 |
| Server | config.yaml xiaozhi.version: 1;manager-api 靠日期 SQL |
无 server.release;REST 无兼容窗;无「此 Server 支持的 generation 范围」 |
| 业务匹配 | MCP 工具列表运行时发现 | 没有「这台 gen1 永远不要 vision」的矩阵;新 API 默认所有旧设备都能打 |
product_generation、product_revision、firmware、capability_set。(board_type, generation),禁止 gen2 包推给 gen1。/task/instance 视为 v1;破坏性变更走新路径或带 Accept-Version,旧客户端有兼容窗。Out of Scope
摄像头驱动、vision MCP 实现、把 cap_set 当 App 商店、为每个 App 升 generation、把 hello.version 改成 2 来表示 1-1。
Protocol
只加字段,不加新 WS type。 旧固件不带这些字段时:Server 视为 小智 AI 1 / revision 0 / cap.v1,保持现网能连。
匹配发生在 hello 与 OTA check,不在每句 ASR。
Client / Server 匹配规则(产品语义)
连接时
Device → generation + revision + firmware + cap_set
Server → 查矩阵:
未知 generation → 拒绝或只开 CHAT
cap_set < server.min → 引导 OTA;OTA 前只跑 cap 交集(例如没有跟读听窗就当 PLAY_AUDIO)
cap_set > server.max → Server 忽略未知能力,不崩溃
generation=1 无 camera → 永不下发 vision 工具
generation=2 → 允许 vision;固件包与 1 分轨
同一硬件出 1-1:只升 product.revision + capability_set + firmware.semver,**不**升 generation。
新传感器:升 generation,新 board_type,新 OTA 目录。
Risks
把业务版本和协议版本混成一个数;1-1 误当成必须换机;Server 静默吞掉未知字段导致「以为支持摄像头」。
Regression Risks
hello 加字段导致旧 Server 解析失败(必须忽略未知键);OTA 板型字符串与 generation 不一致导致升错包。
不是新 Device 能力。Manifest / Task JSON 标明 assessment.timing:
| timing | 听窗结束后 | 代表 | 实现阶段 |
|---|---|---|---|
deferred |
立刻下一步;metrics 后台可晚到 | 跟读、故事复述、打卡录音 | Phase 4 |
inline |
先 Server 评估,**再** speak 反馈,然后下一题 |
倒背数字、成语接龙、口算 | Phase 4b |
共同点:判题只在 Server;设备只收到已有 speak / play_audio;固件无 if correct、无 JUDGE。
差别:跟读可以评估失败仍往下播;倒背若评估失败应 speak「没听清」之类再进入下一题,**不能**把反馈拖到家长事后打开 App 才算完成这一回合。
倒背示例(Server 编排,可后补进 4b-plan):
speak 数字,间隔 ~1s(Server 睡或以后 D11 wait)
speak「开始」
listen 固定时长
ASR + parser → metrics(对了几个、准确率)
speak 反馈(及时、可含定量,如「倒对了 4 个」)
下一题或结束
成语接龙:听完用户一句 → Server 判是否合法接龙 → 马上 speak 下一成语或纠错提示。同样是 inline。
口算:默认同 inline(对/错或报出正确答案属于业务流)。若某练习模式只要交卷后看报表,再在 Task JSON 改成 deferred。
Objective
三个代表 Task 只加 Server Task / Parser / Prompt。其中倒背、接龙(及默认口算)必须是 inline:听窗结束就要评估并出声反馈,**禁止**做成跟读那样的后评估。
Why Now
跟读只覆盖「录完继续」。规则型/游戏型回合若不及时反馈,产品就不是那个 App。
Dependencies
Phase 4 的听窗、Instance、metrics 字段。另增:听窗结束 → await 短评估 → speak(仍不改固件)。
Scope
倒背:间隔出题 → 「开始」→ 录音窗 → 立刻报对了几个/准确率。
接龙:用户说完 → 立刻合法性与下一提示。
口算:默认同 inline。
出题 TTS 语言 = device.locale(无则 zh)。Parser 仍产出定量 metrics[];反馈文案由 Server 生成后 speak,不是固件模板。
Out of Scope
新 Mode、新 DeviceState、MultiNet 业务词、新 WS、JUDGE 命令、难度引擎产品化、小程序、phrase pack、把跟读改回流内纠错。
Client
禁止改 C++。
Acceptance
倒背一轮:录音结束后 数秒内 设备说出评估结果,再出下一题或结束。断评估服务时有超时兜底 speak,不得死等。固件 git diff 为空。
施工单:以后写 phase-4b-plan.md(本文件只钉时机差异)。
Objective
权威任务表已在 7a-B ai_parent_task。本阶段补:设备已开机但本地闹钟漏触发时,云端按分钟再推 START_APP_TASK。RTC 仍只负责「下一次」唤醒。
Why Now
7a 完成后「每天准时」仍可能两边漏一刀;云扫描是对账,不是日历真相的第二份拷贝。
Dependencies
7a-B plan 表;Phase 1 START_APP_TASK。
Scope
到期扫描;同一 plan+同一分钟幂等一次;跳过正在跑的 mqtt_immediate。
Out of Scope
再做一张平行日历;Device 上的复杂 Plan DSL。若 7a J5 已落地,本阶段可标部分完成。
Protocol
复用已有 MQTT 命令,不新增种类。PAUSE/RESUME 若做,必须是 Spec D14,不是第五套协议。
Objective
资源权威在 Server;设备只缓存文件。同时落地 设备默认语言(在线半) 与 翻译/双语的可替换语言对。
Why Now
跟读换标准音、多 App 音频,不能靠手工拷 SD。词表若继续写死中文,德语机联网后仍只能喊「开始跟读」。
Dependencies
Phase 3。不依赖 4b、不依赖 6b 固件。现网 ai_agent.language / lang_code 可先当 Chat 语种来源。
Scope — 资源
清单 / DOWNLOAD / resource_id。可选缓存 manifest。设备仍只执行 skills[]。
Scope — Locale(在线,本阶段必须做)
见下文 「语言模型」。phrase pack、device.locale、翻译/双语 language_pair。热路径:ASR 文本用该 locale 的 enter_phrases 匹配;TTS 进场语用该 locale;Chat 系统提示与音色跟 locale。
Out of Scope
App Store;把判题 JSON 当固件逻辑;德语离线唤醒(6b / 可能永久做不到);Phase 4 时钟重做。
Objective
没网时,唤醒词与系统级口令(切换入口 / 复读机 / 回 Chat)与 device.locale 一致。**不是新 Device 能力种类**(Spec:MultiNet 词表可配)。
Why Now / 为何单独
ESP-SR 的 WakeNet / MultiNet 按语种出模型。中文口令是拼音音素;英语是另一套 MN;官方 没有 德语 MultiNet 可预期。把「烧一套德语句表」塞进 Phase 6 会假装离线德语已经存在。
Scope
NVS locale;从 assets 加载该语种的 wake + 系统命令表。v1 只承诺 zh 与 en(有模型才做)。切换仍只允许系统级词,禁止把「开始跟读」写进固件。
Out of Scope
为泰/法/德训练唤醒模型(产品/数据项目,不是编码 Phase);运行时从云下载声学模型进 PSRAM(除非以后单独立项)。
接受现实
locale=de-DE 的设备:在线菜单/Chat 可以是德语;离线唤醒可以仍是英文或中文 SKU,直到有模型。文档必须写清,不要当 bug。
Objective
小程序在 7a 之上:改 Schedule;**设置设备默认语言与翻译/双语语言对**;PAUSE;听原声完善。
Dependencies
Phase 7a + Phase 5 + Phase 6。6b 不是前提:控制台改 locale 后,在线立即生效。
Scope
UI。D9 长按退出若未做可一并。语言对只能选 App Manifest 声明的 supported_pairs。
Out of Scope
开发者平台、支付、在小程序里训练唤醒词、硬件代际管理。
Objective
第三方 Task JSON 只能引用 Spec 已冻结 Skill。校验失败即拒。
Dependencies
Phase 6;InteractionMode 集合稳定。
Out of Scope
GPIO、设备脚本引擎、新传感器。
账号与权益。不改 Opus,不上情绪诊断。
分三层,不要混成「一个 language 字段搞定唤醒和翻译」。
| 层 | 是什么 | 例子 | 难度 |
|---|---|---|---|
A 设备默认语言 device.locale |
开机 Chat、进场 TTS、在线场景口令、无语言对的 App(倒背、口算、故事复述) | zh-CN / en-US / de-DE |
在线:**容易**(Server phrase pack + 已有 ai_agent.language)。离线唤醒/口令:**不容易**,见 6b |
B App 语言对 language_pair |
翻译、双语对话的可替换选项 | 翻译 th↔fr;对话 en↔de |
容易,纯 Server;一个 App + 参数,不要每种语言对一个 app_id |
| C 资源内容语言 | 音频 MP3/txt 本身 | 英语跟读课永远是英文音频 | 跟 lesson 包走,不跟 locale。德语机练英语跟读:菜单德语、喇叭音频英语 |
功能 1 好不好做:
runtime.py 硬编码词表换成 locales/{locale}/phrases.json,hello 时带上 device.locale。**工作量中等、风险低,Phase 6。**system.h。英语官方 MN 可做第二套 assets。**德语没有现成 ESP-SR 模型时,离线入口做不到**,只能在线。不要承诺「改一个配置全世界离线德语」。功能 2 怎么配:
不要再复制 english_translation / english_conversation 两个 App 名。Manifest:
app_id: translation
default_pair: ["zh","en"] # 设备 locale 为 zh 时的缺省
supported_pairs: [["zh","en"],["th","fr"],["en","de"], ...]
instance.options.language_pair # 家长/控制台覆盖
app_id: bilingual_chat
default_pair: ["zh","en"]
supported_pairs: [["zh","en"],["en","de"], ...]
语义:用户说 lang_a → 只答 lang_b,反之
翻译机:未指定时仍可 auto 检测,目标语取 pair 的另一侧或 target_lang。
缺省 pair 的推导:[device.locale 的主语言, 机构配置的 L2],没有 L2 则 zh-en。
倒背 / 故事复述 / 口算:只有 A,TTS 与听窗提示用 device.locale。不要给它们配 language_pair。
权威: device.locale 在 manager-api(绑定/出厂);Agent.language 与其对齐,避免两套打架。xiaozhi-server 连接时读取,固件 NVS 只服务 6b 离线。设备 仍然没有 tenant_id。
禁止: 为每种语言对改 C++;把「开始跟读」的德语写进固件;Phase 4 做 Locale。
对齐 Spec §4–5。每个 Phase 必须同时有 Server→Device 与 Device→Server,禁止单端表。
Phase 2
Device AUDIO_COMPLETED|STOPPED ──detect──► Server
Device listen 流 + VAD ────────► Server ASR / D8 v1 report
Server SPEAK / PLAY_AUDIO / 回 CHAT ──tts/mcp──► Device
Server ensure_app dirs ──MCP/MQTT──► Device mkdir(运输,非新能力)
Phase 3 ✅
Server TaskSession JSON ──HTTP upsert──► manager-api Instance
无新 Device 能力;设备不持有 instance_id
Phase 4 ✅
Server 一次 JSON playlist ──MCP──► Device
Device 本地播→听窗→下一句
Device 听流(旁路 ASR/report) ──► Server 后评估 metrics
Device playlist_completed ──detect──► Server 回 CHAT
跟读:分析失败不挡下一句;无 JUDGE
Phase 7a
小程序 场景任务(立即/计划) ──HTTP──► manager-api
立即 START_APP_TASK mqtt_immediate ──MQTT──► Device
计划 SYNC_SCHEDULE 全表 ──MQTT──► Device schedule.json
Device 挑最近一次 ──Alarm1──► 唤醒/到点 StartAppTask
7a-D GET instance / chat ──oauth2──► 文本+可选录音
无新 WS type;无 metrics UI
Phase 4b
Device 听流 ──► Server ASR + parser(inline,短超时)
Server SPEAK 反馈 / 下一题 ──► Device
仍无 JUDGE、无固件 if correct;评估在业务流内,不能拖到后评估
Phase 5
Server TASK_START ──MQTT──► Device
Device TASK_STARTED/COMPLETED ──ack/event──► Server
Phase 6
Server FETCH ──DOWNLOAD──► Device SD
Device PLAY_AUDIO(resource) ──event──► Server
Phase V(最后)
Device hello/OTA 带 generation+revision+cap_set ──► Server 矩阵
Server 交集业务 / 引导 OTA / 拒未知 SKU ──► Device
旧固件缺字段 = 当前这一款 SKU;不加新 WS type
| 长期目标 | Roadmap |
|---|---|
| Device 能力冻结 | Freeze 文档 + Phase 2 补事件/采集 |
| Task Runtime 在 Server | P2 Session → P3 Instance ✅ → P4 后评估 ✅ → P4b 流内评估 |
| 新 App 不改 C++ | P4b 三个代表 Task 验收 |
| 跟读语音对象 | P2 D8 v1 → P3 挂 step → P4 本地 wav/txt → P6 标准音下载 |
| Scheduler | P7a 任务全表 + 设备只写下一闹钟;临时优先于计划;P5 到点补推可选 |
| App ≠ Firmware | 贯穿;P6 资源、P8 沙箱 |
| 设备默认语言 / 语言对 | P6 在线 pack + pair;P6b 离线 zh/en;P7b 控制台;P4b 继承 locale |
| 产品代际 / 端云匹配 | Phase V,最后;现网一款硬件视为当前 SKU |
| 家长可见练习 | P7a 场景任务下发 + 7a-D 历史(无分数);语言对已作为双语参数;PAUSE P7b |
| 心理陪伴 / 主持人 | 无新硬件;复用 listen/speak + Server Memory |
| Subscription | P9 |
来自 Spec §17 与 §21:
branch(if correct) 放进固件wait Skill、TASK_PAUSE、本地 WAV 上传、indicate 大改tenant_id(最早缝在 Phase 6,产品化 Phase 7b)app_id 或新 WS type下一编码阶段: 只打开 phase-7a-plan.md。跟读/泛听热路径与欢迎词/翻译/中英锁定。先 7a-A「全表 + 只写下一次闹钟」,不要再做 10 槽一对一。History 与 metrics 后置。