# xiaoda **Repository Path**: chging/xiaoda ## Basic Information - **Project Name**: xiaoda - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-07-07 - **Last Updated**: 2026-07-08 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 小搭 · 桌面 AI 生活伙伴 > 定位:住在你桌上的靠谱伙伴——你正常跟它说话,它正常帮你把事办了。 > 架构原则:**端侧轻量化 + 云端 LangGraph 大脑 + 手机 App 承接高风险操作** > 对外一句话:**它陪你,但不监视你。** 本仓库为三端完整实现(技术方案 V2.1,含开发期修订:设备端底座改为 ESP-ADF 官方 Coze Agent 音频方案、C6 从机固化不升级、新增设备侧 MCP)。 | 模块 | 技术栈 | 状态 | | --- | --- | --- | | [xiaoda_app](xiaoda_app/) 手机 App | Flutter | ✅ 可运行,APK 已产出,7 项单测通过 | | [xiaoda_cloud](xiaoda_cloud/) 云端 | FastAPI + LangGraph | ✅ 可运行(dev 零依赖),12 项单测 + 端到端冒烟通过 | | [xiaoda_device](xiaoda_device/) 设备固件 | ESP-IDF + ESP-ADF (P4+C6) | 📐 代码完成,待硬件编译验证 | --- ## 一、总体架构 ```text ┌──────────────────────────────────────────────────────────┐ │ 桌面设备(ESP32-P4 + ESP32-C6) → xiaoda_device │ │ 唤醒 / AFE前处理 / 本地命令词 / Opus编解码 / LVGL UI / 灯效 │ └───────────────┬──────────────────────────────────────────┘ │ WebSocket(Opus音频流) + MQTT(状态/任务下发) ┌───────────────▼──────────────────────────────────────────┐ │ 云端 → xiaoda_cloud │ │ voice-gateway ── agent-core(LangGraph) ── memory-service │ │ │ │ │ │ │ 流式ASR/TTS task-scheduler PG+pgvector │ │ │ Redis │ │ push-service │ └───────────────┬──────────────────────────────────────────┘ │ APNs/厂商推送 + 深度链接 ┌───────────────▼──────────────────────────────────────────┐ │ 手机 App(Flutter) → xiaoda_app │ │ 账号授权 / 记忆管理 / 任务中心 / 高风险确认 / 打车外卖跳转 │ └──────────────────────────────────────────────────────────┘ ``` 职责边界(第一天就画死,不许越界): | 层 | 只负责 | 坚决不做 | | --- | --- | --- | | 设备 | 听、说、显示、灯光、本地高频命令 | 任何模型推理、任务逻辑 | | LangGraph | 单回合内的理解、决策、工具编排、风险门 | 记忆存储、定时调度、语音编解码 | | 图外服务 | 记忆读写、任务调度、推送 | 对话逻辑 | | App | 授权、支付确认、隐私管理 | 常驻对话入口(那是设备的事) | --- ## 二、硬件方案 ### 2.1 模块清单 | 模块 | 选型 | 说明 | | --- | --- | --- | | 主控 | **ESP32-P4**(双核 RISC-V @400MHz,PIE AI 扩展) | UI、音频前处理、状态机 | | 无线 | **ESP32-C6**(SDIO 连接,esp-hosted 从机) | Wi-Fi 6 / BLE 配网 | | 麦克风 | **双数字麦 + 1 路回采参考**(不是 3 麦) | ESP-SR AFE 最多 2 麦 + 1 ref | | 音频 Codec | **ES7210(4ch ADC:2麦+1回采)+ ES8311(DAC)** | 无回采通道的 ES8388 不予考虑 | | 功放 | **TFA9894**(smart amp,带 DSP 与扬声器保护) | 复用现有料号与调试经验 | | 扬声器 | 2 英寸全频 + 被动振膜 | 目标"卧室级温暖好声音" | | 屏幕 | 1.3–2.8 英寸 **QSPI 接口**小屏 | 不走 MIPI-DSI | | 灯光 | RGB 灯环(RMT 驱动) | 状态/呼吸/情绪灯效 | | 交互 | 顶部触摸 + 实体确认键 + **物理麦克风拨杆** | 硬件级断麦,用户可见 | | 供电 | Type-C 5V/2A | 第一版不做电池 | | 存储 | Flash 16MB + PSRAM 32MB | UI 资源、Opus 缓冲、双分区 OTA | ### 2.2 硬件层关键决策 1. **回采参考通道是刚性需求**:支持"边放音乐/TTS 边被用户打断"(barge-in), AEC 必须拿到功放输出回环信号。ES7210 第 3 通道接功放回采, 沿用 P4-Function-EV-Board 原生方案。 2. **唤醒词定制有商务周期**:WakeNet 自定义唤醒词走乐鑫付费定制(数周), Demo 用预置词,品牌唤醒词在 ID 定型时同步下单,**列入项目里程碑**。 3. **OTA(V2.1 修订)**:P4 主固件双分区 OTA + 回滚; **C6 esp-hosted 从机固件固化,不做从机升级**——C6 定位为固定的 Wi-Fi 模块,esp-hosted 对 P4 的 OTA 流量完全透明。 4. **安全基线**:Flash 加密 + **Secure Boot v2** 双开,设备唯一证书烧录 eFuse,TLS 双向认证。 ### 2.3 开发路径 阶段 2 直接用 **ESP32-P4-Function-EV-Board**(板载 C6-MINI-1、 ES8311/ES7210、触摸屏接口、32MB PSRAM)跑通交互闭环,再画自有板。 --- ## 三、设备端软件(xiaoda_device,V2.1 修订版技术路线) **不从零写固件。** 底座与移植关系: | 来源 | 内容 | | --- | --- | | **ESP-ADF 官方 Coze Agent 例程**(底座) | 音频前端全套:`audio_recorder` 引擎(AFE: AEC/NS/VAD + WakeNet + MultiNet)、播放管线、esp_audio_codec Opus——前端音频调试问题由官方方案解决 | | **xiaozhi-esp32**(移植其设计) | ① OTA:版本检查/激活码/服务器配置下发/回滚保护协议;② MCP:设备侧工具(音量/模式/状态)经消息通道供云端 LLM 调用 | | **自有实现** | 全局状态机(含离线态)、与自有 voice-gateway 的协议、双通道网络仲裁、LVGL 状态 UI、灯环状态语言 | **不接 Coze / 小智服务器**,协议对齐自有云端 `xiaoda_cloud`。 ### 3.1 FreeRTOS 任务划分 ```text audio_task recorder引擎事件(唤醒/VAD/命令词) + 净化PCM→Opus上传 playback_task 句级流水播放(首句即播)+ Opus解码 + barge-in打断 local_cmd_task MultiNet 命令词分发:"停止/音量/晚安模式/专注模式" ui_task LVGL 状态界面 + 字幕/确认卡片 led_task 呼吸/倾听/思考/待确认/执行 灯效(50Hz 引擎) network_task WebSocket(音频/对话/MCP) + MQTT(任务) + 在线仲裁 state_machine 全局状态仲裁(单一事实源) ``` **端云混合识别**:高频固定指令(静音、晚安、停止、音量)走 MultiNet 本地识别不出网——断网可用、低延迟、省 token。 ### 3.2 音频上行格式 **Opus 24–32kbps**(16kHz 单声道),不传 PCM。 ### 3.3 状态机(含离线态) | 状态 | 屏幕 | 灯光 | 触发 | | --- | --- | --- | --- | | 待机 | 头像/时间 | 低亮呼吸 | 默认 | | 唤醒 | "我在" | 光环亮起 | 唤醒词 | | 倾听 | 声波 | 光随声动 | VAD 活动 | | 思考 | "我想一下" | 慢速流动 | 尾点判停后 | | 执行 | 任务卡片 | 稳定光 | 工具调用中 | | 待确认 | 确认卡片 | 明显脉冲 | risk_gate 中断 | | 专注 | 极简时钟 | 低亮 | 番茄钟/白噪音 | | 睡前 | 晚安界面 | 渐暗暖光 | 晚安模式 | | 静音 | 断麦图标 | 灯光变暗 | 物理拨杆 | | **离线** | **"我掉线了"** | 灰色慢闪 | 网络断开 | 优先级仲裁:**物理断麦 > 离线 > 会话状态**。离线态是角色感底线: 本地命令词仍可控制,屏幕明确告知,绝不允许"叫不应、无反应"。 ### 3.4 设备侧 MCP 设备是一个 MCP server:JSON-RPC 2.0 经现有 WebSocket 以 `{"type":"mcp","payload":...}` 隧道传输(不新开连接),云端 agent-core 可调用 `self.get_device_status` / `self.audio.set_volume` / `self.mode.set` 等设备工具。 --- ## 四、语音链路与延迟预算 用户感知指标:**从说完话到设备开口 ≤1.8 秒**。 | 环节 | 预算 | 手段 | | --- | --- | --- | | VAD 尾点判停 | 300–500ms | AFE VAD(固件配置 420ms hangover) | | 流式 ASR | ~0(增量识别) | 火山流式 ASR,边说边转 | | 意图路由 | 200–300ms | 小模型(doubao-lite 档)结构化输出 | | LLM 首 token | 400–800ms | 强模型仅用于 chat_node | | TTS 首包 | 200–300ms | 火山双向流式 TTS | | 网络+编解码 | ~200ms | Opus + 就近接入 | 三条铁律:ASR 必须流式;**TTS 必须按句切分流水播放**(首句立即合成 开播,绝不等全文——网关 `sentencer.py` + 固件句级播放队列实现); 意图分类与闲聊分模型。 声音人格:豆包语音合成 2.0 音色经火山引擎 API 直调,不经 Coze。 --- ## 五、云端服务拓扑(xiaoda_cloud) MVP 单体部署(一个 FastAPI 进程),五个逻辑服务边界从第一天画清: ```text app/gateway/ voice-gateway WS(Opus/对话/MCP隧道) + 分句缓冲 + ASR/TTS抽象 app/agent/ agent-core LangGraph 单回合推理决策(见第六节) app/memory_service.py memory-service 读路径(同步<150ms) + 写路径(异步) + 夜间整理 app/scheduler_service.py task-scheduler APScheduler 扫任务表 → 主动图调用 app/push_service.py push-service MQTT设备下发 + App推送 + MCP工具调用 app/api.py REST 与 App 契约一致 + /confirm + /ota/check app/repos.py 存储层 内存实现(dev) ↔ PG+pgvector(生产, schema.sql) ``` ### 存储选型(收敛版) | 用途 | 技术 | 说明 | | --- | --- | --- | | 结构化数据 | **PostgreSQL** | 单库起步 | | 向量记忆 | **pgvector** | 十万级用户前不迁移 Milvus/Qdrant | | 缓存/轻量队列 | **Redis(含 Stream)** | 不上 Kafka | | LangGraph 检查点 | PG(AsyncPostgresSaver) | 与主库同实例 | | 对象存储 | 云厂商 OSS | 音频摘要、日志归档 | ### 模型矩阵 | 用途 | 档位 | 候选 | | --- | --- | --- | | 意图路由/实体抽取 | 快而便宜 | doubao-lite / deepseek-chat | | 闲聊/情绪对话 | 强模型 | doubao-pro / DeepSeek / Claude(可切换) | | 记忆抽取(异步批处理) | 中档 | deepseek-chat | | ASR / TTS | 云 API | 火山流式 ASR + 豆包 TTS 2.0 双向流式 | dev 模式(默认):内存后端 + Mock LLM/ASR/TTS,零外部依赖跑通全链路。 --- ## 六、agent-core:LangGraph 设计 ### 6.1 State ```python class AgentState(TypedDict, total=False): messages: Annotated[list, add_messages] # 短期对话,checkpointer 托管 user_id: str trigger: str # "voice" | "proactive" | "app" intent: str # chat | task | query context_pack: dict # 记忆读路径组装的上下文 pending_action: dict | None risk_level: str # low | medium | high ``` ### 6.2 图结构(实现修订:interrupt 与副作用分离) ```text entry → assemble_context 读记忆(同步,预算<150ms) → router 小模型意图分类 + 槽位抽取(一次调用双产出) ├─ chat_node 强模型,流式回复(闲聊/情绪/睡前) ├─ query_node 天气/路线/查询类工具 → 回复 └─ task_plan_node 组装动作方案 → risk_gate 风险分级门(纯路由,无副作用) ├─ low → execute_tools → respond ├─ medium → await_voice_confirm(interrupt) ← 图持久化暂停 └─ high → push_to_app(落确认单+推送) → await_app_confirm(interrupt) → respond 统一出口 ``` > 实现要点:`interrupt()` 恢复时会**重跑所在节点**,因此有副作用的 > push_to_app 必须独立成节点,等待节点内只做 interrupt 与决策处理。 ### 6.3 确认流的恢复路径 - **语音确认**:网关收到下一句 ASR 结果,`AgentService.handle_utterance` 检测 thread 停在等待节点 → 确认语义 → `Command(resume={"approved": True})`。 - **App 确认**:`POST /confirm/{thread_id}` → 同样 `Command(resume=...)`。 - 同一套 interrupt/resume 覆盖两条确认路径,跨设备一致性由 PG checkpointer 保证。thread_id = `{user_id}:{date}`,按天切, 跨天连续性交给记忆系统。 ### 6.4 角色人格层 人格是 assemble_context 注入的 prompt 资产(`app/llm.py PERSONA_SYSTEM`): 自然、平等、温和、偶尔损一句,不卖萌;不暧昧、不撒娇、不叫主人、 不制造情感依赖;低频克制;带着默认方案来确认;低置信记忆先口头求证。 --- ## 七、记忆系统(图外,产品护城河) ### 三层 Schema ```json // 画像(每次全量注入) {"食物偏好": "偏辣,不爱奶茶", "作息": "00:30后睡", "互动偏好": "不喜频繁打扰"} // 事件(pgvector 检索注入) {"event": "周五上午面试", "time": "...", "confidence": 0.92, "status": "待提醒"} // 日摘要(夜间任务生成) {"date": "...", "summary": "项目压力大...", "emotion": "疲惫", "follow_up": "..."} ``` ### 读写路径 - **读**(同步 <150ms):画像全量 + 今明任务直查 + pgvector top-5。 **confidence < 0.8 的记忆带 [未确认] 标记注入**,prompt 规定先口头求证。 记错比不记更伤信任,此机制不可省。 - **写**(异步):回合摘要 → 队列(生产 Redis Stream)→ worker 攒批调 抽取 LLM → 三层 schema 候选写入。绝不阻塞对话回合。 - **夜间整理**:合并重复、衰减过期事件、生成日摘要。 ### 记忆准入 只记:长期偏好、明确事件、用户主动"帮我记住"、高频习惯。 不记:临时情绪碎片、未确认敏感推断、未授权联系人细节。 App 记忆页直读记忆表:**逐条可见、逐条可删、删除即物理删除**。 --- ## 八、任务系统与主动性(图外) 任务类型固定八种:reminder / todo / calendar / query / draft / food_prepare / taxi_prepare / sleep_routine。 **路由用小模型分类 + 显式条件边,不引入动态 planning**;LangGraph 的价值是 interrupt/checkpoint/streaming 三件套,而非自由编排。 task-scheduler 每分钟扫描到期任务 → **系统触发的图调用**(同一张图、 同一当日 thread)→ 提醒是带上下文说出来的 → TTS → MQTT 下发设备 亮灯播报。可靠性约定:先标记再播报,播报失败重置回 pending 重试 (提醒一次都不能漏)。 --- ## 九、工具系统:打车/外卖(prepare 模式) 第一版铁律:**设备只做方案准备,手机完成确认与支付。** - **打车**:设备无 GPS,**出发地 = 设备绑定的家庭地址**(App 配网时 设置),不在家场景整条链路自然回落手机。 路线查询 → 估算出门时间 → taxi_prepare 任务 → 到点提醒 + App 确认 → 深度链接跳转高德/滴滴。 - **外卖**:读画像(口味/预算/本周已点)→ 三选一推荐(语音+屏幕卡片) → 语音选择 → App 确认 → 深度链接跳转美团/饿了么。 不做自动支付、不做平台自动化下单。供给侧优先级:高德聚合打车 API > 外卖深度链接跳转 > 任何形式的自动化。 --- ## 十、App 方案(xiaoda_app) 微信小程序无主动推送,撑不起"设备触发 → 手机弹确认",因此阶段 2 起 用 Flutter 原生 App。模块全部实现: 设备绑定(BLE 配网 + 家庭地址)/ 账号授权(外卖/打车/日历)/ 记忆管理(三层 Tab、未确认标记、物理删除)/ 任务中心 / 高风险确认(确认卡片 + 三选一 + `POST /confirm/{thread_id}` + 深度链接)/ 角色设置(音色、主动频率)/ 隐私设置(情绪/位置/联系人分类开关 + 全量删除)。 BLE/推送/云端 API 均走抽象接口(Mock ↔ 真实实现可切换), `lib/core/config.dart` 的 `useMock=false` + `baseUrl` 即接真实后端。 --- ## 十一、通信与安全 | 链路 | 协议 | 用途 | | --- | --- | --- | | 设备↔云 | WebSocket(TLS) | 实时 Opus 音频流、对话、MCP 隧道 | | 设备↔云 | MQTT(TLS) | 状态上报、任务/灯效下发、主动提醒 | | 设备↔云 | HTTPS | OTA 检查/下载、激活、配置 | | 设备↔手机 | BLE | 配网、近场绑定 | | 云↔App | APNs/厂商推送 | 高风险确认、执行结果 | 安全基线:TLS 全链路 + 设备唯一证书(eFuse)+ Flash 加密 + Secure Boot v2 + P4 双分区 OTA(含回滚)。 ## 十二、隐私设计 物理麦克风拨杆(硬断麦、用户可见)/ 本地唤醒(未唤醒不上传音频)/ 记忆可查看、可删除、可分类关闭(情绪/位置/联系人)/ 高风险操作强制 确认 / 不做摄像头 / 不做暧昧成瘾与强情感依赖设计。 --- ## 十三、MVP 三阶段 1. **阶段 1 纯软件验证**(小程序,2–4 周):仅验证需求"用户是否需要 一个记得他生活的伙伴"。指标:D7/D30 留存、日均语音次数、记忆授权率、 晚安仪式完成率、提醒完成率、付费意愿。**D30 留存不达标,硬件不开模。** 同期并行:唤醒词定制下单、本仓库后端开发(已完成)。 2. **阶段 2 开发板 Demo**(P4-Function-EV-Board,4–8 周):本仓库三端 联调,闭环两条链路,全链路延迟压到 ≤1.8s。**当前所处阶段。** 3. **阶段 3 ID 样机**(3 方向 × 5–10 台,30 天真实试用):验证桌面 C 位 意愿、外观方向、899–1299 元付费意愿。 ### 两条生死链路(开发取舍以不阻塞它们为准) ```text 链路A(记忆+任务+主动性): "明天上午提醒我问供应商外壳进度" → router(reminder) → 写任务表 → "记下了" → 次日10点 scheduler 触发 proactive 图调用 → 带上下文生成提醒语 → MQTT 下发 → 设备亮灯播报 ✅ 已端到端验证 链路B(风险门+跨设备确认): "今晚不知道吃什么" → 读口味画像 → 三方案 → risk_gate(high) → push_to_app → interrupt 暂停落盘 → App 确认 → resume → 深度链接跳转下单 ✅ 已端到端验证 ``` --- ## 十四、运行与联调 ```bash # 云端(dev 模式,零外部依赖) cd xiaoda_cloud && python -m venv .venv && .venv/Scripts/activate pip install -r requirements.txt uvicorn app.main:app --port 8080 pytest # 12 项:两条链路 + REST/WS 契约 # 设备模拟器(无硬件联调,含 MCP 应答) python tools/device_sim.py ws://localhost:8080/ws/device demo-user # App(Flutter 3.44+) cd xiaoda_app && flutter pub get && flutter run flutter build apk --release # Android 安装包 # 连真实后端:lib/core/config.dart → useMock=false + baseUrl # 固件(需 ESP-IDF 5.3+ 与 ESP-ADF) cd xiaoda_device && idf.py set-target esp32p4 && idf.py build flash monitor ``` ## 十五、优先级(收尾原则) 1. 语音链路稳定(全链路 ≤1.8s,打断可靠) 2. 记忆系统可控(confidence 机制 + 可删除) 3. 提醒任务可靠(一次都不能漏) 4. 角色表达自然(prompt 资产持续迭代) 5. 风险门万无一失(宁可多确认,不可误执行) 6. 状态反馈完整(含离线态) 7. 音频体验不差(TFA9894 调音值得花时间) 8. App 授权与隐私管理完整 红线:自动支付、消息代发、摄像头一律不做;Coze 永远不进核心链路 (记忆存储、任务系统、风险门、设备协议、主动调度)。