编辑 | blame | 历史 | 原始文档

小智 AI Server Architecture Plan

文档:小智 AI Server —— Task、语音分析与用户评估平台架构 Plan
Version: V1.1
Date: 2026-08-30
本文在 V1.0 概念稿上,依据《Xiaozhi AI 开放应用平台 Master Plan》与《Architecture Audit》修订。
只设计,不编码。
与《小智 AI 硬件开放应用平台 —— 总体架构与开发 Plan》V1.1 成对阅读。


0. 本文定位

本文只定义 Server(仓库 xiaozhi-esp32-server)如何从「实时语音对话后端」演进为「Task 编排 + 语音对象 + 评估」平台。

硬件执行细节见 Client Plan。本文只规定 对设备的契约 与 云端模块 / 数据 / API。

工作区另有 smartlearning/(课程 JSON + MQTT DOWNLOAD/PLAY_MEDIA)。它更接近 App Sync,但**未接入** Xiaozhi Server。本文把它当作可吸收的旁路,而不是第三套长期业务云。

相对 V1.0 的关键修正:

V1.0 V1.1(本次)
一上来拆 Gateway/一堆 Assessment 微服务 逻辑模块分开,物理仍是 Python xiaozhi-server + Java manager-api
Phase 1 就做跟读+倒背+口算三套评估 Phase 1 = 英语复读编排且 不评估;Phase 2 = 跟读 + ASR 文本比对
设备与 Server 各有一套完整 Task Runtime 权威 Task Runtime 只在 Server;设备是 Task Executor
音频规划为对象存储,但未对齐现状 承认现状是 ai_agent_chat_audio LONGBLOB;演进再迁对象存储
Agent 未区分 Agent ≠ App;Agent 继续做人设/模型配置
8~10 个平台阶段混在一起 与 Client 对齐为 Phase 1/2/3,其后评估平台再拆子阶段

1. 当前 Server 是什么(Audit 事实)

双栈,不是微服务网:

模块 入口 职责
xiaozhi-server main/xiaozhi-server/app.py WS /xiaozhi/v1/、OTA HTTP、实时 ASR/LLM/TTS
manager-api AdminApplication.java 用户/设备/Agent/插件/聊天落库
manager-web / mobile — 管理端
digital-human — 测试端,非主链路

一次对话:

Device → ConnectionHandler (session_id = uuid4)
  → VAD → ASR → intent / chat()
  → UnifiedToolHandler (Plugin / MCP / IoT)
  → TTS → type=tts/stt/llm/mcp + Opus
  → 可选 report → POST /agent/chat-history/report
  → ai_agent_chat_history + ai_agent_chat_audio (WAV)

关键代码:

阶段 位置
入站 core/connection.py _route_message
VAD/ASR core/handle/receiveAudioHandle.py
意图 core/handle/intentHandler.py
LLM ConnectionHandler.chat
TTS 出站 core/handle/sendAudioHandle.py
上报 core/handle/reportHandle.py → WAV
工具 plugins_func/* + unified_tool_handler.py

已有可复用: Agent、Plugin、MCP、function call、session_id、可选 WAV、play_music(但走 TTS 通道,**不适合**复读循环)。

不存在: App、Task、Step、TaskInstance、InteractionMode、Assessment、Plan、Subscription。
session_id 是 WS 连接级,不是 TaskInstance。


2. 目标(仍是 V1.0 愿景,但分层落地)

Xiaozhi Server
  ├── Device Gateway        ← 现有 WS / MQTT 网关,保留
  ├── Chat Orchestration    ← 现有 ConnectionHandler.chat
  ├── Task Runtime          ← 新增,权威编排
  ├── Media / Audio Object  ← 从「聊天附件」演进为可挂 Step 的音频对象
  └── Assessment            ← Phase 2 起;先文本比对,后语音特征

最终数据流(目标态,不是 Phase 1):

Schedule → TaskInstance → Step → InteractionMode
  → Device Skill → 儿童语音
  → 保存 Audio 对象 → ASR → Assessment → Metric → 家长报告

Phase 1 截断在「Mode=PLAY_AUDIO 驱动设备播放」;不要求评估与家长报告。


3. 职责边界(与 Client Plan 对齐)

Server
  创建 / 推进 / 结束 TaskInstance
  指定 InteractionMode
  调用设备 Skill(MCP 或 type=task)
  ASR / LLM / TTS / Assessment
  音频对象与 step 关联
  App JSON 与资源 URL 的权威

Client
  执行 Skill、切换 Mode、回报 Event
  不持久化 Step 历史、不评分

禁止在 Python 对话热路径里写死 if english_repeat 作为长期形态;Phase 1 允许一个 编排插件,Phase 2 必须升到 Task Runtime + JSON 定义。


4. 逻辑模块 vs 物理部署

V1.0 列出的 Gateway / Task Service / Assessment Service / Emotion … 全部作为逻辑边界。

物理部署保持:

xiaozhi-server (Python)     实时:连接、ASR、LLM、TTS、Mode 切换、Task 步进(运行时)
manager-api (Java)          配置与持久化:User、Device、Agent、Task 定义/实例、音频元数据、评估结果
对象存储(Phase 2+)        原始音频;第一期可继续 BLOB,但 API 按 audio_id 访问

不要为第一个复读 Task 拆新进程。

模块映射:

逻辑模块 Phase 落点
Device Gateway 0 已有 websocket_server.py / MQTT gateway
Chat Orchestration 0 已有 ConnectionHandler
Interaction Mode 开关 1 ConnectionHandler 上 interaction_mode;非 CHAT 跳过 chat()
Repeat Orchestrator 1 plugins_func 或独立薄模块;MCP self.mp3.play
Task Runtime 2 Python 运行时状态机 + Java 实例表
Audio Object 2 扩展上报:挂 step_instance_id;逐步迁出 LONGBLOB
Assessment v0 2 expected_text vs ASR;Java 或 Python 均可,结果入库
App / Resource 3 吸收 smartlearning 清单 + 下载 URL;Java 为权威
Scheduler / Plan 3 manager-api + 定时;不要用设备 RTC 闹钟冒充
Voice Feature / Baseline / Emotion 3+ 异步队列;禁止进实时 TTS 路径
Subscription / Developer API 更后 不做 Phase 1–2

5. 现有对话链路:必须保留

无 Task 时行为与现网一致:

listen → ASR → intent/LLM/tools → TTS

协议 hello/listen/abort/iot/mcp/ping 与下行 stt/tts/llm/mcp 禁止改语义。

插入方式:

_route_message / startToChat / chat()
  之前判断 interaction_mode
  CHAT → 原路径
  PLAY_AUDIO / FOLLOW_READ → 不调用 chat()
  FOLLOW_READ 的语音仍走 ASR.receive_audio,结果写入 Step 而非 Dialogue

play_music 继续服务「用户说播放歌曲」。**不要**用它实现英语复读(它占用 TTS 队列,和课程 SD 播放冲突)。


6. Agent vs App

Agent(已有 ai_agent) App(新建,Phase 3)
是什么 人设 + ASR/LLM/TTS/插件配置 业务容器(英语老师、口算…)
谁用 每台设备当前绑定一个 儿童可订阅多个,同时只 Active 一个
Phase 1 继续用 Agent 跑 Chat 不建 App 表也可以做复读 Demo

Phase 1 复读可以挂在「当前 Agent + 一个插件」,不必先有 App 实体。Phase 3 再把 Task Definition 归到 App 下。

不要把 ai_agent 改名为 App,也不要在 Agent 上堆 Workflow JSON 作为长期模型(临时可以,正式模型见第 10 节)。


7. Task Runtime(Server 权威)

7.1 职责

加载 Task Definition
创建 TaskInstance
按 Step 推进
设置 Connection.interaction_mode
下发 skill.execute / MCP
等待 Device Event 或 ASR 完成
写 StepInstance
决定下一步 / 结束 / 失败

运行时可活在 ConnectionHandler 旁的 TaskRuntime 对象(每连接一个当前 Instance)。持久化在 manager-api。

7.2 状态

CREATED → READY → RUNNING
  → WAITING_DEVICE | WAITING_USER | WAITING_AI
  → COMPLETED | FAILED | CANCELLED | TIMEOUT

设备只缓存 RUNNING 的当前 step;重连后 Server 重放或结束。

7.3 Definition 与 Instance 分离(保留 V1.0)

Definition:模板(英语复读 10 遍)。
Instance:某日某设备的一次执行(进度、状态、结果)。

7.4 Phase 1 特例

没有正式 Runtime 也可以:

插件 english_repeat(n, resource)
  loop: MCP play → wait play.completed 或超时
  mode=PLAY_AUDIO 期间禁止 chat()

这是为了验证链路;Phase 2 用 JSON Step 替换该循环。


8. InteractionMode 在 Server 的含义

Server 是 Mode 的 指定者:

Step.mode = PLAY_AUDIO | FOLLOW_READ | CHAT | LISTEN | …
  → conn.interaction_mode = …
  → 可选下行 mode.set(Phase 2)
Mode Server 行为
CHAT 现有 startToChat / chat()
PLAY_AUDIO 不 ASR 对话、不 LLM;驱动 play;等完成事件
FOLLOW_READ 先 play,再收听;ASR 文本进 Step;**不**进 Dialogue/LLM
LISTEN 只 ASR,结果给当前 Step
QUIZ/GAME Phase 3:出题在 Server,设备 CHAT 或 TTS+LISTEN

V1.0 的「Interaction Runtime 作为独立服务」降级为 ConnectionHandler 上的 mode 字段 + TaskRuntime 策略表。


9. 音频架构

9.1 现状

  • 入:Opus 流;内部 ASR PCM 16k
  • 出:Opus(hello 里常见 24k / 60ms)
  • 落库:chat_history_conf==2 时 PCM/Opus 转 WAV 进 ai_agent_chat_audio.audio(注释写 opus,实际 WAV)
  • audio_id 仅在上报后存在;history 有 session_id,**无** task/step

9.2 原则(保留 V1.0)

跟读/评估不要只存 ASR 文本。原始音频是可重分析资产。

但 Phase 1 复读 可以不存用户音频(用户可能没说话)。

9.3 演进

Phase 2 最小:

沿用 reportHandle WAV 上报
字段增加 task_instance_id, step_instance_id, purpose=follow_read
audio_id 写入 step_instance
仍可暂存 BLOB

Phase 2+ 目标(V1.0 对象存储):

DB: audio_id, user/device, task/step, storage_key, duration, format, sample_rate
Blob: 对象存储 raw wav/opus
不要把长期课程音频继续堆在 MySQL LONGBLOB

Segment: 跟读一步一段用户音频即可;单词级切分放到评估模型需要时再做。不要 Phase 2 就上完整 AudioSession 树。

设备文件录音 / pending 上传: Client Phase 3;Server 预留 upload API,不阻塞跟读 v0。

时间戳:连接级足够做 v0;NTP 与精确 latency 放评估 Phase 3。Sening 已有时钟同步指令,可复用,不算 Server 新服务。


10. 数据模型

10.1 现有表(保留,Chat 继续用)

表 作用
sys_user 账号
ai_device 设备;user_id agent_id mac_address
ai_agent 人设与模型;chat_history_conf
ai_agent_chat_history 会话文本;session_id audio_id chat_type
ai_agent_chat_audio 音频 BLOB
ai_agent_plugin_mapping Agent ↔ 插件
ai_ota / 模型 / RAG 等 与 Task 无关,不动

Chat 历史 不要改语义去存 Task;用新表或可空外键扩展。

10.2 Phase 2 最小新表

task_definition     id, app_id(可空), name, version, json_body, interaction 默认 mode
task_instance       id, device_id, task_definition_id, session_id,
                    status, current_step, started_at, ended_at
step_instance       id, task_instance_id, step_index, mode, status,
                    audio_id, asr_text, result_json, started_at, ended_at

第一期 json_body 可内嵌 steps,不必先拆 task_step 定义表。

10.3 Phase 3+(V1.0 清单的子集,按需)

app / app_version / app_subscription
plan / schedule
audio_segment          # 从 chat_audio 迁出
assessment / assessment_metric
user_metric_baseline
daily_summary

V1.0 的 emotion_signal、developer 宽表 不要列入 Phase 2 DDL。

Child 实体:现网是 User+Device。Phase 3 若需要「一个家长多个孩子」再拆 child;Phase 1–2 用 user_id + device_id。


11. Assessment

保留 V1.0 原则,收紧落地。

11.1 三层(概念保留)

L1 任务对错 / 文本匹配     ← Phase 2 v0
L2 语音特征(语速、停顿)  ← 异步,Phase 3
L3 趋势 / 基线 / 参与度    ← 要有足够 Instance

情绪只做 信号 不是诊断(V1.0 §20 保留),且 晚于 L1。

11.2 英语跟读 v0(Phase 2)

expected_text vs ASR text
→ 准确率 / 是否说完
→ 即时 TTS 反馈(走现有 TTS)
→ 结果写入 step_instance.result_json

不在 Phase 2 上发音模型、音素对齐、word timing(有则存 ASR 原始 JSON,评估器后补)。

11.3 口算 / 倒背 / 成语

归 Phase 3+ Task Definition,用 QUIZ/GAME + ASR 解析。**不要**为它们先改 Client。

11.4 评估版本化(保留 V1.0)

assessment.model_version
同一 step 可追加新评估行,禁止覆盖旧结果

实时路径只做 L1;L2+ 走队列,避免卡住 TTS。


12. 协议与 API

12.1 设备协议

Phase 1:只增加 MCP 调用(已有 type=mcp)。Server 主动 tools/call 播放。

Phase 2:与 Client Plan 相同的 task.* / mode.set / 完成事件。Python TextMessageType 增加枚举,Handler 与 hello/listen/mcp 并列。

二进制 Opus 不改。MQTT 网关 16 字节头逻辑保持。

12.2 HTTP API(manager-api)

Phase 1:可无新 API(插件 + 管理端现有配置足够触发 Demo)。

Phase 2:

POST /task/instance          启动(deviceId, taskId, params)
GET  /task/instance/{id}     查询状态与 steps
POST /agent/chat-history/report  扩展可选 task/step 字段(兼容旧客户端)

Phase 3:

/apps /resources /schedule /assessment /reports

V1.0 一次铺开 /analytics /developer —— 后置。

上报仍走现有 manage_api_client.report,避免再造一条聊天管道。


13. Plugin / MCP 复用

Server Plugin     编排、业务判断、调 ASR 结果
Device MCP        播放、音量、屏、下载(设备 Skill)
Server MCP        外部工具,与 Task 无强绑定

英语复读 Phase 1:Server Plugin 调 Device MCP。
不要把复读写进固件,也不要新建与 UnifiedToolHandler 平行的第二套工具总线。


14. smartlearning 吸收策略

已有能力 归属
课程 JSON / manifest Phase 3 App Resource;权威迁入 manager-api
MQTT DOWNLOAD / PLAY_MEDIA Client 板级已实现;Server 最终经 Xiaozhi 连接下发同等语义
场景识别 HTTP 不进入 Xiaozhi 主链路,除非产品明确要

禁止让 Xiaozhi Server 与 smartlearning 长期双写同一设备状态。Phase 1 Demo 若只能跑 Sening,允许暂时打 snlp,但 Coding Plan 必须标明技术债。


15. 分阶段(Server)

与 Client Plan 编号一致。

Phase 1 — 复读编排,不破坏 Chat

  • ConnectionHandler.interaction_mode:CHAT | PLAY_AUDIO
  • PLAY_AUDIO 时:不 chat()、不把课程当用户意图
  • 插件:循环 N 次 MCP/PLAY_MEDIA(或等价)
  • 不建 Task 表、不评估、不改 history 语义、不拆微服务
  • Chat 回归:mode 回 CHAT 或连接仍按现网 listen

验收:管理端或一句触发可让设备复读;同时唤醒聊天与现网一致。

Phase 2 — Task Runtime 切片 + 跟读 v0

  • task_definition / task_instance / step_instance
  • 协议 task.* + mode.set(若 MCP 不够表达步进)
  • FOLLOW_READ:ASR 写入 step;扩展 report 关联 audio_id
  • Assessment v0:文本比对 + 结果 JSON
  • 仍不要求对象存储、基线、情绪、家长小程序

验收:一次跟读 Instance 可查询到各 step 的音频与文本与分数。

Phase 3 — 平台与评估深化

  • App / Resource Sync(吸收课程清单)
  • Schedule / Plan(家长「每天 19:30」)
  • 音频迁对象存储
  • 异步 Voice Feature;可选 Baseline
  • QUIZ 等新 Task 只加 Definition,不加固件业务
  • 再往后:Emotion Signal、Subscription、Developer API(V1.0 后半段)

16. 禁止事项(Server)

  1. 为 Task 重写 ASR/TTS Provider 或 WS 帧格式
  2. 用 play_music 冒充课程复读
  3. 把 Task 行塞进 ai_agent_chat_history 当正式模型
  4. Phase 1 上情绪/心理/参与度大盘
  5. Phase 1 拆微服务 / 上独立 MQ 评估集群
  6. 改 hello/listen/tts 字段含义
  7. 让设备成为 Step 权威
  8. 未读 ConnectionHandler 就新写一套对话服务器
  9. 与 smartlearning 永久双栈调度

17. AI Coding 约束

  1. 先读 connection.py、receiveAudioHandle.py、reportHandle.py、Agent 上报 API、现有表结构。
  2. 默认 Chat 必须可关 Task 独立运行。
  3. 实时路径只做 Mode 分流与 L1 评估;重分析异步。
  4. 新表新协议都要向后兼容旧设备(忽略未知 type / 可空 task 字段)。
  5. Phase 1 能用插件解决则不改 Java DDL。

18. 与 Client Plan 的契约

Server 保证:

  • CHAT 连接行为向后兼容
  • 非 CHAT mode 不误触发 LLM
  • Instance 权威状态可查询
  • Phase 2 音频能挂到 step

Server 要求 Client:

  • 提供可调用的 play_audio(至少一块目标板)
  • FOLLOW_READ 时继续上传 Opus
  • 完成事件可关联 session / instance
  • 不在固件写评估

统一验收链(目标态):

Server 创建 Instance → mode + skill → Device 执行 → Event/Audio → ASR → Assessment → 查询 Instance

Phase 1 只验证前半:创建意图 → play 循环 → Chat 仍可用。


19. 下一阶段

下一步不是实现评估平台,而是产出:

Phase 1 Coding Plan
  ├── Server:mode 旁路 + 复读插件
  ├── Client:复用 MCP/PLAY_MEDIA + 音频互斥(已有 PauseSdCardMp3)
  └── 回归:现有 Chat E2E

V1.0 中的家长报告分级、跨任务分析、开发者分成等,保留为 Phase 3 以后的产品附录,不进入近期架构施工图。