EdgeHippo · MVP 产品设计与软件开发任务书
代号 EdgeMemory-MVP | 载体:ESP32-S3 N16R8(板 B)+ N8R8(板 A) | v1.2 | 2026-10-26
上游输入:《EdgeMemory 市场与产品战略报告 v1.0》(2026-10-26)
本文档把该报告的战略结论转译为可执行的工程任务 :硬件分工、软件分层、数据模型、任务清单(WBS)、三场景知识库规格与测试用例集。
修订说明(v1.0 → v1.1 → v1.2)
本版针对三条反馈做了修订,其中第一条的结论与直觉相反 :OTA 对容量的影响不是「要不要」的问题,而是「槽开多大」的问题。
反馈 v1.0 的做法 v1.1 的修订与结论
① OTA 是否保留 未分析,默认沿用现有双槽(各 4 MB) 建议保留 OTA,但把 app 槽从 4 MB 压到 2 MB。 实测固件 1.59 MB 却占着两个 4 MB 槽,白扔 4.8 MB。压缩后 edgehippom 从 7.875 MB 提到 11.875 MB ,容量 8,000 → 14,448 条 (推算、未实测 ;v1.1 当时按旧几何推算是 12,900 条),且 OTA 能力完整保留。详见新增 3.5 节
② MVP 不接传感器 W4-01 要求板 A 挂振动/温度/电流传感器 全部改为确定性合成数据源。 MVP 只用基础主板,不接任何外设传感器。收益:可复现、可回归、零接线工作量、不占 RAM。代价:真实采集吞吐验证推迟到 P1。详见 6.4 节 与 S1 场景修订
③ eXtremeDB 优势必须保留 只说「emdb 后端替换,接口不变」 新增 4.4 节「优势保留矩阵」 :把 eXtremeDB 的 14 项能力逐条映射到 emlite 的设计约束与验收点,确保替换前后行为与性能特征一致。尤其锁定三条 Andrei Gorine 反复强调的硬约束:malloc-free、事务感知的 flash 管理、截止时间可分析
关于「每日邮件」中 Andrei 与 Steve 的材料: 本地文件与邮件中均未检索到原文存档(已全盘检索 D:\OneDrive\文档\SmartEDB 与邮箱,无 Andrei/Steve 关键字命中)。本版改以两人的公开发表材料 为依据:
· Steve Graves(CEO) :2026-09-01《How eXtremeDB ANN indexes and time series / sensor data fusion work together》;《Justifiably Taboo: Avoiding malloc-free APIs In Military/Aerospace Embedded Code》。
· Andrei Gorine(CTO / 联合创始人) :eXtremeDB/rt 2.0 发布声明(2025-10-23,xFile / xFlash / TFTL / 截止时间策略);ODBMS.org 深度访谈《When a Millisecond Is a Promise》;Dr. Dobb's 内存管理文章(eXtremeDB 运行时不调用 malloc);eXtremeDB/rt 服务版发布(2026-06-15,1 GB flash 库仅需 40 KB 内存)。
若手头那批「每日邮件」能导出存档,可据此再校核一轮——尤其关注是否有未公开的 ANN 参数与 MCU 端 footprint 数据。
v1.1 → v1.2 修订(方案 C 专项评估)
问题 v1.1 的假设 v1.2 的实测与结论
方案 C(app 槽 1.5 MB)是否更合适 评价为「⚠️ 固件余量仅 0.3 MB,加回功能模块即爆」——按裁剪后固件 ≈ 1.2 MB 估算 实测推翻该估算,方案 C 应从「激进」改判为「不可行」。 实测裁剪 cam/mic/gps 只能省约 120 KB (而非 400 KB):三个自有模块 .text 合计仅 8.4 KB,大头是 esp32-camera 组件 83.7 KB + I2S 驱动 31.1 KB。MVP 完整态固件预计 ≈1.45 MiB ,1.5 MB 槽余量 <5% ,且 MVP 还要新增 TinyUSB(+60–100 KB)与 emlite(+30–50 KB)。结论:维持方案 B(2 MB 槽) 。详见新增 3.5.7 节
目录
修订说明(v1.0 → v1.1)
执行摘要:三条硬发现与产品定义
MVP 边界:做什么 / 明确不做什么
硬件基线:双板分工与容量实测口径
3.5 OTA 与分区决策(v1.1 新增 / v1.2 修订)
3.5.7 方案 C 专项评估(v1.2 新增)
软件架构:五层 + 双后端引擎 HAL
4.4 eXtremeDB 优势保留矩阵(v1.1 新增)
数据模型:schema 草案
软件开发任务总表(WBS)
场景 S1:工业设备振动故障指纹库
场景 S2:野外巡检记忆包与物理接力
场景 S3:专业私域知识库(首销 SKU)
测试用例集(三场景 + 非功能)
里程碑、Go/No-Go 与工时汇总
风险登记与已知工程坑
一、执行摘要:三条硬发现与产品定义
硬发现 ①|eXtremeDB SDK 目前不在开发机上。 已全盘检索 C:\emgw-build 与 C:\Espressif,未找到任何 McObject / eXtremeDB 的头文件、库或组件(components/ 下只有 esp32-camera)。这意味着「引擎层」不能作为 MVP 的前置依赖 ,否则整个项目会被授权谈判单方面卡死。
工程对策:引擎层做成双后端 HAL。 先自研 emlite 后端(纯 C,flash-backed HNSW + 列式时序环 + WAL 事务),让 P0 全部闭环可以在不等授权 的情况下跑通并拿到实测数据;eXtremeDB 到位后作为 emdb 后端替换,接口不变。这样授权谈判从「阻塞全部」降级为「性能与成本优化项」。
硬发现 ②|真实可用容量比战略报告推算的少 30%。 报告第 6 章按「Flash − 固件」粗算,给出 N16R8 ≈ 11 MB 可用。但按本机
实际分区表 partitions_emgw_16m.csv,引擎分区(旧线性库分区)只有
0x7E0000 =
7.875 MB ;8 MB 版更是只有
0x200000 =
2.0 MB 。重新测算后,容量档位应从「16,000 / 6,000 条」下修为
「10,000 / 2,500 条」 。
工程对策: ①
v1.1 进一步发现:容量损失主要不是来自 flash 总量,而是 app 槽开太大 ——固件只有 1.52 MB 却占着两个 4 MB 槽。压缩到 2 MB ×2 后,
edgehippom 提到 11.875 MB / 3.875 MB,档位
上修为 14,448 / 3,419 条 (
推算、未实测 ,口径
rec_pages×4080×85%/644;v1.1 旧推算为 12,900 / 3,700),且 OTA 完整保留。详见
3.5 节 ;② 所有对外叙事一律用实测口径,不要用报告里的推算值。
硬发现 ③|好消息:双板互联已经跑通了。 现有 link_mgr.c(1459 行)+ NimBLE 已实现双板互联与碎片同步,A/B 两板分别固化形态标识(Dev-A = form=gamma-card,Dev-B = form=usb-dongle,均为对等外设本体、无上下级),MAC 与设备 ID 已写入 eFuse。也就是说 MVP 的 α 形态(模组嵌入宿主)验证不需要新增任何硬件工作 ,直接复用。此外 em_store.c 已实现 edgehippom 分区的 append-only 记录日志与导出/压缩,可作为 emlite 的存储底座改造起点。
v1.2 补注(ADR-018): 本条原始描述为「1 gateway + 2 edge」「A/B 固化 role=edge / role=gateway」,那是上一代 EdgeMemory Gateway 架构的上下级分层残留,已废止。现行口径:两块板都是 EdgeHippo 外设本体,板级一律用形态 表达,对等无层级。
1.1 产品定义(一句话)
EdgeMemory-MVP = 一块 N16R8 板 + 一条 USB 线 + 一个拖进去的 .emf 包 = 一台完全离线可用的记忆外设;再用一块 N8R8 板作为宿主,证明这套能力可以作为「器官」被嵌进别人的设备。
要素 MVP 定义
产品名 EdgeHippo(EdgeMemory),MVP 版本 v0.1(内部代号 EdgeMemory-MVP)
形态 β 原型(USB Dongle)= 板 B(form=usb-dongle);γ 磁吸卡形态原型 = 板 A(form=gamma-card)。两者跑同一套固件,仅形态标识(form) 与容量档不同,对等无上下级 (ADR-018)
核心交易 宿主提供查询向量 → 板上做「相似度 + 时间 + 精确条件」的混合检索 → 返回命中的记忆条目与可回溯的时序证据 → 结果回写为新记忆(闭环)
唯一杀手级 UX 拖拽即灌库 :USB 上同时呈现一个串口和一个虚拟 U 盘,把 .emf 碎片包像拷 MP3 一样拖进去,设备自动校验 → 合并 → 建索引。零驱动、免安装、免联网
不可妥协的规格 断网状态下全部核心能力完整可用;检索路径不经过任何网络
1.2 与战略报告的对应关系
战略报告结论 本任务书如何落地
卖「能力」不卖「算力」 板侧不做 embedding、不跑模型;W4 只做统计/频谱特征,ML 特征一律由 Host/Hub 回写
单机即有完整价值 Go/No-Go ① 的验收全部在单板断网 条件下执行(见第 10 章 N 组测试)
碎片必须自洽、离线可验签 .emf 结构(第 5 章)+ W5-02/W5-03 打包器与校验器 + TC-F-* 验签测试
优先暴露 MCP,不做私有 API W3-05 MCP shim,三个场景统一走 MCP 查询接口,CDC 行协议只作调试面
必须绑定单一杀手场景 第 7–9 章三个场景各有独立验收与 Go/No-Go 判据,M9 由产品负责人基于实测拍板,不由市场部选
β 形态(¥399)为首个 SKU 板 B 就是 β 原型;S3 场景(私域知识库)即其定价锚验证载体
二、MVP 边界:做什么 / 明确不做什么
✅ 做(MVP 范围内)
板侧 flash-backed ANN 检索 (int8 / 384d / HNSW + IVF 粗划分)
板侧 时序写入与三级留存 (L0 原始环 / L1 分钟聚合 / L2 特征向量)
混合查询 :相似度 + 时间范围 + 设备/碎片/标签等精确条件,同一事务内
事务 :WAL + commit/rollback,随机掉电后库可开
记忆策略层 :工作/短期/长期三态、遗忘淘汰、近重复去重、重要性评分
闭环回写 :检索结果(含成功/失败)写回为新记忆
USB 复合设备 CDC + MSC;拖拽 .emf 灌库
MCP 接口 暴露记忆资源
PC 侧工具链 :embedding → 构图 → 打包 → 灌库 → 基准测试
三场景 知识库与测试用例
❌ 不做(明确划出边界)
板侧 embedding / LLM 推理 ——上一版报告已论证 S3 上无实用价值
算力共享 、token 积分、任何形式的结算——合规红线且战略已否决
检索路径上的 任何网络依赖 (Wi-Fi/BLE 只用于搬运与管理)
γ 磁吸卡(iOS USB 限制)、δ SD 卡形态(SDIO slave 待验证)——列为 P2 期权
多节点一致性 、分布式事务
摄像头 / 麦克风 / GPS——MVP 阶段从固件裁剪掉 ,见 W0-04(这三个模块占用大量 RAM 与 Flash,是容量与延迟的主要干扰项)
任何外接传感器 (振动、温湿度、电流、加速度计、ADC/I2C/SPI 外设)——v1.1 明确:MVP 只用基础主板,一根线不接。 时序数据一律用确定性合成数据源 注入板 A,详见 6.2 节
外壳、电池、量产认证(EMC/CE)——P2 阶段
关于裁剪摄像头/麦克风/GPS 的说明: 现有固件 cam_mgr.c(375) + mic_mgr.c(361) + gps_mgr.c(277) 加上 merged-*.bin 已达 1.59 MB,且 cam/mic 需要大量 PSRAM 缓冲。MVP 的目标是把尽量多的 RAM 让给 ANN 工作集 (报告第 6 章:成本主导项是 I/O 与 cache 命中,不是 CPU)。这三个模块在 α 形态评估阶段可按需重新启用,但不进 MVP。
2.1 MVP 验收总判据(Go/No-Go ①)
# 判据 阈值(全部必须达成)
G1 容量:N16R8 单板装入的记忆条数 可行性门槛 ≥ 8,000 条 ;按 3.5 节方案 B 分区(edgehippom 11.875 MB)目标 ≥ 12,000 条 (v1.1 上调;按新几何推算稳态约 14,448 条 ,未实测 )。库须可正常打开并检索
G2 延迟:12,000 条库上混合查询 P50 < 10 ms,P99 < 30 ms (板侧,不含 USB 往返),且 P99/P50 < 4(抖动可控)
G3 内存:检索过程 RAM 峰值 PSRAM 占用 ≤ 5 MB ,内部 DRAM 峰值 ≤ 180 KB (给 Wi-Fi/BLE/协议栈留余量)
G4 闭环:时序 → 特征 → ANN → 回写 全链路跑通,且回写的新记忆在下一次检索中可被命中
G5 UX:拖拽灌库 拖入 .emf 后 ≤ 60 s 完成 12,000 条合并并可查询(含校验);错误包必须被拒绝且不损坏原库
G6 断网:飞行模式 关闭 Wi-Fi/BLE 后,G1–G5 全部复测通过
G7 事务:随机掉电 100 次 库 100% 可打开,无条目数异常增长/丢失,最多丢失最后一次未 commit 事务
若 G1–G7 任一项未过: 按战略报告第 11 章的处理——回退为纯软件授权路线,不做硬件。但注意本任务书的对策: 若未过项是容量或延迟,且原因是 emlite 自研后端实现不佳,则应先尝试接入 emdb(eXtremeDB)后端再判;只有双后端都未过,才判硬件路线不成立。
三、硬件基线:双板分工与容量实测口径
3.1 双板分工(沿用现有资产,不新增硬件)
项目 板 A:Seeed XIAO ESP32-S3 板 B:S3-N16R8-DevKit
规格 8 MB Flash + 8 MB PSRAM 16 MB Flash + 8 MB PSRAM
MVP 形态(form) gamma-card γ 磁吸卡形态原型 usb-dongle β USB Dongle 形态原型 (首个自销 SKU)
形态代号 γ 磁吸卡形态原型 β USB Dongle 形态原型(首个 SKU 的原型)
MAC / 设备 ID 44:BD:8D:71:FA:C8 → EME-71FAC8 14:C1:9F:21:E9:80 → EME-21E980
现网 IP 192.168.1.46 192.168.1.5(知识库 4343 条 / 946 KB,改前必须 --backup )
app1 偏移 (W0-05 后两板同构;旧 0x300000 / 0x410000 作废)0x210000 0x210000
LED GPIO21(低电平点亮) WS2812 实测 GPIO48 (勿试 38)
MVP 主接口 BLE(与 B 互联,复用 link_mgr)+ 传感器输入 USB-OTG GPIO19(D−)/GPIO20(D+) 复合设备 + BLE
容量档位 (推算、未实测 ;按改分区表前的旧分区表)LITE ≈ 2,500 条(扩容后 4,500 条) BASE ≈ 10,000 条(扩容后 13,700 条)
两块板都是外设本体,差别只在形态与容量: 8 MB 版 edgehippom 为 3.875 MB,稳态约 3,419 条 (推算、未实测 ),装一个 1,800 条的专科专家包后仍有一倍余量,足以演示「专科大夫」这一叙事。差异只在容量与接口 :β 形态(板 B)走 USB-OTG 直插电脑,是首个自销 SKU;γ 形态(板 A)走磁吸卡贴附。两板对等、无上下级 ——旧的「A 做 HOST 宿主、模拟客户主控去调用 B」是上一代 EdgeMemory Gateway 的上下级分层残留,已废止(ADR-018)。
3.2 容量实测口径(按现状 分区表重算,替换报告第 6 章推算值)
v1.1 注: 下表是按现状 分区表(app 槽 4 MB / 2.94 MB)算出的保守值。按 3.5 节方案 B 压缩 app 槽后,实际档位应上修为 N16R8 ≈ 12,900 条、N8R8 ≈ 3,700 条 (均为推算、未实测 ),后续章节的容量数字以方案 B 为准。v1.2 补注(W0-05 已执行): 按新几何重算的权威值为 N16R8 ≈ 14,448 条、N8R8 ≈ 3,419 条 (同为推算、未实测 ,口径 rec_pages×4080×85%/644);本表(0x810000 / 0x5F0000)为改分区表之前 的历史账,已不再适用。
单条记忆成本:int8 向量 384 B + HNSW 链接(M=16) 128 B + 摘要 ≤150 B = 662 B;页/索引/元数据开销按 12% 计。
板 edgehippom 分区 字节 理论条数 规划口径 扩容选项
N16R8(B) 0x810000 / 0x7E0000 8,257,536 10,976 10,000 条 app 槽 4 MB → 2.5 MB,edgehippom → 9.875 MB ≈ 13,700 条
N8R8(A) 0x5F0000 / 0x200000 2,097,152 2,787 2,500 条 app 槽 2.94 MB → 2.25 MB,edgehippom → 3.375 MB ≈ 4,500 条
v1.2 修订(实测): app 镜像实测 edgehippom-<board>-<ver>.bin = 1,530,080 B(1.459 MiB) ,merged-devkit-16m.bin = 1,595,616 B。v1.1 假设「裁剪 cam/mic/gps 后降至 ~1.1 MB」不成立 ——按 .map 逐段统计,可裁剪部分仅约 120 KB (esp32-camera 83.7 KB + I2S 驱动 31.1 KB + cam/mic/gps 三个自有模块 8.4 KB),裁剪后约 1.34 MiB;MVP 还要新增 TinyUSB 与 emlite,完整态预计 ≈1.45 MiB 。因此 app 槽下限应为 2 MB (余量 ≈38%),1.5 MB 槽不可行。详见 3.5.7 节 。
3.3 碎片容量规划(由此倒推叙事)
碎片类型 条目规模 N16R8 可装 N8R8 可装 典型内容
专家记忆包 1,500–2,500 4–6 个 1 个 某人的会议/偏好/决策历史
设备档案包 400–1,000 10–25 个 3–6 个 某型号设备故障模式、工况参数、维修记录
域知识包 5,000–8,000 1–2 个 — 产品线 SOP、区域法规、质检标准
感知模式包 持续生长 按留存策略 按留存策略 闭环产出的时序特征向量
对外叙事必须诚实:卖的不是「随身带一个图书馆」,而是「随身带一个记得你 / 记得这台机器 / 记得这套工艺的专科大夫」。
3.4 引脚分配(MVP)
功能 板 B(usb-dongle) 板 A(gamma-card) 说明
USB-OTG GPIO19 D− / GPIO20 D+ — β 形态命脉。与 USB-Serial-JTAG 共用同一 PHY,同一时间只能一个工作
Console / 下载 UART0 GPIO43/44 UART0 GPIO43/44 MVP 把 console 从 USB-Serial-JTAG 切到 UART0,把 GPIO19/20 完整让给 OTG
板间互联(主) NimBLE(现有 link_mgr) NimBLE 已跑通,零新增硬件
板间互联(备) UART1 GPIO17 TX / GPIO18 RX UART1 GPIO17 TX / GPIO18 RX α 形态模组评估用(SPI 方案 P1 评估)。须在 boards/BOARD_*.md 核对实际引出情况
传感器输入 — 不接(v1.1 修订) 改用确定性合成数据源在板内生成,见 6.2 节 。真实采集推迟到 P1(W4-07)
LED WS2812 GPIO48 GPIO21(低电平点亮) 沿用现有状态机
USB 通道切换的三个坑(本项目已有实战经验,必须在 W0-02 一次性处理干净):
PHY 冲突: ESP32-S3 的 USB-OTG 与 USB-Serial-JTAG 共用 GPIO19/20 与同一个 PHY。要跑 TinyUSB 复合设备就必须让出 PHY。后果是不能再通过 USB 串口烧录和看日志 ——因此 W0-02 必须先把 console 切到 UART0,并在板 B 上接一个 USB-UART 转换器(CP2102/CH343)用于开发与排障。
sdkconfig 写法的坑: CONFIG_ESP_CONSOLE_* 是一个 choice 组。在 sdkconfig.defaults 里给其它成员写 =n 会导致整组失效、回退到默认 UART。正确做法是只给目标成员写 =y,绝不给其它成员写 =n。
VBUS 监测: 自供电设备需通过分压或比较器检测 VBUS(S3 引脚 3.3 V 耐压,不能直接接 5 V)。β 形态量产前必须处理。
3.5 OTA 与分区决策(v1.1 新增 / v1.2 修订)
v1.2 补注(2026-10-28 · W0-05 已执行):分区表方案 B 已落地,本章口径以本节为准。
分区名: 旧 edgemem(动态记忆分区)与 kb_static(静态知识库分区)
已删除并合并为单一引擎分区 edgehippom (subtype 0x42,起始 0x410000)。
两板分区表同构 ,只有 edgehippom 大小不同:
Dev-B(N16R8)= 0xBE0000 = 11.875 MB = 3,040 页 ;
Dev-A(N8R8)= 0x3E0000 = 3.875 MB = 992 页 。
烧录偏移: 0x0 bootloader / 0x8000 partition / 0xe000 ota_data /
0x10000 app0 / 0x210000 app1 。
旧的 app1 偏移 8MB 板 0x300000、16MB 板 0x410000 全部作废 。
容量(★推算、未实测★): 口径 rec_pages × 4080 × 85% / 644。
Dev-B rec_pages = 2,683 → 稳态约 14,448 条 ;
Dev-A rec_pages = 635 → 稳态约 3,419 条 。
本章其余各处出现的 12,900 / 3,700 条是 v1.1 按旧几何推算的旧值,同为推算、未实测,尚未按新几何逐表重算 (见下面 3.5.2 / 3.5.3 表下的口径说明)。
不可逆代价已发生: 改分区表 = 已灌记忆全部作废、必须整片重烧 + 重灌。
执行前已整分区镜像备份 C://emgw-build//backup_20261028//devb_edgemem_4MB.bin(4,343 条真实遥测)。
先给结论:OTA 强烈建议保留,而且它几乎不牺牲容量——真正吃掉容量的是「app 槽开得过大」。
现网固件实测 merged-devkit-16m.bin = 1,595,616 B ≈ 1.52 MB ,却被塞进两个 4 MB 的 OTA 槽,白扔了约 4.8 MB (相当于 5,900 条记忆)。把槽压到 2 MB 后,edgehippom 从 7.875 MB 提到 11.875 MB ,容量从 8,000 条涨到 14,448 条 (推算、未实测 ;v1.1 旧推算 12,900 条),而 OTA 能力完整保留 。
3.5.1 分区账怎么算
Flash 可用空间 = 总容量 − 头部(bootloader 0x0 + 分区表 0x8000 + nvs + otadata = 0x10000)− 尾部余量(0x10000)。
换算系数:1 MB edgehippom ≈ 1,227 条 (推算、未实测 )(662 B/条含 12% 开销 → 752 B/条)。时序区按 N16R8 = 1.375 MB、N8R8 = 0.875 MB 预留。
3.5.2 N16R8(板 B,16 MB)四种方案
方案 app 槽 ×2 edgehippom 记忆库 容量(推算、未实测 ) 评价
A 现状4 MB ×2 = 8 MB 7.875 MB 6.5 MB 8,000 ❌ 浪费 4.8 MB,无理由维持
B 推荐2 MB ×2 = 4 MB 11.875 MB 10.5 MB 12,900 ✅ +61% 容量,OTA 完整保留,代码零改动
C 激进1.5 MB ×2 = 3 MB 12.875 MB 11.5 MB 14,100 ❌ v1.2 改判:不可行。 实测裁剪后固件 ≈1.34 MiB,MVP 完整态 ≈1.45 MiB,1.5 MB 槽余量 <5%。只比 B 多 1,200 条(+9.3%)却承担爆槽风险
D 去掉 OTA单槽 2 MB 13.875 MB 12.5 MB 15,300 ⚠️ 只比 B 多 2,400 条,却失去回滚能力
OTA 的真实净代价 = B vs D = 2,400 条(−15.7%)。 而 B 相对现状 A 的收益是 +4,900 条(+61%)。也就是说:容量问题 87% 来自槽开大了,只有 13% 来自 OTA 本身。
推算口径说明(2026-10-28): 上表「容量」列为 推算值、未实测 (记忆库 MB × 1,227 条/MB)。W0-05 执行后按 rec_pages × 4080 × 85% / 644 重算,方案 B 的权威值应为 14,448 条 ;与表内 12,900 条的差异来自 ADR-015 压缩时序区后记录区占比提高,本表尚未按新几何重算 ——以本节开头的 v1.2 补注为准。
3.5.3 N8R8(板 A,8 MB)四种方案
方案 app 槽 ×2 edgehippom 记忆库 容量(推算、未实测 ) 评价
A 现状2.94 MB ×2 = 5.88 MB 2.0 MB 1.4 MB 1,700 ❌ 8 MB 板上最严重的浪费
B 推荐2 MB ×2 = 4 MB 3.875 MB 3.0 MB 3,700 ✅ +118%,余量 0.8 MB 仍充足
C 激进1.75 MB ×2 = 3.5 MB 4.375 MB 3.5 MB 4,300 ❌ v1.2 改判:不推荐。 1.75 MB 槽余量 ≈0.3 MiB(<20%);而板 A 只需装 1,800 条专家包,B 方案(推算 3,419 条、未实测)已有一倍余量,多 600 条无实际价值
D 去掉 OTA单槽 2 MB 5.875 MB 5.0 MB 6,100 ⚠️ 多 2,400 条,失去回滚
推算口径说明(2026-10-28): 上表「容量」列为 推算值、未实测 。方案 B 的权威值应为 3,419 条 (rec_pages × 4080 × 85% / 644);表内 3,700 条为 v1.1 旧推算,尚未按新几何重算 ——以本节开头的 v1.2 补注为准。
3.5.4 推荐分区表(可直接替换)
# partitions_emgw_16m.csv —— v1.1 方案 B(N16R8)
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000,
app0, app, ota_0, 0x10000, 0x200000,
app1, app, ota_1, 0x210000, 0x200000,
edgehippom, data, 0x42, 0x410000, 0xBE0000,
# 0x410000 + 0xBE0000 = 0xFF0000,尾部留 64 KB 余量
# edgehippom subtype = 0x42(旧 edgemem/kb_static 的 0x40/0x41 已废止)
# 稳态容量约 14,448 条(rec_pages 2,683 × 4080 × 85% / 644)—— 推算、未实测
# partitions_emgw.csv —— v1.1 方案 B(N8R8)
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000,
app0, app, ota_0, 0x10000, 0x200000,
app1, app, ota_1, 0x210000, 0x200000,
edgehippom, data, 0x42, 0x410000, 0x3E0000,
# 0x410000 + 0x3E0000 = 0x7F0000,尾部留 64 KB 余量
# edgehippom subtype = 0x42(旧 edgemem/kb_static 的 0x40/0x41 已废止)
# 稳态容量约 3,419 条(rec_pages 635 × 4080 × 85% / 644)—— 推算、未实测
3.5.5 三条必须知道的配套事实
事实 含义
OTA 不碰知识库 edgehippom 是独立分区,OTA 只写 app0/app1。升级固件不会破坏已灌入的记忆 ——这对「记忆资产」类产品是底线要求,现有 ota_mgr 已满足
OTA 代码已经写好 现有 main/ota_mgr.c 已实现:双 OTA 槽 + BOOTLOADER_APP_ROLLBACK_ENABLE + 启动 5 s 后 em_ota_mark_valid() 自证 + POST /ota(X-OTA-Token)+ ota_upload.py。保留 OTA = 零工作量;去掉 OTA 反而要改代码
槽大小有硬下限 槽必须 ≥ 固件镜像大小。v1.2 实测:现状 1.459 MiB,裁剪后 ≈1.34 MiB,MVP 完整态 ≈1.45 MiB → 2 MB 槽余量 ≈0.55 MiB(38%)。建议设一条构建期硬门槛:app 镜像 > 槽 × 0.8 即告警、> 槽 × 0.9 即失败 (见 W0-06)。一旦加回任一功能模块,必须重新评估
改槽的成本是不可逆的 app 槽变小 → app1 结束地址前移 → edgehippom 起始偏移改变 → 已灌入的库全部作废,必须整片重烧 + 重灌。分区不能向后增长 。所以「先用 B、容量不够再改 C」这条路是有代价的,不能当作免费选项
给 β 形态留的第三选项(P1 评估):UF2 拖拽升级替代 OTA 双槽。
ESP-IoT-Solution 有官方「Virtual USB Flash Drive UF2 OTA」方案——既然 β 形态本来就要做虚拟 U 盘,拖固件升级和拖 .emf 灌库可以用同一套交互,UX 上更统一,还能省下整个第二槽(N16R8 → 15,300 条)。
但风险要写清楚:单槽写入中断 = 变砖,只能串口救砖。 由于 β 形态插在用户电脑上、USB 在手,风险可接受;α 模组形态(焊在客户设备里)绝不可采用,必须保留双槽 OTA。
3.5.6 决策与执行
阶段 采用方案 理由
MVP(P0) 方案 B:双槽 OTA,槽 2 MB 迭代频繁,回滚能力是刚需;已验证的代码零改动;容量 +61% / +118%
P1(β 工程样机) 评估 UF2 拖拽升级 vs 保留双槽 取决于变砖风险接受度与 UX 统一价值
P2(α 模组量产) 强制保留双槽 OTA 焊死在客户设备内,无 USB 救援通道
执行注意事项(沿用现有铁律): 分区表是板级配置 ,两板各有各的 CSV,禁止跨板拷贝 sdkconfig;改分区表后必须整片重新烧录 (分区表变了,OTA 无法跨分区布局升级),所以这个改动要在正式灌库前 做掉,之后不要再动。改完先用 esptool flash-id 确认 Flash 容量,再核对 sys.info 输出的分区信息。
3.5.7 方案 C 专项评估(v1.2 新增)
v1.1 把方案 C 标为「激进但可行」,理由是「裁剪后固件约 1.2 MB,1.5 MB 槽余量 0.3 MB」。这个 1.2 MB 是估的,v1.2 用实机 .map 把它测出来了,结论相反。
实测:裁剪 cam/mic/gps 到底能省多少
数据源:C:\emgw-build\fw_ascii\build_devkit_16m\edgehippom-<board>-<ver>.map(devkit/16m 变体,逐段统计 .text + .rodata + .dram)。
可裁剪项 实测占用 说明
esp32-camera 组件83.7 KB 唯一的大头。三个自有模块只是它的薄封装
I2S 驱动(esp_driver_i2s) 31.1 KB 麦克风用;若合成源与音频都去掉可全额释放,保守按 25 KB 计
cam_mgr.c3.1 KB 自有代码
mic_mgr.c2.9 KB 自有代码
gps_mgr.c2.4 KB 自有代码
可省合计(保守) ≈ 115–123 KB 远小于 v1.1 假设的 400 KB
对比参照:cli_json.c 一个文件就 13.8 KB,link_mgr.c 10.3 KB。真正的 flash 大头是 WiFi/BLE/mbedTLS(libnet80211、libbtdm_app、psa_crypto 等都在 20–57 KB 量级),这些 MVP 一样也砍不掉 。
MVP 完整态固件尺寸预算
构成 尺寸(MiB) 依据
现状 app 镜像 1.459 edgehippom-<board>-<ver>.bin = 1,530,080 B(实测)
− 裁剪 cam/mic/gps −0.115 上表实测
+ TinyUSB 复合设备(CDC + MSC) +0.06 ~ 0.10 device stack + class driver 量级估算,待 W0-03 冒烟后实测
+ emlite 引擎(HNSW + 时序 + WAL) +0.03 ~ 0.05 目标 .text ≤ 60 KB(见 4.4 节)
+ 调试命令 / 性能计数器 +0.01 ~ 0.02 MVP 必带
MVP 完整态预计 ≈ 1.44 – 1.49 MiB 中位 1.45 MiB
三个方案按实测重算
方案 槽 余量(MiB) 余量 % 判定
B (N16R8)2.0 MB 0.51 ~ 0.56 34–38% ✅ 安全,采用
C (N16R8)1.5 MB 0.01 ~ 0.06 1–4% ❌ 基本等于零余量,且现有固件就已超出(1.459 > 1.5 减去对齐开销后装不下)
C (N8R8)1.75 MB 0.26 ~ 0.31 15–18% ❌ 过紧;板 A 只需 1,800 条,B 方案(推算 3,419 条)已够
结论:方案 C 不合适,两板都不采用。
① 收益极小 :N16R8 只多 1,200 条(+9.3%),N8R8 只多 600 条(+16%)。容量判据 G1 的门槛是 8,000 条、目标 12,000 条,方案 B 的 14,448 条已经超额 (推算、未实测 ),多出来的 9% 不改变任何产品叙事(对外都是「万条级」)。
② 风险极大且不可逆 :槽爆了不是「功能降级」,而是现场设备永远停在旧固件 ——esp_ota 在写入前校验失败会拒绝升级,设备带病运行且无法远程修复。对 β 形态(插在用户电脑上、靠 OTA 迭代)这是致命的。
③ 改槽要重灌库 :edgehippom 起始偏移会变,已灌入的记忆全部作废。为了 9% 的容量赌一次不可逆操作,期望值为负。
真正值得去争的容量杠杆,不在 app 槽上。 三个按性价比排序:
每条字节数(杠杆最大,可达 +50% ~ +150%)。 当前口径 662 B/条 = 384 B 向量(int8 × 384 维)+ 150 B 摘要 + 索引开销。若改用 256 维 embedding,或把向量再做一次 PQ/SQ 量化(384 B → 96–128 B),容量直接翻倍以上。代价是召回率与延迟,必须用 S1/S3 场景实测换 (已列为 WBS 任务 W1-14 )。这一项的量级远超方案 C 的 9%。
时序区预算重分配(+1,100 条,零风险)。 方案 B 给 N16R8 预留 1.375 MB 时序区。但 v1.1 已决定 L0 原始波形放 PSRAM 不落 flash,L1 是分钟级聚合,L2 是特征向量 —— 实际用量很可能远小于 1.375 MB。实测后若只用到 0.5 MB,可把 0.875 MB 划回记忆库,+1,100 条。
把「记忆库 / 时序区」的比例从分区表静态切分,改成 edgehippom 分区内部动态分配。 这样将来调比例不用改分区表、不用整片重烧 ,只需重灌。强烈建议在 emlite 设计里就这么做 (W1-02)。
四、软件架构:五层 + 双后端引擎 HAL
4.1 分层
L4 接口层 usb_cdc(行协议) usb_msc(拖拽灌库) ble(link_mgr) mcp_shim http(仅灌库/OTA)
L3 策略层 EdgeMemory:生命周期(工作/短期/长期) / 遗忘淘汰 / 冲突消解 / 去重 / 重要性
L2 引擎层 EM Engine HAL ← 单一真源接口,两套可替换后端
├─ emdb : eXtremeDB 后端(目标形态,授权到位后启用)
└─ emlite : 自研 flash-backed HNSW + 列式时序环 + WAL(P0 立即可用)
L1 存储层 edgehippom 分区 / PSRAM cache / 页管理 / CRC32 / 磨损均衡
L0 平台层 ESP-IDF v6.1 + FreeRTOS + TinyUSB + NimBLE
为什么必须做双后端(这是本设计最重要的一个决定): 战略报告把「McObject 的 MCU 端授权条款」列为阻塞全部 的第一待验证项。如果不做 HAL,MVP 会在 W1 第一天就停下来等律师和商务。做了 HAL 之后:
① eXtremeDB 变成性能优化项 而非前置阻塞项;
② 手上有了 emlite 的实测数据,与 McObject 谈授权时议价地位完全不同 (能拿出真实的容量/延迟数字,而不是求人给方案);
③ 万一授权谈崩,产品仍然成立——只是容量与延迟差一档。
4.2 引擎 HAL 接口(em_engine.h,单一真源)
/* 生命周期 */
em_err_t em_open (const em_cfg_t *cfg, em_db_t **out);
em_err_t em_close(em_db_t *db);
/* 事务 */
em_err_t em_txn_begin (em_db_t *db);
em_err_t em_txn_commit(em_db_t *db); /* 掉电安全:要么全见,要么全不见 */
em_err_t em_txn_abort (em_db_t *db);
/* 记忆条目 */
em_err_t em_mem_put (em_db_t *db, const em_mem_t *m, uint64_t *id);
em_err_t em_mem_get (em_db_t *db, uint64_t id, em_mem_t *out);
em_err_t em_mem_del (em_db_t *db, uint64_t id);
/* 混合查询:向量 + 精确条件 + 时间范围,同一事务 */
em_err_t em_query(em_db_t *db, const em_query_t *q, em_hit_t *hits,
size_t max_hits, size_t *n_out);
/* em_query_t {
const int8_t *vec; uint16_t dim; /* 宿主提供,板侧不 embedding */
uint16_t topk; uint16_t ef_search;
uint16_t frag_mask; /* 限定碎片 */
uint32_t t0, t1; /* 时间范围(时序/记忆共用) */
uint16_t dev_id; uint8_t level; /* 精确条件 */
float min_salience;
} */
/* 时序 */
em_err_t em_ts_append(em_db_t *db, uint16_t dev_id, uint8_t ch, uint32_t ts, float v);
em_err_t em_ts_agg (em_db_t *db, uint32_t win_ms); /* L0 → L1 分钟聚合 */
/* 碎片 */
em_err_t em_frag_install(em_db_t *db, const char *path); /* 灌库 */
em_err_t em_frag_list (em_db_t *db, em_frag_t *out, size_t *n);
em_err_t em_frag_remove (em_db_t *db, uint16_t frag_id);
/* 运维 */
em_err_t em_stat(em_db_t *db, em_stat_t *out); /* 条数/字节/RAM峰值/命中率 */
em_err_t em_gc (em_db_t *db, float water_mark); /* 遗忘淘汰 */
emdb 与 emlite 必须同时通过上述同一组接口的一致性测试(W1-08),否则 HAL 形同虚设。
4.3 目录结构(在现有 fw_ascii 上增量,不推倒重来)
main/
├── app_main.c (现有,改:形态标识 form;旧 role 已废止)
├── em_engine.h ★ 新增:HAL 接口单一真源
├── em_engine_lite.c ★ 新增:emlite 后端(页管理 + HNSW + 时序环 + WAL)
├── em_engine_db.c ★ 新增:emdb 后端(eXtremeDB,授权到位后填)
├── em_ann.c ★ 新增:int8 距离核 + HNSW 遍历 + IVF 粗划分
├── em_ts.c ★ 新增:列式时序 L0/L1/L2
├── em_wal.c ★ 新增:事务日志与崩溃恢复
├── em_mem.c ★ 新增:策略层(生命周期/遗忘/去重/重要性)
├── em_frag.c ★ 新增:.emf 碎片包解析、校验、安装
├── em_mcp.c ★ 新增:MCP shim
├── usb_dev.c ★ 新增:TinyUSB 复合设备 CDC+MSC
├── usb_msc_disk.c ★ 新增:虚拟 U 盘 + 拖拽灌库
├── em_store.c (现有,改造:底层改用 em_engine,保留 store.map 诊断)
├── cli_json.c (现有,扩展:mem.* / frag.* / ts.* / ann.* 命令)
├── link_mgr.c (现有,复用:板间 BLE 互联与碎片接力)
├── led_mgr.c wifi_mgr.c ble_mgr.c ota_mgr.c kb_ota.c http_srv.c (保留)
└── cam_mgr.c mic_mgr.c gps_mgr.c (MVP 裁剪:Kconfig 控制,默认 n)
固件分层纪律(沿用现有约定): 通用层(main/ 框架与协议)改动必须两板回归 ;板级差异一律走 boards/sdkconfig.<board_id> + 分区表 + CONFIG_EMGW_*,禁止跨板拷贝 sdkconfig 。构建唯一入口 build_board.ps1 -Board xiao|devkit|all,升级前先问清是哪块板。
4.4 eXtremeDB 优势保留矩阵(v1.1 新增)
emlite 先行不代表可以随便写一个「能跑就行」的向量检索——那样到替换时等于重写一遍。本节把 eXtremeDB 的公开能力逐条映射为 emlite 的设计约束与验收点 ,确保替换前后行为语义一致、性能特征连续 。以下能力描述均取自 McObject 官方技术规格页、Steve Graves 技术文章与 Andrei Gorine 的公开发表材料(见修订说明中的来源清单)。
4.4.1 先锁定三条来自 Andrei Gorine 的硬约束
这三条是 eXtremeDB 区别于「普通嵌入式 KV 存储」的根本,也是
emlite 最容易做错的地方,必须写进设计约束而不是事后优化:
运行时不调用 malloc。 eXtremeDB 核心运行时实现自有内存管理器,不使用系统 malloc(Andrei Gorine, Dr. Dobb's;McObject FAQ 明确答复)。emlite 必须全部预分配内存池 ——这不只是性能问题,它直接决定 P99 抖动 ,也正呼应 Steve Graves《Justifiably Taboo: Avoiding malloc-free APIs》的论点。
flash 的不可预测性来自介质之上的层,不是 flash 本身。 NAND/SPI flash 的读、编程、擦除在物理层有明确时序;不可预测性来自 FTL 与文件系统(缓冲、日志、写重排、延迟分配)。emlite 必须做「事务感知的 flash 管理」:擦除与 GC 只在事务边界之外或后台执行,查询关键路径上只允许读和顺序写。 这与白皮书「成本主导项是 I/O」完全一致。
回滚成本必须绑定到已知写集。 eXtremeDB/rt 用 CoW 显式跟踪修改页,使回滚时间可分析 ;并在 flash I/O、页管理、锁等待周围布高分辨率时序检查点,让内核能在执行期间判断事务是否还能满足截止时间。emlite 的 WAL 必须记录写集,且 em_txn_abort 的耗时必须可预测并被实测。
一个互相印证的判断: Andrei 说「控制时间比收集每一条数据更重要 ——航电中用已经过期的传感器数据,可能比直接跳过它更危险」;官方白皮书说「为可预测性调优,而非峰值召回 」。两句话是同一个原则的两种表述,它同时是 emlite 的调优准则和 G2 判据里「P99/P50 < 4」这条的来源。
4.4.2 优势保留矩阵(14 项)
# eXtremeDB 能力 emlite 必须如何体现 验收点 替换后
1 原生 ANN 索引 (HNSW/Vamana),事务一致 ——官方强调「不是 bolted-on 外部库,不参与其余数据流」ANN 索引更新必须走同一个 WAL 事务;commit 时数据与索引同时生效,abort 时索引一并回滚。禁止「先写数据、再异步建索引」 TC-C-04/05 事务测试必须覆盖索引 ;索引与数据不一致即判失败 直接切 HNSW/Vamana
2 sequence 列式时序存储 (官方规格列出的专用类型)时序按列存储 + delta 压缩,Chunk 按时间分区;不用行式 TC-C-06;写入吞吐 ≥1600 点/s 改用 sequence 类型
3 混合查询 :ANN + B-tree/Hash/R-tree/KD-tree/Patricia/Trigram/User-defined 同引擎同事务 至少实现 B-tree(时间/dev_id/frag_id)+ Trigram(文本模糊)+ ANN;必须保留 user-defined 索引接口 TC-C-03 混合查询正确性;与「先 ANN 后过滤」参考实现一致 补全其余索引类型
4 ACID + 三种事务管理器 (MURSIW / Exclusive / MVCC)+ 事务优先级 + delayed commit实现 MURSIW(多读单写) ——最契合 FreeRTOS 单写者模型;事务优先级映射到 FreeRTOS 任务优先级 TC-C-04/05 + TC-N-07 MVCC 为 emdb 增量优势
5 事务日志 + CRC ;CRC 兼作未授权篡改检测 WAL + CRC32;同一套 CRC 用于 .emf 碎片验签(离线、无网) TC-N-07 掉电;TC-F-03 篡改包必须被拒 直接对应
6 极小 footprint :Edge Client ≤8 KB;核心运行时约 200 KB;rt 服务版实测 1 GB flash 库仅需 40 KB 内存 (元数据+缓存+栈)把「代码体积 + RAM 占用」列为硬指标 而非副产品。8 MB 分区的 RAM 占用应远低于 PSRAM 5 MB 上限 新增 TC-N-11 :记录 emlite 的 .text 体积与峰值 RAM,作为替换收益的基线预期数量级改善
7 运行时不调用 malloc (自研内存管理器)全预分配池 :页缓存池、HNSW 遍历栈、查询结果缓冲均在 em_open 时按 cfg 分配完毕代码审查 + 运行期 heap_caps 水位监测(稳态无增长) 行为一致
8 compact data layout (内部引用压到 16 bit)条目内引用用 uint16;frag_id/dev_id 用定宽字段,不用指针 单条成本实测 ≤ 752 B(含开销) 编译时开关
9 类型安全 API (编译期捕获类型错误,避免 void*)schema 生成强类型 C 结构体;HAL 接口不用 void* 传数据 编译期;em_query_t 等结构全字段显式 DDL 编译期生成
10 Active Replication Fabric :边→服多层复制、断网排队 、双向MVP 不实现复制,但 HAL 必须预留 em_sync_* 接口与出队/入队语义 ,空实现即可 接口存在且语义与 ARF 对齐(write-first → commit → 上行 → 回收本地) 直接启用,Hub 中继与碎片同步即基于此
11 确定性 / 硬实时 :CoW deadline-aware 事务模型 + 多档截止时间策略事务 API 预留 deadline_us 参数;超时按策略中止而非无限等待 TC-N-02 的 P99;abort 耗时可预测(新增 TC-N-12 ) eXtremeDB/rt 全部能力
12 TFTL 事务感知 flash 管理 :磨损均衡/GC/坏块与事务调度协同擦除与 GC 只在事务边界外执行;查询路径只读 + 顺序写;坏块表预建 TC-N-02 抖动指标;TC-N-08 磨损均衡分布 交由内核
13 引擎内特征提取 :array/math/statistical 函数;多速率传感器按共同时间窗对齐/重采样 em_ts 提供窗口统计(min/max/mean/rms/峰度 + FFT 频段能量);多速率对齐在引擎内完成TC-C-06;W4-02 单窗口 ≤15 ms 改用内建函数
14 混合存储 (按表指定 in-memory / persistent)+ 事务内快照 热碎片常驻 PSRAM、冷数据落 flash 按表配置;em_snapshot 在事务内产出一致镜像 em_stat 能分表报告;快照可回灌直接对应
4.4.3 emlite 的自有硬指标(三个不可退让的数字)
指标 目标 说明
代码体积(.text) ≤ 60 KB eXtremeDB 核心约 200 KB、Edge Client ≤8 KB。emlite 是裁剪版,理应更小 ;超过 100 KB 说明实现膨胀,需重审
运行期动态内存分配 0 次 em_open 之后到 em_close 之前,不允许 malloc/free
abort 耗时可预测性 P99 ≤ 2×P50 写集显式跟踪 → 回滚时间与写集大小线性相关,不得出现长尾
这三个数字同时是「替换收益」的度量基线:接入 emdb 后重测同一组指标,差值即为授权谈判中值得付出的溢价。
4.4.4 一个值得抄的工程做法:flash 仿真层
eXtremeDB/rt 服务版提供了「硬件无关 flash 仿真」——用事务文件映射模拟 raw flash / managed NAND / eMMC / SD 卡的访问行为,让团队在拿到物理硬件之前 就能调优存储布局与缓存参数。
emlite 应照做: 把 L1 存储层抽象出一个 em_flash_io 接口(读页 / 写页 / 擦除块),除真实 esp_partition 实现外,再提供一个基于文件的仿真实现 (可注入人为延迟与坏块)。收益有三:
① W6-01 的单元测试全部可以在 PC 上跑 ,不必依赖硬件,85% 覆盖率的引擎层单测变得现实;
② 掉电测试(TC-N-07)可以在仿真层精确控制断电时刻 ,比物理断电更容易复现与定位;
③ 可以在没有第二块板的情况下评估不同 flash 布局对 P99 的影响。
4.4.5 替换验收清单(W1-13 的细化)
# 验收项 判据
1 同一数据集在两后端上的 top-k 结果集合 完全一致(排序容差 ±1 位)
2 事务语义(原子/一致/隔离/持久) TC-C-04/05 + TC-N-07 两后端均通过
3 混合查询语义(ANN + 精确条件 + 时间窗) TC-C-03 结果一致
4 三条硬约束 malloc-free、事务感知 flash 管理、abort 可预测——emdb 必须不劣于 emlite
5 容量与延迟 同分区下 emdb 的容量 ≥ emlite、P99 ≤ emlite。否则不切换
6 策略层与接口层零改动 切换后端只需改一行构建配置,em_mem.c / em_frag.c / em_mcp.c 不动
五、数据模型:schema 草案
用统一的 schema 语言描述,emdb 后端直接编译成 eXtremeDB DDL,emlite 后端映射为等价 C 结构体 + 定长页布局。两份定义必须同源同构 ——这是报告第 7.1 节「模式统一」原则的工程落实,避免 PC 侧打包器与板侧布局漂移。
5.1 记忆表 Memory(核心)
class Memory {
uint64 id; /* 全局唯一,单调递增 */
uint32 ts_ms; /* 创建时间 */
uint16 frag_id; /* 所属碎片包 —— 物理接力与卸载的最小单位 */
uint8 level; /* 0=工作记忆 1=短期 2=长期 */
uint8 src; /* 来源:0灌库 1时序闭环 2宿主写入 3接力 */
float salience; /* 重要性 0..1,遗忘淘汰的输入 */
uint32 access_cnt; /* 命中次数 */
uint32 last_access_ms; /* 最近命中,LRU 输入 */
uint16 dev_id; /* 关联设备(精确条件) */
uint16 tags; /* 标签位图(精确条件) */
char payload[150]; /* 摘要正文,UTF-8,硬上限 150 B */
vector<int8, 384> emb; /* int8 量化向量 */
unique tree<uint64> pk;
tree<uint16, uint64> by_frag;
tree<float, uint64> by_salience;
tree<uint32, uint64> by_time;
ann<cosine, 384> ann_idx; /* HNSW,M=16,ef_construct=200 */
};
payload 150 B 是硬约束,不是建议值。 中文一字 3 字节,150 B ≈ 50 个汉字。打包器(W5-02)必须做截断并留 4 B 终止符,且绝不能在多字节字符中间截断 ——否则会产生非法 UTF-8,在 JSON 输出时整帧损坏(本项目已有此坑:JSON 缓冲含中文不能用 256 B,须 768 B)。
5.2 时序三表(闭环的物理载体)
class Sample { /* L0 原始:环形,必然被覆盖 */
uint64 id; uint32 ts_ms; uint16 dev_id; uint8 ch; float val;
unique tree<uint64> pk; tree<uint32, uint64> by_time;
};
class Window { /* L1 分钟聚合:趋势追溯、合规留痕 */
uint64 id; uint32 win_start; uint16 dev_id;
float min[16], max[16], mean[16], rms[16];
unique tree<uint64> pk; tree<uint32, uint64> by_time;
};
class Pattern { /* L2 特征向量:闭环产物,长期资产 */
uint64 id; uint32 win_start; uint16 dev_id; uint8 label;
float confidence;
vector<int8, 384> emb;
uint64 src_win_id; /* ★ 可回溯到产生它的那段时序 */
ann<cosine, 384> ann_idx;
unique tree<uint64> pk; tree<uint32, uint64> by_time;
};
src_win_id 这一列是整个方案的技术内核:ANN 命中后能直接回溯到生成它的那一段传感器历史 ——这正是 McObject 官方文章给出的路径终点,也是「记忆」区别于「硬盘」的地方。
5.3 碎片表 Fragment 与账本
class Fragment {
uint16 frag_id; char name[24]; uint32 version;
uint32 count; uint32 bytes; uint32 crc32;
uint8 sig[64]; /* 来源签名(离线可验签) */
uint32 install_ms; uint8 state; /* 0安装中 1就绪 2损坏 3卸载中 */
unique tree<uint16> pk;
};
5.4 .emf 碎片包结构(与 schema 同源)
memory-fragment.emf 一个自洽、可离线验证的记忆单元
├── manifest.json schema 版本 / 条数 / 维度 / 量化方式 / 领域标签 / 时间范围
├── vectors.bin int8 向量,【按 IVF 簇顺序排列】
├── graph.bin HNSW 链接,离线构建,已优化落盘顺序
├── payload.bin 每条 ≤150 B 摘要(可选加密)
├── timeseries.bin 附带的时序特征历史(可选)
└── signature 来源签名 + CRC32(离线可验签)
三原则(报告 7.1,工程化为强制校验项):
① 自洽 :一个包必须能独立加载、独立检索、独立验证。em_frag_install 必须拒绝任何声明外部依赖的 manifest。
② 离线可验签 :无网、无 Hub 也能校验完整性与来源——这是「物理接力」成立的前提。
③ 模式统一 :打包必须用与板侧同源的 schema 定义,禁止 PC 侧另写一份。
5.5 三级留存策略(遗忘机制的物理实现)
层级 粒度 速率 7.875 MB 可存 作用
L0 原始100 Hz × 16 CH ≈ 2.4 KB/s ≈ 80 分钟 环形缓冲,只服务事后取证,必然被覆盖
L1 分钟聚合1 min × 16 CH ≈ 15 KB/h ≈ 30 天 趋势追溯、合规留痕
L2 特征向量每 10 s 一窗,按 5% 保留 ≈ 220 KB/天 ≈ 50 天且持续生长 识别出的工况模式、异常指纹 —— 长期资产
「原始波形只留 80 分钟,但它提炼出来的模式会留很久。就像人忘记三年前某顿饭吃了什么,却记得那次食物中毒。」
这组对比同时回答三个常被追问的问题:为什么不上云、为什么能长期学习、以及「记忆」和「硬盘」的区别是什么(硬盘什么都留,记忆会挑)。
5.6 修正:L0 不落 flash,L2 靠去重收敛(Flash 预算分配)
对战略报告 6.6 节的一处必要修正。 原表把 L0 原始波形算进 11 MB flash 预算,得出「80 分钟」。但引擎分区实测只有 7.875 MB,且必须与向量库共享;按原分配,L0 只能分到不到 1 MB(约 7 分钟),而 L1「30 天」需要 10 MB 以上——
两个数字都不成立 。修正如下:
L0 原始波形放在 PSRAM 环形缓冲,不落 flash。 10 s 窗口 @ 4 kHz × 3 轴 × int16 = 240 KB,PSRAM 完全吃得下。窗口特征化在 RAM 内完成。只有被判定为异常 的窗口才转存 flash 取证区(降采样包络 12 KB/窗)。这既正确也更省。
L2 不做无限生长,靠去重收敛。 新 Pattern 入库时若与已有条目余弦 > 0.95,则合并更新 而非新增(复用 W2-03 的去重器)。稳态下 L2 收敛为该设备的「工况模式字典」,经验规模 500–2,000 条。去重机制就是 L2 的容量控制阀 ——这也正好是「记忆会挑」的工程实现。
区域 MVP 预算 单位成本 承载量 说明
记忆向量库 (Memory + ANN)6.5 MB 662 B/条,含 12% 开销 → 752 B ≈ 8,200 条 MVP 主验证对象,预算优先给它
L1 五分钟聚合 0.6 MB 5 CH × 4 统计量 × 4 B / 5 min = 960 B/h ≈ 27 天 趋势追溯、合规留痕
L2 特征向量 0.5 MB 384 B + 链接 128 B = 512 B(含开销 582 B) ≈ 900 条 去重收敛后稳态 ≤ 600 条
异常取证波形 0.2 MB 降采样包络 12 KB/窗 ≈ 16 个事件 配合 L1 时间索引定位
元数据 / 预留 0.075 MB — — 碎片表、WAL 区等
合计 7.875 MB 分区扩容到 9.875 MB 后,记忆向量库可提到 8.5 MB ≈ 11,000 条
量产平衡方案(时序权重更高时):记忆 5.0 MB(≈6,300 条)/ L1 1.2 MB(≈54 天)/ L2 1.2 MB(≈2,100 条)/ 取证 0.4 MB。各区大小应为 Kconfig 可配 ,不由代码写死。
5.7 计算分层(明确每一层算力从哪来)
计算任务 在哪里做 频率 说明
Embedding(文档原文) PC / Hub 灌库时 离线预计算核心;可换任意小模型而无需改板侧
ANN 索引构建 PC / Hub 灌库时 聚簇 + 构图 + 压缩 + 顺序布局 ,产出 .emf
查询侧 Embedding Host 提供 每查询 宿主/Hub 算好向量下发,板侧不做 embedding
相似度检索 板上 每查询 核心能力,目标 < 30 ms
时序写入 / 窗口聚合 板上 持续 多速率对齐由引擎处理
窗口特征化 板上 (Hub 兜底)持续 统计量/频谱板上可算;需 ML 则由 Hub 算后回写
记忆策略(遗忘/冲突) 板上 持续 策略必须贴着数据,不依赖网络
LLM 推理 / 生成 不做 — 明确划出边界
六、软件开发任务总表(WBS)
共 7 个工作包(WP0–WP6)、51 项任务 。优先级:P0 阻塞 P1 主路径 P2 增强 。人日为单人估算(含自测),未含评审与返工缓冲(建议按 ×1.3 计)。
WP0 · 基建与基线(Board Bring-up)先做,建立信心
战略报告提示:USB 复合设备有两个官方示例可参考,风险最低,应最先做。本工作包先把它前面的路铺平。
编号 任务 交付物 验收标准 依赖 人日
W0-01 建立 EdgeHippo 构建变体:按形态 区分(form=usb-dongle(B) / form=gamma-card(A)),变体 usb-dongle-16m(B) / gamma-card-8m(A) sdkconfig.usb_dongle_16m、sdkconfig.gamma_card_8m、BOARD_*.md 更新build_board.ps1 可分别产出两板固件;sys.info 的 form 字段正确(gamma-card / usb-dongle);两板均能启动— 2
W0-02 USB 通道切换 :console 从 USB-Serial-JTAG 切到 UART0,启用 TinyUSBsdkconfig 变更集 + 板 B 外接 USB-UART 转换器接线说明 板 B 通过 GPIO19/20 枚举为 USB 设备;UART0 日志正常;USJ 不再占用 PHY 。注意 choice 组只能写 =y W0-01 3
W0-03 TinyUSB 复合设备冒烟:CDC + MSC 同时枚举(官方示例移植) usb_dev.c 骨架Windows / macOS / Linux 均无需驱动 ;串口与虚拟盘同时可用;D+ = GPIO20、D− = GPIO19 W0-02 3
W0-04 固件裁剪 :cam / mic / gps 由 Kconfig 控制,MVP 默认关闭Kconfig 开关 + 裁剪后 bin bin ≤ 1.2 MB ;启动后可用堆增加 ≥ 300 KB;store.map 显示 RAM 水位下降 W0-01 2
W0-05 v1.1改 已执行 2026-10-28 分区表改方案 B (见 3.5 节 ):两板 app 槽均压到 2 MB ×2 ,edgehippom 提到 11.875 MB / 3.875 MBpartitions_emgw.csv / _16m.csv v2OTA 双槽仍可用且实测升级成功;store.map 报出新 edgehippom 容量。必须在任何正式灌库前完成 W0-04 2
W0-06 性能基线测量 :内部 DRAM / PSRAM 可用量、heap 水位、flash 顺序写与页读吞吐baseline.md(实测数字)给出四个实测值:PSRAM 可用、DRAM 峰值余量、flash 4 KB 页读延迟、1 MB 顺序写耗时。后续所有容量/延迟推算以本基线为准 W0-04 2
W0-07 备份与回滚预案:板 B 现网 4343 条知识库导出归档 kb/export 备份文件 + 恢复脚本可在 10 分钟内把板 B 恢复到当前状态 — 1
W0-06 v1.2新增 构建期槽位余量硬门槛 :脚本解析 app 镜像大小,与分区表 app 槽比对build_board.ps1 增加检查步骤> 槽 × 0.8 告警、> 槽 × 0.9 构建失败 。防止方案 C 式的爆槽在无人察觉时发生(见 3.5.7 )W0-05 1
WP0 小计 16
WP1 · 引擎层(EM Engine HAL)核心,最长
编号 任务 交付物 验收标准 依赖 人日
W1-01 定义 HAL 接口 em_engine.h(第 4.2 节全部 API)头文件 + 接口文档 + 空实现桩 两后端共用同一头文件;编译期可切换后端;接口评审通过 W0-01 2
W1-02 存储层:edgehippom 分区页管理(4 KB 页)、CRC32、坏页标记、简易磨损均衡 em_store 底层改造 + 单元测试1 万次随机读写后无坏页累积;掉电后已 commit 页数据完整 W0-05 5
W1-03 int8 距离核 :384 维 int8 余弦/内积,Xtensa 优化em_ann.c 距离核 + 微基准单次距离计算 ≤ 1.2 μs (240 MHz);与朴素实现结果一致(误差 0) W1-01 3
W1-04 flash-backed HNSW :M=16 / ef_construct=200,页式图存储 + PSRAM 缓存em_ann.c HNSW 实现10,000 条构建成功;单条内存占用 ≤ 512 B(向量+链接);工作集尽量常驻 PSRAM W1-02, W1-03 10
W1-05 IVF 粗划分 :离线聚簇 + 查询时只触及 top-n 簇(MCU 级推荐做法)IVF 索引 + 簇元数据 开启 IVF 后 P99 抖动下降(对比测试);命中率损失 ≤ 3% W1-04 6
W1-06 列式时序 L0 环形缓冲:16 CH × 100 Hz,delta 压缩 em_ts.c写入吞吐 ≥ 1600 点/s ;环形覆盖正确;7.875 MB 下 ≥ 80 分钟 W1-02 4
W1-07 L1 分钟聚合 + L2 特征向量写入 聚合器 + Pattern 表 整分触发聚合,误差 ≤ 1e-5;L2 只保留判定为「有意义」的窗口 W1-06 4
W1-08 WAL 事务 :begin/commit/abort,崩溃恢复em_wal.c随机掉电 100 次,库 100% 可打开 ;未 commit 事务完全回滚W1-02 6
W1-09 混合查询 :ANN + 时间范围 + dev_id/frag_id/tags/level 精确过滤,同事务em_query 实现过滤条件与 ANN 结果交集正确;src_win_id 可回溯;先过滤后精排 路径可用 W1-05, W1-07 6
W1-10 碎片管理:em_frag_install/list/remove,manifest 解析与签名校验 em_frag.c损坏包 / 越界包 / 依赖外部的包 全部被拒绝且不损坏原库 W1-09 5
W1-11 运维接口:em_stat(条数/字节/RAM 峰值/缓存命中率)+ em_gc 统计与淘汰 store.map 能输出全部指标;GC 按 salience + LRU 淘汰到水位线以下W1-09 3
W1-12 P2 emdb 后端:接入 eXtremeDB,替换 emliteem_engine_db.c通过 W1-13 一致性测试;容量与延迟优于 emlite(否则不切换) 授权到位 12
W1-13 P2 双后端一致性测试:同一数据集在两后端上的查询结果逐条比对 一致性测试套件 top-k 结果集合完全一致(排序容差 ±1 位);事务语义一致 W1-12 4
W1-14 v1.2新增 向量降维 / 量化实验 :384d int8 基线 vs 256d vs PQ/SQ 量化,测召回率与容量离线实验脚本 + 板侧实测 给出「每条字节数 × 召回率 × P99 延迟」三维对照表;若 256d 或量化后召回率下降 ≤5% 而容量提升 ≥40%,则采纳 (这是比压 app 槽高一个量级的容量杠杆,见 3.5.7 ) W1-04 5
WP1 小计(emlite 路径 W1-01…W1-11 + W1-14) 59
WP1 小计(含 emdb 后端 W1-12/W1-13/W1-14) 75
W1 的三条工程铁律(来自官方白皮书,必须遵守):
① 内存型 HNSW 在 MCU 上不实用 ,必须走 flash-backed,由 DBMS 管理页与缓存;
② Vamana 比 HNSW 更脆 ——工作集超出 cache 就断崖式下降,HNSW 是渐进退化。约束设备上优先 HNSW ;
③ 成本主导项是 I/O 而不是返回数据量 ,优化方向是顺序布局与减少随机读 ,不是缩小结果集。
如果 P0 实测 P99 > 50 ms,先调这三项(IVF 削减 + 离线按簇顺序落盘 + 热碎片常驻),不要换 MCU 。
WP2 · 策略层(EdgeMemory)差异化所在
ObjectBox 核心数据库免费,纯「嵌入式向量库」会撞上免费壁垒。差异必须建立在策略层——遗忘、冲突消解、闭环回写,这些是需要真实长期运行才能调对的东西。
编号 任务 交付物 验收标准 依赖 人日
W2-01 记忆生命周期状态机:工作 → 短期 → 长期,迁移条件与阈值 状态机 + 迁移规则表 三态可观测(mem.stats 分态计数);迁移阈值可按碎片配置 W1-09 4
W2-02 遗忘与淘汰:salience 时间衰减 + 访问频率加权 + 容量水位触发 GC 遗忘策略 库达 95% 水位时自动淘汰到 85%;高 salience 与近期命中条目不被淘汰 (回归测试) W1-11, W2-01 5
W2-03 近重复去重与冲突消解:余弦相似度阈值判定 + 版本保留策略 去重器 灌入 500 条含 100 条近重复的数据,重复率下降 > 90%;冲突条目保留新版本且可回溯旧版本 W1-09 5
W2-04 闭环回写 :检索结果(含成功/失败标签)写回为新记忆,并影响后续检索权重回写逻辑 回写的新记忆在下一次检索中可被命中 (这判定了闭环是否真成立) W2-01 5
W2-05 记忆健康检查:碎片完整度、孤立向量、过期条目、索引一致性 mem.check 命令 + Hub 上报字段人为损坏一个碎片后能被检出并报出 frag_id W1-11 3
WP2 小计 22
六、软件开发任务总表(WBS)· 续
WP3 · 接口层产品感知面
编号 任务 交付物 验收标准 依赖 人日
W3-01 CDC 行协议扩展:mem.put/get/query/del、frag.install/list/remove/verify、ts.append/agg/query、ann.bench cli_json.c 扩展沿用单行 JSON {"id":n,"cmd":"name","args":{}};全部命令有 help;中文 msg 缓冲 ≥ 768 B W1-09 5
W3-02 MSC 虚拟 U 盘 + 拖拽灌库 :写入 .emf → 自动校验 → 合并索引usb_msc_disk.c拖入后 ≤ 60 s 完成 10,000 条合并并可查;错误包拒绝且不坏原库;全平台零驱动 W0-03, W1-10 8
W3-03 U 盘状态回写:把灌库结果/错误写成 STATUS.TXT 放在虚拟盘上 状态文件生成 用户拖入后不接串口也能知道成功与否 W3-02 2
W3-04 BLE 碎片接力:基于现有 link_mgr 做 .emf 点对点传输 接力协议扩展 两板间传输 1 MB 碎片包成功;断点续传;接收方离线验签通过 W1-10 6
W3-05 MCP shim :把记忆资源暴露为 MCP 接口(不做私有 API)em_mcp.c + 协议文档标准 MCP 客户端可直接查询;三个场景统一走此接口 W3-01 6
W3-06 断网自检模式 :sys.offline 一键关闭 Wi-Fi/BLE,仅留 USB 供电自检命令 + LED 指示 执行后 G1–G5 全部可复测;LED 进入「离线就绪」态 W3-01 2
W3-07 Nagle + 延迟 ACK 处理 :响应合并成一次 send,httpd open_fn 设 TCP_NODELAY传输层修正 连续查询帧率不塌陷(本项目已有此坑:不处理会从 10 fps 掉到 0.33 fps) W3-01 1
W3-08 P2 Host SDK:Python / Node.js 封装(CDC + MCP 双通道) SDK 包 + 示例 10 行代码完成「灌库 → 查询」 W3-05 5
WP3 小计(MVP 范围 W3-01…W3-07) 30
WP4 · 时序闭环(场景侧)技术内核
编号 任务 交付物 验收标准 依赖 人日
W4-01 v1.1改 多速率合成数据源 :板内确定性生成 3 轴振动(4 kHz) + 温度(1 Hz) + 电流(10 Hz),不接任何硬件 em_sim_src.c + ts.inject 命令三速率按共同时间窗对齐;同一 seed 逐字节可复现 ;吞吐打满 W1-06 写入上限 W1-06 3
W4-02 窗口特征化 :每 10 s 窗口计算统计量(min/max/mean/rms/峰度)+ FFT 频段能量特征化器 单窗口特征化 ≤ 15 ms (否则撑不住 10 s 周期下的多设备);FFT 结果可复现 W4-01 6
W4-03 特征向量组装与归一化:多传感器特征合并为单个 384 维向量 向量组装器 输出向量与 PC 侧同算法结果一致(误差 ≤ 1e-4)——保证离线/在线两侧可比 W4-02 3
W4-04 L2 入库与「有意义」判定:异常度 / 新颖度阈值 保留策略 稳态数据下保留率 ≤ 5%(否则 7.875 MB 撑不住长期生长) W4-03 4
W4-05 混合查询场景化封装:「这台设备、这个工况、这个时间范围内,历史上最相似的 5 个状态」 查询模板 + 示例 返回结果含 src_win_id,可回溯原始波形区间 W1-09 3
W4-06 结果回写闭环(与 W2-04 打通):命中 → 人工/自动确认 → 新指纹入库 闭环演示脚本 新写入的指纹在下一次查询中可被命中 W2-04, W4-05 3
W4-07 P2 真实传感器采集 (v1.1 新增,P1 执行):板 A 挂加速度计 + 温度 + 电流,与合成源跑同一数据集做对照采集任务 + 驱动 真实数据下的召回率与误报率,相对合成数据偏差 ≤ 10% ;采集吞吐满足写入上限 W4-01 5
WP4 小计 (MVP 范围 W4-01…W4-06)22
WP5 · PC / Hub 工具链决定 UX 成败
编号 任务 交付物 验收标准 依赖 人日
W5-01 384 维中文 embedding 选型与验证 :候选模型在真实私域语料上的召回对照选型报告 + 固化模型版本 对比 768 维基线的召回损失 ≤ 3%;给出「384 够不够用」的明确结论(报告待验证项 3) — 5
W5-02 .emf 打包器 :文件/PDF/Markdown → 分块 → embedding → IVF 聚簇 → HNSW 构图 → 按簇顺序布局 → 签名emf_pack.py(含 --dump)产出的包能被板侧安装;顺序布局可验证 (簇内 ID 连续);同一输入的产物可复现(确定性) W5-01 8
W5-03 .emf 校验器:manifest/vectors/graph/payload 一致性、CRC、签名离线验签 emf_verify.py能检出「改一个字节」「少一条」「维度不符」「越界 payload」四类注入错误 W5-02 4
W5-04 灌库 CLI:CDC 灌库 + MSC 拖拽(两条路径)+ 进度与错误报告 emf_upload.py(默认预检、--backup)两条路径等效;失败时能定位到具体条目 W3-02 4
W5-05 基准测试工具 :批量查询出 P50/P99/吞吐/RAM 峰值/cache 命中率emf_bench.py + 报告模板一次运行产出 Go/No-Go ① 所需的全部数字(G1/G2/G3) W3-01 4
W5-06 三场景语料构建:S1/S2/S3 各一套真实或仿真语料 + 查询集 corpus/ 三套 + 查询集(含 ground truth)每套可打包为 .emf;查询集带人工标注的相关条目,用于算召回 W5-02 8
W5-07 P2 Hub 控制台:碎片版本管理、批量分发、设备记忆健康检查看板 Web 控制台扩展 可给 200 台设备下发新版碎片包并看到状态 W5-04 10
WP5 小计(MVP 范围 W5-01…W5-06) 33
WP6 · 测试与验收Go/No-Go 唯一依据
编号 任务 交付物 验收标准 依赖 人日
W6-01 单元测试:距离核 / 页管理 / WAL / 去重 / 遗忘,覆盖边界与异常 测试套件(host 侧可跑) 覆盖率 ≥ 70%(引擎层 ≥ 85%);CI 可跑 W1-*, W2-* 5
W6-02 三场景集成测试(第 10 章 TC-S1/S2/S3 全部用例) 测试报告 全部用例通过,或记录为「已知缺陷 + 影响评估」 WP1–WP5 8
W6-03 非功能测试 :N 组(延迟/容量/掉电/断网/耐久/灌库成功率)实测数据表 G1–G7 七项判据全部有实测数字 ,替换本报告所有「推算」标注W5-05 6
W6-04 Alpha 演示包:三个场景各一段 3 分钟可复现演示脚本 演示脚本 + 录屏 不联网、不需要解释即可看懂;客户可自助复现 W6-02 3
W6-05 Go/No-Go ① 评审包:实测数据 + 缺陷清单 + 决策建议 评审文档 可支撑产品负责人一次性拍板 W6-03 2
WP6 小计 24
6.2 合成数据源规格(v1.1 新增:MVP 不接传感器)
决策:MVP 全程只用基础主板,一根传感器线都不接。 时序数据由板内确定性合成数据源 生成,或由 PC 侧生成后经 CDC/BLE 注入。
✅ 四条收益
可复现 :同一 seed 产出逐字节一致的数据流,回归测试才有意义
可构造边界 :「8 类故障各 20 个样本」直接生成即可;真实世界要等故障发生
零硬件工作量 :不用选型、布线、调驱动、排查 I2C 时钟拉伸
不占 RAM、不干扰延迟 :采集驱动与 DMA 缓冲会挤占 ANN 工作集,而这正是 G2/G3 要测的
⚠️ 两条代价(记为已知局限)
无法验证真实采集吞吐 :4 kHz × 3 轴的实际采样能力、ADC 噪声等真实问题推迟
合成与真实数据的分布差异 会影响召回率结论的可信度
缓解: W4-07 在 P1 用真实传感器跑同一数据集对照,要求偏差 ≤ 10%。
在 W4-07 完成前,对外不得宣称 S1 的召回率已获真实数据验证。
通道 速率 类型 生成模型(确定性,seed 可控)
振动 X / Y / Z 4 kHz int16 CWRU 风格参数化模型 :基频正弦(转频 f₀)+ 2/3 次谐波 + 周期性冲击串(故障特征频率 BPFO / BPFI / BSF)+ 高斯白噪声(SNR 可配)。8 类故障 = 8 组参数
温度 1 Hz float 缓变基线 + 日周期 + 阶跃(异常升温)+ 噪声
电流 10 Hz float 负载周期 + 启动冲击 + 谐波 + 噪声
工况切换 事件 — 按脚本在 8 种稳态工况间切换,模拟真实产线节奏
/* 命令接口 */
{"cmd":"ts.inject","args":{"ch_mask":7,"rate_hz":4000,"seed":12345,
"fault":"bpfo","severity":0.6,"dur_s":30}}
/* 同一 seed + 同一参数 ⇒ 任何一块板上产出完全一致的字节流 */
{"cmd":"ts.script","args":{"file":"s1_scenario.json"}} /* 按脚本跑完整场景 */
关键设计要求:合成源必须放在板内,不能只放在 PC 侧。 这样「时序写入吞吐」「窗口特征化耗时」「L0 环形覆盖」这些指标仍然是真实的——数据确实进了 L0 环、确实做了 FFT、确实占了 flash;只有「数据从哪来」是假的 。这保住了 WP4 绝大部分的验证价值。
6.3 工时汇总
工作包 任务数 MVP 人日 含 P2 人日 说明
WP0 基建与基线 7 15 15 先做,风险最低,建立信心
WP1 引擎层 13 54 70 最长。emdb 后端为 P2 增量
WP2 策略层 5 22 22 差异化所在,需长期运行调参
WP3 接口层 8 30 35 拖拽灌库是 UX 成败点
WP4 时序闭环 7 22 27 技术内核。v1.1 改为合成数据源(−2),真实采集移入 P2(+5)
WP5 PC/Hub 工具链 7 33 43 决定 UX,也决定能否对外演示
WP6 测试与验收 5 24 24 Go/No-Go 唯一依据
合计 54 206 242 按 ×1.3 缓冲:MVP ≈ 268 人日 (v1.2 新增 W0-06 / W1-14 共 6 人日)
单人全职约 12–13 个月 ;2 人并行(固件 1 + 工具链 1)约 6.5 个月 ,与战略报告 P0(M1–M4)+ P1(M5–M9)的节奏基本吻合。若只做 Go/No-Go ① 所需的最小集(WP0 + W1-01…W1-11 + W3-01/02 + W5-01/02/05 + W6-03),约 130 人日 ,2 人约 3 个月 可拿到第一个实测结论。
v1.1 变化: 去掉传感器让 MVP 减少 2 人日,但真实采集验证(W4-07)移入 P2,含 P2 总量 +3 人日。
七、场景 S1|工业设备振动故障指纹库(时序主导 · α 形态)
要素 内容
痛点 20 台注塑机的智能化改造预算不到 8 万元;非计划停机代价高。边缘侧本地跑异常检测,行业口径非计划停机平均降 30–40%
我们的角色 α 模组(记忆器官)嵌入设备主控;Hub 侧批量构建与分发故障指纹包
为什么首选 McObject 官方技术文章明确点名工业设备场景;付费方明确(设备制造商 / 工厂);工程验证已存在
板位 板 A(N8R8)= 设备主控原型(采集 + 发起查询);板 B(N16R8)= 记忆外设(存指纹库 + 检索)。互联走现有 BLE link_mgr
能力侧重 时序主导 :时序写入 → 窗口特征 → ANN 检索 → 混合条件过滤 → 回写新指纹
7.1 数据规格
通道 速率 类型 来源与说明
振动 X / Y / Z 4 kHz int16 板内合成(v1.1) :CWRU 风格参数化模型,seed 可控、逐字节可复现。见 6.2 节。MVP 不接加速度计
温度 1 Hz float 板内合成 :基线 + 日周期 + 阶跃 + 噪声(模拟油温 / 料筒温度)
电流 10 Hz float 板内合成 :负载周期 + 启动冲击 + 谐波(模拟主轴电机电流)
设备数 3 台同型号注塑机(dev_id = 1 / 2 / 3),用于验证精确条件过滤
S1 的验证边界要如实写清: 本场景在 MVP 阶段验证的是「时序 → 特征 → ANN → 混合查询 → 回写」这条链路本身 ,不是「真实振动信号能被识别」。在 W4-07(P1 真实传感器对照)完成前,85% 召回率这个数字只能表述为「合成数据集上的召回率」。
7.2 知识库碎片构成(灌入板 B)
frag_id 碎片名 条数 内容 来源 字节
1 fp-inj-v1 故障指纹库1,200 8 类故障 × 150 条窗口特征向量 (轴承内圈/外圈/滚动体、齿轮断齿、不平衡、不对中、松动、螺杆磨损) CWRU 轴承公开数据集 + 参数化仿真合成 0.90 MB
2 base-op-v1 工况基线库600 3 型号 × 8 种正常工况的稳态特征 现场采集或仿真 0.45 MB
3 maint-v1 维修记录800 历史工单摘要(现象 / 原因 / 处置 / 结果),每条 ≤150 B 工厂 MES 导出后离线 embedding 0.60 MB
4 spec-v1 工艺参数300 SOP 关键参数与阈值 工艺文档 0.23 MB
灌库合计 2,900 装载后剩余约 5,300 条空间给 L2 生长与新指纹回写 2.18 MB
7.3 典型查询与闭环
Q1 纯相似 vec=<当前10s窗口特征>, topk=5
→ 返回最相似的 5 个历史状态 + 每个的 src_win_id
Q2 混合查询 vec=<当前特征>, dev_id=2, t0=30天前, t1=now, topk=10
→ 「这台设备、最近一个月内,最相似的 10 个状态」★ 核心卖点
Q3 条件过滤 vec=<当前特征>, tags=温度过高, min_salience=0.6, topk=5
→ 相似度与精确条件在同一事务内完成
闭环 检出异常 → 人工确认为「螺杆磨损」→ 回写为新指纹(level=2, salience=0.9)
→ 30 天后同类特征再次出现时,Q1 应能直接命中该指纹
7.4 场景级判据
召回: 注入 8 类故障各 20 个测试样本,已知故障类型的 top-1 命中率 ≥ 85% ;top-5 ≥ 95%
误报: 稳态正常工况下,被判定为「新颖/异常」(相似度低于阈值)的比例 ≤ 5%
闭环有效性: 人工确认后回写的指纹,在后续同类样本中可被命中(这是闭环成立的唯一证据)
可回溯: 任一条 ANN 命中都能通过 src_win_id 取回产生它的那段时序区间并绘图
八、场景 S2|野外巡检记忆包与物理接力(断网 · β 形态)
要素 内容
痛点 隧道、船舶、野外无网;巡检经验随人员流失;换班时上下文断裂
我们的角色 β 外设本体。巡检员下班把记忆外设带回办公室同步,符合现有工作流
为什么选 β 形态的最佳落脚点;物理接力 是最难被软件复制的差异化(Oki 的 Memchip 已用同一叙事卖到 $1,799)
板位 双板都用上 :板 A(N8R8)= 专家的随身记忆卡;板 B(N16R8)= 巡检员的外设。这是唯一需要「接力」的场景
能力侧重 纯语义 + 物理接力 + 断网 。时序只作辅助(环境读数、点位时间)
8.1 数据规格
通道 类型 说明
巡检记录文本 UTF-8 短文本 语音转写或手写录入,每条先截断/摘要到 ≤150 B 后 embedding
点位 ID / 设备编号 uint16 作为精确过滤条件(tags / dev_id)
时间戳 uint32 时间范围过滤;也是「上次这个点位什么时候出过问题」的依据
环境读数 1 Hz float 温湿度、瓦斯浓度等,写入 L1 聚合
8.2 知识库碎片构成
frag_id 碎片名 条数 内容 来源 字节
1 sop-tunnel-v1 规程包1,200 巡检 SOP、判定标准、处置流程 工程方规程文件 0.90 MB
2 defect-v1 历史缺陷包2,500 近 3 年缺陷记录(现象/部位/处置/结果) 历史工单导出 1.88 MB
3 expert-zhang-v1 专家经验包1,800 老张 20 年经验的口述整理(装在板 A 上随身带走 ) 访谈整理 1.35 MB
4 site-v1 点位拓扑包400 点位关系、易发问题部位 图纸 + 台账 0.30 MB
板 B 装载 (碎片 1/2/4)4,100 剩余约 4,100 条给现场新增记录与接力包 3.08 MB
板 A 装载 (碎片 3,专家随身)1,800 N8R8 升级后 3,419 条档位(推算、未实测),装 1,800 条仅占一半,仍有余量接纳现场新增记录 1.35 MB
8.3 三种接力的完整演示路径
① 物理接力 专家带着板 A(装着 expert-zhang-v1)到现场
→ 拔下 → 插到巡检员的设备上 → 巡检员的宿主立刻获得老张的经验
→ 最低信任成本,最难被软件复制
② 近场接力 板 A 与板 B 通过 BLE 点对点传输 expert-zhang-v1(1.35 MB)
→ 传输的是几百 KB 的自洽产物,不是 GB 级模型权重
→ 接收方【离线验签】通过后合并入库
③ Hub 中继 回办公室后板 B 插 USB → 同步到 Hub
→ Hub 汇总全天新增记录 → 构建新版 defect-v2 → 次日批量下发全班组
8.4 典型查询
Q1 vec=<"拱顶渗水伴有白色析出物">, topk=5
→ 命中历史缺陷记录 + 老张经验中的相关条目
Q2 vec=<"渗水">, site_id=K12+300, t0=2024-01-01, t1=now, topk=10
→ 「这个点位历史上出过几次同类问题,怎么处置的」
Q3 纯条件(无向量) site_id=K12+300, tags=结构类, topk=20
→ 验证精确条件路径不依赖 embedding 也能工作
8.5 场景级判据
断网可用性: Wi-Fi 与 BLE 全关(仅 USB 供电)时,Q1–Q3 全部可答,延迟与联网时一致(±5%)
接力完整性: BLE 传输 1.35 MB 专家包后,接收方条数、CRC、抽样检索结果与发送方一致
离线验签: 篡改 1 字节的包必须被拒绝;无网状态下也能拒绝 (这是物理接力成立的前提)
换班连续性: 模拟换班(板 B 拔下 → 插入另一台宿主),新宿主检索结果与原宿主一致
九、场景 S3|专业私域知识库(纯语义 · 首销 SKU 定价锚)
要素 内容
痛点 跨设备失忆;私域资料不敢上云(PIPL/DSL);Agent 每次都要重新喂上下文
我们的角色 β USB Dongle 成品形态。这是首个 SKU(¥399)的定价锚验证载体
为什么选 与 Plaud / 笔记熊 / Oki 直接竞争,保留一个 SKU 作定价锚但不作收入主项 ;同时它是唯一能压满 N16R8 容量(12,000 条)的场景,正好验证 G1
板位 板 B(N16R8)直插 PC;板 A 不参与(或作为第二块随身副本演示)
能力侧重 纯语义 RAG :无时序、无传感器,纯文本碎片 + MCP 接口
9.1 知识库碎片构成(压满容量,用于验证 G1 )
v1.1 更新: 按 3.5 节方案 B ,N16R8 记忆库 ≈ 14,448 条(推算、未实测 ),故 S3 的满载规模从 8,000 条上调到 12,000 条 (占记忆库约 83%,推算)。这是唯一能把容量压到判据线附近的场景。
frag_id 碎片名 条数 内容 来源 字节
1 docs-core-v1 技术文档包9,000 产品技术文档、API 手册、规格书(按语义切块,非按页) PDF / Markdown 离线 embedding 6.77 MB
2 meeting-2026Q3 会议纪要2,200 决策记录与结论(含被后续决策推翻的旧结论 ,用于测冲突消解) 会议记录 1.65 MB
3 pref-v1 个人偏好800 写作风格、常用术语、忌讳表达 人工整理 0.60 MB
合计(满载) 12,000 ≈ 9.02 MB —— 落在 G1 的 12,000 条目标上 9.02 MB
9.2 灌库与查询路径(全部离线)
灌库 ① PC 侧:docs/ → 切块 → embedding(384d) → IVF聚簇 → HNSW构图 → 顺序布局 → .emf
② 拖 .emf 进虚拟 U 盘 → 板侧校验 → 合并 → STATUS.TXT 回写结果
③ 全程无外网,可在飞行模式的笔记本上完成
查询 MCP 客户端(或 Host SDK)
→ 宿主侧算查询向量
→ CDC/MCP 下发 {"cmd":"mem.query","args":{"vec":[...],"topk":5}}
→ 板侧返回命中的 payload 摘要 + 相似度 + frag_id
→ 宿主用摘要组装 prompt(原文留在 PC 侧,板侧只存 150 B 摘要)
9.3 典型查询与特殊用例
Q1 常规 vec=<"eXtremeDB 的 ANN 索引支持哪些距离度量">, topk=5
Q2 碎片限定 vec=<"上周关于定价的结论">, frag_id=2, topk=5
Q3 ★冲突消解 vec=<"我们的目标客户是谁">, topk=5
预期:返回最新结论,且【能指出存在被推翻的旧结论】
—— 这是策略层相比纯向量库最直观的差异
Q4 去重 灌入 500 条含 100 条近重复的笔记 → 库内重复率应显著下降
Q5 卸载 frag.remove(1) 后,剩余 2,000 条仍可正常检索(碎片自洽性验证)
9.4 场景级判据
满载可用: 12,000 条装载后,P50/P99 仍满足 G2(这是 G1 与 G2 的联合验证点 )
断网: 笔记本飞行模式下完成灌库与查询全流程
冲突消解: Q3 能正确返回最新结论并标记旧结论;不能返回互相矛盾的两条却不加区分
碎片自洽: 单独卸载任一碎片后,其余碎片功能完全不受影响
定价锚: 完成 30 人的可用性观察,记录「愿意为这个能力付多少钱」的分布(输入战略报告待验证项 4)
9.5 三场景能力覆盖对照(证明「器官」可跨行业复用)
维度 S1 工业故障指纹 S2 野外巡检 S3 私域知识库
主导能力 时序 → 特征 → ANN 语义 + 接力 纯语义 RAG
时序使用 核心(L0/L1/L2 全用) 辅助(仅 L1 环境) 不用
接力模式 Hub 中继 物理 + 近场 + Hub 三种全用 物理(换台电脑)
碎片数量 4 4(跨两板) 3
装载量 2,900 条(留生长空间) 4,100 + 1,800 条 12,000 条(满载)
形态 α 模组 β 外设 β 外设(首销 SKU)
验证的判据 G4 闭环 G6 断网 + 接力 G1 容量 + G2 延迟
三个场景共用同一套固件、同一份 schema、同一个 .emf 格式 ,差异只在灌进去的碎片与宿主是谁。这就是「不做品类,做器官」在工程侧的证明方式。
十、测试用例集
共 52 条用例 :核心 TC-C-* 8 条、碎片/灌库 TC-F-* 8 条、场景各 8 条(S1/S2/S3)、非功能 TC-N-* 12 条 (v1.1 新增 TC-N-11 footprint 基线、TC-N-12 abort 可预测性)。用例列:前置 → 步骤 → 预期 。
10.1 核心引擎(TC-C)
编号 用例 前置 步骤 预期
TC-C-01 距离核正确性 已知 100 组向量与参考结果(PC 侧算好) 板侧计算并回传 与参考结果误差 = 0(int8 定点,不允许有偏差)
TC-C-02 HNSW 召回率 1,000 条库;100 条查询向量 + 暴力搜索 ground truth ef_search 取 16/32/64 三档ef=32 时 top-10 召回 ≥ 95% ;ef=16 ≥ 88%
TC-C-03 混合查询正确性 库内设 3 个 dev_id、2 个 frag_id、时间跨度 30 天 下发 vec + dev_id + 时间范围 结果全部 满足全部精确条件;与「先 ANN 后过滤」的参考实现一致
TC-C-04 事务原子性 空库 begin → 写 100 条 → 人为断电 → 重启 库可打开,条目数 = 0(未 commit 完全回滚)
TC-C-05 事务持久性 空库 begin → 写 100 条 → commit → 立即断电 → 重启 条目数 = 100,内容完整(CRC 校验通过)
TC-C-06 时序环形覆盖 L0 PSRAM 环配置为 10 s 持续写入 60 s 环内始终为最近 10 s;无越界、无内存泄漏(heap 水位稳定)
TC-C-07 L2 去重收敛 空库 注入 500 个高度相似(余弦 > 0.95)的窗口特征 库内条目数 ≤ 50 (收敛),且检索仍能命中代表条目
TC-C-08 回溯取证 已有带 src_win_id 的 L2 条目 ANN 命中后按 src_win_id 取时序 返回对应时间窗的 L1 聚合数据,时间戳与窗口起点一致
10.2 碎片与灌库(TC-F)
编号 用例 前置 步骤 预期
TC-F-01 MSC 拖拽灌库(正常) 12,000 条 .emf 拖入虚拟 U 盘,等待 STATUS.TXT 出现 ≤ 60 s 完成;STATUS.TXT 报成功与条数;mem.stats 条数一致
TC-F-02 CDC 灌库等效性 同上 .emf 改用 CDC 路径灌入另一块板 两板条数、抽样检索结果完全一致
TC-F-03 篡改包拒绝 把 vectors.bin 改 1 字节 拖入 拒绝安装 ;STATUS.TXT 报 CRC 失败;原库条数不变
TC-F-04 无网验签 合法包 + 篡改包各一 关闭 Wi-Fi/BLE,仅 USB 供电,重复 TC-F-01/03 结果完全一致 —— 验签不依赖网络
TC-F-05 维度不符拒绝 manifest 声明 384,实际 768 维 拖入 拒绝;不写入任何数据;不损坏原库
TC-F-06 超长 payload 拒绝 payload 中含 200 B 条目 拖入 拒绝(150 B 硬上限);报告越界条目序号
TC-F-07 依赖外部的包拒绝 manifest 中声明 depends_on 拖入 拒绝 —— 自洽性是强制校验项
TC-F-08 碎片卸载自洽 3 个碎片共 12,000 条 frag.remove(1) → 检索剩余 2 个碎片检索完全正常;空间被回收;无孤立向量残留
10.3 场景 S1(TC-S1)
编号 用例 前置 步骤 预期
TC-S1-01 灌库与装载 4 个碎片共 2,900 条 逐包灌入板 B 条数 2,900;em_stat 字节数与预算表一致(±5%)
TC-S1-02 故障识别 top-1 8 类故障各 20 个测试样本(带标签) 逐条查询,取 top-1 top-1 命中率 ≥ 85%
TC-S1-03 故障识别 top-5 同上 取 top-5 ≥ 95%
TC-S1-04 稳态误报率 10 分钟正常工况连续数据 逐窗口查询,统计相似度低于阈值的比例 ≤ 5%
TC-S1-05 混合查询(设备+时间) 3 台设备 30 天数据 dev_id=2, t0/t1=最近30天结果全部属于 dev 2 且在时间窗内;与参考实现一致
TC-S1-06 闭环回写 一个被人工确认为「螺杆磨损」的异常窗口 回写为新指纹(level=2, salience=0.9)→ 重新灌入同类样本 新指纹被命中 ,且排在 top-3 内
TC-S1-07 可回溯取证 任一 ANN 命中 按 src_win_id 取原始窗口并导出 CSV CSV 可被 PC 侧绘图;时间戳连续、点数正确
TC-S1-08 长时间跑机 板 A 连续采集,板 B 持续入库 连续运行 72 小时 无重启、无内存泄漏(heap 水位波动 < 5%)、L2 条目数收敛不发散
10.4 场景 S2(TC-S2)
编号 用例 前置 步骤 预期
TC-S2-01 双板装载 板 B 4,100 条;板 A 1,800 条 分别灌库 条数正确;板 A 占用 ≤ N8R8 档位(2,500 条)
TC-S2-02 语义检索质量 50 条带 ground truth 的查询集 top-5 检索 召回 ≥ 90% (人工标注相关条目)
TC-S2-03 物理接力 板 A 装着专家包 拔下板 A → 插入另一台宿主 → 查询 新宿主立刻能检索到专家包内容;结果与原宿主一致
TC-S2-04 近场接力(BLE) 两板 BLE 已配对 板 A → 板 B 传输 1.35 MB 专家包 传输成功;接收方条数 +1,800;抽样检索结果与发送方一致
TC-S2-05 接力中断续传 同上 传输到 50% 时人为中断 → 重试 续传成功;不产生半包或重复条目
TC-S2-06 全程断网 两板 Wi-Fi/BLE 关闭(仅 USB 供电) 执行 Q1–Q3 全部查询 全部可答;延迟与联网时差异 ≤ 5%
TC-S2-07 点位+时间混合查询 含 site_id 与时间戳的记录 site_id=K12+300, t0/t1 + 向量结果全部属于该点位且在时间窗内
TC-S2-08 Hub 中继与版本升级 Hub 上有 defect-v2 板 B 回办公室 → USB 同步 → 下发 v2 本地新增记录上传完整;v2 安装后旧版可回滚
10.5 场景 S3(TC-S3)
编号 用例 前置 步骤 预期
TC-S3-01 满载灌库 12,000 条三个碎片 拖入并等待完成 条数 12,000;占用 ≈ 9.0 MB;em_stat 与预算表一致
TC-S3-02 满载延迟 同上满载库 1,000 次随机查询 P50 < 10 ms,P99 < 30 ms (对应 G2)
TC-S3-03 语义检索质量 100 条带 ground truth 的查询集 top-5 检索 召回 ≥ 90%
TC-S3-04 冲突消解 库内含被推翻的旧结论与新结论 查询「我们的目标客户是谁」 返回最新结论,并标记存在被推翻的旧结论 ;不得返回两条矛盾结论却不加区分
TC-S3-05 近重复去重 500 条含 100 条近重复的笔记 灌入后统计 库内近重复下降 > 90% ;代表性条目保留
TC-S3-06 碎片限定查询 三个碎片 frag_id=2 + 向量查询结果全部来自碎片 2;不跨碎片污染
TC-S3-07 MCP 端到端 标准 MCP 客户端 不经自定义协议,纯 MCP 完成一次查询 成功返回;证明不依赖私有 API
TC-S3-08 飞行模式全流程 笔记本飞行模式 灌库 → 查询 → 卸载,全流程 全部成功;无一次对外网络请求(抓包确认)
10.6 非功能测试(TC-N,直接对应 Go/No-Go ①)
编号 对应 用例 步骤 阈值
TC-N-01 G1 容量实测 从 1,000 条起逐步灌入至失败,记录临界条数 临界 ≥ 12,000 条 (可行性门槛 8,000 条);记录实际值与失败模式(空间不足 / OOM / 超时)
TC-N-02 G2 延迟分布 12,000 条库,1,000 次查询,记录每次板侧耗时 P50 < 10 ms,P99 < 30 ms,P99/P50 < 4
TC-N-03 G3 内存峰值 检索过程中采样 PSRAM 与内部 DRAM 峰值 PSRAM ≤ 5 MB ;内部 DRAM 峰值 ≤ 180 KB
TC-N-04 G4 闭环成立性 回写新记忆 → 下一轮检索是否命中 命中,且排在 top-3 内
TC-N-05 G5 灌库耗时与成功率 12,000 条包连续灌 20 次(含 5 次错误包) 正常包 100% 成功且 ≤ 60 s;错误包 100% 被拒且不坏原库
TC-N-06 G6 断网复测 sys.offline 后复测 N-01…N-05全部通过,数值偏差 ≤ 5%
TC-N-07 G7 随机掉电 100 次 脚本随机时刻断电,重启后检查库 100% 可打开 ;条目数无异常增长/丢失;最多丢失最后一次未 commit 事务
TC-N-08 耐久 Flash 磨损 10 万次条目的写-删循环 无坏页导致的数据丢失;磨损均衡生效(擦写次数分布均匀)
TC-N-09 吞吐 连续查询吞吐 CDC 连续 10,000 次查询 ≥ 30 QPS (含 USB 往返);不出现 Nagle 塌陷 (若 < 5 QPS 即命中该坑)
TC-N-10 长稳 7×24 小时跑机 板 A 持续合成注入 + 板 B 持续入库与查询 无自发重启;无内存泄漏;若重启先查栈溢出 (抓 Rebooting 前 30 行)
TC-N-11 footprint 基线 (v1.1 新增)记录 emlite 的 .text 体积与运行时峰值 RAM 编译后取 .text;运行时采样 PSRAM 与 DRAM 峰值 .text ≤ 60 KB;运行期 malloc 次数 = 0 (4.4.3 硬指标)。此数据是替换 emdb 后算收益的基线
TC-N-12 abort 耗时可预测性 (v1.1 新增)不同写集大小(10 / 100 / 1000 条)各 abort 200 次 记录每次 abort 耗时 P99 ≤ 2×P50 ;耗时与写集大小线性相关,无长尾(Andrei Gorine:回滚成本必须绑定到已知写集)
两个必测的历史坑(本项目已踩过,MVP 必须回归):
① Nagle + 延迟 ACK :板端响应必须合并成一次 send,httpd open_fn 要设 TCP_NODELAY,否则连续查询会从 10 fps 塌到 0.33 fps(TC-N-09 就是为它设的)。
② 周期性自发重启 :源码里没有 esp_restart 却定期重启,先查栈溢出 。已知:NimBLE host 栈需 ≥ 8192;hub_task 栈 6144 内不得放大缓冲;大数组改用堆分配(TC-N-10)。
十一、里程碑、Go/No-Go 与执行顺序
阶段 周期 任务 出口交付物 判据
M1 铺路第 1–3 周 WP0 全部 + W1-01(HAL 接口定义) 两板构建变体、USB 复合设备冒烟通过、性能基线 baseline.md 板 B 在三大平台零驱动枚举成功
M2 引擎第 4–9 周 W1-02…W1-09(存储/距离核/HNSW/IVF/时序/WAL/混合查询) emlite 后端可跑;单板 12,000 条可查TC-C-01…08 通过
M3 工具链第 7–11 周 (与 M2 并行) W5-01/02/03/05(embedding 选型、打包器、校验器、基准工具) 可产出 .emf;可跑基准 TC-F-03…07 通过(错误包全拒)
M4 接口第 10–13 周 W3-01/02/03/06/07(CDC 协议、MSC 拖拽灌库、断网自检) 拖 .emf 进 U 盘即灌库 TC-F-01/02/04 通过
M5 策略第 12–15 周 WP2 全部(生命周期/遗忘/去重/闭环回写/健康检查) 策略层可用;mem.check 输出健康度 TC-C-07、TC-S3-04/05 通过
M6 闭环第 14–17 周 WP4 全部(采集/特征化/L2 入库/回写) S1 端到端闭环演示 TC-S1-01…08 通过
M7 三场景第 16–19 周 W5-06(语料)+ W6-02(集成测试)+ W3-05(MCP) 三场景集成测试报告 + Alpha 演示包 TC-S1/S2/S3 全部通过
M8 非功能第 18–21 周 W6-03 非功能测试 + W1-11 调优 实测数据表 (替换所有推算值)TC-N-01…10 通过
M9 决策第 22 周 W6-05 评审包 Go/No-Go ① 评审 G1–G7 全部达成
11.1 Go/No-Go ① 的处置规则
情况 处置
G1–G7 全部达成 进入 P1(形态与 SDK):β Dongle 工程样机 50 台 + Host SDK + 拜访 ≥10 家客户、落地 ≥3 家 PoC
仅容量或延迟未过 (G1/G2),且用的是 emlite先不判死 。启用 emdb(eXtremeDB)后端重测后再判。这是双后端 HAL 设计的价值所在
G1/G2 未过,且原因是 I/O 主导 调三项再测:① IVF 粗划分削减触及面;② 离线按簇顺序落盘;③ 热碎片常驻 PSRAM。不换 MCU
G5(拖拽灌库)未过 单独评估:这是 UX 卖点不是技术内核。若降级为 CDC 灌库仍可用,可判「有条件通过」并记录为风险
G7(掉电一致性)未过 一票否决,不得进入 P1。 事务一致是这个产品的立身之本,也是否决所有竞品的唯一硬指标
双后端均未过 回退纯软件授权路线,不做硬件(战略报告第 11 章既定处置)
11.2 与战略报告路线图的对齐
本任务书覆盖战略报告的 P0(M1–M4 技术闭环验证) 并延伸到 P1 前半段。P0 出口即本任务书 M9。差异在于:战略报告 P0 只有 4 个月,本任务书按 2 人并行估到约 5 个月(22 周)——多出的部分主要是双后端 HAL 的额外工作量(W1-12/13 的 16 人日)与三场景语料构建(8 人日) 。若授权提前到位且只验证一个场景,可压缩回 4 个月。
十二、风险登记与已知工程坑
12.1 风险登记册
# 风险 等级 缓解 触发后的处置
R1 McObject 授权条款不利或谈崩 高 双后端 HAL(emlite 先行)——本任务书的核心对策 用 emlite 继续;容量降一档,商业模型仍成立
R2 实测容量/延迟达不到 G1/G2 高 W0-06 先测基线;IVF + 顺序布局 + 常驻三项优化 先换后端再判;仍不过则回退软件授权
R3 USB PHY 冲突导致开发效率下降 中 W0-02 一次性切干净;板 B 常备 USB-UART 转换器 改用 OTA 更新(现有 ota_mgr)+ UART0 日志
R4 384 维中文 embedding 质量不足 中 W5-01 做召回对照实验,早期就要结论 改用 768 维 → 容量减半(12,000 → 6,000 条),需重估叙事
R5 场景缺位(Limitless 的死法) 高 M9 强制绑定单一杀手场景,由产品负责人基于 PoC 数据拍板 不做「什么都能记住」的通用 SKU
R6 自研 HNSW 实现缺陷(召回/崩溃) 中 TC-C-02 用暴力搜索做 ground truth 对比;W6-01 单测覆盖 ≥85% 降低 ef/M 参数保稳定;优先保 P99 而非峰值召回
R7 板 B 现网 4343 条数据丢失 中 W0-07 先备份再动;--backup 成默认动作 10 分钟内可恢复
R8 栈溢出 / 内存泄漏导致长稳失败 中 TC-N-10 七天长稳;启动即打 heap 水位基线 按已知坑集合逐项排查(NimBLE 8192、大数组改堆)
R9 改分区表后未及时重烧 ,导致后续灌库全废中 把分区表改动排在 W0-05,必须在任何正式灌库之前完成 ;先 esptool flash-id 确认容量,改后用 sys.info 核对整片重烧 + 重灌知识库(板 B 现网 4343 条须先备份)
R11 v1.2新增 固件膨胀撑爆 app 槽 :MVP 陆续加入 TinyUSB、emlite、调试命令后,2 MB 槽余量从 38% 被吃掉中 W0-06 构建期硬门槛 (>0.8 告警 / >0.9 失败);每次合并前看 size 输出。v1.2 实测基线:现状 1.459 MiB,完整态预计 1.44–1.49 MiB 先裁 cli_json 的冷门命令与 link_mgr 的 mesh 部分;仍不够则需改分区表(整片重烧 + 重灌)
R10 合成数据结论被误当成真实数据 对外表述中 所有测试报告与对外材料强制标注「合成数据集」;W4-07 完成前不得宣称真实场景召回率 W4-07 立即执行,做真实/合成偏差对照
R11 emlite 实现膨胀(体积/RAM 超标),削弱替换收益中 4.4.3 的三个硬指标(≤60 KB / 0 次 malloc / abort P99 ≤ 2×P50)设为门禁 评审实现,必要时裁剪功能而非放宽指标
12.2 已知工程坑清单(本项目实战积累,MVP 必须遵守)
坑 正确做法
USB-OTG 与 USB-Serial-JTAG 共用 PHY 同一时间只能一个工作。β 形态要并存必须:① 用外部 PHY,或 ② 烧 eFuse 切 JTAG。PCB 阶段决定,事后不可改 。MVP 先把 console 切 UART0
sdkconfig 的 choice 组 给非目标成员写 =n 会导致整组失效并回退默认值。只给目标成员写 =y
Nagle + 延迟 ACK 响应合并成一次 send;httpd open_fn 设 TCP_NODELAY。否则 10 fps → 0.33 fps
中文 JSON 缓冲 含中文 msg 不能用 256 B(一字 3 字节会切出非法 UTF-8),用 768 B
payload 截断 150 B 硬上限,绝不能在多字节字符中间截断
周期性自发重启 源码无 esp_restart 却重启 → 先查栈溢出 (抓 Rebooting 前 30 行)。NimBLE host 栈 ≥ 8192;hub_task 6144 内不得放大缓冲
esp_partition_next()末尾自 release,调用方不可再 release(double free → tlsf assert → 重启)
构建退出码被吞 idf.py build 2>&1 | while read 会吞退出码导致旧 bin 被误判成功。验证是否上新板看 sys.info 的 build_time ,不看 exit code
多任务共串口 必须单锁整行原子写 (cmd_console_write() + esp_log_set_vprintf()),各源各把锁无效
板级配置纪律 boards/ 是唯一真源,禁止跨板拷贝 sdkconfig ;升级先问清是哪块板;固件更新首选 OTA,串口只用于首刷与排障
12.3 下一步的四个动作(本周可做,零成本)
# 动作 产出与意义
1 向 McObject 发书面询问 :MCU 端分发授权条款 + eXtremeDB 9.0 的 ANN / Edge Client / Active Replication Fabric 是否在现有授权内 + 千片/万片阶梯价仍是唯一的全局阻塞项。但现在不是"阻塞全部"了 ——手上有了 emlite 计划,谈判地位不同
2 跑 W0-06 性能基线 :板 B 上实测 PSRAM 可用量、flash 4 KB 页读延迟、1 MB 顺序写耗时半天就能出结果。这一个数字能把本任务书所有"推算"标注换成实测起点
3 跑 W0-03 USB 复合设备冒烟 (官方示例直接移植)风险最低、信心价值最高。拖文件即灌库 这个 UX 一旦跑通,整个产品的说服力立刻成立
4 改分区表为方案 B (app 槽 4 MB → 2 MB,见 3.5 节 )零成本换来 +61% / +118% 容量 。两行 CSV 的事,风险极低。但必须赶在正式灌库之前做 ——分区表变了要整片重烧,之后再动就得重灌所有知识库