# Phase 1 Completion Review > Date: 2026-08-31 > Basis: **current code** (not the original Phase 1 wish-list) > Compared against: `phase-1.md` · Master Plan · Architecture Audit · Client Plan V1.1 · Server Plan V1.1 > Repositories: `xiaozhi-esp32-2.2.6` (Client) · `xiaozhi-esp32-server` (Server) 本文件只记录事实、差异、债务与对 Master Plan 的修正建议。不包含下一阶段的详细编码任务(见 `phase-2-plan.md`)。 --- ## 1. 当前代码盘点(以仓库为准) ### 1.1 Phase 1 实际改动的文件 #### Client(`xiaozhi-esp32-2.2.6`) | 文件 | 角色 | |------|------| | `main/boards/sening-xiaozhi-s3/app_task.h` | **新增。** 设备侧 Task 启动 / pending / 离线口令 / 复读记忆 | | `main/boards/sening-xiaozhi-s3/app_task.cc` | **新增。** `Board_StartAppTask`、优先级、NVS pending、`last_rep`、技能分发 | | `main/boards/sening-xiaozhi-s3/mqtt.c` | `START_APP_TASK`;`SET_ALARM` 可附带 `app_id/task_id/params` 写入 pending | | `main/boards/sening-xiaozhi-s3/sening_xiaozhi_s3.cc` | MCP `self.mp3.play` 增加 `repeat` / `power_off_after` / 空 name 回退;开机 `Board_ResolveBootOrRestore` | | `main/boards/sening-xiaozhi-s3/mp3_player.cc` | 整首循环 N 次;自然结束才 `power_off`;`repeat_left` | | `main/boards/sening-xiaozhi-s3/system.h` / `system.c` | 离线口令宏;`SDCard_Play_MP3_With_Speed_Repeat` | | `main/audio/wake_words/afe_wake_word.cc` | MultiNet 注册 4 条离线口令 | | `main/audio/wake_words/custom_wake_word.cc` | 同上 | | `main/application.cc` | `SendListenDetect`:没网且通道未开时不 `WakeWordInvoke` | 未改:Opus 热路径、`DeviceState` 迁移表、`hello/listen/tts/stt` 字段含义。非 Sening 板无 App Task 执行器。 #### Server(`xiaozhi-esp32-server`,仅 Python `xiaozhi-server`) | 文件 | 角色 | |------|------| | `core/app_runtime/__init__.py` | **新增模块。** | | `core/app_runtime/registry.py` | 加载 `apps.json`(bundled;可选 `data/apps.json`) | | `core/app_runtime/apps.json` | App / Task 注册表 | | `core/app_runtime/runtime.py` | `start_app_task` / `switch_app` / mode 分流 / 口令 / 跟读轮次 / 翻译 | | `plugins_func/functions/switch_app.py` | LLM 可调的切 App | | `plugins_func/functions/start_repeater.py` | 打开复读机 | | `plugins_func/functions/start_shadowing.py` | 打开跟读 | | `plugins_func/functions/translate.py` | 连接 LLM 翻译(智控台 Key) | | `mcp_servers/translate/server.py` | 独立 translate MCP(回退) | | `mcp_server_settings.json` | 注册 `english-translate` | | `core/connection.py` | 连接内存:`active_app_id` / `interaction_mode` / `tool_policy` 等 | | `core/handle/receiveAudioHandle.py` | `startToChat` 前按 mode 分流;口令优先于 LLM | | `core/handle/textHandler/listenMessageHandler.py` | `[app_task]` / `[voice_entry]` | | `core/providers/tools/unified_tool_manager.py` | `filter_tools` 白名单 | | `config.yaml` | 加载 `switch_app` / `start_repeater` / `start_shadowing` | #### manager-api / manager-web **无 App Runtime 相关改动。** 无新表、无新 REST。智控台仍只管理人设 / 插件绑定。 (历史对话里 manager-web 的 `vue.config.js` / teleport 修复与 Phase 1 业务无关,不计入本阶段架构。) ### 1.2 实际增加的模块 | 模块 | 位置 | 职责 | |------|------|------| | App Runtime | Server `core/app_runtime/` | 注册表 + 统一 `start_app_task` + mode 行为 | | Device Task Gateway | Client `app_task.cc` | 三通道汇合、抢占、pending、本地 Skill 执行 | | Translate plugin + MCP | Server plugins + `mcp_servers/translate` | 翻译旁路 `chat()` | | Repeater / Shadowing plugins | Server plugins | 进入对应 Task | 没有:Task Runtime 状态机类、Step 引擎、Assessment 服务、Scheduler 服务、App Store。 ### 1.3 实际增加的 API | 类型 | 名称 | 说明 | |------|------|------| | REST | **无** | manager-api 未增接口 | | Python 插件 | `switch_app` | `app_id` + 可选 `task_id` | | Python 插件 | `start_repeater` | 可选 `name/repeat/power_off_after` | | Python 插件 | `start_shadowing` | 无参数 | | Python 插件 | `translate` | `text` + 可选语言 | | Device MCP | `self.mp3.play` 扩展 | `repeat`、`power_off_after`;`name` 可空 | | Device MCP | `self.mp3.get_status` | 已有;增加 `repeat_left` | ### 1.4 实际增加的协议 **没有**新的 Xiaozhi WS `type`。热路径语义冻结得到遵守。实际采用的是「复用 listen detect 文本」和「色宁 MQTT 新 action」。 | 通道 | 载荷 | 用途 | |------|------|------| | WS `listen` `state=detect` | `[app_task]{app}\|{task}\|{source}` | 设备通知 Server 进入某 Task(`execute_skills=false`,避免复读双播) | | WS `listen` `state=detect` | `[voice_entry]` | 离线「切换模式」且**已联网**时要菜单 | | MQTT `snlp/v1/.../cmd` | `action=START_APP_TASK` | 通道①即时启动 | | MQTT `SET_ALARM` | 可选 `app_id/task_id/params` | 写入设备 pending,通道② | 未增加:`type=task`、`mode.set`、`play.completed` 独立消息、`speech.stopped`。 ### 1.5 实际增加的数据库结构 **无。** App 状态在 `ConnectionHandler` 内存。设备 pending / `last_rep` 在 NVS。WS 断线后 Server 回到 default chat;设备 pending 仍在本地。 ### 1.6 Client 架构变化 Phase 1 之前(Audit): ```text Application 单例 + DeviceState + Opus 双工 + MCP Sening 旁路:self.mp3.* / snlp MQTT PLAY_MEDIA / RTC 闹钟 离线「切换模式」只打日志 ``` Phase 1 之后: ```text Application(Chat 热路径不变) └── Board_StartAppTask(Sening 板级 Task Gateway) ├── source 优先级 mqtt_immediate > schedule > voice > default_chat ├── NVS pending + last_rep ├── 技能查找表 k_task_skills[](固件内硬编码 id,不是业务 if 树) └── 本地执行 self.mp3.play / 或只 notify Server MultiNet:切换模式 / 复读机 / 开始复读 / 退出复读 没网:切换模式不连云;复读机可播上次音频或 SD 第一首 ``` InteractionMode **没有**成为固件枚举。设备不持久化 App 历史。DeviceState 仍只管听/说/升级。 ### 1.7 Server 架构变化 Phase 1 之前: ```text ConnectionHandler.chat() 是唯一对话编排 Agent + Plugin + MCP 无 App / 无 InteractionMode ``` Phase 1 之后: ```text receiveAudioHandle.startToChat → 口令 match_voice_switch(先于 LLM) → mode 分流: PLAY_AUDIO 忽略上行 SHADOWING handle_shadowing_turn(不 chat) TRANSLATION run_translation(不 chat) BILINGUAL wrap 后仍 chat() CHAT 现网 intent/LLM App Runtime:apps.json + start_app_task 工具:inherit_agent | allowlist ``` 权威状态仍在 **当前 WS 连接内存**,不是 TaskInstance 表。 ### 1.8 Client ↔ Server 实际通信流程 ```text ① 小程序 / MQTT 调试客户端 START_APP_TASK ↓ snlp MQTT Board_StartAppTask ├─ 本地 Skill(复读:SD MP3) └─ 若 Xiaozhi 通道已开:listen detect [app_task] ↓ Server start_app_task(execute_skills=false) 更新 active_app_id / interaction_mode,TTS 播报 ② SET_ALARM + pending 到点 RTC 唤醒 → Board_ResolveBootOrRestore 非 chat 计划 → 直接 StartAppTask(schedule) 否则 → chat.conversation ③ 离线语音 MultiNet 复读机 → 本地播放,不依赖 Server MultiNet 切换模式 → 仅 IsNetworkReady 时 [voice_entry] 在线 ASR 短句 → match_voice_switch → start_app_task ④ Chat 热路径(未离开 CHAT) Mic → Opus → ASR → LLM → TTS → Speaker 与 Phase 1 前相同 ``` ### 1.9 Task Runtime 当前实现状态 | 能力 | 状态 | |------|------| | 统一入口 `start_app_task` | **有**(Server + 设备各一份) | | App / Task 注册表 | **有**(Server JSON;固件另有技能表) | | InteractionMode 分流 | **有**(连接字符串,5 种 mode) | | Step / StepInstance | **无** | | TaskInstance 持久化 | **无** | | Event(play.completed 等) | **无正式协议**;播放结束设备会 `[app_task]chat` 通知回聊 | | 跟读 | **有 Demo**:TTS 范读 + ASR 轮次 + 回声抑制;无归档、无评分 | | Assessment / Metric | **无** | 结论:这是 **薄 App Runtime + 单 Task 动作**,不是 Master Plan 的 Task Runtime。 ### 1.10 测试情况 | 项 | 现状 | |----|------| | `phase-1.md` §10 验收清单 | 文档存在,**仓库内无对应自动化用例** | | xiaozhi-server pytest / unittest(App Runtime) | **无** | | 固件单元测试(app_task / MultiNet) | **无** | | 现有测试资产 | 仅 ASR/TTS/LLM performance_tester | | 实际验证方式 | 人工烧录 + 重启 Server + MQTT/口令联调 | **Phase 1 在工程上「做完了功能」,没有「测完了回归」。** 这是进入 Phase 2 前最大的过程风险,不是功能缺口。 --- ## 2. Phase 1 Implementation Review(计划 vs 代码) ### 2.1 对照表 | 项目 | 原计划(`phase-1.md`) | 实际实现 | 差异原因 | 后续处理 | |------|------------------------|----------|----------|----------| | 薄 App 框架 | Server JSON + `active_app_id`;设备无 App 目录 | 已实现;注册表在 `core/app_runtime/apps.json` | — | 保持;不要下发到 SD | | Default `chat.conversation` | 配网/开机进入并主动开口 | pending 默认 chat;`agent_proactive` + 进入 CHAT 时 TTS 招呼 | 冷场再催促未做成可配循环 | Phase 2 不优先;可配次数留债 | | 三通道 + 优先级 | MQTT > Schedule > Voice | 设备 `Board_AppTask_SourcePriority`;Server `SOURCE_PRIORITY` | 两端各算一次,可能短暂不一致 | Phase 2 用 skill_event 对齐结束态即可,不合并 MQTT | | `START_APP_TASK` | 新 MQTT action | 已实现 | — | 保持 | | pending + 闹钟唤醒 | NVS;非 chat 计划不先闲聊 | `Board_ResolveBootOrRestore` + `SET_ALARM` 写 pending | Server **无** Schedule 权威表 | 接受;权威表放到 Scheduler Phase | | 离线「切换模式」 | 不再空 log;进菜单 | 有网才 `[voice_entry]`;没网跳过 | 实施中发现 WakeWordInvoke 会干等 Server | **正确修正**,写入架构 V2 | | 复读 N 次在设备 | `repeat` 参数 | mp3_player 循环 | — | 保持 | | `power_off_after` | 自然结束才软关机 | 已实现 | — | 保持 | | 翻译旁路 LLM chat | 独立 MCP | **主路径改为 `conn.llm` + translate 插件**;MCP 仅回退 | 独立 MCP 依赖占位 Key,智控台 Key 才是现网 | **正确修正**;MCP 可降级为可选 | | 工具白名单 | allowlist | `filter_tools` | — | 保持 | | Xiaozhi `type=task` | 明确不做 | 未做 | — | Phase 2 仍不做完整 type=task | | Java 新表 | 明确不做 | 未做 | — | Phase 3 再做 Instance 表 | | 三个 App | chat / 复读 / 翻译 | **四个 App + 跟读 Task**:另增 `english_conversation`、`shadowing` | 产品要把跟读/中英对话尽早可演示 | 跟读仍是 Demo;正式采集是 Phase 2 | | 固件无业务名 | 禁止 `if (app == english)` | 固件 `k_task_skills[]` **含 app_id 字符串** | MQTT 离线启动必须能查 Skill,无法只问 Server | 接受为「配置表」;禁止再加英语评分/音频逻辑 | | 口令表在 Assets JSON | 映射表可扩 | 固件硬编码 4 条拼音;在线口令在 `runtime.py` | MultiNet 容量与误触发 | **正确收窄**;不要把翻译/跟读塞进 MultiNet | | apps.json 路径 | 建议 `data/apps.json` | bundled `core/app_runtime/apps.json`,可选 data 覆盖 | 部署更简单 | 保持 | | PLAY_AUDIO 忽略 ASR | 是 | 是 | — | 保持 | | 用户唤醒复位 chat | 是;闹钟不复位 | `on_user_wakeup`;`[app_task]` 不走唤醒 | — | 保持 | | 无 play.completed | 接受 | 播完设备直接切回 chat 并 detect | Server 仍不知道第几遍 | Phase 2 补 skill_event | | 小程序 UI | 后置 | 未做 | — | Parent UI 很后 | | 测试清单 | 详细 checkbox | 无自动化、无书面跑测记录 | 赶功能 | **Phase 2 必须带 pytest + 手工回归表** | ### 2.2 哪些设计被修改(相对原文 Plan) 1. **离线入口收窄**:只保留「切换模式 + 复读机/开始复读/退出复读」。翻译/跟读/中英对话只走在线 ASR。 2. **没网不连云**:`SendListenDetect` 在无网且通道未开时直接 return。 3. **复读可完全离线**:NVS `last_rep` + SD 第一首;注册表仍只在 Server。 4. **翻译实现**:连接 LLM 优先于独立 MCP 进程。 5. **Mode 集合扩大**:`SHADOWING`、`BILINGUAL` 提前落地(Client Plan 把 TRANSLATION/GAME 放在 Phase 3)。 6. **跟读提前**:不是 SD 范读 + 录音对象,而是 TTS 句子列表 + 文本回声过滤。 7. **协议挂钩**:用 `[app_task]` / `[voice_entry]` 寄生在 `listen/detect`,而不是新 type。 这些修改应视为 **Phase 1 的真实架构**,后续 Phase 不得假装「设备仍只有 CHAT+PLAY_AUDIO」。 ### 2.3 哪些设计没有实现 - 冷场多次主动开口(可配间隔) - 口令→id 的设备端 JSON/Assets 表 - Server 侧 Schedule 权威存储 - `play.completed` / 遍数上报 - 跟读音频对象与 step 关联 - Assessment - 非法 `app_id` 的系统化错误码(MQTT 有 ack;语音多为 TTS 句子) - Phase 1 测试计划的自动化 - 非 Sening 板的复读 ### 2.4 实施中发现的问题 1. `self.mp3.play` 立即 `accepted`,Server 无法编排 N 次循环 → 循环必须在设备(Plan 已预见,代码证实)。 2. 独立翻译 MCP 的 yaml Key 与智控台 Key 分裂 → 改走 `conn.llm`。 3. ASR 常把结果包成 `{content,language,emotion}` → 必须拆 `content`,否则翻译/口令失败。 4. 跟读/翻译时喇叭回声会当用户插话 → AEC 打断仅限 `CHAT`/`BILINGUAL`;跟读再加文本相似度过滤。 5. 「切换模式」在没网时 `WakeWordInvoke` 会挂起 → 必须短路。 6. 设备本地启动复读后再通知 Server,若 `execute_skills=true` 会 **播两遍** → `[app_task]` 必须 `execute_skills=false`。 7. MultiNet 词表不能塞满业务口令,否则误触发且没网也无法跑翻译。 ### 2.5 技术债务(实施产生) 见第 5 节分级。核心:双技能表、寄生协议、无测试、跟读不是音频任务、App 状态不落库。 ### 2.6 原先没考虑到、但已出现的问题 - 用户口语「模式」与内部 `InteractionMode` / App 命名冲突(已规定:对用户仍说「模式」,对代码仍用 App/Task)。 - 离线复读与在线权威状态会分叉:没网播完后 Server 仍以为在 CHAT。 - 固件必须认识 `english_learning` 才能离线执行,与「业务名不上固件」理想不完全一致。 - manager-web 开发构建问题(teleport/`usedExports`)与 App 无关,但说明控制台栈也有债,不要在 Phase 2 顺手大改。 --- ## 3. 与 Master Plan 核心抽象对照 | 抽象 | 当前是否存在 | 实现位置 | 完成程度 | 是否需要调整 | 未来是否扩展 | |------|--------------|----------|----------|--------------|--------------| | **App** | 是(薄) | Server `apps.json` + `active_app_id`;设备技能表有 app_id | 连接级容器,无安装/订阅/资源包 | 保持「Server 权威、不下发 SD」 | Phase 6 再做资源与清单 | | **Task** | 是(薄) | `apps.json` tasks + `start_app_task` | 一个 Task ≈ 一种动作,无 Step 图 | 不要把跟读 Demo 当成完整 Task Definition | Phase 3 起 JSON Step | | **Step** | 否 | — | 0% | Phase 2 **不要**先上完整 Step 引擎 | Phase 3+ 跟读一步一 Step | | **Skill** | 是(MCP + 板级) | 设备 MCP;Server 调 DeviceMCP;固件 `k_task_skills` | 能跑 play/stop/power_off/translate | 双表必须当契约维护 | 核心 `play_audio` 平台化后移 | | **InteractionMode** | 是(Server 字符串) | `conn.interaction_mode` | `CHAT/PLAY_AUDIO/TRANSLATION/SHADOWING/BILINGUAL` | 固件仍无 Mode 枚举,可保持正交 | 正式 FOLLOW_READ 可与 SHADOWING 合并命名 | | **TaskInstance** | 否 | — | 0% | Phase 2 只用内存/文件 Session,不建 Java 表 | Phase 3 落 manager-api | | **StepInstance** | 否 | — | 0% | 同上 | 跟读采集后才有意义 | | **Event** | 部分 | `[app_task]` / `[voice_entry]`;MQTT ack | 无统一 Event 模型 | Phase 2 增加 `[skill_event]` 即可,不上第四套总线 | 以后再考虑 `type=task` | | **Audio** | 聊天附件级 | `ai_agent_chat_audio` LONGBLOB;跟读未强制归档 | 跟读轮次未必走 report | Phase 2 必须把跟读 ASR/音频挂上 Session | 再迁对象存储 | | **Assessment** | 否 | — | 0% | 不要在 Phase 2 做评分 | Phase 4 文本比对 v0 | | **Metric** | 否 | — | 0% | — | Assessment 之后 | | **Schedule** | 半截 | 设备 RTC + pending;无 Server 日历 | 能 7 点唤醒复读 | 不要用 RTC 冒充家长计划权威 | Phase 5 Server Scheduler | | **Plan** | 否 | — | 0% | — | 家长任务管理 | | **Subscription** | 否 | — | 0% | — | 平台后期 | **符合 Master Plan 的方向:** 权威在 Server、设备执行、Chat 热路径保留、App 不是固件、复读不走 `play_music`。 **不符合或提前/滞后:** - Server Plan 说 Phase 1 可以没有 App 实体 → 实际做了薄 App,这是 **有益提前**,应写进 Master Plan。 - Client Plan 说 Phase 1 甚至不需要 `activeAppId` → 实际设备有 pending app_id,Server 有 active_app_id。 - 跟读/中英对话/翻译 Mode 提前 → Master Plan 的 Phase 边界要按代码改,而不是把已落地功能假装「未开始」。 - TaskInstance / Assessment / Scheduler 仍未开始 → 与 Master Plan 一致,不要在下一阶段一次做完。 --- ## 4. Current Architecture V2(基于代码) ### 4.1 Current Client Architecture V2 ```text ESP32-S3 (sening-xiaozhi-s3) ├── Application::Run DeviceState: Idle/Listening/Speaking/... │ ├── AudioService Opus 16k 热路径(未改语义) │ ├── Protocol (Xiaozhi WS/MQTT) hello/listen/abort/tts/stt/mcp │ └── MCP Server self.mp3.* / self.power_off / alarm / ... │ ├── WakeNet + MultiNet │ 口令: 切换模式 | 复读机 | 开始复读 | 退出复读 │ → Board_Handle_Voice_Command │ └── Task Gateway (app_task.cc) ← Phase 1 新增 Board_StartAppTask(app, task, params, source) ├── 优先级抢占 / preempt skills ├── NVS pending + last_rep ├── k_task_skills[] 查 Skill └── 执行: SD MP3 循环 | notify Server | 空 Skill 只切态 旁路(仍并存): snlp MQTT START_APP_TASK / SET_ALARM / PLAY_MEDIA / DOWNLOAD DS3231 RTC 闹钟唤醒 → OnRestoredFromPowerOff → ResolveBootOrRestore ``` 非 Sening 板:无 Task Gateway;翻译等纯 Server Mode 仍可走 Xiaozhi WS。 ### 4.2 Current Server Architecture V2 ```text xiaozhi-server (Python) ├── ConnectionHandler │ session_id (WS 连接级,≠ TaskInstance) │ active_app_id / current_task_id / interaction_mode / tool_policy │ shadowing_index / shadowing_prompt │ ├── receiveAudioHandle.startToChat │ 1. match_voice_switch │ 2. mode 分流(不进 chat 的: PLAY_AUDIO / SHADOWING / TRANSLATION) │ 3. CHAT / BILINGUAL → intent + LLM │ ├── app_runtime │ registry(apps.json) │ start_app_task / switch_app / filter_tools │ handle_shadowing_turn / run_translation │ ├── Plugins: switch_app, start_repeater, start_shadowing, translate ├── Device MCP executor → self.mp3.play/stop └── 可选 Server MCP translate 进程 manager-api (Java) 用户/设备/Agent/聊天 WAV ← 未参与 App Runtime manager-web 智控台 ← 未参与 ``` ### 4.3 Client ↔ Server Architecture V2 ```text ┌──────────── 小程序 / MQTT 客户端 ────────────┐ │ START_APP_TASK / SET_ALARM │ └──────────────────┬──────────────────────────┘ │ snlp MQTT ▼ ┌──────── Client ────────┐ Xiaozhi WS ┌──────── Server ────────┐ │ Task Gateway │◄── listen detect ──►│ App Runtime │ │ [app_task] [voice_entry] │ start_app_task │ │ SD MP3 Skill │◄── type=mcp ───────►│ DeviceMCP play/stop │ │ Chat AudioService │◄── opus/tts/stt ───►│ ASR / LLM / TTS │ │ pending NVS │ │ connection memory │ └────────────────────────┘ └──────────┬─────────────┘ │ 现有 report ▼ manager-api chat_history + audio BLOB ``` 同一时刻:一个设备一个 active App/Task。Chat 与 Task 音频互斥沿用 `PauseSdCardMp3`。 --- ## 5. 技术债务 ### P0 — 不解决就无法安全继续开发 | ID | 债务 | 立即修? | |----|------|----------| | P0-1 | **无 App Runtime 自动化测试**,Phase 2 极易回归 Chat / 口令 / 复读双播 | **是。** Phase 2 第一刀就是 pytest + 手工回归表,否则不准加表/加协议 | | P0-2 | 跟读 Demo 被误当成「已有 FOLLOW_READ 采集」——没有 prompt/asr/audio 绑定,Assessment 无处落点 | **是(作为 Phase 2 目标)。** 允许暂时存在评分,不允许继续假装已采集 | P0 不是「系统不能跑」,而是「下一阶段会建在流沙上」。 ### P1 — 近期应该解决 | ID | 债务 | 立即修? | |----|------|----------| | P1-1 | 无 `play.completed`:Server 靠设备主动切回 chat | Phase 2 用 `[skill_event]`,不要新 WS type | | P1-2 | 双技能表:`apps.json` vs `k_task_skills[]` 会漂 | Phase 2 写契约检查清单;不同步下载 JSON | | P1-3 | 寄生协议 `[app_task]` 与唤醒词/ASR 文本空间重叠 | 保持前缀约定;文档化;Phase 2 加 skill_event 前缀 | | P1-4 | 离线复读与 Server 连接态分叉 | 允许暂时存在;重连后以设备 notify 或下次 detect 对齐 | | P1-5 | 跟读范读走 TTS 而非音频音频,和复读资源模型不一致 | Phase 2 可先采集 TTS 跟读;SD 范读放到资源 Phase | | P1-6 | 翻译双实现(plugin + MCP) | 允许暂时存在;Phase 2 不删 MCP,测试以 plugin 为准 | | P1-7 | `BILINGUAL` 仍走 `chat()`,靠 prompt 约束,易夹杂语言 | 允许暂时存在;不是 Phase 2 主路径 | ### P2 — 平台化时再解决 | ID | 债务 | 立即修? | |----|------|----------| | P2-1 | 双 MQTT(Xiaozhi vs snlp) | 否 | | P2-2 | App 状态不落库 | 否(Phase 3 Instance) | | P2-3 | 复读仅 Sening | 否 | | P2-4 | 聊天 WAV LONGBLOB | 否 | | P2-5 | smartlearning 课程云未吸收 | 否(Phase 6) | | P2-6 | 固件认识业务 app_id 字符串 | 否;保持查找表,禁止业务分支膨胀 | | P2-7 | 无 `type=task` / `mode.set` | 否;等 Instance 真正需要步进再加 | | P2-8 | 小程序 / 家长日历 UI | 否 | --- ## 6. Master Plan 再审视 ### 已完成(相对长期愿景的「第一刀」) - Chat 作为 default App/Task 活下来 - 设备可执行非 Chat 的播放 Skill - Server 可按 Mode 跳过 LLM - 三通道进入 Task 的骨架 - App 与 Agent 分离(Agent 仍是人设;App 是 `apps.json`) ### 正在进行 - 英语学习:复读可用;跟读仅 Demo - 翻译 / 中英对话:可用,未产品化评估 ### 需要调整的设计 1. **「Phase 1 不做 App」作废。** 薄 App Runtime 已是 Current Architecture V2 的核心,后续只加深,不推倒重来。 2. **「跟读 = Client Phase 2 才出现」作废。** Mode 和口令已在;缺的是采集与 Instance。 3. **「用 type=task 才能做 Task」暂缓。** 寄生 detect + MQTT 已够启动;先补 Event 与 Session,再考虑新 WS type。 4. **「apps 下到 SD」明确拒绝。** 与 Phase 1 后期结论一致,Master Plan 的 App Sync 改为「资源下发、定义留云」。 5. **离线策略写入 Master Plan:** MultiNet 只保留总入口 + 可离线执行的 Skill(复读);云能力口令走 ASR。 ### 已不合理或应降优先级 - 第一阶段就上 QUIZ/GAME 完整 Mode - Phase 2 一次做完 Task 表 + 评分 + 对象存储 + 新协议 - 合并双 MQTT 作为近期目标 - 把设备建成完整 Task Runtime ### 需要新加入的能力(代码已逼出来) - 离线可执行 Skill 与「仅在线 Mode」的明确分类 - ASR JSON `content` 规范化(所有非 Chat Mode 都要) - 喇叭回声策略按 Mode 配置(打断 / 忽略 / 文本过滤) --- ## 7. 结论:Phase 1 是否 Done **功能 Done(带条件):** 薄框架 + chat 默认 + 复读 + 翻译 + 三通道挂钩 + 离线复读,且未破坏协议语义、未改 Java DDL。 **工程未 Done:** 无自动化测试、无跟读采集、无播放完成事件、双表漂移风险。 **因此:** 不开启 Java Task 表、不开启 Assessment、不开启 App Store。 下一阶段只做一件事:把「音频任务」从 Demo 变成 **可归档的跟读会话**(见 `roadmap.md` / `phase-2-plan.md`)。