Date: 2026-09-18
对照:当前仓库代码 ·roadmap.md(2026-09-02)·phase-1-review.md·phase-2-review.md·phase-3-review.md·phase-4-plan.md
产品决策:家长端(小程序)提前;小智硬件代际 / 多版本(原 Phase V)放到最后。
粒度:架构与项目管理。不是 Coding Plan。
下一编码阶段:phase-7a-plan.md——家长任务下发(场景+立即/计划;RTC 只写最近一次)+ 执行记录(后,无计量 UI)。
原则不变:每完成一个 Phase → Completion Review → Architecture 更新 → Roadmap Review → 下一份 Phase Plan。
本文取代旧路线图里「下一编码 = Phase 4 / Phase V 可与 4 并行」的排序。
跟读/复读已经能在**这一款**色宁设备上完整跑完:清单一次下发、设备本地播→听→下一句、后评估定量、本地 wav + 同名 txt、Instance 可入库。缺的不是再做一个英语 App,而是**家长能设一天的计划,设备自主开/关/切模式**;历史记录第二刀,分数先不给家长看。
| 判断 | 说明 |
|---|---|
| Phase 1–4 产品骨架 | 可用。 对话 / 翻译 / 中英 / 复读 / 跟读已在设备上验收通过(锁定路径见 .cursor/rules) |
| Phase 4 相对原施工单 | 目标达成,执行器换了地方。 步进权威从「Server 时钟 + 每句 MCP」改成「设备播放列表循环」;后评估仍在 Server,不指挥喇叭 |
| 演示闭环缺口 | 无云端计划表;闹钟 pending 只有一份;已开机到点不切模式;课文写死;manager-mobile 无计划页;Instance GET 仅 server secret |
| 下一刀 | Phase 7a 家长任务下发。全表同步、RTC 只写下一时刻;立即优先于计划;History 后做;metrics UI 不做 |
| 原 Phase V | 最后做。 现网只有一款硬件;hello 代际字段不增加演示能力 |
不要在 7a 之前开倒背/口算/接龙、不要做摄像头兼容矩阵、不要把课文下载平台化当成选课前提(SD 手工拷卡 + catalog 与卡上路径一致即可)。不要先做分数页。
| 编号 | 旧 Roadmap 一句话 | 代码事实(2026-09-18) | 状态 |
|---|---|---|---|
| Phase 1 | 薄 App Runtime | apps.json + start_app_task;CHAT / PLAY_AUDIO / TRANSLATION / BILINGUAL / SHADOWING;MQTT START_APP_TASK;离线口令挂钩 |
完成(有债,见 §2.1) |
| Freeze | Capability Spec v1.0 | 文档冻结 | 完成 |
| Phase 2 | 事件 + 采集 | [skill_event] + duration_ms;TaskSession JSON;SD /{app}/{task}/lessons |
完成(跟读已不是 TTS 范读) |
| Phase 3 | TaskInstance 持久化 | 三表 + PUT/GET;report 可回写 audio_id |
完成(GET 鉴权不对家长;见 §2.3) |
| Phase 4 | 跟读时钟 + 后评估 | 设备播放列表 + listen_ratio 听窗;expected_text / metrics;本地 data/recordings + 同名 .txt |
完成(与原文「固件零 diff」不符,见 §3) |
| Phase V | 产品代际 + 端云矩阵 | 无 generation/revision/cap_set | 未做 → 调到最后 |
| Phase 4b | 倒背 / 口算 / 接龙 inline | 仅 apps.json 意图槽预留 |
未做 → 演示闭环之后 |
| Phase 5 | Server Scheduler | 设备 RTC + NVS pending;**无**云端日历表 | 未做 → 权威表并入 7a-B;5 剩到点补推 |
| Phase 6 | 资源 DOWNLOAD + 在线 Locale | 只有 mkdir;词表仍硬编码中文 | 未做 |
| Phase 6b | 离线 Locale OTA | 仅现网中文 MultiNet | 未做 |
| Phase 7 | 家长任务管理 | manager-mobile 无计划/Instance UI |
未做 → 7a 下发优先、历史后置 |
| Phase 8 / 9 | 开发者 / 订阅 | — | 后置 |
已落地(设备可用)
chat.conversation · 翻译 · 中英对话 · 复读清单 · 跟读清单
TaskSession JSON · Instance 三表 · 后评估 metrics · 本地 wav/txt
未落地(挡住「真实使用」)
家长:按场景创建任务(泛听/跟读/双语…);立即执行或周期计划
固件:本地计划全表;RTC 只编程最近一次;已开机到点执行
云端 ai_parent_task + SYNC_SCHEDULE(不要 10 槽 SET_ALARM 一对一)
历史:oauth2 读 Instance / 聊天(7a-D,无 metrics)
只列**仍影响产品或后续施工**的缺口。已在对应 *-review.md 写过、且不再挡演示的过程债(例如「Phase 1 无 pytest」)从略——Phase 2 之后已有 pytest。
| 缺口 | 现状 | 是否挡 7a / 演示 |
|---|---|---|
| 家长小程序 UI | manager-mobile = 智能体列表 + 配网 + 聊天记录,不是练习控制台 |
挡。 7a 本体 |
| Server Schedule 权威表 | 只有设备 SET_ALARM(软件最多 10 条)+ 唯一 NVS pending |
挡。 7a:云端任务表 + 设备全表;DS3231 只写下一时刻。不要把 ALARM_MAX_NUM 当家长上限 |
| 冷场多次主动开口 | 进入对话有欢迎词;可配循环催促未做 | 不挡 |
| 非 Sening 板复读 | Task Gateway 仅 sening-xiaozhi-s3 |
不挡(就这一款) |
| 双技能表 | 固件 k_task_skills[] + Server apps.json |
不挡;禁止再为新 App 扩固件表 |
| 离线/在线状态分叉 | 没网复读结束后 Server 仍可能以为在 CHAT | 演示保持在线 |
| 缺口 | 现状 | 是否挡 7a / 演示 |
|---|---|---|
| D8 v1.1 本地文件上传 | 跟读 wav 在 xiaozhi-server 磁盘;chat report 另走 BLOB | 家长播录音依赖现有 chat_audio 或 只展示文本。完整听原声可后做 |
D11 wait Skill |
听窗在设备墙上时钟 | 不挡跟读;4b 间隔出题再用 |
| D9 长按退出 Task | 口令退出已有 | 不挡 |
D10 indicate |
无 | 不挡 |
| 跟读句子表曾在 Server | 已改: 整份 playlist JSON 一次下发,设备排序执行 | 已是现网;文档须承认 |
| 缺口 | 现状 | 是否挡 7a / 演示 |
|---|---|---|
| GET 鉴权 | ShiroConfig:/task/instance/** 全部 server。计划写 oauth2,实施因「不能按方法拆过滤器」改成 server |
挡 7a-D。 Dispatch 不依赖读 Instance。History 再拆 oauth2 新路径;PUT 仍 server |
prompt_text 仍是 SD 路径 |
原文在 expected_text |
UI 必须显示 expected_text,不要把路径当课文 |
upsert 失败后 _skip_upsert |
本会话不再上报。audio_id 已改为 VARCHAR(255) 消掉截断 |
部署 Liquibase 后新会话正常;旧 skip 会话需重新跟读 |
| 查询副本非权威 | 权威 = 连接内存 + data/task_sessions/*.json |
家长读库即可演示;不要把库当步进引擎 |
见下一节。对家长 History:**asr_text + expected_text + 可选 chat_audio 已够**。metrics 已入库,7a 不展示。不要等音素、及格线、流利度。
phase-4-plan.md)钉死的模型设备(当时要求零 diff)
播一句 → completed(duration_ms) → Server 开听窗 → 时钟到了 MCP 播下一句
分析全部后置、定量、允许失败;无 passed;无 JUDGE。
SRAM / 58 句清单证明:每句再 MCP 一次会把设备卡死或截断列表。现网是:
Server 一次 JSON playlist(url|name, repeat, speed;speed 默认 1.0)
Device PSRAM 清单,本地循环:
播一句 → 关解码器 → 听窗 = 墙钟播放时长 × listen_ratio(1.2)
→ 录音上行 → 下一句
清单结束 → audio.playlist_completed → Server 播「跟读结束」回对话
Server ASR 只暂存/评估,不进 chat/LLM
后评估 text_similarity_v0 → step.metrics
data/recordings/{mac}/{mode}/{date}/{time}_{asr|tts}_*.wav
同 stem .txt(UTF-8)
复读 同样一次下发清单;播完「复读结束」;播放中忽略闲聊
离线口令:退出复读 / 我们来聊天吧
锁定(已验收,后续禁止为修跟读去改):开机欢迎词时序、CHAT / TRANSLATION / BILINGUAL 的 ASR→LLM 路径。
| 原计划条目 | 代码 | 结论 |
|---|---|---|
| 固件零 diff | app_task.cc 播放列表、听窗、listen_ratio;解码器/唤醒词在听窗前关掉 |
有意偏离。 设备成为步骤循环执行器,Server 不再逐句 MCP |
| 下一句只由 Server 时钟触发 | 设备墙上时钟;Server 旁路评估 | 语义仍是「分析不挡喇叭」,触发器换端 |
expected_text 来自 txt 契约 |
resolve_expected_text;禁止用路径做相似度 |
符合 |
metrics[] 无 passed |
text_similarity_v0 0–1 |
符合 |
| 说错/不说仍下一句 | 听窗到点就进下一句;静音也落 wav | 符合 |
| 退出立刻回 Chat | 口令 is_exit_to_chat |
符合 |
| Liquibase 新列 | expected_text / metrics / assessed_at;后又 audio_id VARCHAR(255) |
符合(255 是 9-18 为路径加的) |
宣称 Phase 4 Done 的产品标准(原 §2.3):热路径流畅 + 后评估定量 —— 达到。
宣称「固件冻结面未移动」—— 不要再写。 冻结的是 Skill 种类,不是「跟读循环必须在云端」。
当场纠错再播、及格线、音素、租户、4b 三个 Task、热路径读卡上 txt、manager-web 打卡页、Locale。
Application 热路径(hello/listen/tts/stt/Opus 语义锁定)
Task Gateway
START_APP_TASK / pending / 离线口令
SET_ALARM 软件表最多 10 时刻;DS3231 只编程下一次 Alarm1
**7a-A:家长计划改走本地全表,不要 10 槽一对一;pending = 下一笔计划**
playlist:repeat + speed + listen_ratio
skill_event:audio.completed|stopped|playlist_completed + duration_ms
SD mkdir /{app}/{task}/lessons
xiaozhi-server
apps.json 权威定义
start_app_task / mode 分流
跟读/复读:一次下发 playlist,不逐句 MCP
TaskSession → JSON + PUT Instance
assessment.py 后评估(不 await 再 play)
audio_archive:recordings + sidecar txt
manager-api
PUT/GET /task/instance 目前仅 server secret
ai_task_instance / step / event
不执行 Skill、不判对错结论
manager-mobile(uni-app,可出微信小程序)
登录 / 智能体 / 配网 / 聊天记录 / 声纹
无:练习会话、metrics、START_APP_TASK、Schedule
manager-web
智控台(人设、模型、OTA)
无跟读页
色宁 MQTT START_APP_TASK 设备侧已通。缺的是小程序发出去,以及用用户身份读 Instance。
设备录音 Opus
→ Server ASR(不进 LLM)
→ recordings/..._asr_....wav + .txt
→ turn.asr_text / expected_text / metrics
→ PUT Instance(audio_id = 相对路径,≤255)
→ 可选 chat-history report → 32 位 blob,回写同一列则覆盖路径
家长 7a-D:**只展示文本**(跟读 expected/asr;对话类走 chat_history)。相似度不渲染。播放原声若要用现成 API,走 chat_audio id,不要假设 manager-api 能读 xiaozhi-server 磁盘路径。
Phase 1–4 ✅ 设备侧英语学习可演示
↓
Phase 7a 家长任务下发 ← 下一编码
│ A 本地计划全表;RTC 只写最近一次;开机到点也执行
│ B ai_parent_task + 场景 catalog + SYNC_SCHEDULE / 立即 START
│ C 小程序:场景参数 + 立即 / 周期
│ D 历史(文本+录音;无分数)
│
├───────────────┐
↓ ↓
Phase 5 到点补推 Phase 6 课文 DOWNLOAD + 在线 Locale
(7a 日历表已建) (换课不靠拷卡时再做;不挡选课)
│
↓
Phase 4b 倒背 / 口算 / 接龙(inline 评估)
│ 固件仍禁止 if correct;用已有 speak/listen
↓
Phase 6b 离线 Locale(仅 zh/en 有模型才做)
Phase 7b 家长完整:语言对、PAUSE、长按退出、听原声完善
Phase 8 开发者 App 平台
Phase 9 订阅
Phase V 产品代际 / 端云兼容 ← 最后(就这一款硬件)
必须串行: 7a-A 固件(全表+下一闹钟)→ 7a-B 云端 → 7a-C 小程序。未完成 A 不要宣称周期任务可用。7a-D 不挡 Dispatch Done。
7a 不依赖: 4b、6 下载、6b、V。SD 已有 unit01 即可选课。语言对可存 params。
5 不挡 Dispatch: 权威表在 7a-B;Phase 5 只补「已开机漏响」的云端再推。
Objective
家长先选场景再填参数:泛听/跟读(课文、遍数、结束后关机或回对话);双语(中英/中法/中日…,可选时长)。可 立即执行(临时,最高优先)或 存为周期计划。设备保存计划全表;DS3231 只写入下一次最近时刻。History 第二刀看文本/录音,**不展示分数**。
Why Now
10 槽闹钟一对一撑不住「每小时整点聊 10 分钟」。芯片本来就只编程下一次。现网 pending 会被覆盖;已开机到点不执行;课文写死;家长文案「复读/复读机」和跟读分不清。
Dependencies
START_APP_TASK / 软关机 / Alarm1;Phase 3 Instance(7a-D);登录与绑设备。不把 SET_ALARM 当任务总线。
Scope
schedule.json 全表;recompute_next_alarm() 写唯一 pending + Alarm1;已开机也执行;软关机前重算。ai_parent_task + 场景/课文/语言对 catalog;计划 SYNC_SCHEDULE;立即 START_APP_TASK。Out of Scope
分数、课文 DOWNLOAD、倒背/口算、OTA 代际、改锁定热路径、用 ALARM_MAX_NUM 限制条数、删旧口令「复读」。
Client(设备)
允许补计划文件、只写下一闹钟、duration 墙钟、on_complete。禁止新 DeviceState、业务 if 树、把 58 句清单塞进 RTC。可新增一条 MQTT SYNC_SCHEDULE(不是新 WS type)。
Acceptance(Dispatch)
立即跟读可打断计划;≥15 条计划含 hourly 全量在设备、芯片只有最近一次;软关机唤醒进正确场景;结束后重算下一闹钟;计划不打断临时。Chat/翻译/中英口令回归不坏。History 不挡 Dispatch Done。
施工单:phase-7a-plan.md。未完成 7a-A 不要宣称周期任务可用。
| 编号 | 一句话 | 相对旧图的变化 |
|---|---|---|
| Phase 5 | 设备已开机漏响时云端再推 START | 任务表已并入 7a-B;本阶段是补救扫描 |
| Phase 6 | 清单 / DOWNLOAD / resource_id;在线 phrase pack |
mkdir 已有。7a 已能存 language_pair;pack 不挡选课 |
| Phase 4b | 倒背/口算/接龙 = assessment.timing=inline + 及时 speak |
挪到家长能看见跟读之后 |
| Phase 6b | 离线 zh/en 词表 OTA | 不挡 7a/7b |
| Phase 7b | PAUSE/RESUME、长按退出、录音播放完善 | 语言对选择已在 7a 双语场景;7b 补控制台与离线词 |
| Phase 8 / 9 | 开发者沙箱 / 订阅 | 不变,更后 |
| Phase V | product.generation/revision + hello/OTA 矩阵 |
最后。 摄像头 SKU 或第二款硬件立项时再打开 |
评估时机表(deferred vs inline)仍有效,见旧 roadmap.md;4b 不得把跟读改回流内纠错。
| 事项 | 最早 |
|---|---|
| 小智 AI 1 / 1-1 / 2 代际字段 | Phase V(最后) |
| 摄像头 / 新传感器 Skill | Phase V 之后 |
| D8 v1.1 本地文件当家长主播放通道 | 7b 或独立;7a 用文本 + 可选 chat_audio |
| D11 wait 一等 Skill | 4b 需要「播完停 800ms」且不想云端睡时 |
| D14 TASK_PAUSE/RESUME | 7b |
新 WS type=command |
仅当 detect 前缀不够;不加新语义 |
| 德语离线唤醒 | 可能永久做不到(无官方 MultiNet) |
家长创建:
立即 跟读 unit01 ×1,结束后回对话 → 马上执行(可打断当前计划)
计划 A 每天 07:30 跟读 unit01
计划 B 每天 10:00 泛听 unit01,结束后软关机
计划 C 每小时整点 双语(中英) 10 分钟,结束后软关机
(计划可以很多条,不是 10)
设备:
本地保存全部计划
软关机前只把「下一次最近」写入 Alarm1
10:00 泛听关机后,闹钟变成 11:00 双语,而不是再占 10 个槽
History(7a-D,不挡 Dispatch):
跟读:每句原文 / ASR / 可选录音
泛听:完成态
双语/翻译/对话:该时段聊天
不展示相似度
branch(if correct) 放进固件audio_id 路径当成 manager-api 可直接 fopen 的文件ai_task_step;家长页渲染 metrics下一编码阶段: 只打开 phase-7a-plan.md。先补本地计划表与只写下一时刻的 RTC,再云端与小程序。对外文案用 泛听 / 跟读。