摘要:大语言模型火了两三年,但一个根本问题始终没被认真解决——AI的记忆是"易失"的。每次对话结束,模型对本次会话内容的理解就消失了。具身AI(Embodied AI)场景更严重:传感器数据、图像帧、IMU数据、机械臂状态……这些多模态数据需要一个专门设计的存储引擎。本文介绍开源项目 moteDB,一个用 Rust 写的嵌入式多模态数据库,以及它背后那些真实的工程权衡。

标签:Rust、数据库、具身AI、向量数据库、嵌入式开发


一、为什么AI需要"持久记忆"

用过 ChatGPT 的人都知道:关掉对话窗口,上下文就消失了。模型并没有真正"记住"你告诉它的事情——它只是在本次上下文中把历史信息塞进了 Token 窗口。

这对个人助手来说勉强可以接受。但对于具身AI(机器人、自动驾驶、工业检测),这是致命问题:

  • 机器人在抓取物体前,需要回忆上次成功抓取同一物体的视觉特征和力度参数
  • 自动驾驶系统需要把异常场景(鬼探头、施工绕行)的传感器数据永久存档,供后续分析
  • 工业机械臂需要关联视觉帧、力矩传感器读数和关节角度,回答"为什么这个工件在三秒前被放下了"

这些数据的特点是:多模态(文本、向量、时序、结构化数据混合)+ 写入密集(传感器通常 100~500Hz)+ 需要跨模态联合查询(“找这个力矩阈值被触发时前后各10帧的图像”)。

现有的存储方案,没有一个能同时满足这三点。


二、现有方案的三个问题

2.1 SQLite:文件锁战争

很多团队最初用 SQLite 存传感器数据。SQLite 足够轻量,单文件,部署简单。但机器人的软件栈往往是多进程的——一个进程写数据库,另一个进程读数据库,中间还有个进程做索引构建。SQLite 的文件锁在多进程并发读写时会竞争:

  • Python 进程 A 正在写,Rust 进程 B 的读取被锁住等待
  • 高频写入(200Hz)时,23ms 的锁等待直接变成可见的伺服电机抖动
  • 传感器数据的追加写入模式天然不适合 B-tree 的随机读写优化

2.2 传统向量数据库:内存墙

Pinecone、Milvus、Qdrant 这些向量数据库设计目标是云端大规模语义搜索。它们用 HNSW(Hierarchical Navigable Small World)构建向量索引——效果很好,但 HNSW 需要把所有向量加载到内存里。

数据规模 向量维度 内存占用
100万条 384维 float32 ~1.5 GB
1000万条 768维 float32 ~24 GB

边缘设备(工控机、机器人主控)通常只有 4~8GB RAM,还得分给模型推理和控制系统。向量索引一跑,内存直接爆了。

2.3 自己写文件:维护地狱

最常见的"解决方案":写个 Python pickle 文件存传感器数据,或者直接存 CSV/JSON。短期内能用,但:

  • 数据膨胀后查询极慢
  • 没有索引,跨模态关联查询几乎不可能
  • 崩溃恢复靠自己写,边界情况一堆
  • 不同模块各写各的,数据孤岛越来越严重

三、moteDB 的设计思路

moteDB 是我们为具身AI场景专门设计的存储引擎,核心目标:在嵌入式设备上,用最小资源完成最多模态的持久存储

三个核心设计决策:

3.1 Rust:无运行时、无GC、2MB 二进制

选 Rust 不是因为它"酷",而是因为嵌入式场景的两个硬约束:

  1. 不能有垃圾回收暂停:GC 的 Stop-the-World 在实时控制循环里是不可接受的
  2. 二进制要足够小:机器人上要同时跑感知、规划、控制多个模块,数据库不能占太多空间

Rust 的所有权系统+生命周期检查在编译时保证内存安全,不需要垃圾回收器。cargo build --release 产出一个静态二进制,2MB,启动时间 3ms。这是有多进程实时控制环的机器人场景里的必需条件。

# 安装 moteDB
cargo add motedb

# 或者
[dependencies]
motedb = "0.1.6"

3.2 LSM-tree:追加写入模式的天然匹配

传感器数据本质上是日志型追加写入——每个时间戳一条新记录,而不是随机更新已有记录。B-tree 在随机写入时需要多次磁盘寻道,LSM-tree 则利用顺序写入的速度优势:

写入路径:  数据 → WAL(持久化)→ MemTable(内存)→ 刷盘到 SSTable

读取路径:  MemTable(热数据)→ 最新 SSTable → 更旧的 SSTable

MemTable 是一个内存中的 BTreeMap,按 key 排序。当 MemTable 满了之后,刷盘成 immutable SSTable,查询时从新到旧逐层扫描。最新写入的数据几乎总在 MemTable 里,读取延迟极低。

这个模式对具身AI非常友好:热数据(最近几秒的传感器帧)全在内存里,查询几乎是内存操作;历史数据在磁盘上,通过分层索引访问。

3.3 多模态统一存储:不是三个数据库,是一个

最 naive 的方案是"每种数据类型用专门的数据库"——向量存 Pinecone,时序数据存 InfluxDB,结构化数据存 SQLite。然后应用层自己实现跨库关联查询。这条路走不远,因为:

  • 跨模态原子查询无法实现:如何在一次事务里同时查向量相似度、时间范围和结构化条件?
  • 运维复杂度爆炸:三个数据库 = 三套部署 + 三套备份 + 三套监控
  • 数据一致性靠应用层保证:传感器数据和对应视觉帧的时间戳对应关系很容易漂移

moteDB 的方案:所有索引类型共享同一个 WAL(Write-Ahead Log),每个索引独立刷盘和压缩,但写人对所有索引同时可见或同时回滚。这样添加新的索引类型(比如全文检索、地理空间索引)不需要修改写入路径,只要实现 Index trait 即可。


四、实战:让机器人记住它看到的一切

场景设定

一个仓库分拣机器人,需要:

  1. 存入货物的视觉特征向量(用于下次识别同款货物)
  2. 记录每次抓取的力矩曲线(时间序列)
  3. 用自然语言描述货物外观,供人工检索

三行代码实现:

use motedb::{MoteDB, DataEntry};

let db = MoteDB::new("./robot_memory.motedb")?;

let warehouse_item = DataEntry::builder()
    .with_vector("vision_feature", &vision_embedding)    // 视觉向量
    .with_scalar("force_curve", serde_json::to_vec(&force_data)?) // 力矩曲线
    .with_text("description", "红色正方形包装,角角有轻微破损")  // 文本描述
    .with_timestamp(now)
    .build()?;

db.insert(b"item_20250706_001", warehouse_item)?;

查询:跨模态联合检索

“找所有力矩超过 5N·m 且外观描述与’红色包装’语义相似的货物记录”:

use motedb::query::{VectorQuery, ScalarQuery, TextQuery};

let results = db.query()
    .vector("vision_feature", &query_embedding, top_k = 10)
    .scalar_gt("max_force", 5.0)                  // 力矩过滤
    .text_similarity("description", "红色包装")    // 文本语义过滤
    .execute()?;

这个查询同时触发了向量索引(DiskANN)、标量索引(B-tree)和全文索引(倒排表),三个索引的结果做交集。所有操作在一个数据库进程内完成,没有跨网络调用。

DiskANN:嵌入式设备的向量搜索

前面提到,HNSW 需要全量内存。moteDB 的向量索引使用 DiskANN——一种可以内存映射的图索引。查询时只访问需要的磁盘页,且访问顺序可预测(最坏情况 I/O 次数有界)。

代价是建索引时间很长(离线完成),但查询时内存占用与数据集大小无关。这正是边缘设备的正确权衡:索引在开发机上构建,部署后只跑查询。


五、性能数据(树莓派 4B 实测)

场景 moteDB SQLite Milvus (HNSW)
200Hz 写入延迟 < 1ms 8~23ms(含锁等待) N/A(无本地模式)
1000条向量范围查询 4ms N/A 2ms(但需 ~1.5GB RAM)
磁盘占用 ~50MB/百万条 ~80MB/百万条 ~200MB/百万条(含索引)
冷启动时间 3ms 50ms > 1s(JVM 启动)
多模态联合查询 ✅ 原生支持 ❌ 需手动 JOIN ❌ 需应用层组合

实测环境:Raspberry Pi 4B(4GB RAM),机器人控制循环 200Hz,背景同时跑一个 YOLOv8 视觉推理进程。


六、谁应该用 moteDB

适合的场景:

  • 边缘设备上的具身AI记忆存储
  • 多模态数据(向量+时序+结构化)需要统一管理的嵌入式系统
  • 对写入延迟敏感(传感器高频写入)
  • 需要跨模态联合查询但不能跑独立向量数据库服务
  • 对内存和二进制大小有严格限制

不适合的场景:

  • 云端大规模向量检索(Pinecone / Qdrant 更好)
  • 写少读多的分析型负载(LSM-tree 的读放大是劣势)
  • 需要强事务语义(moteDB 目前是最终一致性)

七、开始使用

GitHub:https://github.com/motedb/motedb

crates.io:cargo add motedb

当前版本 0.1.6,支持:

  • 向量存储 + DiskANN 索引
  • 标量数据(JSON / 二进制)存储
  • 时间序列自动分区
  • 多索引联合查询
  • 完整的崩溃恢复(WAL)

v0.2.0 已在开发中,包含两阶段索引架构和谓词下推优化,clippy 零警告,749 个并发测试全部通过。


写在最后:moteDB 不是万能药。它不会比调优过的 Postgres 在分析查询上更快,不会比 Pinecone 在召回率上更准。它的每一个设计决策,都是在具身AI的约束条件下权衡的结果。如果你也面临同样的约束,欢迎试试;如果不是,SQLite 挺好的。

至少现在,你知道这些权衡是怎么回事了。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐