内容
StromaDB
**StromaDB** 是一款源代码开放、采用 Rust 语言开发的**实时 GraphRAG 引擎,针对大型语言模型(LLM)优化**:它融合了**意义(向量)× 结构(有类型图)× 时间(双时间)**,使 LLM 可以在毫秒级检索相关且结构正确的上下文,基于实时更新的图。

<sub>内置控制台(`stroma-serve`,访问地址:`http://localhost:7687/`):探索邻域,运行类型感知向量搜索,检查节点及其嵌入,组合查询 — 所有操作均为实时。</sub>
该项目针对**单个组织的有限规模**(每个组织的图规模有限),这使得低成本和高性能同时实现:热工作集适合内存,占用空间小,空闲租户可以缩减至零。
> 状态:**核心引擎已实现并经过性能测试** — 持久化变更日志(帧式 WAL,分组提交,fsync),IVF-PQ 向量索引,精确重排序,类型化混合读取,可组合查询 IR(点查询 / 类型近似邻居搜索 / 展开 / 过滤 / top-k),增量实时查询维护,以及 `stroma` 命令行工具。1.0 版本之前:单节点,单线程服务;详见 [docs/DECISIONS.md](docs/DECISIONS.md) 了解和路线图。`stroma` 命令行工具和 `stroma-serve` HTTP 接口与引擎一同发布。源代码开放(Elastic License v2)。
## 为什么选择 StromaDB
实时 LLM 检索需要一个能够即时处理数据流并支持**类型感知混合查询**的图。现有的解决方案无法满足这一需求:
- 向量数据库是**无类型感知**的 — 它们返回语义上接近但结构上错误的结果(例如,“Python”技能、文档和人员在纯 ANN 搜索中看起来相似)。
- 属性图(Neo4j 等)是面向批处理的,而不是原生支持流式数据。
- `Postgres + pgvector` 将意义和结构分离在不同的 I/O 路径上,对于流式更新处理效率低下。
StromaDB 专为 LLM 检索而设计支持流式数据,向量 + 类型化图,低成本,有限规模。
## 核心功能
- **类型感知混合搜索** — 通过图类型过滤和重排序 ANN 候选结果,避免不同类型结果的错误融合。
- **类型化属性图** — 具有每条**(层级,角色,分配)的显式类型边,存储在独立的存储中,与事实数据一同加载和读取;加载过程应用最小约束检查(域/范围,基数)。
- **流式数据加载,无写入阻塞** — 仅追加的变更日志; overload 时显式反压。
- **可组合的操作符查询 IR** — `点查询 / 类型近似邻居搜索 / 过滤 / top-k` 作为流水线组合(过滤器覆盖类型,当前值和**有效时间截止值**)。常驻查询通过增量:通常重新计算并求差,以及**键控增量**维护完整性/规则查询(O(touched),经过验证等同于完全重新计算)。统一一次性查询和实时查询的代数是设计方向;任意流水线的完整差异数据流维护在路线图中。
- **时间读取** — 事实携带有效时间;**有效时间截止值**的点读取返回过去某个时间点生效的值,事务时间截止值是版本向量 pin(`strict` / `fresh` 读取模式)。完整的时间查询范围(`ever` / `overlap以及多值边的有效时间)正在开发中。
- **无内部模型** — 确定性检索/查询层;LLM 始终是调用者。模型编写的摘要存储为 provenance,与断言事实保持不同。
## 控制台(网页 UI)
`stroma-serve` 包含一个内置的网页控制台 — 一个独立的 HTML 文件,无需构建步骤 — 在 `http://localhost:7687/` 提供服务。它是一个 GPU 渲染(WebGL2)的图浏览器,具有三种对等模式:
- **探索** — 按跳跃距离和类型范围过滤节点的邻域,实时力布局,可拖动节点,图上距离标签;检查任意节点直到其嵌入。
- **查询** — 运行点查询/展开读取,类型感知向量搜索或“查找相似”,并在图上显示结果。
- **组合** — 逐步链接基元(源 → 展开 → 过滤 → top-k),每个阶段都有结果计数。
当数据库更改时,图会实时更新(红色 **LIVE** 指示器指示流正在馈送)。会话登录,浅色/深色主题和 EN / JA / ZH 已内置。
```bash
stroma-serve --db ./mydb --addr 127.0.0.1:7687
# 然后在浏览器中打开 http://localhost:7687/
```
首先加载[示例数据集](examples/),以便在大约一分钟内探索一个已填充的图。
## 快速入门(命令行)
```bash
cargo install --path crates/stroma-cli # 安装 `stroma` 二进制文件
stroma init --db ./mydb
cat > data.jsonl <<'EOF'
{"type_def":{"name":"Person"}}
{"type_def":{"name":"Project"}}
{"pred_def":{"name":"works-on","cardinality":"many","domain":"PersonProject"}}
":{"name":"age","cardinalitydomain":"Person_value":"int"}}
id":1,""}}
{"node2,"type"}}
{"fact":{"1,"predicate":"works":{"node":2}}}
{"fact":{"subject":1,"predicate":"age","object":{"int":34}}}
EOF
stroma ingest data.jsonl --db ./mydb # 持久化(每块 fsync),类型化,验证
echo '{"node":1,"vector":[1.0,0.0,0.0,0.0]}' > emb.jsonl
stroma embed emb.jsonl --db ./mydb # 嵌入式接收器,永不计算
stroma query point 1 age --db ./mydb # {"one":{"int":34}}
stroma query expand 1 works-on --db ./mydb # {"nodes":[2]}
echo '[1.0,0.0,0.0,0.0]' > q.json
stroma query search --type Person --k 5 --vector-file q.json --db ./mydb
stroma stats --db ./mydb
```
仅保存权威输入( WAL,模式/,接收的嵌入);存储(向量索引)在打开时重新构建。
## 快速入门(Docker)
在没有本地 Rust 工具链的情况下运行 HTTP 接口 — 在首次运行时初始化一个新的数据卷:
```bash
docker compose up # 构建镜像,在 localhost:7687 提供服务(在卷中持久化)
# 或不使用 compose:
docker build -t stromadb .
docker run -p 7687:7687 -v stroma-data:/data stromadb
curl -s localhost:7687/health
curl -s -X POST localhost:7687/ingest -d '{"type_def":"Person"}}'
```
包含 `stroma`(入口点),以及 `` 命令行工具和 `stroma-m 二进制文件。
## 服务(HTTP)
`stroma-serve` 通过 HTTP 公开同一个数据库,以便代理或不嵌入引擎的情况下查询和摄取数据 — 这是 LLM 调用者的预期接口。它还在同一地址提供内置的网页[控制台](#console-web-ui)(如上所述)。
```bash
stroma-serve --db ./mydb --addr 127.0.0.1:7687 线程池:并发读取,独占写入
curl -s localhost:7687/health
curl -s -X POST localhost:7687/query -d '{"op":"expand","subject":1,"predicate":"works-on"}'
curl -s -X POST localhost:7687/query -d '{"op":"search","type":"Person","vector":[...],"k":10,"allowed_labels":7}'
# retrieve_context:组装,带时间戳,当前值上下文准备好供 LLM 使用
curl -s -X POST localhost:7687/query -d '{"op":"retrieve_context","type":"Doc","vector":[...],"content":"body","date":"created_at","k":8}'
curl -s -X POST localhost:7687/ingest -d '{"fact":{"subject":1,"predicate":"works-on","object":{"node":2}}}'
# 边属性:附加属性到边上,然后读取它们
curl -s -X POST localhost:7687/ingest -d '{"fact":{"subject":1,"predicate":"works-on","object":{"node":2},"props":{"role":"lead","allocation":60}}} -s -X POST7/query -d '{"op":"edge_props","subject":1,"predicate":"works-on","object":{"node":2}}'
curl -s localhost:7687/stats
```
设置来自标志或环境变量(标志 > 环境变量 > 默认值)— 参见 **[docs/CONFIGURATION.md](docs/CONFIGURATION.md)** 和 `.env.example`。
读取操作具有 authz 范围(`allowed_labels` 是调用者的 AB掩码),并带有 `as_of` 版本向量。v1 按顺序处理请求(单线程引擎,1.0 之前);并发读取在路线图中。
## MCP(代理工具)
`stroma-mcp` 通过 stdio 使用模型上下文协议,公开数据库作为 LLM 代理可以直接调用的工具 — `point`,`expand`,`search`(authz 范围的混合),`stats`,`ingest`。
```bash
stroma --db ./ # stdin/stdout 上的换行分隔 JSON-RPC 2.0
```
将 MCP 客户端指向该命令;`tools/list` 返回模式,`tools/call` 运行工具并以文本内容返回 JSON 结果。
## 性能(已测量,可复制)
单节点,单线程,进程内。合成聚类 768-d 向量(bge-class 分布),Apple M 系列笔记本电脑。每一行都可以通过 `crates/stroma-core/examples/` 中的一个命令复制。
| 操作 | 结果 | 复制 |
|---|---|---|
| 混合读取 — 向量 top-10 + 类型/标签过滤 + 1 跳展开,**同时持久写入** | **p50 0.86 ms / p99 1.84 ms** @ 0.5M 文档 | `--example c2b_integrated` |
| 写入 → 查询可见(持久 fsync + 向量添加 + 一致性视图刷新) | **单数字毫秒**;视图刷新为 O(更改的键),而非 O(状态) | `--example c2b_integrated` |
| 过滤召回率@10 @ 50% 类型选择性(重叠聚类数据,精确重排序) | **~0.99–1.0** at ~1 ms warm p99 | `--example ann_nprobe_curve` |
| 冷启动恢复(RTO) | **0.81 s for 5M 事实**; torn-write → **0 数据丢失** | durability_slo` |
| 摄入(追加 + 组提交 fsync) | **~7M 事实/s** | `--example durability_slo` |
| 热层内存 | **96 B/向量** PQ 代码(32 倍 vs 原始 f32);原始重排序层是冷的/可以是 SSD 的 | `--example ann_slo` |
| 集成开环(写入 + 读取 + 实时查询) | **0 数据丢失**,版本一致的读取 | `--example c2b_integrated` |
注意:数字来自上述硬件上的运行 — 在您的硬件上运行示例。尾部延迟(p99)被报告,而不仅仅是中位数。没有供应商比较;有关已知限制(单线程服务,文件-WAL 压缩待处理,冷-SSD 重排序警告),请参见 [docs/DECISIONS.md](docs/DECISIONS.md)。