如何把 TensorFlow Lite 模型存附件?

解读

在国内实际项目中,TensorFlow Lite 模型文件(*.tflite)通常体积在 几百 KB 到几十 MB 之间,属于二进制大对象(BLOB)。CouchDB 的文档-附件机制天然适合存放此类文件,既能利用 HTTP/REST 接口直接上传下载,又能借助 多主复制 把模型同步到边缘节点,实现“离线优先、端云协同”的 AI 场景。面试官问这道题,核心想验证两点:

  1. 你是否理解 CouchDB 附件与文档分离、又强关联 的设计;
  2. 你是否能在国内网络环境下给出可落地、可运维的完整方案,包括断点续传、增量同步、权限控制与灰度发布。

知识点

  1. 附件存储原理:CouchDB 把附件存成 独立 BLOB,文档体内只保留 content_typelengthdigest(MD5)等元数据,不占用 JSON 序列化大小,因此单文档上限仍是 8 MB 限制,但附件本身无硬上限(生产建议 ≤ 50 MB,避免复制积压)。
  2. 两种上传方式
    • PUT /db/doc_id/att_name?rev=rev 传统方式,需先读最新 rev;
    • PUT /db/doc_id 一次提交 multipart/related(含 JSON + 附件),可减少一次往返,适合移动端弱网。
  3. 压缩与缓存:CouchDB 默认 gzip 压缩文本,但不会二次压缩二进制,因此 .tflite 建议提前压缩成 .tgz 再上传,可省 20–40% 流量;同时返回头带 ETag,边缘节点可用 If-None-Match增量缓存
  4. 安全合规:国内项目需过等保 2.0,附件 URL 必须走 HTTPS + 签名;CouchDB 内置 _security 对象可绑定 roles: ["model-reader"],配合 JWT 代理层(如 OpenResty)实现细粒度鉴权
  5. 灰度与版本管理:利用 复制过滤器 selector: {"model_version": {"$gte": "2.1.0"}},把不同版本模型定向同步到不同边缘集群,实现按设备型号灰度

答案

步骤一:准备模型
mobilenet_v2.tflitegzip -9 压缩成 mobilenet_v2.tgz,节省流量。

步骤二:构造 multipart 请求

curl -X PUT https://couch.example.com/ai_models/mobilenet_v2 \
  -H "Authorization: Bearer ${JWT}" \
  -H "Content-Type: multipart/related; boundary=boundary123" \
  -H "Accept: application/json" \
  --data-binary @- << EOF
--boundary123
Content-Type: application/json

{
  "_id": "mobilenet_v2",
  "type": "tflite_model",
  "model_version": "2.1.0",
  "target_devices": ["rk3566", "esp32s3"],
  "description": "量化 INT8 模型,准确率 71.2%"
}

--boundary123
Content-Type: application/gzip
Content-Disposition: attachment; filename="mobilenet_v2.tgz"

...<binary data>...
--boundary123--
EOF

返回 201,{"ok":true,"id":"mobilenet_v2","rev":"1-abc"} 即成功。

步骤三:移动端下载

URL url = new URL("https://couch.example.com/ai_models/mobilenet_v2/mobilenet_v2.tgz");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestProperty("If-None-Match", localEtag);
if (conn.getResponseCode() == 304) {
    // 无更新,直接用缓存
} else {
    // 流式写入 /data/data/<pkg>/models/
}

步骤四:灰度同步
中心集群给文档打标 "canary": true,边缘节点复制过滤器:

{"selector": {"canary": {"$exists": false}}}

验证稳定后,去掉 canary 字段,全量复制。

拓展思考

  1. 超大模型(>100 MB) 如何破?
    可拆分为 分片附件(part_00、part_01…),客户端并行拉取后本地拼接;或把 CouchDB 作为元数据仓库,实际 BLOB 存入 国内 S3 兼容存储(如 OSS、COS),文档里只保留 外部 URL + SHA256,实现“元数据-数据分离”,仍利用 CouchDB 的复制能力同步索引信息
  2. 模型热更新 如何零停机?
    在 Android 端实现 双缓存目录/models/active//models/pending/;下载完成后校验 SHA256,再原子 rename 目录,秒级切换;同时监听 CouchDB /_changes?feed=continuous 接口,长轮询增量更新,流量高峰也不阻塞业务线程
  3. 联邦学习场景 如何防止模型泄露?
    把附件 加密后再上传(AES-256-GCM,密钥由 国密 SM2 协商),CouchDB 仅存储密文;边缘节点下载后,在 TEE(可信执行环境) 内解密并训练,训练完立即擦除明文,满足国内数据出境监管要求。