Doramagic 项目包 · 项目说明书

mnem 项目

生成时间:2026-05-15 02:27:44 UTC

项目介绍

Mnem 是一个用 Rust 编写的本地优先(local-first)知识图谱系统,旨在为 AI Agent 提供可靠、持久的记忆层。它将外部文档(PDF、Markdown、代码等)解析、分块、提取实体和关系,构建成结构化的有向图,支持版本化、冲突检测和密码学签名验证。

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 核心对象模型

继续阅读本节完整说明和来源证据。

章节 支持的源格式

继续阅读本节完整说明和来源证据。

章节 分块策略详解

继续阅读本节完整说明和来源证据。

概述

Mnem 是一个用 Rust 编写的本地优先(local-first)知识图谱系统,旨在为 AI Agent 提供可靠、持久的记忆层。它将外部文档(PDF、Markdown、代码等)解析、分块、提取实体和关系,构建成结构化的有向图,支持版本化、冲突检测和密码学签名验证。

资料来源:crates/mnem-core/README.md

核心定位

Mnem 不是向量数据库,也不是传统的关系型知识库。它是一个本地优先的 DAG(有向无环图)存储,其设计目标包括:

设计目标说明
本地优先数据完全存储在本地,零云依赖
版本化完整的操作日志,支持分支、回滚和合并
可验证支持 Ed25519 签名和吊销列表验证
AI 友好专为 LLM/Agent 场景设计,支持上下文检索
多源解析支持 PDF、Markdown、代码、会话记录等多种格式

资料来源:crates/mnem-core/src/lib.rs

系统架构

Mnem 采用分层架构,核心分为以下几个 crate:

graph TD
    subgraph "表现层"
        CLI[mnem-cli]
        HTTP[mnem-http]
        MCP[mnem-mcp]
    end
    
    subgraph "核心层 mnem-core"
        OBJ[objects: Node/Edge/Commit]
        PROLLY[prolly tree]
        STORE[Blockstore trait]
        RETRIEVE[Retriever]
        SIGN[Signer/Verifier]
    end
    
    subgraph "数据接入层 mnem-ingest"
        PDF[PDF 解析]
        MD[Markdown 解析]
        CODE[代码解析]
        CONV[会话解析]
        CHUNK[分块策略]
        EXTRACT[实体/关系提取]
    end
    
    CLI --> HTTP
    HTTP --> MCP
    CLI --> mnem-core
    HTTP --> mnem-core
    MCP --> mnem-core
    mnem-core --> mnem-ingest

资料来源:crates/mnem-core/src/lib.rs

核心对象模型

资料来源:[crates/mnem-core/src/objects/node.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-core/src/objects/node.rs)
对象类型用途
Node图中的顶点,包含摘要、属性、上下文句子和可选内容
Edge图中的边,连接两个 Node,支持关系类型标签
Commit快照,包含一次操作后图的完整视图
Operation操作记录,包含时间戳、作者、签名等元信息
View读取视角,持有 heads 引用

数据接入流程

当用户向 Mnem 导入文档时,数据会经过以下处理流程:

graph LR
    A[原始文档] --> B[格式检测]
    B --> C{解析器选择}
    C -->|Markdown| D[parse_markdown]
    C -->|PDF| E[pdf 文本提取]
    C -->|代码| F[tree-sitter 解析]
    C -->|会话| G[JSON/JSONL 解析]
    D --> H[Section 列表]
    E --> H
    F --> H
    G --> H
    H --> I[分块策略]
    I --> J[Chunk 向量]
    J --> K[实体提取]
    K --> L[关系提取]
    L --> M[Transaction 提交]

资料来源:crates/mnem-ingest/src/lib.rs

支持的源格式

扩展名源类型默认分块策略
.md / .markdownMarkdownParagraph
.txt纯文本SentenceRecursive (256 tokens)
.pdfPDFSentenceRecursive (512 tokens)
.json / .jsonl会话记录Session (10 条消息)
.rs / .py / .js / .ts代码Structural

资料来源:crates/mnem-ingest/src/pipeline.rs

分块策略详解

资料来源:[crates/mnem-ingest/src/chunk.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-ingest/src/chunk.rs)
策略说明适用场景
Paragraph按双换行分割Markdown 文档
Recursive词窗口滑动,固定 overlap通用场景(向后兼容)
SentenceRecursive基于 Unicode 句子边界(UAX #29)打包纯文本、PDF
Session按对话轮次分组,边界在角色返回 user 时触发会话记录
Structural每 section 一个 chunk代码(函数/类级别)

实体与关系提取

Mnem 提供了多层次的实体和关系提取能力:

资料来源:[crates/mnem-ingest/src/extract.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-ingest/src/extract.rs)
提取器描述
RuleExtractor基于规则的提取,使用正则和启发式方法
KeyBertAdapter使用 KeyBERT 进行统计实体识别(需启用 keybert feature)
LLM Extractor使用 Ollama LLM 进行提取(需启用 ollama feature)

Sidecar 提取器

支持外部提取服务:

# Cargo.toml
mnem-ingest = { features = ["sidecar-docling"] }  # 或 ["sidecar-unstructured"]

资料来源:crates/mnem-ingest/src/lib.rs

检索系统

Mnem 提供了一套专为 Agent 设计的多阶段检索管道:

资料来源:[crates/mnem-core/src/retrieve/mod.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-core/src/retrieve/mod.rs)
graph TD
    Q[用户查询] --> F[过滤阶段]
    F --> V[向量检索]
    V --> S[稀疏检索]
    S --> R[重排序]
    R --> P[Token 预算打包]
    P --> R[最终结果]

检索配置参数

参数默认值说明
retrieve.limit-最大返回结果数
retrieve.budget-Token 预算上限
retrieve.vector_cap-向量检索结果数上限
retrieve.graph_expand-图扩展节点数
retrieve.graph_depth-图扩展深度
retrieve.rerank_top_k-重排序候选数
retrieve.hyde_max_tokens-HyDE 最大生成 Token 数

资料来源:crates/mnem-cli/src/config.rs

版本化与分支

Mnem 使用 DAG 结构存储版本历史,每次提交产生一个新的 Commit 节点:

graph LR
    A[Commit A] --> B[Commit B]
    B --> C[Commit C]
    C --> D[Commit D]
    B --> E[Commit E<br/>分支]
    E --> F[Commit F]
    D --> G[Commit G]
概念说明
Head当前分支的最新提交
Branch通过 refs 引用的命名指针
Merge检测两个分支的冲突并合并

资料来源:crates/mnem-http/src/handlers.rs

冲突检测

资料来源:[crates/mnem-core/src/repo/conflict.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-core/src/repo/conflict.rs)

Mnem 支持基于策略的合并冲突检测:

策略说明
ConflictPolicy::Default标准的冲突检测
ConflictPolicy::Manual手动解决冲突

密码学安全

资料来源:[crates/mnem-core/src/lib.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-core/src/lib.rs)
组件功能
Signer使用 Ed25519 对 Operation 进行签名
Verifier验证签名有效性
RevocationList支持吊销列表验证

CLI 命令

资料来源:[crates/mnem-cli/src/commands/ingest.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-cli/src/commands/ingest.rs)
命令功能
mnem init初始化新仓库
mnem ingest <path>导入文档
mnem get <id>获取节点详情
mnem query <text>语义检索
mnem branch分支管理
mnem merge合并分支
mnem integrate集成到 AI 工具(Claude Code、Cursor 等)

常用 ingest 选项

mnem ingest notes.md                                    # 自动检测格式
mnem ingest --chunker recursive --max-tokens 1024 book.pdf
mnem ingest --recursive docs/                          # 递归导入目录
mnem ingest --text "Hello world"                        # 导入纯文本

HTTP API

资料来源:[crates/mnem-http/src/handlers.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-http/src/handlers.rs)
端点方法说明
/v1/nodesGET获取节点列表
/v1/nodes/{id}GET获取指定节点
/v1/ingestPOST导入文档
/v1/branchesGET获取分支列表
/v1/branchesPOST创建分支
/v1/retrievePOST检索

MCP Server

Mnem 提供了 MCP(Model Context Protocol)集成,支持 AI 工具直接访问知识图谱:

graph LR
    A[Claude Code / Cursor] <--> B[MCP Server]
    B --> C[mnem-core]

资料来源:crates/mnem-cli/src/integrate.rs

支持的集成平台:

平台配置文件
Claude Code~/.claude/CLAUDE.md
Cursor~/.cursor/rules/mnem.mdc
Continue~/.continue/config.json
Zed~/.config/zed/settings.json
Gemini CLI~/.gemini/GEMINI.md

技术特性

资料来源:[crates/mnem-core/src/lib.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-core/src/lib.rs)
特性说明
#![forbid(unsafe_code)]完全禁用 unsafe 代码
规范编码所有对象支持字节级精确的编解码往返
DAG-CBOR使用 DAG-CBOR 作为主要序列化格式
Prolly Tree用于高效存储和查询的 Prolly Tree 实现
Tree-sitter代码解析支持 10+ 主流编程语言

使用示例

初始化仓库

mnem init my-knowledge-base
cd my-knowledge-base

导入文档

# 导入 Markdown
mnem ingest README.md

# 导入 PDF
mnem ingest --chunker sentence_recursive document.pdf

# 递归导入目录
mnem ingest --recursive ./docs

# 导入代码文件
mnem ingest src/main.rs

检索知识

mnem query "Mnem 的检索算法是如何工作的?"

分支管理

mnem branch create feature-x
mnem branch switch feature-x
# ... 进行修改 ...
mnem commit -m "添加新功能"
mnem merge feature-x

总结

Mnem 是一个功能完整的本地优先知识图谱系统,特别适合需要持久化记忆的 AI Agent 场景。它通过:

  1. 多格式解析 - 支持 PDF、Markdown、代码、会话等
  2. 智能分块 - 针对不同内容类型优化分块策略
  3. 实体提取 - 规则、统计和 LLM 三种提取方式
  4. 版本控制 - DAG 结构支持分支和合并
  5. 可验证性 - Ed25519 签名确保数据完整性
  6. AI 友好 - 专为 Agent 设计的检索和渲染机制

为开发者提供了一个可靠、可信的知识管理基础设施。

资料来源:README.zh-CN.md

资料来源:[crates/mnem-core/README.md](https://github.com/Uranid/mnem/blob/main/crates/mnem-core/README.md)

安装指南

本文档详细说明 mnem 项目的各种安装方式、依赖要求以及初始化配置流程。mnem 是一个基于 Rust 构建的知识图谱管理工具,支持 CLI、HTTP 服务和 MCP(Model Context Protocol)三种接入方式。

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 硬件要求

继续阅读本节完整说明和来源证据。

章节 软件依赖

继续阅读本节完整说明和来源证据。

章节 方式一:从源码编译安装

继续阅读本节完整说明和来源证据。

系统要求

硬件要求

组件最低要求推荐配置
内存4 GB8 GB 或以上
磁盘空间500 MB2 GB(用于本地数据库和向量索引)
处理器x86-64多核处理器

软件依赖

mnem 的核心由 Rust 语言编写,运行时依赖以下组件:

  • Rust 工具链:建议使用最新稳定版(stable)
  • OpenSSL:用于 HTTPS 通信和加密操作
  • pkg-config:系统库链接管理
  • protoc:Protocol Buffers 编译器(部分功能需要)

资料来源:crates/mnem-cli/src/main.rs

安装方式

mnem 提供多种安装途径,可根据使用场景选择合适的方式。

方式一:从源码编译安装

#### 前置准备

# 安装 Rust 工具链(如尚未安装)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# 安装系统依赖(Ubuntu/Debian)
sudo apt-get install -y build-essential pkg-config libssl-dev

# 安装系统依赖(macOS)
brew install openssl pkg-config

#### 编译步骤

# 克隆仓库
git clone https://github.com/Uranid/mnem.git
cd mnem

# 使用 Cargo 构建所有 crate
cargo build --release

# 安装二进制文件到 ~/.cargo/bin
cargo install --path crates/mnem-cli

编译完成后,可执行文件 mnem 将被安装到 Cargo 的 bin 目录。

方式二:使用安装脚本

项目提供了自动化安装脚本,支持 Linux、macOS 和 Windows。

#### Linux / macOS

curl -fsSL https://raw.githubusercontent.com/Uranid/mnem/main/scripts/install.sh | bash

脚本会自动检测系统平台,下载或编译对应版本的二进制文件。

#### Windows PowerShell

irm https://raw.githubusercontent.com/Uranid/mnem/main/scripts/install.ps1 | iex

脚本支持 PowerShell 5.1 及以上版本,会将 mnem.exe 添加到 PATH 环境变量。

方式三:Docker 部署

mnem 支持通过 Docker 容器运行,包含完整的 HTTP 服务和 MCP 服务器。

#### Dockerfile 结构

# 使用 Rust 官方镜像作为构建阶段
FROM rust:1.75 as builder

# 安装构建依赖
RUN apt-get update && apt-get install -y \
    pkg-config libssl-dev

# 复制源码并编译
WORKDIR /app
COPY . .
RUN cargo build --release --bin mnem-http

# 运行阶段使用轻量级镜像
FROM debian:bookworm-slim
COPY --from=builder /app/target/release/mnem-http /usr/local/bin/
EXPOSE 8080
CMD ["mnem-http"]

资料来源:Dockerfile

#### docker-compose 编排

version: '3.8'

services:
  mnem:
    build: .
    ports:
      - "8080:8080"
    volumes:
      - mnem-data:/data
    environment:
      - MNEM_DATA_DIR=/data
      - OLLAMA_BASE_URL=http://ollama:11434
    restart: unless-stopped

  ollama:
    image: ollama/ollama:latest
    volumes:
      - ollama-data:/root/.ollama
    restart: unless-stopped

volumes:
  mnem-data:
  ollama-data:

资料来源:docker-compose.yml

#### 启动 Docker 服务

# 构建并启动容器
docker-compose up -d

# 查看日志
docker-compose logs -f mnem

# 停止服务
docker-compose down

初始化配置

首次使用 mnem 前需要进行仓库初始化和基础配置。

仓库初始化

# 初始化新的 mnem 仓库
mnem init

# 指定自定义数据目录
mnem init --path ~/.my-mnem

初始化命令会在指定目录下创建 .mnem/ 子目录,包含以下结构:

.mnem/
├── repo.redb      # 主数据库(Redb 键值存储)
├── config.toml    # 用户配置文件
└── blocks/        # DAG-CBOR 数据块存储

资料来源:crates/mnem-cli/src/commands/init.rs

配置文件

初始化后生成的 config.toml 包含以下配置项:

[user]
# 用户标识(可选)
name = "Your Name"
email = "[email protected]"

[llm]
# Ollama 服务配置
base_url = "http://localhost:11434"
model = "llama3.2"
timeout_secs = 120

[ner]
# 命名实体识别提供者
provider = "rule"  # 可选: "none", "rule"

[ingest]
# 默认分块策略
chunker = "auto"  # 可选: "paragraph", "recursive", "session", "structural"

资料来源:crates/mnem-cli/src/config.rs

验证安装

# 检查 mnem 版本
mnem --version

# 查看当前仓库状态
mnem status

# 列出所有可用命令
mnem --help

成功安装后,mnem status 应显示仓库已初始化且无待提交操作。

接入方式

mnem 提供三种主要的接入方式,可根据使用场景选择。

CLI 模式

命令行模式适合日常笔记记录和知识管理:

# 添加节点
mnem add node -s "Alice 住在柏林"

# 添加关系
mnem add edge --from <src-uuid> --to <dst-uuid> --label 朋友

# 检索知识
mnem retrieve "Alice 住在哪里"

HTTP 服务模式

通过 HTTP API 提供服务,支持远程访问和程序化集成:

# 启动 HTTP 服务(默认端口 8080)
mnem http serve

# 指定端口
mnem http serve --port 9090

# 后台运行
mnem http serve --daemon

API 端点示例:

方法端点说明
GET/v1/status获取服务状态
POST/v1/nodes创建节点
GET/v1/nodes/{id}获取节点详情
POST/v1/ingest批量导入文档

资料来源:crates/mnem-http/src/handlers.rs

MCP 模式

MCP(Model Context Protocol)模式允许 AI 助手直接访问 mnem 知识图谱:

# 启动 MCP 服务器
mnem mcp serve

# 配置 Claude Desktop 使用 mnem MCP
# 编辑 ~/.claude/settings.json

资料来源:crates/mnem-mcp/src/lib.rs

依赖可选功能

mnem 的部分功能需要额外的依赖库支持。

文档解析依赖

功能依赖启用方式
PDF 解析doclingcargo build --features sidecar-docling
高级解析unstructuredcargo build --features sidecar-unstructured
KeyBERT 向量提取keybertcargo build --features keybert
LLM 实体提取ollamacargo build --features ollama

资料来源:crates/mnem-ingest/src/lib.rs

向量检索依赖

mnem 的检索功能依赖嵌入模型生成向量表示,可通过以下方式配置:

[embedder]
# 本地 Ollama 嵌入模型
provider = "ollama"
model = "nomic-embed-text"
base_url = "http://localhost:11434"

安装流程图

graph TD
    A[开始安装] --> B{选择安装方式}
    B -->|源码编译| C[安装 Rust 工具链]
    B -->|安装脚本| D[下载安装脚本]
    B -->|Docker| E[安装 Docker]
    
    C --> F[克隆仓库]
    D --> G[执行安装脚本]
    E --> H[配置 docker-compose]
    
    F --> I[cargo build]
    G --> J[验证二进制]
    H --> K[docker-compose up]
    
    I --> L[初始化仓库]
    J --> L
    K --> L
    
    L --> M[配置 config.toml]
    M --> N{选择接入模式}
    
    N -->|CLI| O[使用 mnem 命令]
    N -->|HTTP| P[启动 http serve]
    N -->|MCP| Q[启动 mcp serve]
    
    O --> R[安装完成]
    P --> R
    Q --> R

卸载

二进制安装卸载

# 删除二进制文件
rm ~/.cargo/bin/mnem

# 删除配置文件(可选)
rm -rf ~/.config/mnem

Docker 卸载

# 停止并删除容器
docker-compose down -v

# 删除镜像
docker rmi mnem-mnem-http

# 删除数据卷
docker volume rm mnem_mnem-data

常见问题

编译失败

如果编译时出现 OpenSSL 相关错误,确保已安装开发库:

# Ubuntu/Debian
sudo apt install libssl-dev

# macOS
brew install openssl@3

权限问题

Linux/macOS 上如遇到权限错误:

# 修复 Cargo bin 目录权限
chmod +x ~/.cargo/bin/mnem

数据库损坏

如遇数据库异常,可尝试重建:

# 备份现有数据
mv ~/.mnem ~/.mnem.bak

# 重新初始化
mnem init

下一步

安装完成后,建议按以下顺序开始使用:

  1. 阅读快速开始指南了解基本操作
  2. 查看命令参考获取完整命令列表
  3. 参考配置文档深入定制功能

资料来源:[crates/mnem-cli/src/main.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-cli/src/main.rs)

系统架构

mnem 是一个基于 Rust 构建的本地优先知识图谱系统,采用内容寻址存储(Content-Addressed Storage)架构,通过 DAG-CBOR 规范实现数据的规范化编解码。该系统支持多端接入,包括命令行界面(CLI)、HTTP API 和 MCP(Model Context Protocol)协议,能够对 Markdown、PDF、代码文件、对话记录等多种格...

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 mnem-core 核心库

继续阅读本节完整说明和来源证据。

章节 mnem-ingest 文档解析库

继续阅读本节完整说明和来源证据。

章节 用户接入层

继续阅读本节完整说明和来源证据。

mnem 是一个基于 Rust 构建的本地优先知识图谱系统,采用内容寻址存储(Content-Addressed Storage)架构,通过 DAG-CBOR 规范实现数据的规范化编解码。该系统支持多端接入,包括命令行界面(CLI)、HTTP API 和 MCP(Model Context Protocol)协议,能够对 Markdown、PDF、代码文件、对话记录等多种格式的文档进行解析、分块、实体提取和语义检索。

核心设计原则

mnem 的核心架构遵循以下设计原则,这些原则贯穿整个系统的实现:

  1. 无 unsafe 代码:mnem-core crate 明确禁用所有 unsafe 代码,确保内存安全 资料来源:crates/mnem-core/src/lib.rs`。
  2. 字节级精确编解码:每个对象类型都保证字节级精确的规范化编码往返特性,即 decode(encode(x)) == xencode(decode(b)) == b 资料来源:crates/mnem-core/src/lib.rs`。
  3. 幽灵类型安全Link<T> 通过泛型参数在编译时防止引用类型混淆,例如 fn parents(&self) -> &[Link<Commit>] 拒绝接受 Link<Node> 资料来源:crates/mnem-core/src/id/link.rs`。
  4. 多端统一解析:单一规范的解析器实现同时服务于 CLI、HTTP 和 MCP 接入面 资料来源:crates/mnem-ingest/src/lib.rs`。

系统分层架构

mnem 系统采用分层架构,各层职责明确,从底层数据存储到顶层用户接口逐层构建。

graph TD
    subgraph 用户接入层
        CLI[mnem-cli<br/>命令行工具]
        HTTP[mnem-http<br/>HTTP API]
        MCP[mnem-mcp<br/>MCP Server]
    end
    
    subgraph 核心库层
        CORE[mnem-core<br/>核心数据模型]
        INGEST[mnem-ingest<br/>文档解析与提取]
    end
    
    subgraph 存储层
        STORE[Blockstore<br/>块存储接口]
        VIEW[View<br/>视图快照]
        COMMITS[Commit<br/>提交历史]
    end
    
    CLI --> CORE
    CLI --> INGEST
    HTTP --> CORE
    HTTP --> INGEST
    MCP --> CORE
    MCP --> INGEST
    INGEST --> CORE
    CORE --> STORE
    CORE --> COMMITS

mnem-core 核心库

mnem-core 是系统的基础核心库,提供所有核心数据结构和算法实现。该库包含以下关键模块 资料来源:crates/mnem-core/src/lib.rs`:

模块功能描述
idCID(内容标识符)、ChangeId、OperationId 以及泛型链接类型 Link<T>
codecDAG-CBOR 编解码器和 DAG-JSON 调试导出
objectsNode、Edge、Commit、Operation、View、IndexSet 等核心对象类型
prollyProlly 树算法(分块器、构建器、查找、光标、diff、合并)
storeBlockstore 和 OpHeadsStore trait 及内存实现
repoReadonlyRepo、Transaction 外观类
index辅助索引(Query、BruteForceVectorIndex)
retrieveAgent 面向的 Retriever,组合过滤、向量和稀疏排序
signEd25519 签名和撤销列表验证

mnem-ingest 文档解析库

mnem-ingest 负责文档的解析、分块和实体提取工作。该库支持多种文档格式的分阶段处理 资料来源:crates/mnem-ingest/src/lib.rs`:

模块功能
mdCommonMark + GFM Markdown 解析
pdf纯 Rust 实现的 PDF 文本层提取
code基于 tree-sitter 的代码解析
conversationChatGPT/Claude/通用对话导出格式处理
text纯文本处理
chunk分块策略(Paragraph、Recursive、SentenceRecursive、Session、Structural)
extract实体和关系提取(RuleExtractor、KeyBertAdapter、LLMExtractor)
sidecar外部工具集成(docling、unstructured)

用户接入层

系统提供三种主要的用户接入方式:

  • mnem-cli:命令行工具,支持本地文件的批量导入、检索和图谱管理
  • mnem-http:基于 Actix-web 构建的 HTTP API 服务端
  • mnem-mcp:Model Context Protocol 服务端,供 AI 代理调用

数据模型

mnem 采用 DAG(有向无环图)结构存储知识图谱,核心对象之间通过 CID(内容标识符)相互引用。

节点(Node)

Node 是图谱中的基本顶点单元,包含以下关键字段 资料来源:crates/mnem-core/src/objects/node.rs`:

classDiagram
    class Node {
        +id: NodeId
        +ntype: String
        +parents: Vec~Link~Commit~~
        +context_sentence: Option~String~
        +summary: Option~String~
        +props: BTreeMap~String, Ipld~
        +content: Option~Bytes~
        +extra: BTreeMap~String, Ipld~
    }
字段类型说明
idNodeId节点唯一标识符
ntypeString节点类型标签(如 "Doc"、"Section" 等)
parentsVec<Link<Commit>>父提交链接
context_sentenceOption<String>上下文句子(Anthropic 2024 contextual retrieval 设计)
summaryOption<String>LLM 可读的摘要文本,默认截断至 8192 字符
propsBTreeMap结构化属性键值对
contentOption<Bytes>不透明载荷(如文档体、文件内容)

Link<T> 是一个泛型封装的 CID,提供编译时类型安全保证。在传输层 Link 与普通 CID 字节相同,但泛型参数在 Rust 类型层面防止了错误的引用操作 资料来源:crates/mnem-core/src/id/link.rs`。

提交(Commit)与操作(Operation)

Commit 记录图谱的快照状态,Operation 记录具体的变更操作,两者共同构成版本控制的基础。

文档解析流程

当用户通过 CLI、HTTP 或 MCP 接入系统进行文档导入时,系统内部执行以下处理流程 资料来源:crates/mnem-ingest/src/pipeline.rs`:

flowchart LR
    A[原始文件] --> B{文件扩展名检测}
    B -->|md/markdown| C[Markdown解析器]
    B -->|pdf| D[PDF解析器]
    B -->|json/jsonl| E[对话解析器]
    B -->|rs/py/js/ts...| F[Tree-sitter代码解析]
    B -->|其他| G[纯文本解析器]
    
    C --> H{分块策略选择}
    D --> H
    E --> H
    F --> H
    G --> H
    
    H -->|Markdown| I[Paragraph分块]
    H -->|PDF/Text| J[SentenceRecursive分块]
    H -->|Conversation| K[Session分块]
    H -->|Code| L[Structural分块]
    
    I --> M[实体提取]
    J --> M
    K --> M
    L --> M
    
    M --> N[Transaction写入]
    N --> O[Commit提交]

源类型自动检测

系统根据文件扩展名自动推断源类型(SourceKind) 资料来源:crates/mnem-ingest/src/types.rs`:

扩展名SourceKind分块策略
.md .markdownMarkdownParagraph
.pdfPdfSentenceRecursive (512 tokens, 64 overlap)
.txtTextSentenceRecursive (256 tokens, 32 overlap)
.json .jsonlConversationSession (10 messages)
.rsCode(Rust)Structural
.py .pyiCode(Python)Structural
.js .mjs .cjsCode(JavaScript)Structural
.ts .tsxCode(TypeScript)Structural
.goCode(Go)Structural
.javaCode(Java)Structural
.c .hCode(C)Structural
.cpp .cc .cxxCode(Cpp)Structural
其他TextSentenceRecursive

分块策略详解

系统提供五种分块策略,适用于不同类型的文档内容 资料来源:crates/mnem-ingest/src/chunk.rs`:

  • Paragraph(段落分块):适用于 Markdown 文档,按段落边界切分
  • Recursive(递归分块):按最大 token 数递归拆分,可配置重叠
  • SentenceRecursive(句子递归分块):先按句子边界对齐,再按 token 限制拆分,适合 PDF 和纯文本
  • Session(会话分块):保留消息对话结构,按最大消息数切分
  • Structural(结构分块):利用 AST 解析提取函数、类、结构体等代码单元

存储架构

mnem 采用内容寻址存储,所有数据通过 CID 唯一标识。存储层提供两个核心 trait 接口:

Blockstore Trait

Blockstore 是底层内容存储接口,负责键值对形式的数据读写。系统支持多种后端实现,包括内存实现(用于测试)和持久化实现。

OpHeadsStore Trait

OpHeadsStore 管理操作头的集合,用于追踪当前工作区的最新状态。

View 与 Commit

  • View:视图快照,包含 refs(引用表)和 heads(头提交集)
  • Commit:提交记录,指向操作链和视图
graph LR
    A[Operation] -->|prev| B[Operation]
    B -->|prev| C[Operation]
    
    D[Commit] -->|ops| A
    D -->|view| E[View]
    
    F[View] -->|heads| G["Vec<Cid>"]
    F -->|refs| H["BTreeMap<String, RefTarget>"]

检索流程

检索(Retrieve)模块负责根据用户查询从图谱中召回最相关的节点 资料来源:crates/mnem-core/src/retrieve/mod.rs`:

  1. 过滤阶段:根据查询条件筛选候选节点
  2. 向量排序:使用嵌入向量计算语义相似度
  3. 稀疏排序:BM25 等稀疏检索方法辅助排序
  4. 重排序:可选的重排序模型优化结果顺序
  5. Token 预算打包:将结果打包至 LLM 上下文预算内

检索模块实现了 Anthropic 2024 年提出的 Contextual Retrieval 技术,通过在节点上存储 context_sentence 字段(上下文句子)来增强检索效果,该字段在嵌入前被添加到 summary 前缀中 资料来源:crates/mnem-core/src/objects/node.rs`。

特性门控

部分功能通过 Cargo feature 进行条件编译控制 资料来源:crates/mnem-ingest/src/lib.rs`:

Feature功能
keybertKeyBERT 统计嵌入器适配器
ollamaOllama LLM 提取器
sidecar-doclingDocling CLI PDF 解析集成
sidecar-unstructuredUnstructured.io 解析集成

总结

mnem 的系统架构体现了现代本地优先应用的设计理念:通过内容寻址确保数据的不可变性和可验证性,采用分层模块化设计支持多种接入方式,利用 DAG 结构自然地表达知识图谱的复杂关系。核心库的纯 Rust 实现保证了类型安全和跨平台兼容性,而丰富的文档解析和分块策略则满足了多样化的知识管理需求。

来源:https://github.com/Uranid/mnem / 项目说明书

Crates结构详解

mnem 是一个基于 Rust 构建的语义记忆系统,采用 IPLD (InterPlanetary Linked Data) 数据模型和 DAG-CBOR 编解码实现内容寻址存储。项目采用工作区 (workspace) 结构,包含多个独立的 crate,每个 crate 负责特定的功能领域。

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 项目依赖关系总览

继续阅读本节完整说明和来源证据。

章节 定位与职责

继续阅读本节完整说明和来源证据。

章节 核心模块

继续阅读本节完整说明和来源证据。

概述

mnem 是一个基于 Rust 构建的语义记忆系统,采用 IPLD (InterPlanetary Linked Data) 数据模型和 DAG-CBOR 编解码实现内容寻址存储。项目采用工作区 (workspace) 结构,包含多个独立的 crate,每个 crate 负责特定的功能领域。

graph TD
    subgraph mnem工作区
        CLI[mnem-cli]
        HTTP[mnem-http]
        MCP[mnem-mcp]
        CORE[mnem-core]
        INGEST[mnem-ingest]
    end
    
    CLI --> CORE
    HTTP --> CORE
    MCP --> CORE
    INGEST --> CORE
    
    CLI --> INGEST
    HTTP --> INGEST
    MCP --> INGEST

核心 Crate 架构

项目依赖关系总览

Crate 名称依赖关系主要功能
mnem-core无内部依赖核心数据模型、存储、检索
mnem-ingest依赖 mnem-core数据解析、分块、实体提取
mnem-cli依赖 mnem-core, mnem-ingest命令行工具
mnem-http依赖 mnem-core, mnem-ingestHTTP API 服务
mnem-mcp依赖 mnem-coreMCP 协议集成

mnem-core 核心库

定位与职责

mnem-core 是整个项目的核心基础设施库,提供底层数据模型、存储抽象和检索能力。该库完全禁止使用 unsafe 代码 (#![forbid(unsafe_code)]),确保内存安全。

核心模块

资料来源:[crates/mnem-core/src/lib.rs](crates/mnem-core/src/lib.rs)

pub mod id;        // 内容标识符
pub mod codec;     // DAG-CBOR 编解码
pub mod objects;   // 核心对象类型
pub mod prolly;    // Prolly tree 算法
pub mod store;     // 存储抽象
pub mod repo;      // 仓库事务
pub mod index;     // 索引实现
pub mod retrieve;  // 检索器
pub mod sign;      // 签名验证

核心对象类型

资料来源:crates/mnem-core/src/objects/node.rs

类型说明
Node核心节点类型,包含摘要、属性、内容和上下文句子
Edge节点间的边关系
Commit提交记录
Operation操作记录
View视图快照
IndexSet索引集合

ID 系统

资料来源:crates/mnem-core/src/id/link.rs

pub struct Link<T: ?Sized> {
    cid: Cid,
    _target: PhantomData<fn() -> T>,
}

Link<T> 是类型化内容引用,基于 CID 但增加了类型安全保证:

  • 编译时类型检查防止引用混淆
  • Link<Commit>Link<Node> 等泛型参数确保语义正确
  • 序列化格式与裸 CID 完全兼容

检索模块

资料来源:crates/mnem-core/src/retrieve/mod.rs

检索模块负责将节点渲染为 LLM 可消费的文本格式,采用 YAML-like 格式:

ntype: <ntype>
id: <uuid>
context: <context_sentence>
summary: <summary>
<prop_key>: <prop_value>

渲染规则:

  • ntypeid 始终存在
  • contextsummary 之前输出(遵循 Anthropic 2024 contextual-retrieval 配方)
  • summary 默认截断至 8192 字符,可通过 MNEM_RENDER_SUMMARY_CAP_CHARS 环境变量配置
  • 标量属性按字母序输出,复杂属性(Link、Map、List)跳过

mnem-ingest 数据摄取库

定位与职责

mnem-ingest 负责将各种格式的源数据(Markdown、PDF、代码、会话等)解析、分块并提取实体关系。

模块架构

graph LR
    subgraph 解析器
        MD[Markdown]
        PDF[PDF]
        CODE[Code]
        CONV[Conversation]
        TEXT[Text]
    end
    
    subgraph 分块器
        PARA[Paragraph]
        REC[Recursive]
        SENT[SentenceRecursive]
        SESS[Session]
        STRUC[Structural]
    end
    
    subgraph 提取器
        RULE[RuleExtractor]
        KEYBERT[KeyBertAdapter]
        LLM[LLMExtractor]
    end
    
    MD & PDF & CODE & CONV & TEXT --> PARA & REC & SENT & SESS & STRUC
    PARA & REC & SENT & SESS & STRUC --> RULE & KEYBERT & LLM

支持的源类型

资料来源:crates/mnem-ingest/src/types.rs

源类型文件扩展名默认分块策略
Markdown.md, .markdownParagraph
Pdf.pdfSentenceRecursive (512 tokens, 64 overlap)
Text其他无扩展名文件SentenceRecursive (256 tokens, 32 overlap)
Conversation.json, .jsonlSession (10 messages)
Code(lang)各类代码文件Structural

分块策略详解

资料来源:crates/mnem-ingest/src/chunk.rs

pub enum ChunkerKind {
    Paragraph,                  // 段落级别
    Recursive { max_tokens, overlap },
    SentenceRecursive { max_tokens, overlap },
    Session { max_messages },   // 会话消息分组
    Structural,                 // 代码结构(函数/类等)
}
策略适用场景关键参数
ParagraphMarkdown 文档
Recursive通用文本递归切分max_tokens, overlap
SentenceRecursive句子边界感知的递归切分max_tokens, overlap
Session对话/聊天记录max_messages
Structural源代码结构解析

代码语言支持

资料来源:crates/mnem-ingest/src/code.rs

语言扩展名Tree-sitter 提取项
Rust.rsfunction_item, struct_item, enum_item, trait_item
Python.py, .pyifunction_definition, class_definition
JavaScript.js, .mjs, .cjsfunction_declaration, class_declaration
TypeScript.ts, .tsx, .mts, .ctsfunction_declaration, class_declaration
Go.gofunction_declaration, type_declaration
Java.javamethod_declaration, class_declaration
C.c, .hfunction_definition, struct_specifier
C++.cpp, .cc, .cxx, .hppfunction_definition, class_specifier
Ruby.rb, .gemspec, .rakemethod_definition, class_module
C#.cs, .csxmethod_declaration, class_declaration

提取器

资料来源:crates/mnem-ingest/src/lib.rs

pub mod extract;           // 规则提取器
#[cfg(feature = "keybert")]
pub mod extract_keybert;  // KeyBERT 统计适配器
#[cfg(feature = "ollama")]
pub mod extract_llm;      // LLM 驱动提取器

提取器特性矩阵:

提取器Feature Flag依赖
RuleExtractor默认启用
KeyBertAdapterkeybertembedding 模型
LLMExtractorollamaOllama 服务

Sidecar 集成

资料来源:crates/mnem-ingest/src/sidecar.rs

提供高级 PDF 解析的后备方案:

SidecarFeature Flag说明
DoclingSidecarsidecar-docling调用 docling CLI
UnstructuredSidecarsidecar-unstructured调用 unstructured-ingest CLI

Sidecar 仅在纯 Rust 解析(parse_pdf)结果质量不足时使用,需手动配置触发。

mnem-cli 命令行工具

定位与职责

mnem-cli 是项目的命令行客户端,提供用户交互接口和配置管理。

主要命令

#### ingest 命令

资料来源:crates/mnem-cli/src/commands/ingest.rs

参数默认值说明
--chunkerauto分块策略:auto, session, paragraph, recursive, sentence_recursive, structural
--max-tokens512目标分块大小(token)
--overlap32相邻分块重叠 token 数
--recursivefalse递归遍历目录
--text-直接摄取内联文本
--ntypeDoc根节点类型标签

配置系统

资料来源:crates/mnem-cli/src/config.rs

配置项分层:

[user]
  name, email, agent_id

[llm]
  provider: openai | ollama
  model
  api_key_env
  base_url
  timeout_secs

[rerank]
  model, api_key_env, base_url

[ner]
  provider: rule | none

[retrieve]
  limit, budget, vector_cap
  graph_expand, graph_decay, graph_depth
  rerank_top_k, hyde_max_tokens

Agent 集成

资料来源:crates/mnem-cli/src/integrate.rs

支持将 mnem 系统提示集成到多种 AI 开发工具:

主机路径存储格式
ClaudeCode~/.claude/CLAUDE.mdMarkdown
GeminiCli~/.gemini/GEMINI.mdMarkdown
Cursor~/.cursor/rules/mnem.mdcMarkdown
Continue~/.continue/config.jsonJSON (systemMessage)
Zedsettings.jsonJSON (assistant.system_prompt)

mnem-http HTTP 服务

定位与职责

mnem-http 提供 RESTful HTTP API,支持外部服务集成。

主要端点

资料来源:crates/mnem-http/src/handlers.rs

#### 分支管理

方法路径说明
GET/v1/branches列出所有分支
POST/v1/branches创建新分支

响应格式示例:

{
  "schema": "mnem.v1.branches",
  "branches": [
    {"name": "main", "head": "<commit-cid>", "is_current": true}
  ]
}

摄取接口

资料来源:crates/mnem-http/src/handlers_ingest.rs

参数说明
chunker分块策略 (auto, paragraph, recursive, session)
max_tokens目标 token 数
overlap重叠 token 数
author提交作者(必需)
message提交消息
extractor提取器选择 (none, keybert)
ner_providerNER 提供者 (rule, none)

mnem-mcp MCP 协议集成

mnem-mcp 提供 Model Context Protocol 协议支持,使 mnem 可作为 AI 代理的记忆后端。详情待补充。

版本与特性矩阵

Crate最小 Rust 版本关键依赖
mnem-core1.75+serde, cid, dag-cbor, tokio
mnem-ingest1.75+tree-sitter-*, pdf-extract
mnem-cli1.75+clap, anyhow, dirs
mnem-http1.75+axum, tower, tokio
mnem-mcp1.75+sse, tokio

总结

mnem 项目采用清晰的模块化架构:

  • mnem-core 提供不可变的 DAG-CBOR 数据模型和检索基础设施
  • mnem-ingest 负责多格式数据的多策略分块与实体提取
  • mnem-cli/http/mcp 提供多渠道访问接口

各 crate 通过严谨的类型系统和内容寻址确保数据一致性和可验证性,完全禁用 unsafe 代码保证了内存安全。

资料来源:[crates/mnem-core/src/lib.rs](crates/mnem-core/src/lib.rs)

知识图谱模型

mnem 的知识图谱模型是一个基于内容寻址(Content-Addressing)的图数据库核心,它采用 IPLD(InterPlanetary Linked Data)规范来组织和管理数据。该模型的核心设计理念是:

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 节点(Node)

继续阅读本节完整说明和来源证据。

章节 边(Edge)

继续阅读本节完整说明和来源证据。

章节 提交(Commit)

继续阅读本节完整说明和来源证据。

概述

mnem 的知识图谱模型是一个基于内容寻址(Content-Addressing)的图数据库核心,它采用 IPLD(InterPlanetary Linked Data)规范来组织和管理数据。该模型的核心设计理念是:

  • 不可变性优先:所有对象一旦写入便不可更改,通过新建版本实现更新
  • 类型安全的链接:使用 Link<T> 泛型确保编译期类型检查
  • DAG 结构:节点和边构成有向无环图(DAG),支持高效遍历和查询
  • 确定性编码:所有对象支持 DAG-CBOR 规范下的字节级精确编解码往返

资料来源:crates/mnem-core/src/lib.rs:1-50

核心对象类型

节点(Node)

节点是知识图谱的基本存储单元,用于表示文档、文本块、实体等各类知识条目。

classDiagram
    class Node {
        +NodeId id
        +NodeType ntype
        +Option~String~ name
        +Option~String~ summary
        +BTreeMap~String, Ipld~ props
        +Option~Bytes~ content
        +Option~String~ context_sentence
        +BTreeMap~String, Ipld~ ext
    }

关键字段说明

字段类型说明
idNodeId节点的唯一标识符(UUID)
ntypeNodeType节点类型(如 DocChunkEntity 等)
nameOption<String>节点的友好名称
summaryOption<String>摘要文本,供 LLM 消费使用
propsBTreeMap<String, Ipld>属性映射表,值为任意 DAG-CBOR 兼容类型
contentOption<Bytes>可选的不透明载荷(如文档正文、文件内容)
context_sentenceOption<String>上下文前缀句(Anthropic 2024 Contextual Retrieval 论文应用)

属性设计原则

  • 标量属性(StringIntegerFloatBool)按 BTreeMap 顺序(字母序)输出
  • 非标量属性(LinkMapListBytesNull)在渲染时被跳过,避免占用 token 预算
  • summary 字段默认截断至 8192 字符,可通过 MNEM_RENDER_SUMMARY_CAP_CHARS 环境变量覆盖

资料来源:crates/mnem-core/src/objects/node.rs:1-150

边(Edge)

边表示节点之间的有向关系,是知识图谱关联结构的载体。

classDiagram
    class Edge {
        +EdgeId id
        +Link~Node~ src
        +Link~Node~ dst
        +String label
        +Option~Ipld~ props
    }

关键特性

特性说明
类型安全srcdst 均为 Link<Node> 类型,编译期确保指向节点
关系标签label 字段描述关系类型(如 knowsauthoredpart_of
属性扩展props 可选地附加关系级别的元数据

图遍历语义

  • 边是单向的:从 src 指向 dst
  • 支持按标签过滤遍历
  • 支持按源节点或目标节点建立索引

资料来源:crates/mnem-core/src/objects/edge.rs:1-80

提交(Commit)

Commit 记录图谱的原子变更快照,包含一次或多次操作的集合。

classDiagram
    class Commit {
        +ChangeId change_id
        +OperationId operation_id
        +Link~Commit~ parent
        +Author author
        +Timestamp timestamp
        +String message
        +Vec~Operation~ operations
    }

变更原子性

  • 每个 Commit 包含完整的 operations 向量
  • 操作类型包括:AddNodeAddEdgeUpdateNodeDeleteNodeDeleteEdge
  • 支持批量原子提交,确保要么全部成功,要么全部回滚

操作类型

操作类型说明
AddNode向图中添加新节点
AddEdge在两节点间建立关系
UpdateNode更新现有节点的属性(通过 Replace 实现)
DeleteNode删除节点(软删除,生成 Tombstone)
DeleteEdge删除边关系

资料来源:crates/mnem-core/src/objects/commit.rs:1-120

墓碑(Tombstone)

Tombstone 是已删除节点的占位符,用于在内容寻址结构中维护图的完整性。

classDiagram
    class Tombstone {
        +NodeId id
        +Timestamp deleted_at
        +Option~Author~ deleted_by
    }

设计目的

  • 在 IPLD 内容寻址系统中,被删除内容的 CID 仍然可能存在于历史记录或其他节点引用中
  • Tombstone 确保遍历时不会因缺失内容而失败
  • 支持后续的垃圾回收机制识别可清理的孤立对象

资料来源:crates/mnem-core/src/objects/tombstone.rs:1-60

Link<T> 是 mnem 的类型安全内容引用封装。

classDiagram
    class Link~T~ {
        -Cid cid
        -PhantomData _target
    }
    Link ..> Cid : contains

核心特性

特性说明
phantom type泛型参数 T 在运行时不占空间,仅用于编译期类型检查
CID 等价底层存储与裸 Cid 完全相同(相同字节、相同 CBOR 标签)
编译期安全fn parents(&self) -> &[Link<Commit>] 会在传入 Link<Node> 时编译失败

使用示例

// 正确的用法:编译通过
let commit_link: Link<Commit> = Link::new(cid);
fn get_parents(link: &Link<Commit>) -> &[Link<Commit>] { ... }

// 错误的用法:编译失败
let node_link: Link<Node> = Link::new(cid);
get_parents(&node_link); // 编译错误:类型不匹配

资料来源:crates/mnem-core/src/id/link.rs:1-80

索引系统

邻接表索引(Adjacency Index)

邻接表是图遍历的核心数据结构,支持高效的关系查询。

graph TD
    A[Node A] -->|knows| B[Node B]
    A -->|authored| C[Node C]
    B -->|knows| D[Node D]
    B -->|part_of| A
    C -->|part_of| A
    
    E[Adjacency Index] -->|out_edges| F[HashMap<NodeId, Vec<Edge>>]
    E -->|in_edges| G[HashMap<NodeId, Vec<Edge>>]

索引结构

索引方向用途
出边索引 (out_edges)给定节点,快速获取其所有出向关系
入边索引 (in_edges)给定节点,快速获取指向它的所有关系

查询能力

  • 按源节点查询所有出边
  • 按目标节点查询所有入边
  • 按边标签过滤
  • 支持多跳路径查询(通过组合调用实现)

资料来源:crates/mnem-core/src/index/adjacency.rs:1-100

数据流与操作语义

写入流程

sequenceDiagram
    participant Client
    participant Transaction
    participant Operation
    participant Commit
    participant Blockstore
    
    Client->>Transaction: begin()
    Client->>Transaction: add_node(node)
    Transaction->>Operation: Create AddNode operation
    Client->>Transaction: add_edge(src, dst, label)
    Transaction->>Operation: Create AddEdge operation
    Client->>Transaction: commit(author, message)
    Transaction->>Operation: Finalize operations
    Transaction->>Commit: Create Commit with operations
    Commit->>Blockstore: Store Commit (CID)
    Transaction->>Blockstore: Store Node/Edge objects
    Blockstore-->>Commit: Store CIDs
    Commit-->>Transaction: Commit CID
    Transaction-->>Client: ReadonlyRepo

图遍历流程

graph LR
    A[输入: 起始节点] --> B[查询邻接表出边]
    B --> C{边过滤条件}
    C -->|无过滤| D[返回所有相邻节点]
    C -->|按标签| E[返回匹配标签的节点]
    D --> F[可迭代结果集]
    E --> F
    F --> G[继续遍历下一跳]

检索与渲染

LLM 友好的节点渲染

检索系统在将节点返回给 LLM 使用前,会将节点渲染为确定性的文本表示。

渲染格式

ntype: <ntype>
id: <uuid>
context: <context_sentence>
summary: <summary>
<prop_key>: <prop_value>
...

渲染规则

字段存在条件位置
ntype始终第1行
id始终第2行
contextcontext_sentence 非空时summary 之前
summarysummary 非空时第3或4行
属性仅标量属性summary 之后

资料来源:crates/mnem-core/src/retrieve/mod.rs:1-100

节点类型枚举

节点类型说明典型属性
Doc文档节点mnem:source_kindtitlemime_type
Chunk文本块节点section_pathtokens_estimate
Entity实体节点NER 提取的实体
Conversation对话会话节点消息序列
Ref引用/指针节点指向其他节点的 Link

约束与不变量

核心约束

  1. #![forbid(unsafe_code)] - mnem-core 禁止使用 unsafe 代码
  2. 字节级精确编解码:每个对象类型必须满足 decode(encode(x)) == xencode(decode(b)) == b
  3. 不可变性:已有对象不可原地修改,只能创建新版本
  4. 类型化链接:所有节点间引用必须通过 Link<T> 类型化

资料来源:crates/mnem-core/src/lib.rs:30-50

与外部系统的集成

摄入管道集成

graph TD
    A[源文件] --> B[解析器 Parser]
    B --> C[分块器 Chunker]
    C --> D[提取器 Extractor]
    D --> E[Transaction]
    E --> F[Node/Edge 对象]
    F --> G[Blockstore]
    G --> H[Commit 提交]

摄入管道将外部文档转换为图谱节点:

  • Doc 节点:原始文档元数据
  • Chunk 节点:分块后的文本段落
  • Entity 节点:NER 提取的命名实体
  • Edge 边:节点间关系(如 Chunk -[part_of]-> DocEntity -[extracted_from]-> Chunk

资料来源:crates/mnem-ingest/src/pipeline.rs:1-80

全局知识图谱

mnem 支持跨仓库的全局知识图谱(~/.mnemglobal),检索时同时搜索当前仓库和全局图谱。

跨图谱链接策略

  • 不在 Edge 中添加 dst_repo: PathBuf(保持文件系统无关性)
  • Phase 1:检索时同时搜索全局图谱
  • Phase 2(未来):在节点属性中添加 _global_anchor 指向全局 CID

资料来源:crates/mnem-cli/src/global.rs:1-50

总结

mnem 的知识图谱模型是一个精心设计的图数据库核心,它通过:

  • 类型安全的链接系统 确保编译期正确性
  • 不可变的内容寻址 提供版本历史和完整性保证
  • 确定性编码 确保跨平台一致性
  • 上下文感知检索 支持 LLM 高效消费图谱数据

该模型为知识管理、AI 代理和语义搜索提供了坚实的数据基础。

资料来源:[crates/mnem-core/src/lib.rs:1-50]()

版本控制机制

mnem 的版本控制机制是一个基于内容寻址存储(Content-Addressable Storage, CAS)的分布式版本控制系统,采用 DAG(有向无环图)结构管理文档变更历史。该系统以操作为核心抽象,支持多分支并行开发、冲突检测与合并、以及加密签名验证等企业级功能。

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 Operation(操作)

继续阅读本节完整说明和来源证据。

章节 ChangeId(变更标识)

继续阅读本节完整说明和来源证据。

章节 View(视图)

继续阅读本节完整说明和来源证据。

概述

mnem 的版本控制机制是一个基于内容寻址存储(Content-Addressable Storage, CAS)的分布式版本控制系统,采用 DAG(有向无环图)结构管理文档变更历史。该系统以操作为核心抽象,支持多分支并行开发、冲突检测与合并、以及加密签名验证等企业级功能。

mnem 的版本控制设计遵循以下核心原则:

  • 无冲突写入:通过事务机制实现原子性操作
  • 去中心化架构:每个仓库独立运行,无中心服务器依赖
  • 可验证完整性:所有操作支持 Ed25519 数字签名
  • 语义保留:变更记录包含 author、task_id、agent_id 等元数据

资料来源:crates/mnem-core/src/lib.rs:10-30

核心数据结构

Operation(操作)

Operation 是版本控制的基本单元,对应传统 VCS 中的 "commit" 概念。

pub struct Operation {
    pub parents: Vec<ChangeId>,                    // 父操作列表(支持多父节点)
    pub view: Cid,                                  // 操作后的视图快照
    pub predecessors: Option<BTreeMap<String, Vec<ChangeId>>>, // 前驱操作
    pub author: String,                             // 作者标识
    pub agent_id: Option<String>,                   // AI 代理标识
    pub task_id: Option<String>,                    // 任务标识
    pub host: Option<String>,                       // 主机标识
    pub time: u64,                                  // Unix 时间戳(微秒)
    pub description: String,                        // 操作描述
    pub signature: Option<Signature>,               // 加密签名
    pub extra: BTreeMap<String, Ipld>,              // 扩展字段
}

关键特性说明:

字段类型用途
parentsVec<ChangeId>支持多父节点,实现 merge 操作的完整历史记录
viewCid指向操作后仓库状态的指针,保证内容可寻址
signatureOption<Signature>Ed25519 签名,用于操作真实性和完整性验证
timeu64微秒级时间戳,支持高精度排序

资料来源:crates/mnem-core/src/objects/operation.rs:30-70

ChangeId(变更标识)

ChangeId 是操作的唯一标识符,用于在 refs 和 parents 中引用操作:

pub struct ChangeId(bytes::Bytes);

ChangeId 通过内容哈希生成,确保相同操作的标识全局一致。

View(视图)

View 记录特定时间点的仓库完整状态,包含:

  • 所有 refs(分支、标签)的当前指向
  • 活动节点集合
  • 墓碑集(tombstones):已删除节点的记录,用于冲突检测

资料来源:crates/mnem-core/src/objects/mod.rs

事务机制

Transaction 事务

Transaction 是 mnem 的核心写操作接口,提供原子性的变更构建与提交能力。

graph TD
    A[创建 Transaction] --> B[add_node 添加节点]
    A --> C[add_edge 添加关系]
    B --> D[resolve_chunker 解析分块器]
    C --> E[extract::RuleExtractor 实体提取]
    D --> F[commit 提交事务]
    E --> F
    G[返回 IngestResult] --> H[ReadonlyRepo]

主要方法:

方法签名功能
add_nodeadd_node(ntype, props, content) -> Result<ChangeId>添加节点到当前事务
add_edgeadd_edge(src, dst, etype) -> Result<()>添加节点间关系
commitcommit(author, message) -> Result<ReadonlyRepo>原子提交事务
ingestingest(tx, bytes, kind) -> Result<IngestResult>端到端导入流程

资料来源:crates/mnem-core/src/repo/transaction.rs:60-120

IngestResult 结果

ingest 方法返回的 IngestResult 包含执行统计信息:

字段类型说明
nodes_addedu32新增节点数
chunks_createdu32创建的文本块数
entities_extractedu32提取的实体数
elapsed_msu64执行耗时(毫秒)

分支与引用管理

Refs 结构

mnem 使用 refs 管理命名引用:

refs/heads/<branch_name>  # 分支头指针
refs/tags/<tag_name>      # 标签引用
HEAD                      # 当前分支指针

分支操作

CLI 提供完整的分支管理能力:

命令功能关键参数
mnem branch列出所有分支-v 详细输出
mnem branch create <name>创建新分支--from <commit> 指定起点
mnem branch delete <name>删除分支--force 强制删除

分支创建流程:

  1. 解析目标 commit(支持 CID、ref 名称、分支短名、HEAD)
  2. 在 View 中创建 refs/heads/<name> 指针
  3. 生成新的 Operation 记录变更
  4. 更新 HEAD 指针(如为当前分支)

资料来源:crates/mnem-cli/src/commands/branch.rs:1-80

标签操作

标签是只读的命名引用,常用于版本标记:

pub enum TagCmd {
    List,                                          // 列出所有标签
    Create { name: String, target: Option<String> }, // 创建标签
    Delete { name: String },                       // 删除标签
}

约束条件:

  • 标签名长度不超过 255 字符
  • 不允许包含空格、制表符、换行符、~^:?*[等特殊字符
  • 创建时必须指定有效的 author

资料来源:crates/mnem-cli/src/commands/tag.rs:1-60

差异比较

Diff 命令

mnem diff 命令用于比较两个提交之间的变更:

mnem diff [options] [<left>] [<right>]
参数说明
<left>左侧 commit(基准),默认 HEAD
<right>右侧 commit(比较目标),默认工作区

输出内容包括:

  • 节点变更(新增/修改/删除)
  • 边的变更(关系增删)
  • 元数据变更(props、content)

合并机制

Merge 策略

mnem 支持三方合并(three-way merge),通过检测冲突实现:

graph TD
    A[开始合并] --> B[加载 left commit]
    A --> C[加载 right commit]
    A --> D[计算 LCA]
    B --> E[detect_conflicts]
    C --> E
    D --> E
    E --> F{检测到冲突?}
    F -->|是| G[返回 MergeConflicts]
    F -->|否| H[自动合并成功]
    G --> I[返回冲突列表]
    H --> J[创建 merge commit]
    J --> K[更新 View]

冲突检测

pub fn detect_conflicts_with_policy(
    repo: &ReadonlyRepo,
    left: Cid,           // 左侧 commit CID
    right: Cid,          // 右侧 commit CID
    lca: Option<Cid>,    // 最近公共祖先
    policy: ConflictPolicy,
) -> Result<MergeConflicts, Error>

冲突类型:

类型说明
ContentConflict内容修改冲突
StructuralConflict结构变更冲突(节点增删)
PropertyConflict属性值冲突

ConflictPolicy 策略

冲突策略控制合并行为:

pub struct ConflictPolicy {
    pub ours_priority: bool,      // true: 优先我们的变更
    pub theirs_priority: bool,    // true: 优先他们的变更
    pub auto_resolve: Vec<ConflictType>, // 可自动解决的冲突类型
}

资料来源:crates/mnem-core/src/repo/merge.rs:1-100

提交流程

Commit 命令

mnem commit 创建新的操作记录:

mnem commit [options] [--message <msg>]
选项默认值说明
--author配置值作者信息
--message自动生成提交消息
--amendfalse修改上一个提交(追加操作)
--no-editfalse跳过编辑器

提交流程:

sequenceDiagram
    participant User
    participant CLI
    participant Transaction
    participant Blockstore
    participant Repo
    
    User->>CLI: mnem commit -m "message"
    CLI->>Repo: 创建 Transaction
    Repo-->>Transaction: 返回 &mut Transaction
    CLI->>Transaction: 加载待提交变更
    CLI->>Transaction: commit(author, message)
    Transaction->>Blockstore: 编码新 View
    Transaction->>Blockstore: 创建 Operation
    Blockstore-->>Transaction: 返回 View CID
    Transaction->>Blockstore: 更新 HEAD ref
    Transaction-->>Repo: 返回 ReadonlyRepo
    Repo-->>CLI: 返回结果
    CLI-->>User: 显示 commit 信息

作者字符串格式:

  • 完整格式:"name <email>"
  • 仅名称:"name"
  • 仅邮箱:"<email>"
  • 仅 agent_id:"mnem-cli" 或配置的 agent_id

资料来源:crates/mnem-cli/src/commands/commit.rs:1-100

签名验证

操作签名基于 Ed25519 算法:

pub signature: Option<Signature>,  // Ed25519 签名

签名流程:

  1. 序列化 Operation(排除 signature 字段)
  2. 使用私钥生成 Ed25519 签名
  3. 附加到 Operation 的 signature 字段

验证流程:

  1. 提取 signature 和公钥信息
  2. 使用公钥验证签名有效性
  3. 确保操作内容未被篡改

资料来源:crates/mnem-core/src/sign.rs

CLI 命令参考

命令总览

命令模块功能
mnem commitcommit.rs创建提交
mnem branchbranch.rs分支管理
mnem tagtag.rs标签管理
mnem diffdiff.rs差异比较
mnem mergemerge.rs分支合并
mnem loglog.rs历史查看

仓库配置

配置文件位于 ~/.config/mnem/config.toml 或仓库根目录的 .mnem/config.toml

[user]
name = "Your Name"
email = "[email protected]"

[llm]
provider = "ollama"
model = "qwen2.5"
base_url = "http://localhost:11434"

[ner]
provider = "rule"  # rule | none

架构设计要点

DAG 持久化

mnem 使用 DAG-CBOR 编码存储 Operation 和 View,确保:

  • 规范化:相同内容产生相同编码
  • 可验证:编码后哈希作为 CID 可验证完整性
  • 高效存储:内容去重通过 CID 实现

无头指针

mnem 不使用传统 Git 的 "head pointer" 链表模式,而是将所有历史直接编码在 Operation 的 parents 字段中。这简化了分支模型,但要求合并时必须显式指定 LCA。

事务隔离

Transaction 提供写隔离:

  • 未提交的变更对其他读者不可见
  • 提交是原子的(全部成功或全部回滚)
  • 支持嵌套事务(通过 savepoint 实现)

资料来源:[crates/mnem-core/src/lib.rs:10-30]()

内容寻址系统

mnem 的内容寻址系统是整个知识图谱存储和检索的基础架构。该系统基于 IPFS 生态的标准规范构建,通过内容的加密哈希值作为内容的唯一标识符,实现了去重、版本追溯和分布式存储等核心能力。

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 核心不变性保证

继续阅读本节完整说明和来源证据。

章节 CID 结构

继续阅读本节完整说明和来源证据。

章节 CID 的编解码

继续阅读本节完整说明和来源证据。

概述

mnem 的内容寻址系统是整个知识图谱存储和检索的基础架构。该系统基于 IPFS 生态的标准规范构建,通过内容的加密哈希值作为内容的唯一标识符,实现了去重、版本追溯和分布式存储等核心能力。

内容寻址的核心思想是:内容本身的哈希值即为该内容的地址。相同的内容必然产生相同的哈希值,这意味着任何节点可以对相同内容达成共识,无需依赖中心化的命名服务器。资料来源:crates/mnem-core/src/id/cid.rs:1-50

核心架构

mnem 的内容寻址系统由多个层次组成,每一层负责不同的职责:

graph TB
    subgraph "内容寻址层次结构"
        A["内容数据<br/>Bytes"] --> B["Multihash<br/>多哈希"]
        B --> C["CIDv1<br/>内容标识符"]
        C --> D["DAG-CBOR<br/>编码"]
        C --> E["DAG-JSON<br/>编码"]
    end
    
    subgraph "上层应用"
        D --> F["Node 节点"]
        D --> G["Edge 边"]
        D --> H["Commit 提交"]
        F --> I["Transaction 事务"]
        G --> I
        H --> I
    end
    
    subgraph "类型系统"
        J["Link&lt;T&gt;<br/>类型化链接"]
        K["ChangeId<br/>变更标识符"]
        L["OperationId<br/>操作标识符"]
    end

核心不变性保证

mnem-core crate 在 crate 级别强制执行以下不变性:

  • #![forbid(unsafe_code)] - 整个核心模块禁止使用 unsafe 代码
  • 每个对象类型必须保持字节级精确的规范化编码往返属性:decode(encode(x)) == x
  • 每个 put 操作必须验证解码后的对象与原始内容一致 资料来源:crates/mnem-core/src/lib.rs:30-45

CID 内容标识符

CID 结构

CID(Content Identifier)是 IPLD 生态系统中用于标识有向无环图(DAG)中节点的标准格式。mnem 使用 CIDv1 格式,支持多种哈希算法。

// CID 结构示意(简化版)
pub struct Cid {
    version: u64,      // CID 版本,通常为 1
    codec: u64,        // 编解码器标识(如 dag-cbor = 0x71)
    hash: Multihash,   // 内容的哈希值
}

CID 的编解码

CID 的序列化采用 IPLD 规范定义的格式,支持二进制(DAG-CBOR)和字符串(base32)两种表示方式:

表示方式用途示例
二进制内部存储、图遍历存储在 Blockstore 中
Base32 字符串人类可读、URL 安全bafybeig... 格式

资料来源:crates/mnem-core/src/id/cid.rs:1-100

Multihash 多哈希

设计理念

Multihash 是一种自描述的哈希格式,它将哈希算法标识和哈希值封装在一起。这种设计允许系统在不破坏已有内容寻址的前提下,演进哈希算法。

┌─────────────┬─────────────┬──────────────────┐
│  算法标识   │  长度 (2B)  │      哈希值       │
│  (varint)   │            │                  │
└─────────────┴─────────────┴──────────────────┘

支持的哈希算法

mnem 通过 multihash crate 支持多种哈希算法,具体使用哪种算法取决于配置和用例。常见算法包括:

算法标识符输出长度适用场景
SHA-2560x1232 字节默认、安全敏感场景
Blake30xb20132 字节高性能需求
Keccak-2560x1b32 字节以太坊兼容

资料来源:crates/mnem-core/src/id/multihash.rs:1-80

幽灵类型化链接

mnem 引入了 Link<T> 类型,这是一种phantom-typed(幽灵类型化)的链接类型,用于在编译期确保类型安全:

pub struct Link<T> {
    cid: Cid,
    _marker: PhantomData<T>,
}

这种设计实现了以下保证:

  • 编译时类型检查:无法将 Link<Node> 错误赋值给期望 Link<Commit> 的位置
  • 运行时零开销:幽灵类型不占用实际存储空间
  • 语义清晰:Link<Node> 表示指向节点,Link<Commit> 表示指向提交

资料来源:crates/mnem-core/src/id/link.rs:1-60

相关的标识符类型

Link<T> 外,系统还定义了以下标识符类型:

类型用途说明
ChangeId变更标识标识一次原子变更操作
OperationId操作标识标识具体的操作实例
EdgeId边标识标识图中的一条边

资料来源:crates/mnem-core/src/lib.rs:20-30

编解码器

DAG-CBOR 编解码器

DAG-CBOR 是 CBOR(Concise Binary Object Representation)的 DAG 扩展,是 IPLD 系统的默认编解码格式。它具有以下特点:

  • 紧凑二进制表示:相比 JSON 节省 30-50% 空间
  • 确定性编码:相同数据必然产生相同字节序列
  • 丰富的类型支持:包括字节串、链接、标签等 IPLD 特有类型
graph LR
    A["Rust Struct"] --> B["Serialize"]
    B --> C["CBOR Bytes"]
    C --> D["Multihash"]
    D --> E["CID"]
    
    F["CID"] --> G["Multihash"]
    G --> H["CBOR Bytes"]
    H --> I["Deserialize"]
    I --> J["Rust Struct"]

资料来源:crates/mnem-core/src/codec/dagcbor.rs:1-100

DAG-JSON 编解码器

DAG-JSON 用于人类可读的调试导出和日志记录。虽然不用于实际存储,但它对于开发和调试至关重要:

特性DAG-JSONDAG-CBOR
用途调试、导出实际存储
可读性人类可读二进制
效率
规范性非严格严格确定性

资料来源:crates/mnem-core/src/codec/dagjson.rs:1-80

对象模型

Node 节点

Node 是内容寻址存储的基本单元,每个节点由以下部分组成:

graph TB
    A["Node"] --> B["id: NodeId"]
    A --> C["ntype: String<br/>节点类型"]
    A --> D["summary: Option&lt;String&gt;<br/>摘要"]
    A --> E["props: BTreeMap<br/>属性映射"]
    A --> F["content: Option&lt;Bytes&gt;<br/>内容负载"]
    A --> G["context_sentence: Option&lt;String&gt;<br/>上下文句子"]

#### 字段语义

字段类型说明
idNodeId节点的唯一标识符
ntypeString节点类型标签(如 "Fact", "Person")
summaryOption<String>LLM 可读的摘要文本
propsBTreeMap<String, Ipld>结构化属性,可包含 Link
contentOption<Bytes>原始二进制负载
context_sentenceOption<String>上下文定位前缀

上下文句子(Context Sentence)是 Anthropic 2024 年上下文检索论文的实现。系统在嵌入前将此句子添加到摘要前,使密集和稀疏检索都能捕获位置和关系上下文。资料来源:crates/mnem-core/src/objects/node.rs:1-100

Edge 边

Edge 表示节点之间的有向关系:

pub struct Edge {
    pub src: NodeId,
    pub label: String,
    pub dst: NodeId,
    pub props: BTreeMap<String, Ipld>,
}

Commit 提交

Commit 封装了一组原子性的变更:

graph TB
    A["Commit"] --> B["change_id: ChangeId"]
    A --> C["parents: Vec&lt;ChangeId&gt;"]
    A --> D["nodes: Vec&lt;Node&gt;"]
    A --> E["edges: Vec&lt;Edge&gt;"]
    A --> F["author: String"]
    A --> G["time: u64"]
    A --> H["message: String"]
    A --> I["signature: Option&lt;Signature&gt;"]

资料来源:crates/mnem-core/src/objects/commit.rs:1-100

内容寻址工作流

写入流程

sequenceDiagram
    participant Client
    participant Transaction
    participant Blockstore
    participant Codec
    
    Client->>Transaction: add_node(node)
    Transaction->>Codec: serialize(node)
    Codec-->>Transaction: dag_cbor_bytes
    Transaction->>Blockstore: put(cid, bytes)
    Blockstore-->>Transaction: CID
    Transaction-->>Client: Link<Node>
    
    Client->>Transaction: add_edge(src, label, dst)
    Transaction->>Transaction: 创建 Edge
    Transaction->>Transaction: 创建 Commit
    Transaction->>Codec: serialize(commit)
    Blockstore->>Blockstore: 存储所有子节点

读取流程

graph LR
    A["Link&lt;T&gt;"] --> B["CID"]
    B --> C["Blockstore.get"]
    C --> D["DAG-CBOR Bytes"]
    D --> E["Codec.deserialize"]
    E --> F["T 类型对象"]

源类型与分块

内容寻址系统与源类型处理紧密集成。SourceKind 定义了支持的源类型:

源类型说明默认分块策略
MarkdownMarkdown 文档Paragraph
Text纯文本SentenceRecursive (256 tokens, 32 overlap)
PdfPDF 文档SentenceRecursive (512 tokens, 64 overlap)
Conversation对话记录Session (10 messages)
Code(lang)代码文件Structural

CodeLanguage 枚举支持以下语言:Rust, Python, JavaScript, TypeScript, Go, Java, C, C++, Ruby, CSharp

资料来源:crates/mnem-ingest/src/types.rs:1-100

检索与渲染

节点渲染

检索系统需要将节点转换为适合 LLM 消费的文本格式。渲染格式如下:

ntype: <ntype>
id: <uuid>
context: <context_sentence>
summary: <summary>
<prop_key>: <prop_value>
...

渲染规则:

  • ntypeid 始终存在
  • contextsummary 之前(遵循 Anthropic 上下文检索方案)
  • summary 长度上限 8192 字符(可配置 MNEM_RENDER_SUMMARY_CAP_CHARS
  • 标量属性按 BTreeMap 顺序(字母序)输出
  • 非标量属性(Link, Map, List, Bytes, Null)被跳过
  • 不透明 content 永不渲染

资料来源:crates/mnem-core/src/retrieve/mod.rs:50-100

配置与扩展

存储后端

mnem 通过 Blockstore trait 定义存储接口,支持多种实现:

pub trait Blockstore {
    async fn get(&self, cid: &Cid) -> Result<Option<Vec<u8>>>;
    async fn put(&self, cid: &Cid, block: &[u8]) -> Result<()>;
}

可扩展性设计

内容寻址系统的扩展点包括:

  • 新的编解码器:实现 Codec trait 可添加新的序列化格式
  • 新的哈希算法:通过 multihash crate 注册新算法
  • 新的对象类型:定义新结构体并实现序列化 trait

总结

mnem 的内容寻址系统建立在一个经过验证的标准之上(IPLD、CID、Multihash),同时通过以下设计决策提供了独特的价值:

  1. 类型安全:通过 Link<T> phantom 类型实现编译期检查
  2. 确定性编码:确保相同内容产生相同 CID,这是内容去重和一致性的基础
  3. 上下文感知:通过 context_sentence 字段增强检索质量
  4. 规范化保证:crate 级别禁止 unsafe,所有编解码经过往返测试

这套系统使得 mnem 能够可靠地管理知识图谱的长期演进,同时保持高效的内容查询和去重能力。

资料来源:[crates/mnem-core/src/id/cid.rs:1-100]()

存储后端

mnem 的存储后端是整个系统的核心基础设施,负责持久化和检索内容寻址的数据块(blocks)。它定义了抽象的存储接口,并提供了多种后端实现,使得上层逻辑与具体存储技术解耦。

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 核心方法

继续阅读本节完整说明和来源证据。

章节 存储保证

继续阅读本节完整说明和来源证据。

章节 CID 与内容映射

继续阅读本节完整说明和来源证据。

架构概览

mnem 采用模块化的存储架构,将存储接口抽象为 trait(特征),支持可插拔的后端实现。当前系统包含两套核心存储抽象和两种后端实现。

graph TD
    subgraph "应用层"
        A["mnem-core<br/>(核心库)"]
        B["mnem-cli<br/>(命令行工具)"]
        C["mnem-http<br/>(HTTP服务)"]
    end
    
    subgraph "存储抽象层"
        D["Blockstore trait"]
        E["OpHeadsStore trait"]
    end
    
    subgraph "后端实现层"
        F["InMemoryBlockstore<br/>(内存实现)"]
        G["RedbBlockstore<br/>(redb持久化)"]
        H["InMemoryOpHeadsStore"]
    end
    
    A --> D
    A --> E
    B --> A
    C --> A
    D --> F
    D --> G
    E --> H

Blockstore 特征

Blockstore 是 mnem 系统中用于存储和检索内容寻址数据块的核心 trait。它定义了读写操作的抽象接口,使得无论底层使用何种存储技术,上层的编解码和 DAG 操作都能正常工作。

核心方法

方法签名功能描述
getfn get(&self, cid: &Cid) -> Result<Option<Vec<u8>>, Error>根据 CID 检索数据块,返回 None 表示不存在
putfn put(&self, block: &[u8]) -> Result<Cid, Error>存储数据块,返回其 CID
hasfn has(&self, cid: &Cid) -> Result<bool, Error>检查指定 CID 的数据块是否存在

资料来源:crates/mnem-core/src/store/blockstore.rs:1-50

存储保证

Blockstore 的实现必须满足以下契约:

  • 幂等性put 操作对相同内容应产生相同的 CID(使用 DAG-CBOR 规范)
  • 一致性:读取已写入的数据必须返回完全相同的字节序列
  • 原子性:单个 put 操作应保持原子性

CID 与内容映射

mnem 使用 CIDv1 作为内容标识符,数据块采用 DAG-CBOR 编码格式。这种设计确保了:

  1. 相同内容始终映射到相同的 CID
  2. CID 包含足够的信息来验证内容完整性
  3. 存储系统无需维护独立的索引来追踪内容

OpHeadsStore 特征

OpHeadsStore 专门用于存储和管理操作头(operation heads)。在 mnem 的操作日志模型中,每个仓库(repo)在任意时刻都可能存在多个并发的操作头,这些头指针指向最新提交的操作序列。

核心方法

方法签名功能描述
get_op_headsfn get_op_heads(&self) -> Result<Vec<OperationId>, Error>获取当前所有操作头
put_op_headsfn put_op_heads(&self, heads: &[OperationId]) -> Result<(), Error>原子性地更新操作头集合

资料来源:crates/mnem-core/src/store/op_heads.rs:1-40

操作头语义

操作头集合代表了仓库的当前状态边界:

  • 无头状态:空的 Vec 表示仓库从未有过任何操作
  • 单头状态:单一操作头表示线性历史
  • 多头状态:多个操作头表示并发分支,需要合并

内存后端实现

mnem-core 包提供了一个内存中的参考实现,适用于测试、开发和单进程场景。

InMemoryBlockstore

基于 BTreeMap<Cid, Vec<u8>> 实现的内存块存储:

graph LR
    A["put(cid, block)"] --> B["BTreeMap insert"]
    C["get(cid)"] --> D["BTreeMap lookup"]
    E["has(cid)"] --> F["BTreeMap contains_key"]

特点:

  • 无持久化能力,进程退出后数据丢失
  • 查询性能为 O(log n),其中 n 为存储块数量
  • 适合单元测试和快速原型开发

InMemoryOpHeadsStore

同样基于内存的 OpHeadsStore 实现,使用 Vec<OperationId> 存储操作头。

Redb 后端实现

mnem-backend-redb 提供基于 redb 的持久化存储实现。redb 是一个纯 Rust 编写的嵌入式事务型 KV 数据库,具有以下特性:

特性

特性描述
纯 Rust无外部依赖,符合 mnem 的安全要求
ACID 事务支持完整的事务语义
嵌入式无需独立的数据库服务器
MVCC多版本并发控制,支持只读事务与读写事务并发

资料来源:crates/mnem-backend-redb/src/lib.rs:1-30

数据库结构

graph TD
    subgraph "redb 数据库"
        subgraph "元数据表"
            M1["op_heads: Vec<OperationId>"]
        end
        subgraph "数据表"
            D1["cid_1: Vec<u8>"]
            D2["cid_2: Vec<u8>"]
            D3["cid_n: Vec<u8>"]
        end
    end

事务管理

RedbBlockstore 实现使用读写事务来保证数据一致性:

  • 写操作:在读写事务中执行 put,事务提交后数据持久化
  • 读操作:使用只读事务,避免阻塞写操作
  • 批量操作:多个 put 可以在同一事务中执行

配置选项

参数类型默认值说明
path&Path必需数据库文件路径
max_db_sizeu644GB数据库文件最大大小
read_transactionsbooltrue是否启用并发只读事务

后端选择指南

场景推荐后端原因
单元测试InMemory快速、无副作用
开发调试InMemory便于检查状态
CLI 工具Redb持久化 + 嵌入式
HTTP 服务Redb事务保证 + 并发支持
内存受限环境InMemory零磁盘占用

与上层模块的关系

graph TD
    subgraph "mnem-core"
        R["Repo / ReadonlyRepo"]
        T["Transaction"]
        O["Operation"]
        N["Node"]
    end
    
    subgraph "存储层"
        BS["Blockstore"]
        OHS["OpHeadsStore"]
    end
    
    R --> BS
    R --> OHS
    T --> BS
    T --> OHS
    O --> BS
    N --> BS

ReadonlyRepoTransaction 通过组合持有 Box<dyn Blockstore>Box<dyn OpHeadsStore>,实现了存储后端的运行时多态。

错误处理

存储操作可能返回以下错误类型:

错误类型触发条件
Error::BlockNotFoundget 操作的 CID 不存在
Error::EncodingDAG-CBOR 编码/解码失败
Error::Store后端存储错误(如磁盘满、IO 错误)

所有存储错误都会向上传播,最终由应用层决定如何处理(如重试、回滚或报告)。

扩展新的后端

要实现新的存储后端,需要完成以下步骤:

  1. 实现 Blockstore trait:提供 getputhas 方法
  2. 实现 OpHeadsStore trait:提供 get_op_headsput_op_heads 方法
  3. 实现 Send + Sync:确保线程安全
  4. 实现 Default:提供零参数构造能力
  5. 处理错误转换:将底层错误映射到 mnem_core::Error

建议参考 mnem-backend-redb 的目录结构:

crates/mnem-backend-redb/
├── src/
│   ├── lib.rs        # 模块导出和公共 API
│   └── blockstore.rs # Blockstore trait 实现
├── Cargo.toml
└── README.md

安全考虑

mnem-core 整个包禁用了 unsafe_code#![forbid(unsafe_code)]),这意味着:

  • 存储后端实现也不能使用 unsafe
  • 数据完整性依赖 Rust 的内存安全保证
  • 持久化数据的可靠性完全由后端实现负责

资料来源:[crates/mnem-core/src/store/blockstore.rs:1-50]()

数据流与摄取管道

摄取管道(Ingestion Pipeline)是 mnem 系统的核心入口,负责将外部源文件(Markdown、PDF、代码、对话记录等)解析、分割、提取并写入仓库图数据库。整个管道设计遵循确定性原则:相同输入无论何时处理,都会产生相同的输出内容与 CID 标识符。

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 模块架构

继续阅读本节完整说明和来源证据。

章节 SourceKind 源类型枚举

继续阅读本节完整说明和来源证据。

章节 Section 结构

继续阅读本节完整说明和来源证据。

概述

摄取管道(Ingestion Pipeline)是 mnem 系统的核心入口,负责将外部源文件(Markdown、PDF、代码、对话记录等)解析、分割、提取并写入仓库图数据库。整个管道设计遵循确定性原则:相同输入无论何时处理,都会产生相同的输出内容与 CID 标识符。

mnem 将每份摄入的文档建模为 Doc + Chunk + Entity 三层节点结构,并通过 relation edges 将实体与原文关联,形成可供检索的语义图谱。资料来源:crates/mnem-ingest/src/lib.rs:25

graph TD
    A[外部源文件] --> B[SourceKind 检测]
    B --> C[专用解析器]
    C --> D[Section 列表]
    D --> E[Chunker 分块策略]
    E --> F[Chunk 列表]
    F --> G[Entity Extractor]
    G --> H[实体与关系]
    H --> I[写入 Transaction]
    I --> J[Commit 提交]
    J --> K[图数据库]

核心组件

模块架构

模块职责关键类型
pipeline端到端管道编排Ingester
chunk分块策略选择与执行ChunkerKind, chunk(), auto_chunker()
mdMarkdown 解析parse_markdown()
pdfPDF 文本提取PdfExtractor
code代码解析(tree-sitter)parse_code()
conversation对话记录解析parse_conversation()
extract实体与关系提取RuleExtractor, Extractor trait
text纯文本处理parse_text()
types类型定义SourceKind, Section, Chunk

资料来源:crates/mnem-ingest/src/lib.rs:10-32

数据类型体系

SourceKind 源类型枚举

管道根据文件扩展名自动检测源类型,不同类型采用不同的解析与分块策略。

扩展名SourceKind默认分块策略
.md, .markdownMarkdownParagraph
.txtTextSentenceRecursive (256 tokens, 32 overlap)
.pdfPdfSentenceRecursive (512 tokens, 64 overlap)
.json, .jsonlConversationSession (max_messages: 10)
.rs, .py, .jsCode(lang)Structural

资料来源:crates/mnem-ingest/src/types.rs:58-75

Section 结构

Section 是解析后的中间表示,包含标题层级与正文内容:

pub struct Section {
    pub heading: Option<String>,  // 标题文本
    pub level: u8,                // 标题层级 (1-6)
    pub body: String,             // 正文内容
}

Chunk 结构

Chunk 是最终存储的基本单元:

pub struct Chunk {
    pub tokens_estimate: usize,   // token 数量估算
    pub text: String,             // 块文本
    pub source_span: SourceSpan,  // 源文件位置
}

资料来源:crates/mnem-ingest/src/chunk.rs:30-45

分块策略详解

ChunkerKind 枚举

管道支持五种分块策略,通过 ChunkerKind 枚举选择。

策略描述适用场景
Paragraph按双换行符分割Markdown 文档
Recursive滑动窗口 token 分块(向后兼容)通用文本
SentenceRecursive基于 Unicode UAX #29 句子边界感知的 token 分块PDF、纯文本
Session按消息数分组对话片段对话记录
Structural每个 Section 一个 Chunk代码文件

资料来源:crates/mnem-ingest/src/chunk.rs:20-30

自动策略选择

auto_chunker() 函数根据源类型返回最佳分块策略:

pub fn auto_chunker(kind: SourceKind, heuristics: ChunkerAuto) -> ChunkerKind {
    match kind {
        SourceKind::Markdown => ChunkerKind::Paragraph,
        SourceKind::Text => ChunkerKind::SentenceRecursive { 
            max_tokens: 256, overlap: 32 
        },
        SourceKind::Pdf => ChunkerKind::SentenceRecursive { 
            max_tokens: 512, overlap: 64 
        },
        SourceKind::Conversation => ChunkerKind::Session { 
            max_messages: 10 
        },
        SourceKind::Code(_) => ChunkerKind::Structural,
    }
}

资料来源:crates/mnem-ingest/src/chunk.rs:100-115

SentenceRecursive 策略特点

  • 基于 Unicode 句子边界(UAX #29),确保块不在句子中间断开
  • overlap 以句子为单位计算
  • 平均块大小更均匀
  • Token 计数采用空格分割估算(tokens_estimate 字段)

管道执行流程

Ingester 核心逻辑

sequenceDiagram
    participant Client
    participant Ingester
    participant Parser
    participant Chunker
    participant Extractor
    participant Transaction

    Client->>Ingester: ingest(bytes, SourceKind)
    Ingester->>Parser: parse(bytes, kind)
    Parser-->>Ingester: Vec<Section>
    Ingester->>Chunker: chunk(sections, ChunkerKind)
    Chunker-->>Ingester: Vec<Chunk>
    Ingester->>Extractor: extract(sections, chunks)
    Extractor-->>Ingester: (Vec<Entity>, Vec<Relation>)
    Ingester->>Transaction: add_node(Doc) + add_node(Chunk) + add_node(Entity)
    Ingester->>Transaction: add_edge(relation edges)
    Ingester-->>Client: IngestResult

关键 API

Ingester::ingest() 方法:

pub fn ingest(
    &self,
    tx: &mut Transaction,
    bytes: &[u8],
    kind: SourceKind,
) -> Result<IngestResult, Error>

参数说明:

参数类型说明
tx&mut Transaction写入事务引用,不自动提交
bytes&[u8]原始字节载荷
kindSourceKind源类型标识

返回值:

字段类型说明
countsCounts节点数量统计
elapsedDuration执行耗时
commit_cidOption<CommitId>留空,调用者需手动 tx.commit()

资料来源:crates/mnem-ingest/src/pipeline.rs:80-110

专用解析器

Markdown 解析器

基于 CommonMark + GFM 规范,支持:

  • ATX/Setex 标题(提取层级)
  • 列表、代码块、表格
  • 返回 Vec<Section>,每个顶级或次级块一个 Section

PDF 解析器

纯 Rust 实现,支持两种模式:

  1. 内置提取:解析 PDF 文本层
  2. Sidecar 扩展:调用外部 doclingunstructured-ingest CLI
#[cfg(feature = "sidecar-docling")]
pub struct DoclingSidecar;

#[cfg(feature = "sidecar-unstructured")]
pub struct UnstructuredSidecar;

资料来源:crates/mnem-ingest/src/sidecar.rs:30-50

代码解析器

使用 tree-sitter 解析代码文件,按函数/类级别提取 Section:

支持语言扩展名
Rust.rs
Python.py, .pyi
JavaScript.js, .mjs, .cjs
TypeScript.ts, .tsx, .mts, .cts
Go.go
Java.java
C/C++.c, .h, .cpp, .cc, .cxx, .hpp
Ruby.rb, .gemspec, .rake, .erb
C#.cs, .csx

对话解析器

支持 ChatGPT、Claude 等导出的 JSON/JSONL 格式:

{
  "messages": [
    {"role": "user", "content": "..."},
    {"role": "assistant", "content": "..."}
  ]
}

实体提取系统

Extractor Trait

pub trait Extractor: Send + Sync {
    fn prepare(&self, sections: &[Section]) -> Result<(), Error>;
    fn extract_entities(&self, sections: &[Section], text: &str) -> Vec<EntitySpan>;
    fn extract_relations(&self, text: &str, entities: &[EntitySpan]) -> Vec<RelationSpan>;
}

资料来源:crates/mnem-ingest/src/extract.rs:50-70

RuleExtractor

默认提取器实现:

  • 实体检测:委托给 NerProvider(默认:大写短语启发式)
  • 关系检测:基于动词窗口正则表达式
r"(?i)\b(?:joined|founded|acquired|owns|hired|married|...)

可选扩展

扩展特性Cargo Feature
KeyBertAdapter统计 NER + embeddingkeybert
OllamaExtractorLLM 驱动 schema 约束 NERollama

Ollama 提取器会对幻觉 span 重新验证,失败时降级为空 Vec 而非错误。

CLI 接口

基本用法

# 摄入单个文件
mnem ingest notes.md

# 指定分块策略
mnem ingest --chunker recursive --max-tokens 1024 book.pdf

# 递归目录
mnem ingest --recursive docs/

命令行参数

参数默认值说明
--chunkerauto策略:`autoparagraphrecursivesessionstructural`
--max-tokens512目标 token 数
--overlap32重叠 token 数
--recursivefalse递归目录
--ntypeDoc根节点标签
--extractornone提取器:`nonekeybert`
--nerruleNER 提供者:`rulenone`

资料来源:crates/mnem-cli/src/commands/ingest.rs:50-80

HTTP API

POST /v1/ingest

请求体:

字段类型说明
filemultipart要摄入的文件
chunkerOption<String>`auto\paragraph\recursive`
max_tokensOption<u32>目标 token
overlapOption<u32>重叠 token
authorString提交作者(必需)
messageOption<String>提交信息
extractorOption<String>`none\keybert`
ner_providerOption<String>`rule\none`

资料来源:crates/mnem-http/src/handlers_ingest.rs:20-50

确定性保证

mnem 摄取管道的设计目标之一是确定性

  1. 解析确定性:相同输入产生相同的 Vec<Section>
  2. 分块确定性SentenceRecursive 使用 Unicode 边界,不依赖运行时状态
  3. 编码确定性:所有对象类型保证字节级精确的编解码往返
  4. CID 确定性:相同内容产生相同 CID,支持去重
#![forbid(unsafe_code)] 确保管道中无未定义行为。

资料来源:crates/mnem-core/src/lib.rs:25-30

Node 输出结构

摄取完成后,仓库中包含以下节点:

节点类型ntype说明
文档节点Doc(可配置)根节点,记录来源
块节点Chunk分块后的内容单元
实体节点实体类型提取的命名实体

每个节点包含:

pub struct Node {
    pub summary: Option<String>,        // 摘要(供 LLM 使用)
    pub props: BTreeMap<String, Ipld>,  // 属性映射
    pub content: Option<Bytes>,          // 原始内容
    pub context_sentence: Option<String>, // 上下文前缀句
}

context_sentence 字段实现 Anthropic 2024 Contextual Retrieval 方案,在嵌入前添加到摘要前缀。

错误处理

错误类型触发条件
Error::ParseFailed解析器拒绝输入
Error::UnsupportedSource不支持的源类型
Error::Commit事务写入失败
Error::Sidecar外部工具缺失或失败

Sidecar 工具错误会包装为 Error::Sidecar { tool, detail }

资料来源:[crates/mnem-ingest/src/lib.rs:10-32]()

混合检索系统

mnem 的混合检索系统(Hybrid Retrieval System)是核心检索引擎,负责在给定的 token 预算内高效地从知识库中召回最相关的内容。该系统通过组合向量检索(dense vector)、稀疏检索(sparse retrieval)和图扩展(graph expansion)等多种策略,为 Agent 提供高质量的上下文上下文。

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 检索器(Retriever)

继续阅读本节完整说明和来源证据。

章节 向量检索(Vector Retrieval)

继续阅读本节完整说明和来源证据。

章节 稀疏检索(Sparse Retrieval)

继续阅读本节完整说明和来源证据。

概述

mnem 的混合检索系统(Hybrid Retrieval System)是核心检索引擎,负责在给定的 token 预算内高效地从知识库中召回最相关的内容。该系统通过组合向量检索(dense vector)、稀疏检索(sparse retrieval)和图扩展(graph expansion)等多种策略,为 Agent 提供高质量的上下文上下文。

mnem 的检索架构遵循以下设计原则:

  • 多策略融合:同时利用密集向量和稀疏向量的互补优势
  • Token 预算感知:严格控制返回内容的 token 消耗
  • 确定性渲染:为 LLM 生成稳定、可预测的输入格式
  • 无 Unsafe 代码:整个检索管线保证内存安全

资料来源:crates/mnem-core/src/lib.rs

检索流程架构

混合检索系统的完整工作流程如下:

graph TD
    A[用户查询 Query] --> B[查询理解层]
    B --> C{检索策略选择}
    C -->|混合模式| D[向量检索分支]
    C -->|混合模式| E[稀疏检索分支]
    C -->|混合模式| F[图扩展分支]
    D --> G[结果融合]
    E --> G
    F --> G
    G --> H[重排序 Rerank]
    H --> I[Token 预算打包]
    I --> J[渲染 Render]
    J --> K[LLM 上下文输出]
    
    L[配置参数] --> B
    L --> D
    L --> E
    L --> F
    L --> H

核心组件

检索器(Retriever)

Retriever 是检索系统的主入口,负责协调各个检索分支的执行和结果融合。

组件职责
Query查询结构体,包含查询文本和检索参数
Retriever主检索器,协调向量、稀疏、图扩展三种检索
BruteForceVectorIndex向量索引,支持暴力搜索和 ANN 近似搜索
QueryEncoder查询编码器,将自然语言查询转换为向量

资料来源:crates/mnem-core/src/retrieve/mod.rs 资料来源:crates/mnem-core/src/retrieve/retriever.rs

向量检索(Vector Retrieval)

向量检索使用密集向量表示来衡量语义相似性。mnem 采用 HNSW(Hierarchical Navigable Small World)算法实现近似最近邻搜索。

参数说明默认值
vector_cap向量检索返回的最大结果数-
limit总体检索结果限制-

HNSW 算法特点

  • 分层结构:构建多层跳表式图结构
  • 贪心搜索:从顶层向下逐层搜索
  • 参数控制:ef_search、ef_construction、m_max 等影响精度和性能

资料来源:crates/mnem-ann/src/hnsw.rs 资料来源:crates/mnem-core/src/index/vector.rs

稀疏检索(Sparse Retrieval)

稀疏检索基于词项精确匹配,适合处理专有名词、代码标识符等精确查询场景。

特性说明
BM25 算法基于词频和文档频率的概率排名
倒排索引高效的词项到文档映射
动态权重根据查询词项在文档中的重要性调整

稀疏检索与向量检索形成互补:向量检索擅长语义相似性,稀疏检索擅长精确词项匹配。

资料来源:crates/mnem-core/src/index/sparse.rs

图扩展(Graph Expansion)

图扩展利用知识图谱的结构信息进行检索扩展。

参数说明
graph_expand图扩展的邻居节点数量
graph_depth图遍历的最大深度
graph_decay距离衰减系数,控制远处节点的影响力

图扩展的工作原理:

  1. 从初始检索结果中的节点开始
  2. 沿着边扩展到相邻节点
  3. 根据 graph_decay 衰减权重
  4. 重复直到达到 graph_depth

资料来源:crates/mnem-cli/src/config.rs

结果融合策略

当启用混合检索时,需要将多个检索分支的结果进行融合。mnem 采用基于分数的加权融合策略。

融合算法

graph LR
    A[向量分数<br/>Vector Score] --> D[分数归一化]
    B[稀疏分数<br/>Sparse Score] --> D
    C[图扩展分数<br/>Graph Score] --> D
    D --> E[权重加权]
    E --> F[分数合并]
    F --> G[排序输出]
    
    H[配置权重] --> E

融合分数计算公式:

final_score = w_vector × norm_vector + w_sparse × norm_sparse + w_graph × norm_graph

其中归一化方法采用 Min-Max 归一化:

norm(x) = (x - min) / (max - min)

资料来源:crates/mnem-core/src/retrieve/fusion.rs

重排序(Rerank)

融合后的候选结果会通过重排序模型进一步优化顺序。

配置项说明
rerank.top_k重排序后保留的结果数
rerank.model重排序模型名称
rerank.base_url重排序 API 端点
rerank.api_key_envAPI 密钥环境变量

支持的 Rerank 提供商:

  • Cohere:Cohere Rerank API
  • Voyage:Voyage AI Rerank API
  • Jina:Jina AI Rerank API

资料来源:crates/mnem-cli/src/config.rs

Token 预算管理

检索系统的一个核心挑战是在严格的 token 预算内最大化信息价值。

预算控制参数

参数说明默认值
budget检索结果的总 token 预算上限动态计算

预算打包算法

  1. 按分数排序:根据融合分数降序排列候选 chunks
  2. 贪心选择:依次添加 chunks 直到达到 budget 限制
  3. 上下文优先:优先保留高相关性、高信息密度的 chunks

资料来源:crates/mnem-core/src/retrieve/mod.rs

渲染与输出

检索结果最终需要渲染为适合 LLM 消费的格式。mnem 采用 YAML 风格的确定性渲染格式。

渲染格式规范

ntype: <ntype>
id: <uuid>
context: <context_sentence>
summary: <summary>
<prop_key>: <prop_value>
...

渲染规则

  • ntypeid 始终输出
  • context(上下文句子)在 summary 之前输出,符合 Anthropic 2024 contextual-retrieval 最佳实践
  • summary 长度默认限制在 8192 字符内,可通过 MNEM_RENDER_SUMMARY_CAP_CHARS 环境变量覆盖
  • 标量属性(String、Integer、Float、Bool)按 BTreeMap 顺序输出
  • 非标量属性(Link、Map、List、Bytes、Null)跳过,避免上下文膨胀
  • 原始 content 字节永不出现在渲染输出中

资料来源:crates/mnem-core/src/retrieve/mod.rs

配置参考

检索配置示例

[retrieve]
limit = 50              # 最大返回结果数
budget = 8192           # token 预算上限
vector_cap = 100        # 向量检索候选数
graph_expand = 5        # 图扩展邻居数
graph_decay = 0.5       # 图距离衰减系数
graph_depth = 2         # 图遍历深度
rerank_top_k = 10       # 重排序后保留数
hyde_max_tokens = 512   # HyDE 生成的最大 token 数

[rerank]
provider = "cohere"     # rerank 提供商
model = "rerank-english-v2.0"
base_url = "https://api.cohere.com"
api_key_env = "COHERE_API_KEY"

[llm]
provider = "openai"     # LLM 提供商(用于 HyDE 等功能)
model = "gpt-4"

环境变量

环境变量说明
MNEM_RENDER_SUMMARY_CAP_CHARS渲染时 summary 的最大字符数,默认 8192

与其他模块的交互

数据依赖

graph TD
    subgraph Ingest Pipeline
        A[Markdown/PDF/Code] --> B[Chunker]
        B --> C[Section/Chunk]
        C --> D[Extractor]
        D --> E[Index Builder]
    end
    
    subgraph Retrieval
        E --> F[Vector Index]
        E --> G[Sparse Index]
        E --> H[Graph Index]
        F --> I[Retriever]
        G --> I
        H --> I
        I --> J[LLM Context]
    end
    
    subgraph Storage
        E --> K[Blockstore]
        I --> K
    end

检索系统依赖 Ingest Pipeline 构建的索引结构:

  1. 分块(Chunking):文档被分割为可检索的 chunks
  2. 索引构建:创建向量索引、稀疏索引和图索引
  3. 存储持久化:索引数据存储在 Blockstore 中

资料来源:crates/mnem-ingest/src/chunk.rs 资料来源:crates/mnem-core/src/index/mod.rs

Chunker 与检索的配合

不同类型的源文档采用不同的分块策略:

源类型Chunker 类型参数
MarkdownParagraph-
TextSentenceRecursivemax_tokens: 256, overlap: 32
PDFSentenceRecursivemax_tokens: 512, overlap: 64
ConversationSessionmax_messages: 10
CodeStructural-

资料来源:crates/mnem-ingest/src/chunk.rs

最佳实践

1. 混合检索配置建议

对于通用场景,推荐使用默认配置:

[retrieve]
limit = 50
budget = 8192
vector_cap = 100

2. 精确查询优化

当查询包含大量专有名词或代码标识符时,启用稀疏检索分支:

  • 稀疏检索对精确词项匹配更有效
  • 与向量检索组合使用可兼顾语义和精确性

3. 图感知查询

对于需要关系推理的查询,增加图扩展参数:

[retrieve]
graph_expand = 10
graph_depth = 3
graph_decay = 0.7

4. Token 预算规划

  • 高频短查询:budget 可设置较低(如 4096)
  • 深度分析查询:budget 可提高至 16384
  • 结合 rerank.top_k 控制重排序计算量

总结

mnem 的混合检索系统通过融合向量检索、稀疏检索和图扩展三大策略,结合重排序和 token 预算管理,为 Agent 提供了灵活且高效的检索能力。系统设计遵循确定性原则,确保相同查询始终产生稳定的输出格式,便于 LLM 理解和处理。

检索系统的配置高度可定制,开发者可根据具体应用场景调整各分支的权重和参数,在检索精度、响应速度和 token 效率之间取得最佳平衡。

资料来源:[crates/mnem-core/src/lib.rs]()

失败模式与踩坑日记

保留 Doramagic 在发现、验证和编译中沉淀的项目专属风险,不把社区讨论只当作装饰信息。

high 来源证据:[feature] hermes support

可能影响授权、密钥配置或安全边界。

medium 能力判断依赖假设

假设不成立时,用户拿不到承诺的能力。

medium 来源证据:[bug] Broken docs links: SPEC.md, ROADMAP.md, and Architecture page

可能增加新用户试用和生产接入成本。

medium 维护活跃度未知

新项目、停更项目和活跃项目会被混在一起,推荐信任度下降。

Pitfall Log / 踩坑日志

项目:Uranid/mnem

摘要:发现 8 个潜在踩坑项,其中 1 个为 high/blocking;最高优先级:安全/权限坑 - 来源证据:[feature] hermes support。

1. 安全/权限坑 · 来源证据:[feature] hermes support

  • 严重度:high
  • 证据强度:source_linked
  • 发现:GitHub 社区证据显示该项目存在一个安全/权限相关的待验证问题:[feature] hermes support
  • 对用户的影响:可能影响授权、密钥配置或安全边界。
  • 建议检查:来源问题仍为 open,Pack Agent 需要复核是否仍影响当前版本。
  • 防护动作:不得脱离来源链接放大为确定性结论;需要标注适用版本和复核状态。
  • 证据:community_evidence:github | cevd_c54919b2b8b340438a9e5aa17291b93a | https://github.com/Uranid/mnem/issues/27 | 来源类型 github_issue 暴露的待验证使用条件。

2. 能力坑 · 能力判断依赖假设

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:README/documentation is current enough for a first validation pass.
  • 对用户的影响:假设不成立时,用户拿不到承诺的能力。
  • 建议检查:将假设转成下游验证清单。
  • 防护动作:假设必须转成验证项;没有验证结果前不能写成事实。
  • 证据:capability.assumptions | github_repo:1221867246 | https://github.com/Uranid/mnem | README/documentation is current enough for a first validation pass.
  • 严重度:medium
  • 证据强度:source_linked
  • 发现:GitHub 社区证据显示该项目存在一个维护/版本相关的待验证问题:[bug] Broken docs links: SPEC.md, ROADMAP.md, and Architecture page
  • 对用户的影响:可能增加新用户试用和生产接入成本。
  • 建议检查:来源显示可能已有修复、规避或版本变化,说明书中必须标注适用版本。
  • 防护动作:不得脱离来源链接放大为确定性结论;需要标注适用版本和复核状态。
  • 证据:community_evidence:github | cevd_5c74e7a10f774af6b0460b5da009d1b4 | https://github.com/Uranid/mnem/issues/23 | 来源讨论提到 windows 相关条件,需在安装/试用前复核。

4. 维护坑 · 维护活跃度未知

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:未记录 last_activity_observed。
  • 对用户的影响:新项目、停更项目和活跃项目会被混在一起,推荐信任度下降。
  • 建议检查:补 GitHub 最近 commit、release、issue/PR 响应信号。
  • 防护动作:维护活跃度未知时,推荐强度不能标为高信任。
  • 证据:evidence.maintainer_signals | github_repo:1221867246 | https://github.com/Uranid/mnem | last_activity_observed missing

5. 安全/权限坑 · 下游验证发现风险项

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:no_demo
  • 对用户的影响:下游已经要求复核,不能在页面中弱化。
  • 建议检查:进入安全/权限治理复核队列。
  • 防护动作:下游风险存在时必须保持 review/recommendation 降级。
  • 证据:downstream_validation.risk_items | github_repo:1221867246 | https://github.com/Uranid/mnem | no_demo; severity=medium

6. 安全/权限坑 · 存在评分风险

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:no_demo
  • 对用户的影响:风险会影响是否适合普通用户安装。
  • 建议检查:把风险写入边界卡,并确认是否需要人工复核。
  • 防护动作:评分风险必须进入边界卡,不能只作为内部分数。
  • 证据:risks.scoring_risks | github_repo:1221867246 | https://github.com/Uranid/mnem | no_demo; severity=medium

7. 维护坑 · issue/PR 响应质量未知

  • 严重度:low
  • 证据强度:source_linked
  • 发现:issue_or_pr_quality=unknown。
  • 对用户的影响:用户无法判断遇到问题后是否有人维护。
  • 建议检查:抽样最近 issue/PR,判断是否长期无人处理。
  • 防护动作:issue/PR 响应未知时,必须提示维护风险。
  • 证据:evidence.maintainer_signals | github_repo:1221867246 | https://github.com/Uranid/mnem | issue_or_pr_quality=unknown

8. 维护坑 · 发布节奏不明确

  • 严重度:low
  • 证据强度:source_linked
  • 发现:release_recency=unknown。
  • 对用户的影响:安装命令和文档可能落后于代码,用户踩坑概率升高。
  • 建议检查:确认最近 release/tag 和 README 安装命令是否一致。
  • 防护动作:发布节奏未知或过期时,安装说明必须标注可能漂移。
  • 证据:evidence.maintainer_signals | github_repo:1221867246 | https://github.com/Uranid/mnem | release_recency=unknown

来源:Doramagic 发现、验证与编译记录