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

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

## 目录

- [项目介绍](#page-introduction)
- [安装指南](#page-installation)
- [系统架构](#page-architecture)
- [Crates结构详解](#page-crates-structure)
- [知识图谱模型](#page-knowledge-graph)
- [版本控制机制](#page-version-control)
- [内容寻址系统](#page-content-addressing)
- [存储后端](#page-storage-backend)
- [数据流与摄取管道](#page-data-flow)
- [混合检索系统](#page-hybrid-retrieval)

<a id='page-introduction'></a>

## 项目介绍

### 相关页面

相关主题：[系统架构](#page-architecture), [安装指南](#page-installation)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [README.md](https://github.com/Uranid/mnem/blob/main/README.md)
- [README.zh-CN.md](https://github.com/Uranid/mnem/blob/main/README.zh-CN.md)
- [crates/mnem-core/README.md](https://github.com/Uranid/mnem/blob/main/crates/mnem-core/README.md)
- [crates/mnem-ingest/src/lib.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-ingest/src/lib.rs)
- [crates/mnem-ingest/src/chunk.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-ingest/src/chunk.rs)
- [crates/mnem-core/src/lib.rs](https://github.com/Uranid/mnem/blob/main/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)
- [crates/mnem-ingest/src/pipeline.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-ingest/src/pipeline.rs)
- [crates/mnem-cli/src/commands/ingest.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-cli/src/commands/ingest.rs)
- [crates/mnem-http/src/handlers.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-http/src/handlers.rs)

</details>

# 项目介绍

## 概述

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

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

## 核心定位

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

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

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

## 系统架构

Mnem 采用分层架构，核心分为以下几个 crate：

```mermaid
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](https://github.com/Uranid/mnem/blob/main/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 导入文档时，数据会经过以下处理流程：

```mermaid
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](https://github.com/Uranid/mnem/blob/main/crates/mnem-ingest/src/lib.rs)

### 支持的源格式

| 扩展名 | 源类型 | 默认分块策略 |
|-------|--------|-------------|
| `.md` / `.markdown` | Markdown | Paragraph |
| `.txt` | 纯文本 | SentenceRecursive (256 tokens) |
| `.pdf` | PDF | SentenceRecursive (512 tokens) |
| `.json` / `.jsonl` | 会话记录 | Session (10 条消息) |
| `.rs` / `.py` / `.js` / `.ts` 等 | 代码 | Structural |

资料来源：[crates/mnem-ingest/src/pipeline.rs](https://github.com/Uranid/mnem/blob/main/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 提取器

支持外部提取服务：

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

资料来源：[crates/mnem-ingest/src/lib.rs](https://github.com/Uranid/mnem/blob/main/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)
```

```mermaid
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](https://github.com/Uranid/mnem/blob/main/crates/mnem-cli/src/config.rs)

## 版本化与分支

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

```mermaid
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](https://github.com/Uranid/mnem/blob/main/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 选项

```bash
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/nodes` | GET | 获取节点列表 |
| `/v1/nodes/{id}` | GET | 获取指定节点 |
| `/v1/ingest` | POST | 导入文档 |
| `/v1/branches` | GET | 获取分支列表 |
| `/v1/branches` | POST | 创建分支 |
| `/v1/retrieve` | POST | 检索 |

## MCP Server

Mnem 提供了 MCP（Model Context Protocol）集成，支持 AI 工具直接访问知识图谱：

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

资料来源：[crates/mnem-cli/src/integrate.rs](https://github.com/Uranid/mnem/blob/main/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+ 主流编程语言 |

## 使用示例

### 初始化仓库

```bash
mnem init my-knowledge-base
cd my-knowledge-base
```

### 导入文档

```bash
# 导入 Markdown
mnem ingest README.md

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

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

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

### 检索知识

```bash
mnem query "Mnem 的检索算法是如何工作的？"
```

### 分支管理

```bash
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](https://github.com/Uranid/mnem/blob/main/README.zh-CN.md)

---

<a id='page-installation'></a>

## 安装指南

### 相关页面

相关主题：[项目介绍](#page-introduction)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [docs/src/install.md](https://github.com/Uranid/mnem/blob/main/docs/src/install.md)
- [Dockerfile](https://github.com/Uranid/mnem/blob/main/Dockerfile)
- [docker-compose.yml](https://github.com/Uranid/mnem/blob/main/docker-compose.yml)
- [scripts/install.sh](https://github.com/Uranid/mnem/blob/main/scripts/install.sh)
- [scripts/install.ps1](https://github.com/Uranid/mnem/blob/main/scripts/install.ps1)
</details>

# 安装指南

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

## 系统要求

### 硬件要求

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

### 软件依赖

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

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

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

## 安装方式

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

### 方式一：从源码编译安装

#### 前置准备

```bash
# 安装 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
```

#### 编译步骤

```bash
# 克隆仓库
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

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

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

#### Windows PowerShell

```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 结构

```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](https://github.com/Uranid/mnem/blob/main/Dockerfile)

#### docker-compose 编排

```yaml
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](https://github.com/Uranid/mnem/blob/main/docker-compose.yml)

#### 启动 Docker 服务

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

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

# 停止服务
docker-compose down
```

## 初始化配置

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

### 仓库初始化

```bash
# 初始化新的 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](https://github.com/Uranid/mnem/blob/main/crates/mnem-cli/src/commands/init.rs)

### 配置文件

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

```toml
[user]
# 用户标识（可选）
name = "Your Name"
email = "your@email.com"

[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](https://github.com/Uranid/mnem/blob/main/crates/mnem-cli/src/config.rs)

### 验证安装

```bash
# 检查 mnem 版本
mnem --version

# 查看当前仓库状态
mnem status

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

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

## 接入方式

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

### CLI 模式

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

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

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

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

### HTTP 服务模式

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

```bash
# 启动 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](https://github.com/Uranid/mnem/blob/main/crates/mnem-http/src/handlers.rs)

### MCP 模式

MCP（Model Context Protocol）模式允许 AI 助手直接访问 mnem 知识图谱：

```bash
# 启动 MCP 服务器
mnem mcp serve

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

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

## 依赖可选功能

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

### 文档解析依赖

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

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

### 向量检索依赖

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

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

## 安装流程图

```mermaid
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
```

## 卸载

### 二进制安装卸载

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

# 删除配置文件（可选）
rm -rf ~/.config/mnem
```

### Docker 卸载

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

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

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

## 常见问题

### 编译失败

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

```bash
# Ubuntu/Debian
sudo apt install libssl-dev

# macOS
brew install openssl@3
```

### 权限问题

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

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

### 数据库损坏

如遇数据库异常，可尝试重建：

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

# 重新初始化
mnem init
```

## 下一步

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

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

---

<a id='page-architecture'></a>

## 系统架构

### 相关页面

相关主题：[Crates结构详解](#page-crates-structure), [知识图谱模型](#page-knowledge-graph), [存储后端](#page-storage-backend)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [crates/mnem-core/src/lib.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-core/src/lib.rs)
- [crates/mnem-ingest/src/lib.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-ingest/src/lib.rs)
- [crates/mnem-ingest/src/pipeline.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-ingest/src/pipeline.rs)
- [crates/mnem-ingest/src/types.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-ingest/src/types.rs)
- [crates/mnem-core/src/id/link.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-core/src/id/link.rs)
</details>

# 系统架构

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)) == x` 且 `encode(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 系统采用分层架构，各层职责明确，从底层数据存储到顶层用户接口逐层构建。

```mermaid
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]()`：

| 模块 | 功能描述 |
|------|----------|
| `id` | CID（内容标识符）、ChangeId、OperationId 以及泛型链接类型 Link<T> |
| `codec` | DAG-CBOR 编解码器和 DAG-JSON 调试导出 |
| `objects` | Node、Edge、Commit、Operation、View、IndexSet 等核心对象类型 |
| `prolly` | Prolly 树算法（分块器、构建器、查找、光标、diff、合并） |
| `store` | Blockstore 和 OpHeadsStore trait 及内存实现 |
| `repo` | ReadonlyRepo、Transaction 外观类 |
| `index` | 辅助索引（Query、BruteForceVectorIndex） |
| `retrieve` | Agent 面向的 Retriever，组合过滤、向量和稀疏排序 |
| `sign` | Ed25519 签名和撤销列表验证 |

### mnem-ingest 文档解析库

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

| 模块 | 功能 |
|------|------|
| `md` | CommonMark + GFM Markdown 解析 |
| `pdf` | 纯 Rust 实现的 PDF 文本层提取 |
| `code` | 基于 tree-sitter 的代码解析 |
| `conversation` | ChatGPT/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]()`：

```mermaid
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~
    }
```

| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | NodeId | 节点唯一标识符 |
| `ntype` | String | 节点类型标签（如 "Doc"、"Section" 等） |
| `parents` | Vec<Link<Commit>> | 父提交链接 |
| `context_sentence` | Option<String> | 上下文句子（Anthropic 2024 contextual retrieval 设计） |
| `summary` | Option<String> | LLM 可读的摘要文本，默认截断至 8192 字符 |
| `props` | BTreeMap | 结构化属性键值对 |
| `content` | Option<Bytes> | 不透明载荷（如文档体、文件内容） |

### 链接类型（Link）

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]()`：

```mermaid
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` `.markdown` | Markdown | Paragraph |
| `.pdf` | Pdf | SentenceRecursive (512 tokens, 64 overlap) |
| `.txt` | Text | SentenceRecursive (256 tokens, 32 overlap) |
| `.json` `.jsonl` | Conversation | Session (10 messages) |
| `.rs` | Code(Rust) | Structural |
| `.py` `.pyi` | Code(Python) | Structural |
| `.js` `.mjs` `.cjs` | Code(JavaScript) | Structural |
| `.ts` `.tsx` | Code(TypeScript) | Structural |
| `.go` | Code(Go) | Structural |
| `.java` | Code(Java) | Structural |
| `.c` `.h` | Code(C) | Structural |
| `.cpp` `.cc` `.cxx` | Code(Cpp) | Structural |
| 其他 | Text | SentenceRecursive |

### 分块策略详解

系统提供五种分块策略，适用于不同类型的文档内容 资料来源：[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**：提交记录，指向操作链和视图

```mermaid
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 | 功能 |
|---------|------|
| `keybert` | KeyBERT 统计嵌入器适配器 |
| `ollama` | Ollama LLM 提取器 |
| `sidecar-docling` | Docling CLI PDF 解析集成 |
| `sidecar-unstructured` | Unstructured.io 解析集成 |

## 总结

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

---

<a id='page-crates-structure'></a>

## Crates结构详解

### 相关页面

相关主题：[系统架构](#page-architecture)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [Cargo.toml](https://github.com/Uranid/mnem/blob/main/Cargo.toml)
- [crates/mnem-core/Cargo.toml](https://github.com/Uranid/mnem/blob/main/crates/mnem-core/Cargo.toml)
- [crates/mnem-cli/Cargo.toml](https://github.com/Uranid/mnem/blob/main/crates/mnem-cli/Cargo.toml)
- [crates/mnem-ingest/Cargo.toml](https://github.com/Uranid/mnem/blob/main/crates/mnem-ingest/Cargo.toml)
- [crates/mnem-http/Cargo.toml](https://github.com/Uranid/mnem/blob/main/crates/mnem-http/Cargo.toml)
- [crates/mnem-mcp/Cargo.toml](https://github.com/Uranid/mnem/blob/main/crates/mnem-mcp/Cargo.toml)
</details>

# Crates结构详解

## 概述

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

```mermaid
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-ingest` | HTTP API 服务 |
| `mnem-mcp` | 依赖 `mnem-core` | MCP 协议集成 |

## mnem-core 核心库

### 定位与职责

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

### 核心模块

```rust
资料来源：[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](crates/mnem-core/src/objects/node.rs)

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

### ID 系统

资料来源：[crates/mnem-core/src/id/link.rs](crates/mnem-core/src/id/link.rs)

```rust
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](crates/mnem-core/src/retrieve/mod.rs)

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

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

渲染规则：
- `ntype` 和 `id` 始终存在
- `context` 在 `summary` 之前输出（遵循 Anthropic 2024 contextual-retrieval 配方）
- `summary` 默认截断至 8192 字符，可通过 `MNEM_RENDER_SUMMARY_CAP_CHARS` 环境变量配置
- 标量属性按字母序输出，复杂属性（Link、Map、List）跳过

## mnem-ingest 数据摄取库

### 定位与职责

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

### 模块架构

```mermaid
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](crates/mnem-ingest/src/types.rs)

| 源类型 | 文件扩展名 | 默认分块策略 |
|--------|------------|--------------|
| `Markdown` | `.md`, `.markdown` | Paragraph |
| `Pdf` | `.pdf` | SentenceRecursive (512 tokens, 64 overlap) |
| `Text` | 其他无扩展名文件 | SentenceRecursive (256 tokens, 32 overlap) |
| `Conversation` | `.json`, `.jsonl` | Session (10 messages) |
| `Code(lang)` | 各类代码文件 | Structural |

### 分块策略详解

资料来源：[crates/mnem-ingest/src/chunk.rs](crates/mnem-ingest/src/chunk.rs)

```rust
pub enum ChunkerKind {
    Paragraph,                  // 段落级别
    Recursive { max_tokens, overlap },
    SentenceRecursive { max_tokens, overlap },
    Session { max_messages },   // 会话消息分组
    Structural,                 // 代码结构（函数/类等）
}
```

| 策略 | 适用场景 | 关键参数 |
|------|----------|----------|
| `Paragraph` | Markdown 文档 | 无 |
| `Recursive` | 通用文本递归切分 | `max_tokens`, `overlap` |
| `SentenceRecursive` | 句子边界感知的递归切分 | `max_tokens`, `overlap` |
| `Session` | 对话/聊天记录 | `max_messages` |
| `Structural` | 源代码结构解析 | 无 |

### 代码语言支持

资料来源：[crates/mnem-ingest/src/code.rs](crates/mnem-ingest/src/code.rs)

| 语言 | 扩展名 | Tree-sitter 提取项 |
|------|--------|-------------------|
| Rust | `.rs` | function_item, struct_item, enum_item, trait_item |
| Python | `.py`, `.pyi` | function_definition, class_definition |
| JavaScript | `.js`, `.mjs`, `.cjs` | function_declaration, class_declaration |
| TypeScript | `.ts`, `.tsx`, `.mts`, `.cts` | function_declaration, class_declaration |
| Go | `.go` | function_declaration, type_declaration |
| Java | `.java` | method_declaration, class_declaration |
| C | `.c`, `.h` | function_definition, struct_specifier |
| C++ | `.cpp`, `.cc`, `.cxx`, `.hpp` | function_definition, class_specifier |
| Ruby | `.rb`, `.gemspec`, `.rake` | method_definition, class_module |
| C# | `.cs`, `.csx` | method_declaration, class_declaration |

### 提取器

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

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

提取器特性矩阵：

| 提取器 | Feature Flag | 依赖 |
|--------|--------------|------|
| `RuleExtractor` | 默认启用 | 无 |
| `KeyBertAdapter` | `keybert` | embedding 模型 |
| `LLMExtractor` | `ollama` | Ollama 服务 |

### Sidecar 集成

资料来源：[crates/mnem-ingest/src/sidecar.rs](crates/mnem-ingest/src/sidecar.rs)

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

| Sidecar | Feature Flag | 说明 |
|---------|--------------|------|
| `DoclingSidecar` | `sidecar-docling` | 调用 docling CLI |
| `UnstructuredSidecar` | `sidecar-unstructured` | 调用 unstructured-ingest CLI |

Sidecar 仅在纯 Rust 解析（`parse_pdf`）结果质量不足时使用，需手动配置触发。

## mnem-cli 命令行工具

### 定位与职责

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

### 主要命令

#### ingest 命令

资料来源：[crates/mnem-cli/src/commands/ingest.rs](crates/mnem-cli/src/commands/ingest.rs)

| 参数 | 默认值 | 说明 |
|------|--------|------|
| `--chunker` | `auto` | 分块策略：auto, session, paragraph, recursive, sentence_recursive, structural |
| `--max-tokens` | 512 | 目标分块大小（token） |
| `--overlap` | 32 | 相邻分块重叠 token 数 |
| `--recursive` | false | 递归遍历目录 |
| `--text` | - | 直接摄取内联文本 |
| `--ntype` | `Doc` | 根节点类型标签 |

### 配置系统

资料来源：[crates/mnem-cli/src/config.rs](crates/mnem-cli/src/config.rs)

配置项分层：

```text
[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](crates/mnem-cli/src/integrate.rs)

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

| 主机 | 路径 | 存储格式 |
|------|------|----------|
| ClaudeCode | `~/.claude/CLAUDE.md` | Markdown |
| GeminiCli | `~/.gemini/GEMINI.md` | Markdown |
| Cursor | `~/.cursor/rules/mnem.mdc` | Markdown |
| Continue | `~/.continue/config.json` | JSON (systemMessage) |
| Zed | `settings.json` | JSON (assistant.system_prompt) |

## mnem-http HTTP 服务

### 定位与职责

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

### 主要端点

资料来源：[crates/mnem-http/src/handlers.rs](crates/mnem-http/src/handlers.rs)

#### 分支管理

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

响应格式示例：

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

### 摄取接口

资料来源：[crates/mnem-http/src/handlers_ingest.rs](crates/mnem-http/src/handlers_ingest.rs)

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

## mnem-mcp MCP 协议集成

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

## 版本与特性矩阵

| Crate | 最小 Rust 版本 | 关键依赖 |
|-------|---------------|----------|
| mnem-core | 1.75+ | serde, cid, dag-cbor, tokio |
| mnem-ingest | 1.75+ | tree-sitter-*, pdf-extract |
| mnem-cli | 1.75+ | clap, anyhow, dirs |
| mnem-http | 1.75+ | axum, tower, tokio |
| mnem-mcp | 1.75+ | sse, tokio |

## 总结

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

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

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

---

<a id='page-knowledge-graph'></a>

## 知识图谱模型

### 相关页面

相关主题：[版本控制机制](#page-version-control), [内容寻址系统](#page-content-addressing), [存储后端](#page-storage-backend)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [crates/mnem-core/src/objects/node.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-core/src/objects/node.rs)
- [crates/mnem-core/src/objects/edge.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-core/src/objects/edge.rs)
- [crates/mnem-core/src/objects/commit.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-core/src/objects/commit.rs)
- [crates/mnem-core/src/objects/tombstone.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-core/src/objects/tombstone.rs)
- [crates/mnem-core/src/index/adjacency.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-core/src/index/adjacency.rs)
- [crates/mnem-core/src/id/link.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-core/src/id/link.rs)
- [crates/mnem-core/src/retrieve/mod.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-core/src/retrieve/mod.rs)
- [crates/mnem-core/src/lib.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-core/src/lib.rs)
</details>

# 知识图谱模型

## 概述

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

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

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

## 核心对象类型

### 节点（Node）

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

```mermaid
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
    }
```

**关键字段说明**：

| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | `NodeId` | 节点的唯一标识符（UUID） |
| `ntype` | `NodeType` | 节点类型（如 `Doc`、`Chunk`、`Entity` 等） |
| `name` | `Option<String>` | 节点的友好名称 |
| `summary` | `Option<String>` | 摘要文本，供 LLM 消费使用 |
| `props` | `BTreeMap<String, Ipld>` | 属性映射表，值为任意 DAG-CBOR 兼容类型 |
| `content` | `Option<Bytes>` | 可选的不透明载荷（如文档正文、文件内容） |
| `context_sentence` | `Option<String>` | 上下文前缀句（Anthropic 2024 Contextual Retrieval 论文应用） |

**属性设计原则**：

- 标量属性（`String`、`Integer`、`Float`、`Bool`）按 BTreeMap 顺序（字母序）输出
- 非标量属性（`Link`、`Map`、`List`、`Bytes`、`Null`）在渲染时被跳过，避免占用 token 预算
- `summary` 字段默认截断至 8192 字符，可通过 `MNEM_RENDER_SUMMARY_CAP_CHARS` 环境变量覆盖

资料来源：[crates/mnem-core/src/objects/node.rs:1-150]()

### 边（Edge）

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

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

**关键特性**：

| 特性 | 说明 |
|------|------|
| 类型安全 | `src` 和 `dst` 均为 `Link<Node>` 类型，编译期确保指向节点 |
| 关系标签 | `label` 字段描述关系类型（如 `knows`、`authored`、`part_of`） |
| 属性扩展 | `props` 可选地附加关系级别的元数据 |

**图遍历语义**：

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

资料来源：[crates/mnem-core/src/objects/edge.rs:1-80]()

### 提交（Commit）

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

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

**变更原子性**：

- 每个 Commit 包含完整的 `operations` 向量
- 操作类型包括：`AddNode`、`AddEdge`、`UpdateNode`、`DeleteNode`、`DeleteEdge`
- 支持批量原子提交，确保要么全部成功，要么全部回滚

**操作类型**：

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

资料来源：[crates/mnem-core/src/objects/commit.rs:1-120]()

### 墓碑（Tombstone）

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

```mermaid
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）

### Link<T> 泛型类型

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

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

**核心特性**：

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

**使用示例**：

```rust
// 正确的用法：编译通过
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）

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

```mermaid
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]()

## 数据流与操作语义

### 写入流程

```mermaid
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
```

### 图遍历流程

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

## 检索与渲染

### LLM 友好的节点渲染

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

**渲染格式**：

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

**渲染规则**：

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

资料来源：[crates/mnem-core/src/retrieve/mod.rs:1-100]()

## 节点类型枚举

| 节点类型 | 说明 | 典型属性 |
|----------|------|----------|
| `Doc` | 文档节点 | `mnem:source_kind`、`title`、`mime_type` |
| `Chunk` | 文本块节点 | `section_path`、`tokens_estimate` |
| `Entity` | 实体节点 | NER 提取的实体 |
| `Conversation` | 对话会话节点 | 消息序列 |
| `Ref` | 引用/指针节点 | 指向其他节点的 Link |

## 约束与不变量

**核心约束**：

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

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

## 与外部系统的集成

### 摄入管道集成

```mermaid
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]-> Doc`、`Entity -[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 代理和语义搜索提供了坚实的数据基础。

---

<a id='page-version-control'></a>

## 版本控制机制

### 相关页面

相关主题：[知识图谱模型](#page-knowledge-graph), [数据流与摄取管道](#page-data-flow)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [crates/mnem-core/src/repo/mod.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-core/src/repo/mod.rs)
- [crates/mnem-core/src/repo/transaction.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-core/src/repo/transaction.rs)
- [crates/mnem-core/src/repo/merge.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-core/src/repo/merge.rs)
- [crates/mnem-core/src/objects/operation.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-core/src/objects/operation.rs)
- [crates/mnem-cli/src/commands/commit.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-cli/src/commands/commit.rs)
- [crates/mnem-cli/src/commands/branch.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-cli/src/commands/branch.rs)
- [crates/mnem-cli/src/commands/diff.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-cli/src/commands/diff.rs)
- [crates/mnem-cli/src/commands/merge.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-cli/src/commands/merge.rs)
</details>

# 版本控制机制

## 概述

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" 概念。

```rust
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>,              // 扩展字段
}
```

**关键特性说明：**

| 字段 | 类型 | 用途 |
|------|------|------|
| `parents` | `Vec<ChangeId>` | 支持多父节点，实现 merge 操作的完整历史记录 |
| `view` | `Cid` | 指向操作后仓库状态的指针，保证内容可寻址 |
| `signature` | `Option<Signature>` | Ed25519 签名，用于操作真实性和完整性验证 |
| `time` | `u64` | 微秒级时间戳，支持高精度排序 |

资料来源：[crates/mnem-core/src/objects/operation.rs:30-70]()

### ChangeId（变更标识）

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

```rust
pub struct ChangeId(bytes::Bytes);
```

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

### View（视图）

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

- 所有 refs（分支、标签）的当前指向
- 活动节点集合
- 墓碑集（tombstones）：已删除节点的记录，用于冲突检测

资料来源：[crates/mnem-core/src/objects/mod.rs]()

## 事务机制

### Transaction 事务

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

```mermaid
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_node` | `add_node(ntype, props, content) -> Result<ChangeId>` | 添加节点到当前事务 |
| `add_edge` | `add_edge(src, dst, etype) -> Result<()>` | 添加节点间关系 |
| `commit` | `commit(author, message) -> Result<ReadonlyRepo>` | 原子提交事务 |
| `ingest` | `ingest(tx, bytes, kind) -> Result<IngestResult>` | 端到端导入流程 |

资料来源：[crates/mnem-core/src/repo/transaction.rs:60-120]()

### IngestResult 结果

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

| 字段 | 类型 | 说明 |
|------|------|------|
| `nodes_added` | `u32` | 新增节点数 |
| `chunks_created` | `u32` | 创建的文本块数 |
| `entities_extracted` | `u32` | 提取的实体数 |
| `elapsed_ms` | `u64` | 执行耗时（毫秒） |

## 分支与引用管理

### Refs 结构

mnem 使用 refs 管理命名引用：

```text
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]()

### 标签操作

标签是只读的命名引用，常用于版本标记：

```rust
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` 命令用于比较两个提交之间的变更：

```bash
mnem diff [options] [<left>] [<right>]
```

| 参数 | 说明 |
|------|------|
| `<left>` | 左侧 commit（基准），默认 HEAD |
| `<right>` | 右侧 commit（比较目标），默认工作区 |

**输出内容包括：**

- 节点变更（新增/修改/删除）
- 边的变更（关系增删）
- 元数据变更（props、content）

## 合并机制

### Merge 策略

mnem 支持三方合并（three-way merge），通过检测冲突实现：

```mermaid
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]
```

### 冲突检测

```rust
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 策略

冲突策略控制合并行为：

```rust
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` 创建新的操作记录：

```bash
mnem commit [options] [--message <msg>]
```

| 选项 | 默认值 | 说明 |
|------|--------|------|
| `--author` | 配置值 | 作者信息 |
| `--message` | 自动生成 | 提交消息 |
| `--amend` | false | 修改上一个提交（追加操作） |
| `--no-edit` | false | 跳过编辑器 |

**提交流程：**

```mermaid
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 算法：

```rust
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 commit` | commit.rs | 创建提交 |
| `mnem branch` | branch.rs | 分支管理 |
| `mnem tag` | tag.rs | 标签管理 |
| `mnem diff` | diff.rs | 差异比较 |
| `mnem merge` | merge.rs | 分支合并 |
| `mnem log` | log.rs | 历史查看 |

### 仓库配置

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

```toml
[user]
name = "Your Name"
email = "you@example.com"

[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 实现）

---

## 延伸阅读

- [存储引擎](./storage-engine.md) - Blockstore 接口与实现
- [检索系统](./retrieval.md) - 基于版本化索引的语义搜索
- [导入管道](./ingestion.md) - 从多源文档到版本化节点

---

<a id='page-content-addressing'></a>

## 内容寻址系统

### 相关页面

相关主题：[知识图谱模型](#page-knowledge-graph), [存储后端](#page-storage-backend)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [crates/mnem-core/src/id/cid.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-core/src/id/cid.rs)
- [crates/mnem-core/src/id/multihash.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-core/src/id/multihash.rs)
- [crates/mnem-core/src/id/link.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-core/src/id/link.rs)
- [crates/mnem-core/src/codec/dagcbor.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-core/src/codec/dagcbor.rs)
- [crates/mnem-core/src/codec/dagjson.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-core/src/codec/dagjson.rs)
- [crates/mnem-core/src/objects/node.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-core/src/objects/node.rs)
- [crates/mnem-core/src/objects/commit.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-core/src/objects/commit.rs)
- [crates/mnem-core/src/retrieve/mod.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-core/src/retrieve/mod.rs)
</details>

# 内容寻址系统

## 概述

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

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

## 核心架构

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

```mermaid
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 格式，支持多种哈希算法。

```rust
// 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-256 | 0x12 | 32 字节 | 默认、安全敏感场景 |
| Blake3 | 0xb201 | 32 字节 | 高性能需求 |
| Keccak-256 | 0x1b | 32 字节 | 以太坊兼容 |

资料来源：[crates/mnem-core/src/id/multihash.rs:1-80]()

## Link 类型系统

### 幽灵类型化链接

mnem 引入了 `Link<T>` 类型，这是一种phantom-typed（幽灵类型化）的链接类型，用于在编译期确保类型安全：

```rust
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 特有类型

```mermaid
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-JSON | DAG-CBOR |
|------|----------|----------|
| 用途 | 调试、导出 | 实际存储 |
| 可读性 | 人类可读 | 二进制 |
| 效率 | 低 | 高 |
| 规范性 | 非严格 | 严格确定性 |

资料来源：[crates/mnem-core/src/codec/dagjson.rs:1-80]()

## 对象模型

### Node 节点

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

```mermaid
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/>上下文句子"]
```

#### 字段语义

| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | `NodeId` | 节点的唯一标识符 |
| `ntype` | `String` | 节点类型标签（如 "Fact", "Person"） |
| `summary` | `Option<String>` | LLM 可读的摘要文本 |
| `props` | `BTreeMap<String, Ipld>` | 结构化属性，可包含 `Link` |
| `content` | `Option<Bytes>` | 原始二进制负载 |
| `context_sentence` | `Option<String>` | 上下文定位前缀 |

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

### Edge 边

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

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

### Commit 提交

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

```mermaid
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]()

## 内容寻址工作流

### 写入流程

```mermaid
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: 存储所有子节点
```

### 读取流程

```mermaid
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` 定义了支持的源类型：

| 源类型 | 说明 | 默认分块策略 |
|--------|------|--------------|
| `Markdown` | Markdown 文档 | Paragraph |
| `Text` | 纯文本 | SentenceRecursive (256 tokens, 32 overlap) |
| `Pdf` | PDF 文档 | 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 消费的文本格式。渲染格式如下：

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

渲染规则：

- `ntype` 和 `id` 始终存在
- `context` 在 `summary` 之前（遵循 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 定义存储接口，支持多种实现：

```rust
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 能够可靠地管理知识图谱的长期演进，同时保持高效的内容查询和去重能力。

---

<a id='page-storage-backend'></a>

## 存储后端

### 相关页面

相关主题：[数据流与摄取管道](#page-data-flow), [知识图谱模型](#page-knowledge-graph)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [crates/mnem-core/src/store/blockstore.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-core/src/store/blockstore.rs)
- [crates/mnem-core/src/store/mod.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-core/src/store/mod.rs)
- [crates/mnem-core/src/store/op_heads.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-core/src/store/op_heads.rs)
- [crates/mnem-backend-redb/src/blockstore.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-backend-redb/src/blockstore.rs)
- [crates/mnem-backend-redb/src/lib.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-backend-redb/src/lib.rs)
</details>

# 存储后端

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

## 架构概览

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

```mermaid
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 操作都能正常工作。

### 核心方法

| 方法 | 签名 | 功能描述 |
|------|------|----------|
| `get` | `fn get(&self, cid: &Cid) -> Result<Option<Vec<u8>>, Error>` | 根据 CID 检索数据块，返回 `None` 表示不存在 |
| `put` | `fn put(&self, block: &[u8]) -> Result<Cid, Error>` | 存储数据块，返回其 CID |
| `has` | `fn 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_heads` | `fn get_op_heads(&self) -> Result<Vec<OperationId>, Error>` | 获取当前所有操作头 |
| `put_op_heads` | `fn 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>>` 实现的内存块存储：

```mermaid
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](https://github.com/cberner/redb) 的持久化存储实现。redb 是一个纯 Rust 编写的嵌入式事务型 KV 数据库，具有以下特性：

### 特性

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

资料来源：[crates/mnem-backend-redb/src/lib.rs:1-30]()

### 数据库结构

```mermaid
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_size` | `u64` | 4GB | 数据库文件最大大小 |
| `read_transactions` | `bool` | true | 是否启用并发只读事务 |

## 后端选择指南

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

## 与上层模块的关系

```mermaid
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
```

`ReadonlyRepo` 和 `Transaction` 通过组合持有 `Box<dyn Blockstore>` 和 `Box<dyn OpHeadsStore>`，实现了存储后端的运行时多态。

## 错误处理

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

| 错误类型 | 触发条件 |
|----------|----------|
| `Error::BlockNotFound` | `get` 操作的 CID 不存在 |
| `Error::Encoding` | DAG-CBOR 编码/解码失败 |
| `Error::Store` | 后端存储错误（如磁盘满、IO 错误） |

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

## 扩展新的后端

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

1. **实现 Blockstore trait**：提供 `get`、`put`、`has` 方法
2. **实现 OpHeadsStore trait**：提供 `get_op_heads`、`put_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 的内存安全保证
- 持久化数据的可靠性完全由后端实现负责

---

<a id='page-data-flow'></a>

## 数据流与摄取管道

### 相关页面

相关主题：[存储后端](#page-storage-backend), [混合检索系统](#page-hybrid-retrieval)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [crates/mnem-ingest/src/lib.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-ingest/src/lib.rs)
- [crates/mnem-ingest/src/pipeline.rs](https://github.com/Uranid/mnem/blob/main/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)
- [crates/mnem-ingest/src/pdf.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-ingest/src/pdf.rs)
- [crates/mnem-ingest/src/md.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-ingest/src/md.rs)
- [crates/mnem-ingest/src/code.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-ingest/src/code.rs)
- [crates/mnem-core/src/prolly/chunker.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-core/src/prolly/chunker.rs)
- [crates/mnem-cli/src/commands/ingest.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-cli/src/commands/ingest.rs)
- [crates/mnem-ingest/src/types.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-ingest/src/types.rs)
- [crates/mnem-ingest/src/extract.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-ingest/src/extract.rs)
</details>

# 数据流与摄取管道

## 概述

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

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

```mermaid
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()` |
| `md` | Markdown 解析 | `parse_markdown()` |
| `pdf` | PDF 文本提取 | `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`, `.markdown` | `Markdown` | Paragraph |
| `.txt` | `Text` | SentenceRecursive (256 tokens, 32 overlap) |
| `.pdf` | `Pdf` | SentenceRecursive (512 tokens, 64 overlap) |
| `.json`, `.jsonl` | `Conversation` | Session (max_messages: 10) |
| `.rs`, `.py`, `.js` 等 | `Code(lang)` | Structural |

资料来源：[crates/mnem-ingest/src/types.rs:58-75]()

### Section 结构

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

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

### Chunk 结构

`Chunk` 是最终存储的基本单元：

```rust
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()` 函数根据源类型返回最佳分块策略：

```rust
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 核心逻辑

```mermaid
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()` 方法：

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

**参数说明：**

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

**返回值：**

| 字段 | 类型 | 说明 |
|------|------|------|
| `counts` | `Counts` | 节点数量统计 |
| `elapsed` | `Duration` | 执行耗时 |
| `commit_cid` | `Option<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 扩展**：调用外部 `docling` 或 `unstructured-ingest` CLI

```rust
#[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 格式：

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

## 实体提取系统

### Extractor Trait

```rust
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`（默认：大写短语启发式）
- **关系检测**：基于动词窗口正则表达式

```rust
r"(?i)\b(?:joined|founded|acquired|owns|hired|married|...)
```

### 可选扩展

| 扩展 | 特性 | Cargo Feature |
|------|------|----------------|
| `KeyBertAdapter` | 统计 NER + embedding | `keybert` |
| `OllamaExtractor` | LLM 驱动 schema 约束 NER | `ollama` |

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

## CLI 接口

### 基本用法

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

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

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

### 命令行参数

| 参数 | 默认值 | 说明 |
|------|--------|------|
| `--chunker` | `auto` | 策略：`auto|paragraph|recursive|session|structural` |
| `--max-tokens` | 512 | 目标 token 数 |
| `--overlap` | 32 | 重叠 token 数 |
| `--recursive` | false | 递归目录 |
| `--ntype` | `Doc` | 根节点标签 |
| `--extractor` | `none` | 提取器：`none|keybert` |
| `--ner` | `rule` | NER 提供者：`rule|none` |

资料来源：[crates/mnem-cli/src/commands/ingest.rs:50-80]()

## HTTP API

### POST /v1/ingest

**请求体：**

| 字段 | 类型 | 说明 |
|------|------|------|
| `file` | multipart | 要摄入的文件 |
| `chunker` | `Option<String>` | `auto\|paragraph\|recursive` |
| `max_tokens` | `Option<u32>` | 目标 token |
| `overlap` | `Option<u32>` | 重叠 token |
| `author` | `String` | 提交作者（必需） |
| `message` | `Option<String>` | 提交信息 |
| `extractor` | `Option<String>` | `none\|keybert` |
| `ner_provider` | `Option<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` | 分块后的内容单元 |
| 实体节点 | 实体类型 | 提取的命名实体 |

每个节点包含：

```rust
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 }`。

---

<a id='page-hybrid-retrieval'></a>

## 混合检索系统

### 相关页面

相关主题：[数据流与摄取管道](#page-data-flow)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [crates/mnem-core/src/retrieve/mod.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-core/src/retrieve/mod.rs)
- [crates/mnem-core/src/retrieve/retriever.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-core/src/retrieve/retriever.rs)
- [crates/mnem-core/src/retrieve/fusion.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-core/src/retrieve/fusion.rs)
- [crates/mnem-core/src/index/mod.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-core/src/index/mod.rs)
- [crates/mnem-core/src/index/vector.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-core/src/index/vector.rs)
- [crates/mnem-core/src/index/sparse.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-core/src/index/sparse.rs)
- [crates/mnem-ann/src/hnsw.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-ann/src/hnsw.rs)
- [crates/mnem-cli/src/config.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-cli/src/config.rs)
- [crates/mnem-ingest/src/chunk.rs](https://github.com/Uranid/mnem/blob/main/crates/mnem-ingest/src/chunk.rs)
</details>

# 混合检索系统

## 概述

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

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

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

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

## 检索流程架构

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

```mermaid
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 采用基于分数的加权融合策略。

### 融合算法

```mermaid
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_env` | API 密钥环境变量 |

支持的 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 风格的确定性渲染格式。

### 渲染格式规范

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

**渲染规则**：

- `ntype` 和 `id` 始终输出
- `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]()

## 配置参考

### 检索配置示例

```toml
[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 |

## 与其他模块的交互

### 数据依赖

```mermaid
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 类型 | 参数 |
|--------|--------------|------|
| Markdown | Paragraph | - |
| Text | SentenceRecursive | max_tokens: 256, overlap: 32 |
| PDF | SentenceRecursive | max_tokens: 512, overlap: 64 |
| Conversation | Session | max_messages: 10 |
| Code | Structural | - |

资料来源：[crates/mnem-ingest/src/chunk.rs]()

## 最佳实践

### 1. 混合检索配置建议

对于通用场景，推荐使用默认配置：

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

### 2. 精确查询优化

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

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

### 3. 图感知查询

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

```toml
[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 效率之间取得最佳平衡。

---

---

## Doramagic 踩坑日志

项目：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.

## 3. 维护坑 · 来源证据：[bug] Broken docs links: SPEC.md, ROADMAP.md, and Architecture page

- 严重度：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

<!-- canonical_name: Uranid/mnem; human_manual_source: deepwiki_human_wiki -->
