# https://github.com/kilhubprojects/memory-mesh 项目说明书

生成时间：2026-05-15 00:17:37 UTC

## 目录

- [MemoryMesh 简介](#page-introduction)
- [快速入门指南](#page-quickstart)
- [系统架构](#page-architecture)
- [索引管道](#page-indexing-pipeline)
- [文件解析器](#page-parsers)
- [文本分块策略](#page-chunkers)
- [搜索引擎](#page-search-engine)
- [结果重排序](#page-reranking)
- [数据连接器](#page-connectors)
- [MCP 工具参考](#page-mcp-tools)

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

## MemoryMesh 简介

### 相关页面

相关主题：[快速入门指南](#page-quickstart), [系统架构](#page-architecture)

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

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

- [src/memorymesh/server/dashboard.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/server/dashboard.py)
- [src/memorymesh/connectors/roam_connector.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/connectors/roam_connector.py)
- [src/memorymesh/connectors/logseq_connector.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/connectors/logseq_connector.py)
- [src/memorymesh/parsing/obsidian_parser.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/parsing/obsidian_parser.py)
- [src/memorymesh/parsing/notion_parser.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/parsing/notion_parser.py)
- [src/memorymesh/connectors/confluence_connector.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/connectors/confluence_connector.py)
- [src/memorymesh/chunking/markdown.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/chunking/markdown.py)
- [src/memorymesh/chunking/code.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/chunking/code.py)
- [src/memorymesh/storage/file_repository.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/storage/file_repository.py)
- [src/memorymesh/core/models/config.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/core/models/config.py)
- [src/memorymesh/core/models/chunk.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/core/models/chunk.py)
- [src/memorymesh/server/rest_api.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/server/rest_api.py)
- [CHANGELOG.md](https://github.com/kilhubprojects/memory-mesh/blob/main/CHANGELOG.md)
</details>

# MemoryMesh 简介

MemoryMesh 是一个模块化的本地知识检索与记忆管理框架，专为 AI 智能体（Agent）设计。它通过统一的多源连接器体系、层级化记忆管理、增量索引管道和灵活的 API 接口，使 AI 能够持久化访问和检索用户的个人知识库，同时保持所有数据的本地化存储。

## 系统架构

MemoryMesh 采用分层架构，从底向上依次为存储层、索引层、检索层、连接器层和服务层。各层职责清晰，通过明确定义的接口进行通信。

```mermaid
graph TD
    subgraph 服务层
        A[REST API]
        B[MCP 工具]
        C[Web Dashboard]
        D[Health Server]
    end
    
    subgraph 连接器层
        E[Roam Connector]
        F[Logseq Connector]
        G[Notion Parser]
        H[Obsidian Parser]
        I[Confluence Connector]
    end
    
    subgraph 索引与检索层
        J[FileIndexer]
        K[SearchEngine]
        L[QueryExpander]
        M[Reranker]
    end
    
    subgraph 记忆管理层
        N[TieredMemoryManager]
        O[EpisodicMemory]
        P[EntityExtractor]
    end
    
    subgraph 存储层
        Q[MetadataStore SQLite]
        R[EmbeddingProvider]
        S[VectorStore]
    end
    
    A --> N
    B --> N
    C --> Q
    D --> Q
    E --> J
    F --> J
    G --> J
    H --> J
    I --> J
    J --> Q
    J --> R
    R --> S
    K --> S
    K --> L
    L --> M
    N --> Q
    O --> Q
    P --> Q
```

资料来源：[src/memorymesh/server/dashboard.py:1-50]()

## 核心模块

### 连接器体系

MemoryMesh 通过统一的连接器接口对接多种知识管理工具，实现文档的自动采集与解析。

| 连接器 | 数据源 | 解析格式 | 关键特性 |
|--------|--------|----------|----------|
| RoamConnector | Roam Research JSON 导出 | 递归块扁平化 | WikiLink 提取、日期过滤 |
| LogseqConnector | Logseq 图谱目录 | Markdown | 块引用转换、属性提取 |
| NotionParser | Notion HTML 导出 | SAX 解析 | UUID 提取、数据库属性 |
| ObsidianParser | Obsidian 库 | Markdown | YAML frontmatter、backlink |
| ConfluenceConnector | Confluence Cloud REST API | HTML | 空间过滤、偏移分页 |

资料来源：[src/memorymesh/connectors/roam_connector.py:1-30]()

#### Roam Research 连接器

RoamConnector 解析 Roam Research 的 JSON 导出文件，将嵌套的块树结构扁平化为纯文本。它会依次应用正则模式去除 Roam 特有语法：

- `{{[[...]]}}` 模板引用
- `[[...]]` 页面引用
- `#[[...]]` / `#tag` 标签语法

```python
_ROAM_PATTERNS: list[re.Pattern[str]] = [
    re.compile(r"\{\{(\[\[.*?\]\])?\}\}"),
    re.compile(r"\[\[([^\]]+)\]\]"),
    re.compile(r"#\[\[([^\]]+)\]\]"),
]
```

资料来源：[src/memorymesh/connectors/roam_connector.py:30-35]()

#### Logseq 连接器

LogseqConnector 读取图谱目录下的 `pages/` 和 `journals/` 子目录，处理以下 Logseq 特有语法：

| 语法模式 | 转换结果 |
|----------|----------|
| `((uuid))` 块引用 | `[block]` |
| `{{embed [[Page]]}}` 嵌入 | `[embed: Page]` |
| `{{query ...}}` 查询块 | 完全移除 |
| `key:: value` 属性行 | 提取至元数据 |

```python
_RE_BLOCK_REF = re.compile(r"\(\([0-9a-f-]{36}\)\)")
_RE_EMBED = re.compile(r"\{\{embed\s+\[\[([^\]]+)\]\]\}\}")
_RE_QUERY = re.compile(r"\{\{query[^}]*\}\}")
```

资料来源：[src/memorymesh/connectors/logseq_connector.py:35-40]()

#### Notion 解析器

NotionParser 基于标准库 `html.parser` 实现 SAX 风格的解析，无需外部依赖。它从导出的 HTML 文件中提取：

- `<title>` 标签内容
- `<h1>` 可见页面标题
- `data-type` 属性（数据库属性类型）
- 可见正文文本（去除标记）

文件名中嵌入的 UUID 用于唯一标识页面：`Page Title a1b2c3...html`

资料来源：[src/memorymesh/parsing/notion_parser.py:1-40]()

#### Obsidian 解析器

ObsidianParser 扩展标准 Markdown 解析，增加以下能力：

- **YAML Frontmatter 提取**：解析 `---` 分隔符之间的元数据
- **WikiLink Backlink 提取**：通过 `[[link]]` 和 `[[link|alias]]` 模式
- **标签解析**：支持 `tags:` 字段和内联 `#tag` 语法

```python
_FRONTMATTER_RE = re.compile(
    r"^---\r?\n(.*?)\r?\n(?:---|\.\.\.)(?:\r?\n|$)",
    re.DOTALL,
)
_WIKILINK_RE = re.compile(r"(?<!!)\[\[([^\[\]|#]+?)(?:\|[^\[\]]*?)?\]\]")
```

资料来源：[src/memorymesh/parsing/obsidian_parser.py:15-25]()

#### Confluence 连接器

ConfluenceConnector 通过 REST API 与 Confluence Cloud 交互，支持：

- **偏移分页**：通过 `start` / `limit` 参数遍历所有页面
- **空间过滤**：通过 `space_keys` 参数限定特定空间
- **HTML 净化**：将 `storage` 格式页面体转换为纯文本
- **HTTP Basic 认证**：使用 `email:api_token` 格式

```python
connector = ConfluenceConnector(ConfluenceConfig(
    base_url="https://myorg.atlassian.net",
    email="me@example.com",
    api_token=SecretStr("my-token"),
    space_keys=["ENG", "DOCS"],
    days_past=90,
))
```

资料来源：[src/memorymesh/connectors/confluence_connector.py:1-50]()

### 文档分块策略

MemoryMesh 实现了多种分块器（Chunker），将解析后的文档拆分为可索引的语义单元。

| 分块器 | 适用场景 | 特性 |
|--------|----------|------|
| RecursiveChunker | 通用文本 | 递归字符级分割，支持 overlap |
| MarkdownChunker | Markdown 文档 | 基于 ATX 标题分割 |
| CodeChunker | 源代码文件 | 基于 AST 节点分割 |

```mermaid
graph LR
    A[ParsedDocument] --> B{Markdown?}
    B -->|是| C[MarkdownChunker]
    B -->|否| D{Code?}
    D -->|是| E[CodeChunker]
    D -->|否| F[RecursiveChunker]
    
    C --> G[Chunk 列表]
    E --> G
    F --> G
```

资料来源：[src/memorymesh/chunking/markdown.py:1-20]()

#### Markdown 分块器

MarkdownChunker 按 ATX 标题（`#`, `##`, …）分割文档，每个分块包含一个章节：标题行及其下方正文。超过 `max_chunk_size` 的章节由递归分块器进一步分割。

`heading_path` 元数据字段记录完整的祖先标题栈，便于搜索命中时精确定位文档位置。

资料来源：[src/memorymesh/chunking/markdown.py:15-40]()

#### 代码分块器

CodeChunker 利用 `tree-sitter` 解析 AST，提取函数、类等节点。每个节点生成一个分块，附带 `function_name`、`class_name` 和 `language` 元数据。未识别的顶级代码作为残差分块处理。

```python
chunks.append(
    Chunk(
        path=doc.path,
        chunk_index=idx,
        text=sub.text,
        metadata=ChunkMetadata(
            language=lang_name,
            function_name=func_name,
            class_name=class_name,
        ),
    )
)
```

资料来源：[src/memorymesh/chunking/code.py:50-70]()

### 层级化记忆管理

MemoryMesh 的 `TieredMemoryManager` 将记忆划分为三个温度层级，实现类似于人类记忆的遗忘曲线管理。

| 层级 | 描述 | 存储位置 |
|------|------|----------|
| Hot | 最近访问或手动固定的内容 | RAM 缓存 |
| Warm | 正常索引的内容（默认） | 向量数据库 |
| Cold | 罕见访问的内容 | 压缩存储，衰减评分 |

```python
class MemoryTier(StrEnum):
    hot = "hot"
    warm = "warm"
    cold = "cold"
```

资料来源：[src/memorymesh/core/models/config.py:40-50]()

#### 记忆分层工作流

```mermaid
graph TD
    A[新索引内容] --> B{Hot 层}
    B --> C[频繁访问?]
    C -->|是| D[保持在 Hot]
    C -->|否| E[移至 Warm]
    E --> F{遗忘策略}
    F --> G{访问频率低}
    G -->|是| H[移至 Cold]
    G -->|否| I[保持在 Warm]
    H --> J[评分衰减]
    J --> K{超过阈值?}
    K -->|是| L[遗忘 Chunk]
```

资料来源：[src/memorymesh/server/rest_api.py:1-30]()

### 实体提取

当配置 `memory.entity_extraction.enabled: true` 且 Ollama 运行中时，`FileIndexer` 会在每个文件索引后自动提取实体并持久化。

实体记录包含：

| 字段 | 类型 | 说明 |
|------|------|------|
| name | string | 实体名称 |
| entity_type | string | 实体类型（如人物、地点、组织） |
| mention_count | int | 提及次数 |

资料来源：[src/memorymesh/server/dashboard.py:80-100]()

### 情景记忆

EpisodicMemory 记录索引过程中的关键事件，用于时间线可视化和审计。

事件记录包含：

| 字段 | 类型 | 说明 |
|------|------|------|
| timestamp | float | Unix 时间戳 |
| event_type | string | 事件类型 |
| source | string | 来源标识 |
| chunk_ids | list[str] | 关联的分块 ID 列表 |

```python
events = ctx.metadata_store.list_episodic_events(since=since_ts, limit=100)
```

资料来源：[src/memorymesh/server/dashboard.py:60-75]()

## 数据模型

### Chunk 模型

Chunk 是 MemoryMesh 的核心数据单元，代表文档的一个可索引片段。

```python
class Chunk(BaseModel):
    path: Path                    # 文档路径
    chunk_index: int              # 分块序号
    text: str                     # 分块文本内容
    start_char: int               # 起始字符偏移
    end_char: int                 # 结束字符偏移
    file_type: str = ""           # 文件类型扩展名
    mtime: float = 0.0            # 文件修改时间
    source_root: str = ""         # 源根目录路径
    metadata: ChunkMetadata       # 分块元数据
    
    @property
    def id(self) -> str:
        return f"{self.path}:{self.chunk_index}"
```

资料来源：[src/memorymesh/core/models/chunk.py:30-50]()

### ChunkMetadata 模型

```python
class ChunkMetadata(ConfigDict):
    heading_path: str = ""         # 完整标题路径（Markdown）
    language: str = ""            # 编程语言（代码块）
    function_name: str = ""       # 函数名（代码块）
    class_name: str = ""          # 类名（代码块）
    backlinks: list[str] = []     # 反向链接列表
    chunk_type: str = ""          # 分块类型标识
```

资料来源：[src/memorymesh/core/models/chunk.py:15-25]()

### FileRecord 模型

FileRecord 记录每个被索引文件的状态信息。

| 字段 | 类型 | 说明 |
|------|------|------|
| path | string | 绝对路径（主键） |
| source_name | string | 所属源名称 |
| sha256 | string | 内容 SHA-256 哈希 |
| mtime | float | 文件修改时间 |
| size_bytes | int | 文件大小 |
| file_type | string | 标准化扩展名 |
| n_chunks | int | 生成的分块数量 |
| status | string | 状态（indexed/parse_error/unsupported/deleted/pending_reindex） |
| error_message | string | 最后一次失败描述 |
| indexed_at | float | 最后索引时间戳 |
| embedding_model_id | string | 使用的嵌入模型 ID |

资料来源：[src/memorymesh/storage/file_repository.py:15-35]()

## 服务端组件

### REST API

MemoryMesh 提供基于 FastAPI 的 RESTful API，支持以下核心操作：

| 端点 | 方法 | 说明 | 权限要求 |
|------|------|------|----------|
| `/api/search` | GET | 搜索记忆内容 | read |
| `/api/sources` | GET | 列出所有数据源 | read |
| `/api/chunks` | GET | 获取分块详情 | read |
| `/api/memory/promote` | POST | 提升分块至热层 | write |
| `/api/memory/forget` | POST | 遗忘分块 | delete |

#### 遗忘操作

遗忘操作将分块降至冷层，使其相关性评分随时间衰减，而非立即删除。

```python
Request body: {"chunk_id": "<path>:<chunk_index>"}

@app.post("/api/memory/forget")
async def forget_chunk(body: dict) -> dict:
    app_ctx.metadata_store.forget_chunk(chunk_id)
    return {"status": "forgotten", "chunk_id": chunk_id}
```

资料来源：[src/memorymesh/server/rest_api.py:20-40]()

### Web Dashboard

Dashboard 是基于 FastAPI + HTMX 的单页应用，运行于 `:8767` 端口。

| 页面 | 路由 | 功能 |
|------|------|------|
| 数据源 | `/` | 列出所有配置的源目录及文件统计 |
| 搜索 | `/search` | 全文搜索界面，支持稀疏/密集模式切换 |
| 记忆层级 | `/tiers` | 热/温/冷分块分布统计 |
| 实体 | `/entities` | 提取的实体列表及类型 |
| 时间线 | `/timeline` | 情景记忆事件时间轴 |
| 知识图谱 | `/graph-ui` | 可视化节点关系图 |

```python
@app.get("/tiers", response_class=HTMLResponse)
async def tiers_page() -> str:
    counts: dict[str, int] = {}
    for tier in MemoryTier:
        entries = ctx.metadata_store.list_chunks_by_tier(tier, limit=None)
        counts[tier.value] = len(entries)
    # ...
```

资料来源：[src/memorymesh/server/dashboard.py:100-130]()

### Health Server

Health Server 提供系统健康检查端点，运行于 `:8766` 端口，在守护进程启动时自动启用，退出时干净关闭。

资料来源：[CHANGELOG.md:20-25]()

## 搜索架构

MemoryMesh 的搜索管道采用多阶段检索与重排序架构。

```mermaid
graph LR
    A[用户查询] --> B[QueryExpander]
    B --> C[词汇变体生成]
    C --> D[并行检索]
    D --> E[密集检索]
    D --> F[稀疏检索]
    E --> G[FuseResults]
    F --> G
    G --> H[SearchReranker]
    H --> I[Top-K 结果]
```

| 组件 | 说明 | 配置项 |
|------|------|--------|
| QueryExpander | 生成查询词汇变体 | `n_lexical_variants` |
| SearchReranker | 重排序候选结果 | `top_k_before_rerank` |
| SentenceTransformers | 密集向量检索 | `model_id` |

### 搜索配置

| 参数 | 默认值 | 说明 |
|------|--------|------|
| `top_k_before_rerank` | 35 | 重排序前保留的候选数量 |
| `n_lexical_variants` | 1 | 查询扩展词汇变体数量 |

资料来源：[CHANGELOG.md:30-40]()

## 配置体系

MemoryMesh 通过 YAML 配置文件管理所有设置。

### 核心配置结构

```yaml
sources:
  - name: "my-vault"
    path: "~/Obsidian/vault"
    recursive: true
    extensions: [".md", ".py"]

memory:
  tiers:
    enabled: true
  forgetting:
    enabled: true
  entity_extraction:
    enabled: true
  episodic:
    enabled: true

embeddings:
  provider: "sentence_transformers"
  model_id: "all-MiniLM-L6-v2"

search:
  reranker:
    top_k_before_rerank: 35
  query_expansion:
    n_lexical_variants: 1
```

资料来源：[src/memorymesh/core/models/config.py:50-80]()

### 代理权限

```python
class AgentPermission(StrEnum):
    read = "read"
    read_index = "read+index"
    read_index_delete = "read+index+delete"
    admin = "admin"
```

资料来源：[src/memorymesh/core/models/config.py:55-65]()

## 索引流程

```mermaid
sequenceDiagram
    participant C as Connector
    participant P as Parser
    participant CK as Chunker
    participant I as FileIndexer
    participant M as MetadataStore
    participant E as EmbeddingProvider
    
    C->>P: fetch_documents()
    P->>P: parse(path)
    P-->>I: ParsedDocument
    I->>CK: chunk(doc)
    CK-->>I: List[Chunk]
    I->>E: embed(chunks)
    E-->>I: List[ChunkWithEmbedding]
    I->>M: upsert_file()
    I->>M: upsert_chunks()
    I->>M: add_episodic_event()
```

### 索引管道关键步骤

1. **连接器采集**：从各数据源获取原始文档
2. **解析转换**：将原始格式转换为 `ParsedDocument`
3. **分块处理**：按策略分割为语义单元
4. **向量化**：通过 EmbeddingProvider 生成向量表示
5. **持久化**：写入 SQLite 元数据存储和向量数据库
6. **事件记录**：写入情景记忆事件

## 版本演进

MemoryMesh 采用语义化版本控制，主要版本功能如下：

| 版本 | 日期 | 核心特性 |
|------|------|----------|
| 0.5.0 | 2026-05-03 | MVP 基线：SQLite、CLI、句子嵌入 |
| 0.6.0 | 2026-05-10 | 层级记忆、Dashboard、授权体系、实体提取、CLIP 图像索引 |

### 0.6.0 新增功能

- **TieredMemoryManager**：层级化记忆管理，替代原有的简单存储
- **DashboardServer**：FastAPI + HTMX Web 界面
- **Auth Guard**：MCP 工具统一授权检查
- **Entity Extraction**：Ollama 驱动的实体识别
- **Health Server**：健康检查端点

资料来源：[CHANGELOG.md:1-50]()

## 技术栈

| 层级 | 技术选型 |
|------|----------|
| 核心框架 | Python 3.11+ |
| Web 框架 | FastAPI + HTMX |
| 数据库 | SQLite3 |
| 向量检索 | Sentence-Transformers |
| CLI | Click |
| 配置 | Pydantic + YAML |
| 日志 | Loguru |
| 代码解析 | tree-sitter |

资料来源：[src/memorymesh/server/dashboard.py:1-20]()

## 快速入门

### 安装依赖

```bash
uv add memorymesh
uv add 'fastapi[standard]'  # 可选：启用 Dashboard
```

### 配置数据源

```yaml
# config.yaml
sources:
  - name: "obsidian-vault"
    path: "~/Obsidian/my-vault"
    type: "obsidian"

memory:
  tiers:
    enabled: true
  entity_extraction:
    enabled: true
```

### 启动服务

```bash
memorymesh start  # 启动守护进程
memorymesh index  # 执行索引任务
```

### 访问 Dashboard

服务启动后访问 `http://localhost:8767` 查看：

- 所有数据源的索引状态
- 全文搜索界面
- 记忆层级分布
- 提取的实体列表
- 情景记忆时间线

---

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

## 快速入门指南

### 相关页面

相关主题：[MemoryMesh 简介](#page-introduction)

```json
{
  "response": "# 快速入门指南\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [config.example.yaml](https://github.com/kilhubprojects/memory-mesh/blob/main/config.example.yaml)\n- [src/memorymesh/cli.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/cli.py)\n- [src/memorymesh/config.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/config.py)\n- [src/memorymesh/core/models/config.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/core/models/config.py)\n- [src/memorymesh/connectors/logseq_connector.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/connectors/logseq_connector.py)\n- [src/memorymesh/connectors/confluence_connector.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/connectors/confluence_connector.py)\n- [src/memorymesh/server/dashboard.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/server/dashboard.py)\n- [CHANGELOG.md](https://github.com/kilhubprojects/memory-mesh/blob/main/CHANGELOG.md)\n\n</details>\n\n# 快速入门指南\n\n## 概述\n\nMemoryMesh 是一个本地优先的个人知识图谱和记忆管理系统，支持从多种数据源（Obsidian、Logseq、Notion、Confluence、Roam Research 等）索引文档，并通过 Ollama 提供的本地 LLM 实现语义搜索、实体提取和记忆分层管理。\n\n本指南将帮助你在几分钟内完成安装、配置和首次索引操作。\n\n## 系统要求\n\n| 组件 | 最低要求 | 推荐配置 |\n|------|----------|----------|\n| Python | 3.10+ | 3.11+ |\n| 内存 | 4 GB | 8 GB+ |\n| 磁盘 | 1 GB 可用空间 | SSD |\n| Ollama | 可选（用于 AI 功能） | 最新版 |\n\n## 安装\n\n### 方式一：pip 安装\n\n```bash\npip install memorymesh\n```\n\n### 方式二：从源码安装\n\n```bash\ngit clone https://github.com/kilhubprojects/memory-mesh.git\ncd memory-mesh\npip install -e .\n```\n\n### 安装可选依赖\n\n```bash\n# 支持 FastAPI 仪表盘\npip install \"fastapi[standard]\"\n\n# 支持 Ollama 集成\npip install ollama\n\n# 支持邮件解析\npip install mailbox\n\n# 支持日历解析\npip install icalendar>=5.0\n```\n\n## 配置文件\n\nMemoryMesh 支持从 YAML 配置文件加载所有设置。默认搜索路径按以下优先级：\n\n1. `./config.yaml`（当前工作目录）\n2. `~/.memorymesh/config.yaml`\n\n### 基础配置示例\n\n```yaml\n# config.example.yaml\nsources:\n  - name: my-notes\n    type: obsidian\n    path: ~/Documents/Obsidian\n    enabled: true\n\nembeddings:\n  model: sentence-transformers/all-MiniLM-L6-v2\n\nserver:\n  host: 0.0.0.0\n  port: 8765\n\nollama:\n  enabled: true\n  base_url: http://localhost:11434\n  model: llama3.2\n```\n\n### 数据源配置详解\n\n| 参数 | 类型 | 默认值 | 说明 |\n|------|------|--------|------|\n| `name` | string | 必填 | 数据源唯一标识名称 |\n| `type` | string | 必填 | 数据源类型：`obsidian`、`logseq`、`notion`、`confluence`、`roam` 等 |\n| `path` | string | 必填 | 本地路径或远程 URL |\n| `enabled` | bool | true | 是否启用该数据源 |\n| `ignore_patterns` | list | 空 | 忽略的文件匹配模式 |\n\n资料来源：[src/memorymesh/core/models/config.py:1-80]()\n\n### 完整配置结构\n\n```yaml\nmemorymesh:\n  sources: []                    # 数据源列表\n  global_ignore: []              # 全局忽略模式\n  embeddings:                    # 向量化配置\n    model: ...\n    device: auto\n  chunking:                      # 分块配置\n    max_chunk_size: 800\n    chunk_overlap: 50\n  ocr:\n    enabled: false\n  search:\n    top_k: 10\n  storage:\n    db_path: ~/.memorymesh/memory.db\n  server:\n    transport: uvicorn\n    host: 0.0.0.0\n    port: 8765\n  ollama:\n    enabled: false\n    base_url: http://localhost:11434\n    model: llama3.2\n  memory:\n    episodic:\n      enabled: true\n    tiers:\n      hot_days: 7\n      warm_days: 30\n      cold_days: 90\n    entity_extraction:\n      enabled: false\n```\n\n资料来源：[src/memorymesh/config.py:1-100]()\n\n## CLI 命令行工具\n\n### 启动守护进程\n\n```bash\nmemorymesh start\n```\n\n守护进程将：\n\n- 启动 API 服务器（默认端口 8765）\n- 启动健康检查服务器（默认端口 8766）\n- 启动 Web 仪表盘服务器（默认端口 8767）\n- 监控文件系统变更（如果 watcher 启用）\n\n### 索引命令\n\n```bash\n# 索引所有已配置的数据源\nmemorymesh index\n\n# 索引指定数据源\nmemorymesh index --source my-notes\n\n# 查看索引状态\nmemorymesh status\n```\n\n### 搜索命令\n\n```bash\nmemorymesh search \"你的搜索关键词\"\n```\n\n### 清理命令\n\n```bash\n# 清理数据库\nmemorymesh clean\n\n# 重置所有数据\nmemorymesh reset\n```\n\n资料来源：[src/memorymesh/cli.py:1-200]()\n\n## 数据源连接器\n\n### Obsidian 连接器\n\n支持从 Obsidian 保险库导入 Markdown 文件，自动提取：\n\n- YAML 前言（tags、aliases、created、modified）\n- `[[wikilinks]]` 作为反向链接\n- 嵌入的图像链接会被过滤\n\n```yaml\nsources:\n  - name: obsidian-vault\n    type: obsidian\n    path: ~/Obsidian/vault\n```\n\n资料来源：[src/memorymesh/parsing/obsidian_parser.py:1-80]()\n\n### Logseq 连接器\n\n支持从 Logseq 图形目录导入，自动处理：\n\n- `((uuid))` 块引用 → `[block]`\n- `{{embed [[Page]]}}` 嵌入 → `[embed: Page]`\n- `{{query ...}}` 查询块（移除）\n- `key:: value` 属性行（提取到元数据）\n\n```yaml\nsources:\n  - name: logseq-graph\n    type: logseq\n    path: ~/Logseq/my-graph\n    config:\n      pages_dir: pages\n      journals_dir: journals\n```\n\n资料来源：[src/memorymesh/connectors/logseq_connector.py:1-100]()\n\n### Notion 连接器\n\n支持解析 Notion HTML 导出文件，提取：\n\n- 页面标题（`<h1>` 或 `<title>`）\n- 数据库属性块（`data-type` 属性）\n- 页面 UUID（从文件名提取）\n\n```yaml\nsources:\n  - name: notion-export\n    type: notion\n    path: ~/Downloads/notion-export\n```\n\n资料来源：[src/memorymesh/parsing/notion_parser.py:1-80]()\n\n### Confluence 连接器\n\n支持从 Confluence Cloud 拉取页面，支持：\n\n- 空间过滤（`space_keys`）\n- 日期过滤（`days_past`）\n- HTML 转纯文本\n\n```yaml\nsources:\n  - name: confluence-docs\n    type: confluence\n    config:\n      base_url: https://myorg.atlassian.net\n      email: me@example.com\n      api_token: ${CONFLUENCE_API_TOKEN}\n      space_keys:\n        - ENG\n        - DOCS\n      days_past: 90\n```\n\n资料来源：[src/memorymesh/connectors/confluence_connector.py:1-80]()\n\n### Roam Research 连接器\n\n支持解析 Roam Research JSON 导出，自动清理：\n\n- `{{[[...]]}}` 模板引用\n- `[[...]]` 页面引用\n- `#[[...]]` / `#tag` 标签语法\n\n```yaml\nsources:\n  - name: roam-export\n    type: roam\n    path: ~/Downloads/roam-export.json\n    config:\n      days_past: 365\n```\n\n## 架构流程\n\n```mermaid\ngraph TD\n    A[配置文件 config.yaml] --> B[ConfigLoader]\n    B --> C[MemoryMeshConfig 验证]\n    C --> D[数据源连接器]\n    D --> E[文档解析器]\n    E --> F[分块处理器]\n    F --> G[向量化引擎]\n    G --> H[SQLite 元数据库]\n    H --> I[搜索服务]\n    I --> J[API / CLI / Web UI]\n    \n    D --> D1[Obsidian]\n    D --> D2[Logseq]\n    D --> D3[Notion]\n    D --> D4[Confluence]\n    D --> D5[Roam]\n    \n    G --> G1[SentenceTransformers]\n    G --> G2[Ollama 本地 LLM]\n    \n    I --> I1[语义搜索]\n    I --> I2[关键词搜索]\n    I --> I3[混合检索]\n```\n\n## 启动流程\n\n```mermaid\nsequenceDiagram\n    participant User\n    participant CLI\n    participant Config\n    participant AppContext\n    participant Server\n    \n    User->>CLI: memorymesh start\n    CLI->>Config: load_config()\n    Config-->>CLI: MemoryMeshConfig\n    CLI->>AppContext: _load_context(cfg)\n    AppContext->>AppContext: 初始化 MetadataStore\n    AppContext->>AppContext: 初始化 EmbeddingProvider\n    AppContext->>AppContext: 初始化 TieredMemoryManager\n    AppContext->>AppContext: 初始化 Auth/RateLimiter\n    CLI->>Server: 启动 APIServer:8765\n    CLI->>Server: 启动 HealthServer:8766\n    CLI->>Server: 启动 DashboardServer:8767\n    Server-->>User: 服务已启动\n```\n\n## 仪表盘\n\nMemoryMesh 提供基于 FastAPI + HTMX 的 Web 仪表盘。\n\n### 访问地址\n\n| 服务 | 默认端口 | 说明 |\n|------|----------|------|\n| API 服务器 | 8765 | MCP 工具和 REST API |\n| 健康检查 | 8766 | 健康状态端点 |\n| Web 仪表盘 | 8767 | 可视化界面 |\n\n### 仪表盘功能\n\n- **数据源概览**：显示已配置的数据源状态\n- **搜索界面**：执行语义和关键词混合搜索\n- **记忆层级**：展示热/温/冷数据块分布\n- **实体列表**：展示提取的命名实体\n- **时间线**：查看情景记忆事件\n- **图谱视图**：可视化知识图谱\n\n资料来源：[src/memorymesh/server/dashboard.py:1-200]()\n\n## Ollama 集成\n\n### 安装 Ollama\n\n```bash\n# macOS/Linux\ncurl -fsSL https://ollama.com/install.sh | sh\n\n# Windows - 从 https://ollama.com/download 下载\n```\n\n### 启动 Ollama\n\n```bash\n# 启动 Ollama 服务\nollama serve\n\n# 下载模型\nollama pull llama3.2\n```\n\n### 配置 MemoryMesh 使用 Ollama\n\n```yaml\nollama:\n  enabled: true\n  base_url: http://localhost:11434\n  model: llama3.2\n\nmemory:\n  entity_extraction:\n    enabled: true\n```\n\n## 记忆分层\n\nMemoryMesh 实现三层记忆模型，自动管理数据访问频率：\n\n| 层级 | 名称 | 保留时间 | 说明 |\n|------|------|----------|------|\n| 热数据 | Hot | 7 天 | 高频访问，保持在内存中 |\n| 温数据 | Warm | 30 天 | 中频访问，定期检查 |\n| 冷数据 | Cold | 90 天+ | 低频访问，触发遗忘机制 |\n\n```yaml\nmemory:\n  tiers:\n    hot_days: 7\n    warm_days: 30\n    cold_days: 90\n  forgetting:\n    enabled: true\n    cold_to_archive_after_days: 180\n```\n\n## 故障排除\n\n### 常见问题\n\n**Q: 配置文件加载失败**\n\n```bash\n# 检查配置文件路径\nmemorymesh status --verbose\n\n# 指定配置文件\nmemorymesh start --config /path/to/config.yaml\n```\n\n**Q: 向量化模型下载失败**\n\n```bash\n# 设置本地文件优先\n# 在代码中设置 SentenceTransformersProvider(local_files_only=True)\n```\n\n**Q: Ollama 连接失败**\n\n```bash\n# 确认 Ollama 正在运行\nollama list\n\n# 测试连接\ncurl http://localhost:11434/api/tags\n```\n\n**Q: 数据库锁定**\n\n```bash\n# 清理锁文件\nrm ~/.memorymesh/*.lock\n```\n\n## 下一步\n\n- 查看 [配置参考](config-reference) 了解完整配置选项\n- 查看 [API 文档](api) 了解 MCP 工具\n- 查看 [开发指南](development) 了解如何贡献代码\n- 查看 [CHANGELOG](CHANGELOG) 了解版本更新\n\n资料来源：[CHANGELOG.md:1-100]()\n"
}

---

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

## 系统架构

### 相关页面

相关主题：[MemoryMesh 简介](#page-introduction), [索引管道](#page-indexing-pipeline), [搜索引擎](#page-search-engine)

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

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

- [ARCHITECTURE.md](https://github.com/kilhubprojects/memory-mesh/blob/main/ARCHITECTURE.md)
- [src/memorymesh/server/app.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/server/app.py)
- [src/memorymesh/server/transports.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/server/transports.py)
- [src/memorymesh/indexer/file_indexer.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/indexer/file_indexer.py)
- [src/memorymesh/parsing/obsidian_parser.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/parsing/obsidian_parser.py)
- [src/memorymesh/connectors/logseq_connector.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/connectors/logseq_connector.py)
- [src/memorymesh/storage/file_repository.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/storage/file_repository.py)
</details>

# 系统架构

MemoryMesh 是一个本地优先的个人知识图谱与记忆管理系统，旨在将分散在各类笔记工具（Obsidian、Logseq、Roam、Notion 等）中的内容统一索引、检索与关联。本页面详细说明其核心系统架构、各模块职责及数据流转路径。

## 整体架构概览

MemoryMesh 采用分层架构，核心组件包括**数据源连接层**、**解析与分块层**、**存储与索引层**、**检索与推理层**，以及**服务与接口层**。各层职责清晰，依赖关系如下：

```mermaid
graph TD
    subgraph 数据源层
        OBS[Obsidian Vault]
        LOG[Logseq Graph]
        ROAM[Roam Research]
        NOTION[Notion Export]
        CONFL[Confluence]
        EMAIL[Email .mbox]
        CAL[Calendar .ics]
    end

    subgraph 连接器层
        OBS_C[ObsidianConnector]
        LOG_C[LogseqConnector]
        ROAM_C[RoamConnector]
        NOTION_C[NotionParser]
        CONFL_C[ConfluenceConnector]
    end

    subgraph 解析层
        MARKDOWN[MarkdownParser]
        OBS_P[ObsidianParser]
        HTML_P[NotionHTMLParser]
    end

    subgraph 分块层
        MD_CHUNK[MarkdownChunker]
        REC_CHUNK[RecursiveChunker]
    end

    subgraph 存储层
        SQLite[(SQLite 元数据库)]
        QDRANT[(Qdrant 向量库)]
        CHROMS[Chroma 向量库]
    end

    subgraph 索引层
        IDX[FileIndexer]
        EMB[EmbeddingProvider]
    end

    subgraph 服务层
        API[FastAPI MCP Server]
        DASH[Dashboard Server]
        HEALTH[Health Server]
        MCP[MCP Tools]
    end

    OBS --> OBS_C
    LOG --> LOG_C
    ROAM --> ROAM_C
    NOTION --> NOTION_C
    CONFL --> CONFL_C

    OBS_C --> OBS_P
    LOG_C --> MARKDOWN
    ROAM_C --> MARKDOWN
    NOTION_C --> HTML_P

    OBS_P --> MD_CHUNK
    HTML_P --> MD_CHUNK
    MARKDOWN --> REC_CHUNK

    MD_CHUNK --> IDX
    REC_CHUNK --> IDX
    IDX --> EMB
    EMB --> QDRANT
    EMB --> CHROMS
    IDX --> SQLite

    SQLite --> API
    QDRANT --> API
    CHROMS --> API
    API --> MCP
    API --> DASH
    API --> HEALTH
```

**资料来源**：[ARCHITECTURE.md](https://github.com/kilhubprojects/memory-mesh/blob/main/ARCHITECTURE.md)

## 核心组件

### 1. 连接器层（Connectors）

连接器负责从各类外部数据源批量读取文档，统一输出为 `ParsedDocument` 对象。各连接器支持的平台如下：

| 连接器 | 配置类 | 数据格式 | 特性 |
|--------|--------|----------|------|
| `ObsidianConnector` | `ObsidianSourceConfig` | Markdown | 解析 YAML frontmatter、`[[wikilinks]]` |
| `LogseqConnector` | `LogseqConfig` | Markdown | 处理 `((uuid))` 块引用、`{{embed}}` 嵌入、`key:: value` 属性 |
| `RoamConnector` | `RoamConfig` | JSON | 递归展平嵌套块、清除 `{{[[...]]}}` 模板语法 |
| `NotionParser` | `NotionSourceConfig` | HTML 导出 | 使用标准库 `html.parser` 解析 |
| `ConfluenceConnector` | `ConfluenceConfig` | REST API | HTTP Basic 认证、分页拉取 |
| `EmailParser` | `EmailSourceConfig` | .mbox | 偏好 `text/plain`，回退到 stripped HTML |
| `CalendarParser` | `CalendarSourceConfig` | .ics | 提取 VEVENT 摘要、时间、地点 |

**资料来源**：[src/memorymesh/connectors/logseq_connector.py:1-80](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/connectors/logseq_connector.py)

### 2. 解析层（Parsers）

解析器将原始文件内容转换为结构化的 `ParsedDocument`，提取纯文本与元数据。

#### Obsidian 解析器

`ObsidianParser` 专门处理 Obsidian 格式的 Markdown 文件：

- **YAML frontmatter 提取**：匹配 `---` 分隔符之间的内容，解析 `tags`、`aliases`、`created`、`modified` 字段
- **Wikilink 提取**：正则 `_WIKILINK_RE = r"(?<!!)\[\[([^\[\]|#]+?)(?:\|[^\[\]]*?)?\]\]"` 捕获双向链接目标
- **过滤嵌入图片**：`![[img]]` 格式被排除在 backlinks 之外

```python
_WIKILINK_RE = re.compile(r"(?<!!)\[\[([^\[\]|#]+?)(?:\|[^\[\]]*?)?\]\]")
```

**资料来源**：[src/memorymesh/parsing/obsidian_parser.py:20-30](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/parsing/obsidian_parser.py)

#### Logseq 解析器

`LogseqConnector` 内置解析逻辑，处理 Logseq 特有语法：

| 语法模式 | 正则 | 转换结果 |
|----------|------|----------|
| 块引用 | `\(\([0-9a-f-]{36}\)\)` | `[block]` |
| 嵌入 | `\{\{embed \[\[([^\]]+)\]\]\}\}` | `[embed: Page]` |
| 查询块 | `\{\{query[^}]*\}\}` | 整块移除 |
| 属性行 | `^([\w-]+)::\s*(.+)$` | 存入 metadata |

**资料来源**：[src/memorymesh/connectors/logseq_connector.py:40-50](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/connectors/logseq_connector.py)

### 3. 分块层（Chunking）

分块策略决定了向量检索的粒度。MemoryMesh 支持以下分块器：

| 分块器 | 策略 | 配置参数 |
|--------|------|----------|
| `RecursiveChunker` | 递归字符拆分 | `chunk_size=800`, `chunk_overlap=50` |
| `MarkdownChunker` | 按 ATX 标题（`#`, `##` 等）切分 | `max_chunk_size=800` |

`MarkdownChunker` 首先按标题分割文档，超出 `max_chunk_size` 的节交给 `RecursiveChunker` 进一步拆分，并保留 `heading_path` 元数据用于精确定位。

**资料来源**：[src/memorymesh/chunking/markdown.py:1-50](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/chunking/markdown.py)

### 4. 存储层（Storage）

#### 元数据存储（SQLite）

`FileRepository` 负责管理 SQLite 数据库中的以下表：

- `files`：文件记录，包含路径、SHA-256、修改时间、块数、索引状态等
- `sources`：数据源配置
- `index_state`：索引状态追踪

文件记录使用 `ON CONFLICT(path) DO UPDATE` 实现 upsert 语义，保证幂等性：

```sql
INSERT INTO files
    (path, source_name, sha256, mtime, size_bytes, file_type,
     n_chunks, status, error_message, indexed_at, embedding_model_id)
VALUES (...)
ON CONFLICT(path) DO UPDATE SET
    source_name = excluded.source_name,
    sha256 = excluded.sha256,
    ...
```

**资料来源**：[src/memorymesh/storage/file_repository.py:15-35](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/storage/file_repository.py)

#### 向量存储

MemoryMesh 支持多种向量数据库作为后端：

| 向量库 | 配置键 | 说明 |
|--------|--------|------|
| Qdrant | `vector_store.type: qdrant` | 高性能向量检索 |
| Chroma | `vector_store.type: chroma` | 轻量级本地向量库 |

向量由 `EmbeddingProvider` 生成，支持 Ollama 本地模型推理。

### 5. 索引层（Indexer）

`FileIndexer` 是索引流程的核心编排器，其主要职责：

```mermaid
graph LR
    A[文件路径] --> B{文件类型判断}
    B -->|Markdown| C[MarkdownChunker]
    B -->|其他| D[TextParser]
    C --> E[RecursiveChunker]
    D --> E
    E --> F[EmbeddingProvider]
    F --> G[向量写入 Qdrant/Chroma]
    E --> H[Chunk 列表]
    H --> I[FileRepository upsert]
```

索引过程中：
1. 根据文件扩展名选择对应 Parser
2. Parser 输出 `ParsedDocument`（含纯文本与元数据）
3. Chunker 将文档切分为 `Chunk` 列表
4. `EmbeddingProvider` 为每个 chunk 生成向量
5. 向量写入向量库，元数据写入 SQLite

**资料来源**：[src/memorymesh/indexer/file_indexer.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/indexer/file_indexer.py)

### 6. 服务层（Server）

#### MCP Server

MemoryMesh 通过 FastMCP 暴露 MCP（Model Context Protocol）工具，提供以下能力：

| MCP 工具 | 功能描述 |
|----------|----------|
| `search_memory` | 混合检索：向量相似度 + 关键词 |
| `ask_memory` | RAG 问答：检索 → 上下文组装 → Ollama 生成 |
| `pin_memory` | 将 chunk 钉住防止遗忘衰减 |
| `forget_memory` | 抑制或冷却指定 chunk |
| `get_memory_tier` | 查询 chunk 所在记忆层级 |

所有工具均通过 `auth_guard.py` 中的 `check_access()` 进行权限校验。

**资料来源**：[src/memorymesh/server/tools/forget_memory.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/server/tools/forget_memory.py)

#### Dashboard Server

基于 FastAPI + HTMX 的 Web 界面，运行在 `:8767` 端口：

| 路由 | 功能 |
|------|------|
| `/` | 数据源概览 |
| `/search` | 检索界面 |
| `/tiers` | 记忆层级分布统计 |
| `/entities` | 提取的实体列表 |
| `/timeline` | 情景记忆时间线 |
| `/graph-ui` | 知识图谱可视化 |

**资料来源**：[src/memorymesh/server/dashboard.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/server/dashboard.py)

#### Health Server

轻量级健康检查端点，运行在 `:8766` 端口，用于进程监控与外部探测。

## 关键数据模型

### ParsedDocument

```python
class ParsedDocument(BaseModel):
    path: Path
    text: str
    file_type: str
    encoding: str = "utf-8"
    metadata: dict[str, object] = Field(default_factory=dict)
```

### Chunk

```python
class Chunk(BaseModel):
    path: Path
    chunk_index: int
    text: str
    start_char: int
    end_char: int
    file_type: str = ""
    metadata: ChunkMetadata = Field(default_factory=ChunkMetadata)
```

**资料来源**：[src/memorymesh/core/models/chunk.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/core/models/chunk.py)

## 配置架构

MemoryMesh 使用 YAML 配置文件管理所有组件行为，主要配置节点：

```yaml
sources:                    # 数据源列表
  - type: obsidian
    path: ~/Vault
  - type: logseq
    vault_path: ~/Logseq/my-graph

vector_store:
  type: qdrant              # 或 chroma
  path: ~/.memorymesh/qdrant

memory:
  tiers:
    enabled: true
    strategy: importance_based
  forgetting:
    enabled: true
    decay_rate: 0.95
  episodic:
    enabled: true

entity_extraction:
  enabled: true
  ollama_url: http://localhost:11434

auth:
  enabled: false            # 默认关闭
```

## 记忆层级系统

MemoryMesh 引入了基于重要性的记忆层级管理：

```mermaid
graph TD
    HOT[热记忆 Hot] --> WARM[温记忆 Warm]
    WARM --> COLD[冷记忆 Cold]
    COLD --> ARCHIVE[归档 Archive]

    style HOT fill:#ff6b6b
    style WARM fill:#feca57
    style COLD fill:#54a0ff
    style ARCHIVE fill:#576574
```

| 层级 | 用途 | 衰减策略 |
|------|------|----------|
| Hot | 高频访问、钉住内容 | 不衰减 |
| Warm | 最近访问 | 轻量衰减 |
| Cold | 长期未访问 | 快速衰减 |
| Archive | 极低相关性 | 可选自动清理 |

`TieredMemoryManager` 根据访问频率与用户显式操作动态调整 chunk 所在层级。

## 认证与权限

`auth_guard.py` 提供统一的权限检查接口：

```python
check_access(ctx: AppContext, action: str, source: str | None) -> bool
```

支持的权限操作：
- `read_source`：读取指定数据源
- `write_source`：修改指定数据源
- `admin`：管理功能

当 `auth.enabled: false`（默认值）时，所有权限检查自动放行。

## 工作流程总览

```mermaid
sequenceDiagram
    participant CLI as CLI (start)
    participant CTX as AppContext
    participant CONN as Connectors
    participant IDX as FileIndexer
    participant EMB as EmbeddingProvider
    participant VDB as Vector Store
    participant SQL as SQLite

    CLI->>CTX: 初始化配置
    CTX->>CONN: 创建连接器实例
    loop 每次索引周期
        CONN->>CONN: fetch_documents()
        CONN-->>IDX: ParsedDocument stream
        loop 每个文档
            IDX->>IDX: parse() → ParsedDocument
            IDX->>IDX: chunk() → Chunk list
            IDX->>EMB: embed(chunks)
            EMB-->>IDX: ChunkWithEmbedding list
            IDX->>VDB: upsert(embeddings)
            IDX->>SQL: upsert(FileRecord)
        end
    end
    CLI->>CTX: 启动 MCP Server
    CTX->>CTX: 注册 MCP 工具
    Note over CTX: Dashboard :8767, Health :8766
```

## 扩展机制

MemoryMesh 设计支持以下扩展点：

1. **自定义 Parser**：继承 `Parser` 基类，注册到 `source.type` 映射
2. **自定义 ChunkStrategy**：实现 `Chunker` 接口
3. **自定义 VectorStore**：实现 `VectorStore` 接口，适配新的向量数据库
4. **自定义 Connector**：实现 `Connector` 接口，从新平台拉取数据

## 技术栈总结

| 层级 | 技术选型 |
|------|----------|
| 核心框架 | Python 3.11+, Pydantic |
| Web 框架 | FastAPI, Starlette |
| 界面 | HTMX, 原生 HTML/CSS |
| 向量库 | Qdrant / Chroma |
| 元数据 | SQLite |
| 本地推理 | Ollama |
| 协议 | MCP (FastMCP) |
| 日志 | Loguru |
| 配置 | YAML + Pydantic ConfigDict |

所有数据默认存储在 `~/.memorymesh/` 目录下，保持完全的本地化与隐私保护。

---

<a id='page-indexing-pipeline'></a>

## 索引管道

### 相关页面

相关主题：[系统架构](#page-architecture), [文件解析器](#page-parsers), [文本分块策略](#page-chunkers), [搜索引擎](#page-search-engine)

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

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

- [src/memorymesh/indexer/file_indexer.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/indexer/file_indexer.py)
- [src/memorymesh/indexer/watcher.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/indexer/watcher.py)
- [src/memorymesh/parsing/registry.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/parsing/registry.py)
- [src/memorymesh/embeddings/registry.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/embeddings/registry.py)
- [src/memorymesh/storage/vector_store.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/storage/vector_store.py)
- [src/memorymesh/storage/bm25_index.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/storage/bm25_index.py)
</details>

# 索引管道

索引管道是 MemoryMesh 的核心子系统，负责将各种来源的文档转换为可搜索的向量和全文索引数据。本页面详细介绍索引管道的架构设计、数据流、核心组件及其交互方式。

## 架构概述

索引管道采用模块化设计，主要包含以下处理阶段：

```mermaid
graph TD
    A[文档源] --> B[解析器 Registry]
    B --> C[解析器 Parser]
    C --> D[ParsedDocument]
    D --> E[分块器 Chunker]
    E --> F[Chunk 列表]
    F --> G[嵌入向量生成]
    G --> H[向量存储]
    G --> I[BM25 索引]
    H --> J[元数据存储]
    I --> J
```

管道支持多种文档格式，包括本地 Markdown、Obsidian 笔记、Notion 导出、Roam Research、Logseq、Confluence 以及 Email 和日历等。资料来源：[src/memorymesh/parsing/obsidian_parser.py]()、[src/memorymesh/parsing/notion_parser.py]()、[src/memorymesh/connectors/logseq_connector.py]()、[src/memorymesh/connectors/roam_connector.py]()、[src/memorymesh/connectors/confluence_connector.py]()

## 核心处理流程

### 1. 文档解析阶段

解析器注册表 (`ParserRegistry`) 根据文件类型和来源配置选择合适的解析器。每种解析器负责将特定格式的文档转换为统一的 `ParsedDocument` 数据结构。

支持的解析器类型：

| 解析器 | 文件类型 | 特殊功能 |
|--------|----------|----------|
| MarkdownParser | .md, .mdx, .markdown | 基础解析 |
| ObsidianParser | .md | YAML frontmatter 提取、wikilink 解析 |
| NotionParser | .html, .htm | Notion 导出格式处理 |
| LogseqConnector | .md | 属性行解析、block 引用处理 |
| RoamConnector | JSON | 递归 block 扁平化 |
| ConfluenceConnector | API | HTML 内容提取 |

资料来源：[src/memorymesh/parsing/registry.py]()

`ParsedDocument` 模型包含以下关键字段：

```python
path: Path
text: str
file_type: str
encoding: str
metadata: dict[str, object]  # 包含 frontmatter、tags、aliases 等
```

资料来源：[src/memorymesh/core/models/chunk.py]()

### 2. 文本分块阶段

分块器将长文档拆分为适合嵌入的段落。每个 `Chunk` 对象包含文本内容、字符位置信息和元数据。

| 分块器 | 适用场景 | 分块策略 |
|--------|----------|----------|
| MarkdownChunker | Markdown 文档 | 按 ATX 标题层级切分 |
| CodeChunker | 源代码文件 | 按函数/类定义节点切分 |
| RecursiveChunker | 通用文本 | 递归字符级切分 |

MarkdownChunker 特别维护 `heading_path` 元数据字段，记录文档中的完整标题路径，便于精确定位搜索结果。资料来源：[src/memorymesh/chunking/markdown.py]()

CodeChunker 使用 AST 解析提取函数名、类名和语言类型，为代码搜索提供语义级支持。资料来源：[src/memorymesh/chunking/code.py]()

### 3. 向量嵌入阶段

嵌入向量生成器将文本块转换为高维向量表示，用于语义相似度搜索。嵌入提供者通过注册表统一管理，支持配置不同的嵌入模型。

```mermaid
sequenceDiagram
    participant C as Chunk
    participant E as EmbeddingProvider
    participant V as VectorStore
    participant M as MetadataStore
    
    C->>E: 批量生成嵌入向量
    E-->>C: embedding: list[float]
    C->>V: 存储向量 + 元数据
    C->>M: 创建 FileRecord
```

资料来源：[src/memorymesh/indexer/file_indexer.py]()

### 4. 混合索引阶段

MemoryMesh 采用混合搜索策略，同时维护向量索引和 BM25 全文索引。

| 索引类型 | 用途 | 存储位置 |
|----------|------|----------|
| 向量索引 | 语义相似度搜索 | VectorStore |
| BM25 索引 | 关键词精确匹配 | BM25Index |

BM25 索引器构建倒排索引，支持按词频和文档频率计算相关性评分。资料来源：[src/memorymesh/storage/bm25_index.py]()

向量存储使用配置的向量数据库，支持多种后端实现。资料来源：[src/memorymesh/storage/vector_store.py]()

## FileIndexer 核心组件

`FileIndexer` 是索引管道的核心编排器，协调各子系统的协作。

### 主要方法

| 方法 | 职责 |
|------|------|
| `index_file(path)` | 单文件索引入口 |
| `index_directory(root, ...)` | 目录批量索引 |
| `process_document(doc, path, source_name)` | 文档处理流水线 |

资料来源：[src/memorymesh/indexer/file_indexer.py]()

### 索引结果记录

索引完成后，系统创建 `FileRecord` 记录文件状态：

```python
FileRecord(
    path=str(path),
    source_name=source_name,
    sha256=current_hash,        # 文件内容哈希
    mtime=stat.st_mtime,        # 修改时间
    size_bytes=stat.st_size,    # 文件大小
    file_type=ext,              # 文件类型
    n_chunks=len(chunks),       # 分块数量
    status="indexed",           # 索引状态
    indexed_at=time.time(),     # 索引时间戳
    embedding_model_id=model_id # 嵌入模型标识
)
```

资料来源：[src/memorymesh/indexer/file_indexer.py]()、[src/memorymesh/core/models/chunk.py]()

### 增量索引机制

系统通过 SHA-256 哈希和 mtime 比对检测文件变化，仅对变更文件重新索引：

```python
current_hash = hashlib.sha256(content).hexdigest()
if current_hash != existing_file.sha256:
    # 重新索引
```

资料来源：[src/memorymesh/indexer/file_indexer.py]()

## 监视器组件

`FileWatcher` 组件监听文件系统变化，触发增量索引。

```mermaid
graph LR
    A[文件系统事件] --> B{事件类型}
    B -->|创建/修改| C[触发索引]
    B -->|删除| D[标记文件已删除]
    B -->|重命名| E[更新文件路径]
```

资料来源：[src/memorymesh/indexer/watcher.py]()

| 功能 | 说明 |
|------|------|
| 增量更新 | 仅索引变更文件 |
| 软删除处理 | 标记而非立即删除 |
| 防抖机制 | 避免频繁触发 |

## 配置选项

### IndexingConfig 主要字段

| 字段 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `chunk_size` | int | 800 | 分块目标字符数 |
| `chunk_overlap` | int | 50 | 分块重叠字符数 |
| `generate_summaries` | bool | False | 是否生成摘要块 |
| `extract_entities` | bool | True | 是否提取实体 |

### EmbeddingConfig 主要字段

| 字段 | 类型 | 说明 |
|------|------|------|
| `provider` | str | 嵌入提供者名称 |
| `model_id` | str | 模型标识符 |
| `batch_size` | int | 批处理大小 |
| `dimensions` | int | 向量维度 |

资料来源：[src/memorymesh/embeddings/registry.py]()

## 错误处理

索引管道内置完善的错误处理机制：

| 错误类型 | 处理策略 | 状态记录 |
|----------|----------|----------|
| 解析错误 | 返回错误文档，记录到 metadata | `parse_error` |
| 编码错误 | 使用 fallback 编码或跳过 | `parse_error` |
| 嵌入失败 | 使用 fallback 提供者 | `index_error` |
| 存储错误 | 回滚事务，记录错误信息 | `index_error` |

`FileRecord` 的 `status` 字段可能值：`indexed`、`parse_error`、`unsupported`、`deleted`、`pending_reindex`。资料来源：[src/memorymesh/core/models/chunk.py]()

## 数据流总结

```
Source File → Parser → ParsedDocument → Chunker → Chunks
                                                      ↓
                                    ┌─────────────────┴─────────────────┐
                                    ↓                                   ↓
                            EmbeddingProvider                  BM25Indexer
                                    ↓                                   ↓
                              VectorStore                         BM25Index
                                    └─────────────────┬─────────────────┘
                                                      ↓
                                              MetadataStore
                                              (FileRecord)
```

索引管道通过模块化设计实现了灵活的文档处理能力，支持多种数据源的统一索引，并提供向量和全文双重搜索能力，满足不同场景的检索需求。

---

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

## 文件解析器

### 相关页面

相关主题：[索引管道](#page-indexing-pipeline), [文本分块策略](#page-chunkers)

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

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

- [src/memorymesh/parsing/base.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/parsing/base.py)
- [src/memorymesh/parsing/markdown.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/parsing/markdown.py)
- [src/memorymesh/parsing/obsidian_parser.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/parsing/obsidian_parser.py)
- [src/memorymesh/parsing/notion_parser.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/parsing/notion_parser.py)
</details>

# 文件解析器

## 概述

文件解析器（Parser）是 MemoryMesh 索引管道中的第一环，负责将各种来源的原始文件转换为统一的 `ParsedDocument` 数据结构。每个解析器专注于特定的文件格式或数据源，提取文本内容和元数据，为后续的分块（Chunking）和向量化（Embedding）做准备。

解析器采用**策略模式**，通过文件扩展名和源类型自动选择合适的解析器实现。系统内置了针对 Markdown、Obsidian、Notion、PDF、DOCX、Email 等格式的专业解析器，同时也支持通过扩展机制接入新的数据源。

资料来源：[src/memorymesh/parsing/base.py]()

## 架构设计

### 解析器基类

所有解析器都继承自 `Parser` 基类，定义统一接口：

```python
class Parser(ABC):
    @property
    @abstractmethod
    def supported_extensions(self) -> frozenset[str]:
        """返回解析器支持的文件扩展名集合"""
        ...

    @abstractmethod
    def parse(self, path: Path) -> ParsedDocument:
        """解析指定路径的文件，返回 ParsedDocument"""
        ...
```

资料来源：[src/memorymesh/parsing/base.py]()

### 解析流程

```mermaid
graph TD
    A[原始文件] --> B{文件类型检测}
    B -->|Markdown .md| C[MarkdownParser]
    B -->|Obsidian .md| D[ObsidianParser]
    B -->|Notion .html| E[NotionParser]
    B -->|PDF .pdf| F[PDFParser]
    B -->|DOCX .docx| G[DOCXParser]
    B -->|Email .eml/.msg| H[EmailParser]
    C --> I[ParsedDocument]
    D --> I
    E --> I
    F --> I
    G --> I
    H --> I
```

### ParsedDocument 数据模型

解析结果封装在 `ParsedDocument` 模型中：

| 字段 | 类型 | 说明 |
|------|------|------|
| `path` | `Path` | 文件绝对路径 |
| `text` | `str` | 提取的纯文本内容 |
| `file_type` | `str` | 规范化文件类型标识 |
| `encoding` | `str` | 源文件编码 |
| `metadata` | `dict` | 格式特定的元数据 |

资料来源：[src/memorymesh/core/models/__init__.py]()

## 内置解析器

### Markdown 解析器

**文件路径**: `src/memorymesh/parsing/markdown.py`

`MarkdownParser` 是标准 Markdown 文件的解析器，使用与文本解析器相同的编码容错读取机制。它将解析结果标记为 `file_type=".md"`，使后续分块层能够选择标题感知的分割器。

```python
class MarkdownParser(Parser):
    @property
    def supported_extensions(self) -> frozenset[str]:
        return frozenset({".md", ".mdx", ".markdown"})

    def parse(self, path: Path) -> ParsedDocument:
        text, encoding, error = _read_with_fallback(path)
        meta: dict[str, object] = {}
        if error:
            meta["error"] = error
        return ParsedDocument(
            path=path,
            text=text,
            file_type=".md",
            encoding=encoding,
            metadata=meta,
        )
```

资料来源：[src/memorymesh/parsing/markdown.py]()

### Obsidian 解析器

**文件路径**: `src/memorymesh/parsing/obsidian_parser.py`

`ObsidianParser` 继承自 `MarkdownParser`，增加了对 Obsidian 特有语法的支持：

| 功能 | 说明 |
|------|------|
| YAML 前置元数据 | 提取 `---` 分隔符之间的内容 |
| Wikilink 反向链接 | 识别 `[[链接]]` 和 `[[链接\|别名]]` 模式 |
| 嵌入图片过滤 | 排除 `![[图片]]` 等嵌入媒体 |
| 标签提取 | 解析 `tags:` 字段和内联 `#标签` 语法 |

```python
# YAML 前置元数据正则
_FRONTMATTER_RE = re.compile(
    r"^---\r?\n(.*?)\r?\n(?:---|\.\.\.)(?:\r?\n|$)",
    re.DOTALL,
)

# Wikilink 提取正则（排除 ![[ 嵌入]]）
_WIKILINK_RE = re.compile(r"(?<!!)\[\[([^\[\]|#]+?)(?:\|[^\[\]]*?)?\]\]")
```

提取的元数据字段：

```python
meta["frontmatter"] = fm_data          # YAML 字段字典
meta["tags"] = tags                     # 标签列表
meta["aliases"] = aliases               # 别名列表
meta["created"] = created              # 创建时间
meta["modified"] = modified             # 修改时间
meta["backlinks"] = wikilink_targets    # Wikilink 目标列表
```

资料来源：[src/memorymesh/parsing/obsidian_parser.py]()

### Notion 解析器

**文件路径**: `src/memorymesh/parsing/notion_parser.py`

`NotionParser` 专门处理 Notion HTML 导出格式，仅依赖标准库 `html.parser`，无需外部依赖。

```python
class _NotionHTMLParser(HTMLParser):
    """SAX 风格解析器，收集纯文本和元数据"""
    
    _SKIP_TAGS: frozenset[str] = frozenset(
        {"style", "script", "head", "meta", "link"}
    )
```

解析能力：

- 提取 `<title>` 标签内容
- 提取 `<h1>` 可见页面标题
- 收集 `data-type` 属性值（数据库属性类型）
- 剥离所有 HTML 标签获取纯文本
- 从文件名提取 Notion 页面 UUID

```python
_UUID_FILENAME_RE = re.compile(
    r"([0-9a-f]{8}(?:[0-9a-f]{4}){3}[0-9a-f]{12})(?:\s|\.|$)",
    re.IGNORECASE,
)
```

Notion 解析器返回的元数据包含：

| 字段 | 说明 |
|------|------|
| `notion_id` | 页面 UUID |
| `database_name` | 所属数据库名称 |
| `title` | 页面标题 |
| `db_properties` | 数据库属性列表 |

资料来源：[src/memorymesh/parsing/notion_parser.py]()

## 支持的文件格式

| 解析器 | 扩展名 | 源类型 |
|--------|--------|--------|
| `MarkdownParser` | `.md`, `.mdx`, `.markdown` | 通用 Markdown |
| `ObsidianParser` | `.md` | `obsidian` |
| `NotionParser` | `.html`, `.htm` | `notion` |
| `PDFParser` | `.pdf` | 通用 |
| `DOCXParser` | `.docx` | 通用 |
| `EmailParser` | `.eml`, `.msg` | 通用 |

## 解析模式

### 编码容错读取

解析器使用 `_read_with_fallback` 函数处理各种文件编码：

```python
def _read_with_fallback(path: Path) -> tuple[str, str, str | None]:
    """尝试 UTF-8 读取，失败时回退到 latin-1"""
```

该函数按顺序尝试：
1. UTF-8 编码
2. 回退到 `latin-1` 编码
3. 返回错误信息而非抛出异常

资料来源：[src/memorymesh/parsing/text.py]()

### 错误处理

所有解析器遵循统一的错误处理策略：

```python
if error:
    meta["error"] = error
    return ParsedDocument(
        path=path,
        text="",
        file_type=file_type,
        encoding=encoding,
        metadata=meta,
    )
```

解析失败时返回空的 `text` 内容，但保留 `error` 字段供诊断使用。

## 与连接器的协作

解析器不仅处理本地文件，还被**连接器（Connector）**模块间接调用：

```mermaid
graph LR
    A[连接器] -->|fetch_documents| B[ParsedDocument]
    B --> C[索引器]
    C --> D[分块]
    D --> E[向量化]
    E --> F[向量数据库]
```

连接器处理远程数据获取和格式转换，然后使用解析器或解析后的格式输出 `ParsedDocument`：

- **RoamConnector** - 解析 Roam Research JSON 导出
- **LogseqConnector** - 处理 Logseq Markdown 文件
- **NotionConnector** - 调用 Notion API 获取页面
- **ConfluenceConnector** - 从 Confluence REST API 获取页面

资料来源：[src/memorymesh/connectors/roam_connector.py]()
资料来源：[src/memorymesh/connectors/logseq_connector.py]()
资料来源：[src/memorymesh/connectors/notion_connector.py]()
资料来源：[src/memorymesh/connectors/confluence_connector.py]()

## 使用示例

### 直接使用解析器

```python
from pathlib import Path
from memorymesh.parsing.obsidian_parser import ObsidianParser

parser = ObsidianParser()
doc = parser.parse(Path("/vault/my-note.md"))

print(f"文本长度: {len(doc.text)}")
print(f"标签: {doc.metadata.get('tags')}")
print(f"反向链接: {doc.metadata.get('backlinks')}")
```

### 配置源类型自动选择

当 `source.type` 配置为 `obsidian` 时，系统自动注册 `ObsidianParser` 处理 `.md` 文件；通用 Markdown 源则使用标准 `MarkdownParser`。

## 扩展新的解析器

实现自定义解析器需继承 `Parser` 基类：

```python
from memorymesh.parsing.base import Parser
from memorymesh.core.models import ParsedDocument

class CustomParser(Parser):
    @property
    def supported_extensions(self) -> frozenset[str]:
        return frozenset({".custom"})
    
    def parse(self, path: Path) -> ParsedDocument:
        # 实现解析逻辑
        return ParsedDocument(
            path=path,
            text=processed_text,
            file_type=".custom",
            metadata={"source": "custom"},
        )
```

## 总结

文件解析器模块是 MemoryMesh 多格式支持的核心，通过统一的 `Parser` 接口和 `ParsedDocument` 数据模型，实现了：

- **格式解耦** - 解析逻辑与索引逻辑分离
- **自动选择** - 根据扩展名和源类型自动路由
- **元数据丰富** - 提取格式特定信息供高级检索使用
- **容错设计** - 编码错误和解析失败不影响整体流程

---

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

## 文本分块策略

### 相关页面

相关主题：[索引管道](#page-indexing-pipeline), [文件解析器](#page-parsers)

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

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

- [src/memorymesh/chunking/base.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/chunking/base.py)
- [src/memorymesh/chunking/recursive.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/chunking/recursive.py)
- [src/memorymesh/chunking/markdown.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/chunking/markdown.py)
- [src/memorymesh/chunking/code.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/chunking/code.py)
- [src/memorymesh/chunking/registry.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/chunking/registry.py)
</details>

# 文本分块策略

## 概述

文本分块策略是 MemoryMesh 项目中用于将大型文档拆分为可管理单元的核心机制。在 RAG（检索增强生成）系统架构中，分块策略直接影响检索质量和生成效果。MemoryMesh 实现了多种专业化的分块器，每种分块器针对特定内容类型进行优化，确保拆分后的文本块（Chunk）既保持语义完整性，又便于后续的向量检索。

系统通过统一的 `Chunk` 数据模型和抽象基类 `Chunker` 接口，支持灵活的扩展机制。文档解析完成后，相应的分块器会根据文件类型自动选择并应用，实现无缝的文档处理流程。

资料来源：[src/memorymesh/chunking/base.py:1-30]()

## 架构设计

### 核心抽象

MemoryMesh 的分块系统采用策略模式设计，核心组件包括：

```mermaid
graph TD
    A[ParsedDocument] --> B[Chunker Registry]
    B --> C{Markdown?}
    B --> D{Code?}
    B --> E{Default?}
    C --> F[MarkdownChunker]
    D --> G[CodeChunker]
    E --> H[RecursiveChunker]
    F --> I[Chunk List]
    G --> I
    H --> I
```

`Chunker` 抽象基类定义了统一的分块接口，所有具体分块器都必须实现 `chunk(doc: ParsedDocument) -> list[Chunk]` 方法。这种设计允许在运行时根据文件类型动态选择最合适的分块策略。

资料来源：[src/memorymesh/chunking/base.py:12-18]()

### 分块器类型对比

| 分块器 | 适用场景 | 分割依据 | 依赖项 |
|--------|----------|----------|--------|
| MarkdownChunker | Markdown 文档 | ATX 标题层级 | 无 |
| CodeChunker | 源代码文件 | AST 语法树节点 | tree-sitter-languages |
| RecursiveChunker | 通用文本 | 字符数/段落/句子 | 无 |

资料来源：[src/memorymesh/chunking/registry.py:44-73]()

## Markdown 分块器

### 工作原理

`MarkdownChunker` 基于 ATX 标题语法（`#`、`##`、`###` 等）对文档进行结构化拆分。每个分块包含一个标题及其下方内容，直到遇到同级或更高级别标题为止。

```mermaid
graph LR
    A["# 文档标题"] --> B["## 第一章节<br>章节内容..."]
    B --> C["## 第二章节<br>章节内容..."]
    B --> D["### 2.1 子章节<br>子内容..."]
    D --> C
```

系统通过正则表达式 `^(#{1,6})\s+(.*)` 匹配所有标题行，并维护一个 heading_stack（标题栈）来追踪当前章节的层级关系。

资料来源：[src/memorymesh/chunking/markdown.py:1-50]()

### 标题路径元数据

每个 Markdown 分块都包含 `heading_path` 元数据字段，记录从根标题到当前标题的完整路径。例如，对于 `### 2.1 子章节`，其 `heading_path` 为 `["文档标题", "第一章节", "子章节"]`。这一特性使搜索命中可以精确定位到文档中的具体位置。

资料来源：[src/memorymesh/chunking/markdown.py:80-85]()

### 溢出拆分机制

当单个章节内容超过 `max_chunk_size`（默认 800 字符）时，`MarkdownChunker` 会调用 `RecursiveChunker` 进行递归拆分，确保最终分块大小符合配置要求。

资料来源：[src/memorymesh/chunking/markdown.py:24-27]()

## 代码分块器

### AST 感知分割

`CodeChunker` 使用 tree-sitter 库解析源代码的抽象语法树（AST），在顶级函数和类定义处进行分割。这种分割方式保持了代码结构完整性，便于检索时代码片段的语义理解。

```mermaid
graph TD
    A[源代码文件] --> B[tree-sitter 解析]
    B --> C[提取顶级节点]
    C --> D{节点类型?}
    D -->|function_definition| E[函数分块]
    D -->|class_definition| F[类分块]
    D -->|其他| G[残留代码处理]
    E --> H[Chunk List]
    F --> H
    G --> H
```

资料来源：[src/memorymesh/chunking/code.py:1-60]()

### 支持的编程语言

| 扩展名 | 语言标识 | 扩展名 | 语言标识 |
|--------|----------|--------|----------|
| .py | python | .go | go |
| .js / .jsx | javascript | .rs | rust |
| .ts / .tsx | typescript / tsx | .rb | ruby |
| .java | java | .php | php |
| .c / .h | c | .swift | swift |
| .cpp / .hpp | cpp | .kt | kotlin |
| .cs | c_sharp | | |

资料来源：[src/memorymesh/chunking/code.py:16-36]()

### 分割节点类型

代码分块器在以下 AST 节点类型处进行分割：

- `function_definition`
- `function_declaration`
- `method_definition`
- `class_definition`
- `class_declaration`

资料来源：[src/memorymesh/chunking/code.py:38-45]()

### 元数据标记

每个代码分块包含丰富的元数据：

- `language`：编程语言名称
- `function_name`：函数名（如适用）
- `class_name`：所属类名（如适用）

这些元数据使搜索结果可以精确定位到具体的代码符号。

资料来源：[src/memorymesh/chunking/code.py:95-100]()

### 回退机制

当发生以下情况时，`CodeChunker` 自动回退到 `RecursiveChunker`：

- tree-sitter-languages 未安装
- 不支持当前文件扩展名
- tree-sitter 运行时错误

资料来源：[src/memorymesh/chunking/code.py:48-55]()

## 递归分块器

### 层级拆分策略

`RecursiveChunker` 采用多层级递归策略，将文本从大到小逐步拆分，直到满足大小约束。

```mermaid
graph TD
    A[完整文本] --> B{是否超过 chunk_size?}
    B -->|否| Z[直接返回]
    B -->|是| C[按段落分割]
    C --> D{段落是否超过限制?}
    D -->|是| E[按句子分割]
    E --> F{句子是否超过限制?}
    F -->|是| G[按字符数硬截断]
    G --> H[合并重叠分块]
    D -->|否| H
    F -->|否| H
    H --> I[Chunk List]
```

资料来源：[src/memorymesh/chunking/recursive.py:1-80]()

### 分割层级

分块器按以下顺序尝试拆分：

1. **段落分割**：按双换行符 `\n\n` 分割
2. **句子分割**：按 `. `、`!`、`?` 等标点分割
3. **字符截断**：按 `chunk_size` 硬截断

每层拆分后，检查子块是否仍超过大小限制，如是则继续下一层拆分。

资料来源：[src/memorymesh/chunking/recursive.py:30-60]()

### 重叠机制

为保持上下文连续性，相邻分块之间存在 `chunk_overlap`（默认 50 字符）的重叠区域。重叠通过向前回溯实现，确保重要内容不会因分割边界而被切断。

资料来源：[src/memorymesh/chunking/recursive.py:62-70]()

## 分块器注册表

### 文件类型选择逻辑

`ChunkerRegistry` 负责根据文件扩展名选择合适的分块器：

```mermaid
graph TD
    A[输入: extension] --> B{是否为 Markdown 扩展名?}
    B -->|是| C[返回 MarkdownChunker]
    B -->|否| D{是否为代码扩展名?}
    D -->|是| E[返回 CodeChunker]
    D -->|否| F[返回 RecursiveChunker]
```

Markdown 扩展名集合：`.md`、`.mdx`、`.markdown`

代码扩展名集合：`.py`、`.js`、`.jsx`、`.ts`、`.tsx`、`.java`、`.c`、`.cpp`、`.h`、`.hpp`、`.cs`、`.go`、`.rs`、`.rb`、`.php`、`.swift`、`.kt`

资料来源：[src/memorymesh/chunking/registry.py:18-28]()

### 获取分块器接口

```python
def get_chunker(
    extension: str,
    chunking_config: ChunkingConfig | None = None
) -> Chunker
```

当 `chunking_config` 为 `None` 时，使用默认配置参数初始化各分块器。

资料来源：[src/memorymesh/chunking/registry.py:30-73]()

## 配置参数

### 分块配置模型

| 配置项 | 类型 | 默认值 | 说明 |
|--------|------|--------|------|
| `max_chunk_size` | int | 800 | Markdown 分块器：单个章节最大字符数 |
| `chunk_size` | int | - | RecursiveChunker：目标分块大小 |
| `chunk_overlap` | int | 50 | RecursiveChunker：相邻分块重叠字符数 |

资料来源：[src/memorymesh/chunking/markdown.py:48-50]()

### 配置使用示例

```python
from memorymesh.chunking.registry import get_chunker
from memorymesh.core.models import ChunkingConfig, MarkdownChunkingConfig

config = ChunkingConfig(
    markdown=MarkdownChunkingConfig(max_chunk_size=1000),
    code=CodeChunkingConfig(max_chunk_size=500),
    default=RecursiveChunkingConfig(chunk_size=300, chunk_overlap=30)
)

chunker = get_chunker(".py", chunking_config=config)
```

## 数据模型

### Chunk 数据结构

```python
class Chunk(BaseModel):
    path: Path                      # 源文件绝对路径
    chunk_index: int                # 文件内分块序号
    text: str                       # 分块文本内容
    start_char: int                 # 在源文本中的起始字符偏移
    end_char: int                   # 在源文本中的结束字符偏移
    file_type: str                  # 文件类型扩展名
    mtime: float                    # 文件修改时间戳
    source_root: str                # 来源配置名称
    metadata: ChunkMetadata         # 结构化元数据
```

资料来源：[src/memorymesh/core/models/chunk.py:35-55]()

### ChunkMetadata 元数据

```python
class ChunkMetadata(BaseModel):
    heading_path: list[str] = []    # Markdown 标题路径
    language: str = ""              # 代码语言标识
    function_name: str = ""         # 函数名
    class_name: str = ""            # 类名
```

资料来源：[src/memorymesh/chunking/markdown.py:82-85]() 和 [src/memorymesh/chunking/code.py:95-100]()

### Chunk ID 标识符

每个 Chunk 具有稳定的唯一标识符，格式为 `<path>:<chunk_index>`，便于跨系统引用和去重。

资料来源：[src/memorymesh/core/models/chunk.py:57-59]()

## 最佳实践

### 调整分块大小

| 使用场景 | 推荐配置 |
|----------|----------|
| 细粒度检索（如代码搜索） | `max_chunk_size=300-500` |
| 文档问答 | `max_chunk_size=800-1000` |
| 长文档摘要 | `max_chunk_size=1500+` |

### 选择分块策略

- **结构化文档**（Markdown）：优先使用 `MarkdownChunker` 保留文档结构
- **源代码**：使用 `CodeChunker` 保持函数/类完整性
- **非结构化文本**：使用 `RecursiveChunker` 按语义层级拆分

---

<a id='page-search-engine'></a>

## 搜索引擎

### 相关页面

相关主题：[系统架构](#page-architecture), [结果重排序](#page-reranking), [MCP 工具参考](#page-mcp-tools)

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

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

- [src/memorymesh/search/engine.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/search/engine.py)
- [src/memorymesh/search/rank_fusion.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/search/rank_fusion.py)
- [src/memorymesh/search/query_expander.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/search/query_expander.py)
- [src/memorymesh/llm/ollama_client.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/llm/ollama_client.py)
- [src/memorymesh/server/tools/ask_memory.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/server/tools/ask_memory.py)
- [CHANGELOG.md](https://github.com/kilhubprojects/memory-mesh/blob/main/CHANGELOG.md)
- [src/memorymesh/server/dashboard.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/server/dashboard.py)
- [ARCHITECTURE.md](https://github.com/kilhubprojects/memory-mesh/blob/main/ARCHITECTURE.md)
</details>

# 搜索引擎

## 1. 概述

MemoryMesh 的搜索引擎是一个混合检索系统，支持密集检索（dense retrieval）和稀疏检索（sparse retrieval）两种方式，并提供可选的重排序（reranking）和查询扩展（query expansion）功能。该引擎是整个知识库问答系统的核心，负责从向量数据库中快速定位相关文本块。

搜索引擎的核心职责包括：

- 接收用户查询文本
- 通过查询扩展生成语义变体
- 并行执行多种检索策略
- 使用排名融合（rank fusion）整合多路检索结果
- 可选地通过 LLM 进行结果重排序
- 返回排序后的搜索命中列表

资料来源：[CHANGELOG.md]()

## 2. 架构设计

### 2.1 整体架构图

```mermaid
graph TD
    A[用户查询] --> B[查询扩展 QueryExpander]
    B --> C[生成多个查询变体]
    C --> D[并行检索 Pipeline]
    D --> E[密集检索 Dense Retriever]
    D --> F[稀疏检索 Sparse Retriever]
    E --> G[排名融合 RankFusion]
    F --> G
    G --> H[可选: 重排序 Reranker]
    H --> I[SearchHit 结果列表]
    
    J[Ollama LLM] -.-> H
    K[向量数据库] -.-> E
    L[元数据存储] -.-> F
```

### 2.2 核心组件

| 组件 | 文件路径 | 职责 |
|------|----------|------|
| SearchEngine | `search/engine.py` | 主编排引擎，协调整个检索流程 |
| QueryExpander | `search/query_expander.py` | 查询扩展，生成语义变体 |
| RankFusion | `search/rank_fusion.py` | 多路结果融合 |
| OllamaClient | `llm/ollama_client.py` | 本地 LLM 调用接口 |
| AskMemory | `server/tools/ask_memory.py` | MCP 工具封装 |

资料来源：[CHANGELOG.md]()

## 3. 检索策略

### 3.1 并行变体检索

SearchEngine 使用 `ThreadPoolExecutor` 实现并行检索。针对扩展后的多个查询变体，系统会并发地向向量数据库发起检索请求，最后将所有结果汇总。这一设计显著提升了长查询的检索效率。

```python
# 伪代码展示并行检索逻辑
def _retrieve_single(self, variant_query: str) -> list[SearchHit]:
    """执行单个查询变体的检索"""

def _fuse_all(self, all_hits: list[list[SearchHit]]) -> list[SearchHit]:
    """融合多路检索结果"""
```

资料来源：[CHANGELOG.md]()

### 3.2 密集检索与稀疏检索

系统支持两种互补的检索模式：

- **密集检索（Dense Retrieval）**：使用文本嵌入模型将查询和文档都编码为向量，在向量空间中进行相似度搜索，适合语义匹配。
- **稀疏检索（Sparse Retrieval）**：基于关键词的传统 BM25 或类似算法，适合精确术语匹配。

两种检索结果通过排名融合算法整合，兼顾语义理解和精确匹配。

### 3.3 摘要块过滤

系统支持在索引阶段生成摘要块（`chunk_type="summary"`），这些摘要块存储在向量数据库中用于提升抽象语义召回率。但在搜索结果返回时，摘要块会被自动过滤掉，不会直接暴露给用户。

资料来源：[CHANGELOG.md]()

## 4. 查询扩展

QueryExpander 负责将用户原始查询扩展为多个语义变体，以提升检索的召回率。

### 4.1 配置参数

| 参数 | 说明 | 默认值 |
|------|------|--------|
| `n_lexical_variants` | 生成的词汇变体数量 | 1 |
| `expansion_model` | 使用的扩展模型 | - |

在最新版本中，`n_lexical_variants` 的默认值从 2 降低到 1，以减少查询噪声。

资料来源：[CHANGELOG.md]()

### 4.2 扩展流程

```mermaid
graph LR
    A[原始查询] --> B[语义分析]
    B --> C[生成变体1]
    B --> D[生成变体2]
    C --> E[合并为查询列表]
    D --> E
    E --> F[并行检索]
```

## 5. 排名融合

当多路检索返回结果后，RankFusion 模块负责将不同检索策略的结果合并为统一的排序列表。

### 5.1 融合策略

融合算法会考虑每个命中结果在不同检索通道中的排名位置，给予排名靠前的结果更高的融合分数。最终返回一个综合排序后的 `SearchHit` 列表。

## 6. 重排序（Reranking）

### 6.1 简介

可选的重排序功能使用 LLM 对初筛结果进行二次排序，以提升结果相关性。

### 6.2 配置参数

| 参数 | 说明 | 默认值 |
|------|------|--------|
| `top_k_before_rerank` | 重排序前保留的候选结果数 | 35 |
| `model` | 使用的重排序模型 | - |

该参数默认值从 20 提高到 35，以防止长描述性查询中的相关文件在重排序前被错误排除。

资料来源：[CHANGELOG.md]()

## 7. 搜索工具（Ask Memory MCP）

Ask Memory 是一个 MCP（Model Context Protocol）工具，封装了搜索引擎用于 AI 对话助手的问答场景。

### 7.1 工作流程

```mermaid
graph TD
    A[用户问题] --> B[混合检索]
    B --> C[上下文组装]
    C --> D[Ollama Generate]
    D --> E[返回答案 + 引用来源]
    
    F[Ollama 不可用] -.-> G[返回来源列表 + 安装提示]
    G --> E
```

### 7.2 返回格式

```python
class AskMemoryResponse:
    answer: str | None       # LLM 生成的回答
    sources: list[SearchHit] # 搜索命中文档
    model: str               # 使用的模型名称
    ollama_available: bool   # Ollama 是否可用
    hint: str | None         # 仅在不可用时返回
```

### 7.3 降级策略

当 Ollama 本地 LLM 服务不可用时，系统会优雅降级：返回原始搜索结果列表，并在响应中包含安装提示（hint），确保不会因 LLM 不可用而完全失败。

资料来源：[ARCHITECTURE.md]()

## 8. Web 界面

### 8.1 搜索页面

MemoryMesh 提供基于 FastAPI + HTMX 的 Web 搜索界面，支持用户直接输入查询词进行搜索。搜索结果以 HTML 形式渲染展示。

### 8.2 路由定义

| 路由 | 方法 | 功能 |
|------|------|------|
| `/search` | GET/POST | 搜索页面，支持 `mode` 参数（dense/sparse/hybrid） |

```html
<!-- 搜索表单示例 -->
<form method="get" action="/search">
  <input name="q" placeholder="输入搜索内容...">
  <select name="mode">
    <option value="hybrid" selected>Hybrid</option>
    <option value="dense">Dense</option>
    <option value="sparse">Sparse</option>
  </select>
  <button type="submit">Search</button>
</form>
```

资料来源：[src/memorymesh/server/dashboard.py]()

## 9. 配置示例

在 `config.yaml` 中配置搜索相关参数：

```yaml
search:
  embedding_model: sentence-transformers/all-MiniLM-L6-v2
  dense:
    top_k: 10
  sparse:
    top_k: 10
  reranker:
    enabled: true
    top_k_before_rerank: 35
  query_expansion:
    enabled: true
    n_lexical_variants: 1
```

## 10. 依赖关系

| 依赖项 | 用途 |
|--------|------|
| `sentence-transformers` | 文本嵌入模型 |
| `faiss` 或 `chromadb` | 向量数据库 |
| `Ollama` | 本地 LLM 推理 |
| `fastapi` | Web 服务框架 |
| `httpx` | HTTP 客户端 |

## 11. 相关文档

- [架构总览](./ARCHITECTURE.md)
- [配置指南](./CONFIG.md)
- [API 参考](./API.md)
- [MCP 工具文档](./MCP_TOOLS.md)

---

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

## 结果重排序

### 相关页面

相关主题：[搜索引擎](#page-search-engine)

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

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

- [src/memorymesh/search/reranker.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/search/reranker.py)
- [src/memorymesh/core/models/config.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/core/models/config.py)
- [src/memorymesh/search/engine.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/search/engine.py)
- [src/memorymesh/search/models.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/search/models.py)
- [CHANGELOG.md](https://github.com/kilhubprojects/memory-mesh/blob/main/CHANGELOG.md)
- [ARCHITECTURE.md](https://github.com/kilhubprojects/memory-mesh/blob/main/ARCHITECTURE.md)
</details>

# 结果重排序

结果重排序（Result Reranking）是 MemoryMesh 搜索系统中提升检索精度的核心机制。该模块在完成初步检索后，通过交叉编码器（Cross-Encoder）对候选结果进行深度语义相关性评分，从而修正纯向量检索可能产生的排序偏差。

## 工作原理

MemoryMesh 采用典型的两阶段检索架构：**密集检索（Dense Retrieval）** → **结果重排序（Reranking）**。

```mermaid
graph TD
    A[用户查询] --> B[密集检索阶段]
    B --> C[召回 Top-N 候选结果<br/>top_k_before_rerank]
    C --> D[重排序阶段]
    D --> E[交叉编码器评分]
    E --> F[按相关性重新排序]
    F --> G[返回 Top-K 最终结果<br/>top_k]
    C -.->|候选集过大<br/>影响精度| D
```

第一阶段使用密集向量检索快速从大规模语料中召回候选文档；第二阶段通过语义更精准的交叉编码器对候选集进行细粒度排序，最终输出高相关性的结果列表。

资料来源：[ARCHITECTURE.md:1-50]()

## 配置参数

重排序功能通过 `SearchRerankerConfig` 进行配置，主要参数如下：

| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `enabled` | `bool` | `True` | 是否启用重排序 |
| `model` | `str` | `"cross-encoder"` | 交叉编码器模型标识 |
| `top_k_before_rerank` | `int` | `35` | 重排序前保留的候选结果数量 |
| `top_k` | `int` | `5` | 最终返回的结果数量 |

> **配置变更历史**：在 v1.2.0 版本中，`top_k_before_rerank` 的默认值从 `20` 提升至 `35`。此调整旨在防止长描述性查询中相关文档在重排序前被过早过滤，从而提升召回率。

资料来源：[src/memorymesh/core/models/config.py:1-100]()
资料来源：[CHANGELOG.md:1-50]()

## 交叉编码器模型

重排序阶段使用的交叉编码器接收查询与文档对（query-document pair），输出单一相关性分数。相比于双编码器（Bi-Encoder）分别编码查询和文档的方式，交叉编码器能够在注意力机制中直接建模两者的交互关系，从而捕获更精细的语义关联。

```mermaid
graph LR
    subgraph 交叉编码器
        Q[Query Token序列] -->|拼接| M[联合输入]
        D[Document Token序列] -->|拼接| M
        M --> AT[Attention层]
        AT --> FC[全连接层]
        FC --> S[相关性分数: 0-1]
    end
```

模型输出范围为 0 到 1 的浮点数，其中：
- `1.0` 表示极高相关性
- `0.0` 表示完全不相关

资料来源：[src/memorymesh/search/reranker.py:1-80]()

## 搜索流程集成

重排序模块嵌入在 `SearchEngine` 的完整检索管线中：

```mermaid
graph TD
    A[search_query] --> B[QueryExpansion]
    B --> C[并行向量检索<br/>ThreadPoolExecutor]
    C --> D[融合多路检索结果]
    D --> E{top_k_before_rerank<br/>≥ top_k?}
    E -->|是| F[交叉编码器重排序]
    F --> G[返回Top-K结果]
    E -->|否| G
```

> **并行优化**：`SearchEngine` 已使用 `ThreadPoolExecutor` 实现多路查询变体的并行检索，提升整体响应速度。

资料来源：[src/memorymesh/search/engine.py:1-100]()
资料来源：[CHANGELOG.md:30-40]()

## 与其他搜索组件的关系

| 组件 | 作用阶段 | 输入 | 输出 |
|------|----------|------|------|
| QueryExpansion | 预处理 | 用户原始查询 | 扩展查询变体列表 |
| EmbeddingProvider | 密集检索 | 查询文本 | 向量表示 |
| VectorStore | 检索 | 查询向量 | Top-N 候选文档 |
| **Reranker** | **重排序** | **候选文档 + 查询** | **重排序后的文档列表** |
| SearchReranker | 最终封装 | 重排序结果 | SearchHit 列表 |

资料来源：[src/memorymesh/search/models.py:1-50]()

## 使用示例

```python
from memorymesh.core.models.config import SearchConfig, SearchRerankerConfig
from memorymesh.search.engine import SearchEngine

# 配置重排序参数
reranker_cfg = SearchRerankerConfig(
    enabled=True,
    top_k_before_rerank=35,
    top_k=5,
)

search_cfg = SearchConfig(
    top_k=5,
    reranker=reranker_cfg,
)

# 初始化搜索引擎
engine = SearchEngine(config=search_cfg, ...)

# 执行搜索（自动触发重排序）
results = engine.search("项目架构设计原则")
```

## 性能考量

1. **候选集大小权衡**：`top_k_before_rerank` 过小可能导致遗漏相关文档，过大则增加交叉编码器的计算开销。默认值 `35` 在大多数场景下取得较好平衡。

2. **模型选择**：交叉编码器模型直接影响重排序质量与推理速度。生产环境可根据硬件条件选择轻量级或高精度模型。

3. **异步支持**：重排序阶段可与密集检索并行执行，通过合理的调度策略进一步降低端到端延迟。

资料来源：[ARCHITECTURE.md:50-100]()

## 配置示例

```yaml
search:
  top_k: 5
  reranker:
    enabled: true
    model: "cross-encoder/ms-marco-MiniLM-L-6-v2"
    top_k_before_rerank: 35
```

该配置启用重排序功能，使用 `ms-marco-MiniLM-L-6-v2` 交叉编码器模型，在重排序前保留 35 个候选结果，最终返回 5 条最相关文档。

---

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

## 数据连接器

### 相关页面

相关主题：[MCP 工具参考](#page-mcp-tools)

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

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

- [src/memorymesh/connectors/registry.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/connectors/registry.py)
- [src/memorymesh/connectors/confluence_connector.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/connectors/confluence_connector.py)
- [src/memorymesh/connectors/roam_connector.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/connectors/roam_connector.py)
- [src/memorymesh/connectors/logseq_connector.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/connectors/logseq_connector.py)
- [src/memorymesh/parsing/obsidian_parser.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/parsing/obsidian_parser.py)
- [src/memorymesh/parsing/notion_parser.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/parsing/notion_parser.py)
</details>

# 数据连接器

## 概述

数据连接器（Connector）是 MemoryMesh 系统用于从外部数据源提取文档的核心模块。每个连接器实现特定平台的协议解析与数据拉取，将来自不同知识管理工具的原始数据转换为统一的 `ParsedDocument` 数据模型。

连接器的设计遵循以下原则：

- **统一接口** - 所有连接器实现 `fetch_documents()` 方法，返回 `Iterator[ParsedDocument]`
- **配置驱动** - 每个连接器配套一个 Pydantic 配置类，通过 `config.yaml` 声明式配置
- **懒加载注册** - 连接器通过 `CONNECTOR_REGISTRY` 字典按需注册，最小化导入开销
- **解析器协同** - 部分连接器（如 Notion、Obsidian）依赖配套的解析器完成文件级别的数据转换

资料来源：[src/memorymesh/connectors/registry.py:1-20]()

## 架构设计

### 组件关系图

```mermaid
graph TD
    A[config.yaml] --> B[ConnectorConfig]
    B --> C[Connector]
    C --> D{fetch_documents}
    D --> E[Iterator[ParsedDocument]]
    E --> F[FileIndexer]
    F --> G[Chunker]
    G --> H[EmbeddingProvider]
    H --> I[VectorStore]
    
    J[CONNECTOR_REGISTRY] --> C
    K[HTTP Auth] --> C
```

### 连接器类型矩阵

| 类型标识 | 连接器类 | 配置类 | 数据源 | 认证方式 |
|---------|---------|-------|--------|---------|
| `confluence` | ConfluenceConnector | ConfluenceConfig | Confluence Cloud REST API | HTTP Basic |
| `roam` | RoamConnector | RoamConfig | JSON 导出文件 | 无（本地文件） |
| `logseq` | LogseqConnector | LogseqConfig | Graph 目录 | 无（本地文件） |
| `notion` | NotionConnector | NotionConfig | Notion API | OAuth/API Token |
| `jira` | JiraConnector | JiraConfig | Jira REST API | HTTP Basic |

资料来源：[src/memorymesh/connectors/registry.py:25-50]()

## 连接器注册机制

### 注册表结构

`CONNECTOR_REGISTRY` 是一个字典，将连接器类型字符串映射到 `(ConfigClass, ConnectorClass)` 元组：

```python
CONNECTOR_REGISTRY: dict[str, tuple[Any, Any]] = {}
```

注册在 `_register()` 函数中通过延迟导入完成，避免在模块初始化时导入所有依赖：

```python
def _register() -> None:
    """Populate CONNECTOR_REGISTRY with all known connectors."""
    from memorymesh.connectors.airtable_connector import (
        AirtableConfig,
        AirtableConnector,
    )
    # ... 其他连接器导入
```

资料来源：[src/memorymesh/connectors/registry.py:15-40]()

### 使用方式

CLI 命令通过注册表动态实例化连接器：

```python
cfg_cls, conn_cls = CONNECTOR_REGISTRY["jira"]
config_obj = cfg_cls(**raw_config_dict)
connector = conn_cls(config_obj)
for doc in connector.fetch_documents():
    indexer.index_parsed_document(doc)
```

## Confluence 连接器

### 功能特性

- **偏移分页** - 通过 `start` / `limit` 参数迭代获取所有页面
- **空间过滤** - 可选限制特定空间密钥（space keys）
- **HTML 清洗** - 将 `storage` 格式的页面体转换为纯文本
- **日期过滤** - 跳过 `days_past` 时间窗口外的页面

资料来源：[src/memorymesh/connectors/confluence_connector.py:1-30]()

### 配置参数

| 参数 | 类型 | 必填 | 说明 |
|-----|------|-----|------|
| `base_url` | str | 是 | Confluence Cloud 实例 URL |
| `email` | SecretStr | 是 | Atlassian 账户邮箱 |
| `api_token` | SecretStr | 是 | API Token（从 id.atlassian.com 生成） |
| `space_keys` | list[str] | 否 | 限制的空间密钥列表 |
| `days_past` | int | 否 | 保留最近 N 天内的页面（默认 90） |

### 认证实现

HTTP Basic 认证使用 `email:api_token` 组合的 base64 编码：

```python
from memorymesh.connectors._auth import basic_header
```

资料来源：[src/memorymesh/connectors/confluence_connector.py:40-45]()

## Roam Research 连接器

### 功能特性

- **递归块扁平化** - 将嵌套块树展平为纯文本字符串
- **Roam 语法清洗** - 移除 `{{[[...]]}}` 模板引用、`[[...]]` 页面引用、`#[[...]]` 和 `#tag` 标签语法
- **日期过滤** - 跳过 `create-time` 或 `edit-time` 超出 `days_past` 窗口的页面
- **空页面跳过** - 跳过无块内容的页面

资料来源：[src/memorymesh/connectors/roam_connector.py:1-35]()

### 导出格式

Roam 导出为单个 JSON 文件，包含页面对象数组，每个对象具有：

- `title` - 字符串
- `children` - 嵌套块对象列表（块可递归包含 `children`）

### 语法模式处理

按顺序应用多个正则表达式清洗 Roam 特定语法：

```python
_ROAM_PATTERNS: list[re.Pattern[str]] = [
    re.compile(r"\{\{(\[\[.*?\]\])"),  # 模板引用
    re.compile(r"\[\[.*?\]\]"),        # 页面引用
    re.compile(r"#\[\[.*?\]\]"),       # 标签页面引用
    re.compile(r"#\w+"),               # 标签
]
```

资料来源：[src/memorymesh/connectors/roam_connector.py:55-60]()

## Logseq 连接器

### 功能特性

- **多目录扫描** - 扫描 `pages/` 和 `journals/` 子目录
- **语法转换** - 处理 Logseq 特定语法
- **属性提取** - 从 `key:: value` 属性行提取元数据
- **维基链接追踪** - 提取并去重的 `[[wikilinks]]` 存储在元数据中
- **日记标记** - 期刊文件标记 `is_journal=True`

资料来源：[src/memorymesh/connectors/logseq_connector.py:1-40]()

### Logseq 语法处理对照表

| 原始语法 | 处理方式 | 示例 |
|---------|---------|------|
| `((uuid))` | 转换为 `[block]` | `((abc123...))` → `[block]` |
| `{{embed [[Page]]}}` | 转换为 `[embed: Page]` | `{{embed [[Note]]}}` → `[embed: Note]` |
| `{{query ...}}` | 完全移除 | `{{query [[tag]]}}` → 移除 |
| `key:: value` | 提取到元数据，从正文移除 | `tags:: #work` → metadata["tags"] |
| `[[wikilinks]]` | 保留原样 | `[[Page A]]` → `[[Page A]]` |
| `- ` 块符号 | 保留为纯文本 | `- content` → `content` |

资料来源：[src/memorymesh/connectors/logseq_connector.py:45-70]()

### 文档处理流程

```mermaid
graph LR
    A[Markdown 文件] --> B[_process_file]
    B --> C{文件存在?}
    C -->|否| D[跳过]
    C -->|是| E[读取文本]
    E --> F[正则替换]
    F --> G[属性提取]
    G --> H[Wikilinks 提取]
    H --> I[ParsedDocument]
```

资料来源：[src/memorymesh/connectors/logseq_connector.py:90-120]()

## 配套解析器

部分数据源需要专门的解析器处理文件格式，而非通过连接器直接拉取。

### Notion HTML 解析器

Notion 导出为单个 `.html` 文件，解析器从文件名提取 UUID、从 `<h1>` 或 `<title>` 提取标题：

```python
# UUID 模式：Page Title a1b2c3...html
_UUID_FILENAME_RE = re.compile(
    r"([0-9a-f]{8}(?:[0-9a-f]{4}){3}[0-9a-f]{12})(?:\s|\.|$)",
    re.IGNORECASE,
)
```

支持扩展名：`.html`, `.htm`

提取的元数据字段：

- `notion_id` - 页面 UUID
- `database_name` - 父目录名
- `db_properties` - 数据库属性列表

资料来源：[src/memorymesh/parsing/notion_parser.py:25-45]()

### Obsidian Markdown 解析器

Obsidian 解析器扩展基础 Markdown 解析：

| 功能 | 说明 |
|-----|------|
| YAML Frontmatter | 提取 `tags`、`aliases`、`created`、`modified` 字段 |
| Wikilink 提取 | 匹配 `[[link]]` 和 `[[link\|alias]]` 模式 |
| 内嵌过滤 | 排除 `![[img]]` 图片引用 |
| 标签提取 | 从 frontmatter 和行内 `#tag` 提取标签 |

支持的 frontmatter 字段映射：

| Frontmatter 字段 | Metadata 键 |
|----------------|------------|
| `tags` | `tags` |
| `aliases` | `aliases` |
| `created` | `created` |
| `modified` | `modified` |

资料来源：[src/memorymesh/parsing/obsidian_parser.py:25-55]()

### Frontmatter 解析正则

```python
_FRONTMATTER_RE = re.compile(
    r"^---\r?\n(.*?)\r?\n(?:---|\.\.\.)(?:\r?\n|$)",
    re.DOTALL,
)
_WIKILINK_RE = re.compile(r"(?<!!)\[\[([^\[\]|#]+?)(?:\|[^\[\]]*?)?\]\]")
```

## HTTP 辅助模块

### 认证模块 (`_auth.py`)

提供基础认证头生成：

```python
from memorymesh.connectors._auth import basic_header
```

支持标准 HTTP Basic 认证，用于 Confluence、Jira 等需要用户名/令牌的服务。

### HTTP 模块 (`_http.py`)

提供统一的 API 请求方法：

```python
from memorymesh.connectors._http import api_get
```

主要功能：

- 自动添加认证头
- 错误处理与日志记录
- JSON 响应解析

## 通用数据模型

### ParsedDocument 结构

所有连接器返回统一的 `ParsedDocument` 对象：

| 字段 | 类型 | 说明 |
|-----|------|------|
| `path` | Path | 文件路径 |
| `text` | str | 提取的纯文本内容 |
| `file_type` | str | 规范化扩展名（如 `.md`、`.html`） |
| `encoding` | str | 文本编码 |
| `metadata` | dict | 源特定元数据 |

### 配置基类模式

每个连接器遵循统一配置模式：

```python
from pydantic import BaseModel

class ConnectorConfig(BaseModel):
    export_path: Path | None = None      # 本地文件模式
    days_past: int = 365                 # 日期过滤窗口
```

## 使用示例

### 配置声明

在 `config.yaml` 中声明数据源：

```yaml
sources:
  - name: confluence-wiki
    type: confluence
    config:
      base_url: "https://myorg.atlassian.net"
      email: "me@example.com"
      api_token: "${CONFLUENCE_TOKEN}"
      space_keys: ["ENG", "DOCS"]
      days_past: 90
```

### 代码使用

```python
from memorymesh.connectors.registry import CONNECTOR_REGISTRY

# 通过注册表实例化
cfg_cls, conn_cls = CONNECTOR_REGISTRY["confluence"]
config = cfg_cls(**source_config["config"])
connector = conn_cls(config)

# 迭代文档
for doc in connector.fetch_documents():
    indexer.index_parsed_document(doc)
```

## 扩展新连接器

添加新连接器的步骤：

1. **创建连接器文件** - 在 `src/memorymesh/connectors/` 下创建 `xxx_connector.py`
2. **定义配置类** - 创建 `XxxConfig(BaseModel)` 配置模型
3. **实现连接器类** - 创建 `XxxConnector` 实现 `fetch_documents()` 方法
4. **注册连接器** - 在 `registry.py` 的 `_register()` 函数中添加导入语句

```mermaid
graph TD
    A[创建 xxx_connector.py] --> B[定义 XxxConfig]
    B --> C[实现 XxxConnector]
    C --> D[实现 fetch_documents]
    D --> E[更新 registry.py]
```

## 注意事项

- **认证安全** - API Token 等敏感信息建议使用环境变量注入（`${VAR_NAME}` 语法）
- **文件锁定** - 本地文件模式（如 Roam、Logseq）直接读取文件，注意并发写入
- **分页处理** - API 类连接器需妥善处理分页，避免漏掉数据
- **日期时区** - 日期比较使用 `datetime` 模块，配置 `UTC` 时区处理

---

<a id='page-mcp-tools'></a>

## MCP 工具参考

### 相关页面

相关主题：[搜索引擎](#page-search-engine), [数据连接器](#page-connectors)

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

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

- [src/memorymesh/server/tools/search_memory.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/server/tools/search_memory.py)
- [src/memorymesh/server/tools/ask_memory.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/server/tools/ask_memory.py)
- [src/memorymesh/server/tools/list_sources.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/server/tools/list_sources.py)
- [src/memorymesh/server/tools/get_document.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/server/tools/get_document.py)
- [src/memorymesh/server/tools/graph_memory.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/server/tools/graph_memory.py)
- [src/memorymesh/server/tools/pin_memory.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/server/tools/pin_memory.py)
- [src/memorymesh/server/tools/forget_memory.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/server/tools/forget_memory.py)
- [src/memorymesh/server/app.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/server/app.py)
- [src/memorymesh/core/models/search.py](https://github.com/kilhubprojects/memory-mesh/blob/main/src/memorymesh/core/models/search.py)
</details>

# MCP 工具参考

MemoryMesh 通过 FastMCP 框架提供一组 MCP（Model Context Protocol）工具，使 LLM 客户端能够访问用户的本地知识库。所有工具均注册在 `FastMCP` 实例上，支持搜索、检索、索引管理、内存分层和知识图谱查询等核心功能。

## 工具概览

MemoryMesh MCP 工具分为以下几大类：

| 类别 | 工具 | 功能描述 |
|------|------|----------|
| **搜索检索** | `search_memory` | 混合检索（向量 + BM25） |
| | `ask_memory` | RAG 问答（基于 Ollama） |
| | `search_by_date` | 按时间范围检索 |
| | `related_documents` | 查找相关文档 |
| **文档管理** | `list_sources` | 列出配置的索引源 |
| | `get_document` | 获取完整文档内容 |
| | `summarize_source` | 生成文档摘要 |
| **索引控制** | `index_now` | 触发立即重建索引 |
| | `sync_source` | 同步数据源 |
| **内存分层** | `pin_memory` | 将分块固定到热层 |
| | `unpin_memory` | 解除固定 |
| | `forget_memory` | 抑制或冷置分块 |
| **知识图谱** | `graph_memory` | 共现图查询 |
| | `get_entity` | 获取实体信息 |
| **时间线** | `query_timeline` | 查询活动历史 |

资料来源：[src/memorymesh/server/app.py:36-52]()

## 工具注册机制

所有 MCP 工具通过统一的注册函数 `register(mcp, ctx)` 挂载到 FastMCP 实例：

```python
def create_mcp(ctx: AppContext) -> FastMCP:
    mcp: FastMCP = FastMCP(
        name="memorymesh",
        instructions=(
            "MemoryMesh gives you read access to the user's personal knowledge "
            "base — local files indexed from configured source directories.  "
            "Use search_memory to find relevant passages, list_sources to "
            "explore what has been indexed, get_document to read a full file, "
            "index_now to trigger an immediate re-index, and ask_memory to "
            "get an LLM-generated answer from your indexed content..."
        ),
    )
    
    # 注册所有工具
    search_memory.register(mcp, ctx)
    list_sources.register(mcp, ctx)
    get_document.register(mcp, ctx)
    index_now.register(mcp, ctx)
    ask_memory.register(mcp, ctx)
    # ... 其他工具
```

工具注册采用依赖注入模式，`ctx`（AppContext）包含所有运行时依赖：搜索引擎、元数据存储、审计日志等。

## 搜索检索类工具

### search_memory

混合检索工具，结合密集向量检索（embedding）和稀疏 BM25 检索。

**函数签名：**

```python
@mcp.tool()
async def search_memory(
    query: Annotated[str, "要搜索的自然语言查询"],
    top_k: Annotated[int, "返回的最大结果数"] = 5,
    mode: Annotated[
        Literal["hybrid", "dense", "sparse"],
        "hybrid: 密集+稀疏混合; dense: 仅向量; sparse: 仅BM25"
    ] = "hybrid",
    source_filter: Annotated[
        list[str] | None,
        "限制搜索的源名称列表"
    ] = None,
    modality: Annotated[
        Literal["all", "text", "image"],
        "搜索的模态类型"
    ] = "all",
) -> SearchResponse
```

**返回类型（SearchResponse）：**

| 字段 | 类型 | 说明 |
|------|------|------|
| `hits` | `list[SearchHit]` | 排序后的搜索结果列表 |
| `mode` | `"hybrid" \| "dense" \| "sparse"` | 使用的检索模式 |
| `duration_ms` | `float` | 查询总延迟（毫秒） |

资料来源：[src/memorymesh/core/models/search.py:1-30]()

### ask_memory

RAG 问答工具，基于 Ollama 本地 LLM 生成答案。

**核心机制：**

```
用户问题 → search_memory → 构建上下文 → Ollama generate → 答案 + 引用源
```

**函数签名：**

```python
@mcp.tool()
async def ask_memory(
    question: str,
    top_k: int = 5,
    model: str | None = None,
) -> AskMemoryResponse
```

**上下文构建参数：**

- `_MAX_CONTEXT_CHARS_PER_HIT = 800`：每个来源片段最多包含 800 字符

**系统提示词模板：**

```python
_RAG_SYSTEM_PREAMBLE = (
    "You are a helpful assistant answering questions about the user's personal "
    "knowledge base. Use only the provided source passages to answer. "
    "If the answer is not in the sources, say so clearly. "
    "Cite the source file paths when relevant."
)
```

**返回类型（AskMemoryResponse）：**

| 字段 | 类型 | 说明 |
|------|------|------|
| `answer` | `str \| None` | LLM 生成的答案 |
| `sources` | `list[SearchHit]` | 检索到的来源片段 |
| `model` | `str` | 使用的 Ollama 模型 |
| `ollama_available` | `bool` | Ollama 是否可用 |
| `hint` | `str \| None` | 仅在 Ollama 不可用时返回安装提示 |

> **容错设计**：当 Ollama 不可用时，`ask_memory` 仍返回检索结果和安装提示，绝不静默失败。

资料来源：[src/memorymesh/server/tools/ask_memory.py:1-50]()

### search_by_date

按时间范围检索文档变更历史。

**典型用途：** 查找特定时间段内修改过的文件内容。

### related_documents

基于共现关系查找相关文档，输入一个 chunk_id，返回与其在相同上下文中出现的其他文档。

## 文档管理类工具

### list_sources

列出所有配置的索引源及其统计信息。

**返回类型（SourcesReport）：**

```python
class SourcesReport(BaseModel):
    sources: list[SourceStats]

class SourceStats(BaseModel):
    name: str                    # 源名称
    path: str                    # 源路径
    recursive: bool              # 是否递归
    n_files_indexed: int         # 已索引文件数
    n_files_pending: int         # 待处理文件数
    n_files_errored: int         # 错误文件数
    last_scan_at: float | None   # 上次扫描时间
    total_chunks: int            # 总分块数
    disk_size_bytes: int         # 磁盘占用
```

### get_document

获取完整文档内容。

**函数签名：**

```python
@mcp.tool()
async def get_document(
    path: Annotated[str, "文档的绝对路径"],
    max_bytes: Annotated[int, "最大读取字节数"] = 1_000_000,
) -> DocumentResponse
```

**返回类型（DocumentResponse）：**

| 字段 | 类型 | 说明 |
|------|------|------|
| `path` | `str` | 文档绝对路径 |
| `content` | `str` | 文件内容（可能截断） |
| `file_type` | `str` | 标准化文件扩展名 |
| `size_bytes` | `int` | 原始文件大小 |
| `mtime` | `float` | 修改时间戳 |
| `truncated` | `bool` | 是否被截断 |

**异常处理：**

- `DocumentNotFoundError`：路径不在任何配置的源中
- `DocumentTooLargeError`：文件超过 `max_bytes`，返回开头 + 摘要

资料来源：[src/memorymesh/core/models/search.py:45-70]()

### summarize_source

对指定源目录生成摘要信息，支持深度分析和要点提取。

## 索引控制类工具

### index_now

强制重新索引指定路径。

```python
@mcp.tool()
async def index_now(
    path: str,
    recursive: bool = True,
) -> IndexResponse
```

**约束条件：**

- 路径必须在某个配置的源目录内
- 返回处理统计：文件数、分块数、耗时

### sync_source

同步数据源，扫描新增、修改和删除的文件，更新索引。

## 内存分层类工具

MemoryMesh 支持内存分层（Memory Tiers），将分块分为 hot、warm、cold 层级，实现访问频率感知的存储优化。

### 内存层级说明

| 层级 | 说明 | 自动行为 |
|------|------|----------|
| **hot** | 热点数据，高频访问 | 手动固定或自动提升 |
| **warm** | 温数据 | 定期维护时根据访问频率调整 |
| **cold** | 冷数据 | 逐步降级，评分衰减 |

### pin_memory / unpin_memory

将分块固定到热层或解除固定。

```python
@mcp.tool()
def pin_memory(
    chunk_id: Annotated[str, "分块标识符，格式为 '<path>:<chunk_index>'"],
) -> dict:
    """固定分块到热层"""
    return {"chunk_id": chunk_id, "tier": "hot", "pinned": True}

@mcp.tool()
def unpin_memory(
    chunk_id: Annotated[str, "分块标识符，格式为 '<path>:<chunk_index>'"],
) -> dict:
    """解除固定，允许正常层级调整"""
    return {"chunk_id": chunk_id, "pinned": False}
```

> 解除固定后，分块在下次维护运行前保留在热层，之后根据访问历史进行升降级。

资料来源：[src/memorymesh/server/tools/pin_memory.py:1-60]()

### forget_memory

抑制或冷置分块，实现内容的渐进式遗忘。

```python
@mcp.tool()
def forget_memory(
    chunk_id: Annotated[
        str,
        "分块标识符，格式为 '<absolute_path>:<chunk_index>'",
    ],
    mode: Annotated[
        Literal["suppress", "cold"],
        "'suppress': 立即隐藏; 'cold': 降级到冷层，评分逐渐衰减"
    ] = "suppress",
) -> dict
```

**模式对比：**

| 模式 | 行为 | 可逆性 |
|------|------|--------|
| `suppress` | 加入抑制列表，立即从搜索结果中隐藏 | 不可逆（需直接数据库访问） |
| `cold` | 降级到冷层，评分逐渐衰减 | 可通过 `pin_memory` 恢复 |

资料来源：[src/memorymesh/server/tools/forget_memory.py:1-50]()

## 知识图谱类工具

### graph_memory

共现图查询工具，基于实体共现关系构建知识图谱。

**典型用途：**

- 发现概念间的关联
- 探索特定实体类型的分布
- 设定最小提及阈值过滤噪声

**服务端缓存：** 图数据在服务器端缓存 60 秒，减少重复计算。

### get_entity

查询特定实体的详细信息，包括属性、关系和上下文。

## 时间线类工具

### query_timeline

查询活动历史记录，包括索引操作、查询历史和变更事件。

**审计日志字段：**

| 字段 | 说明 |
|------|------|
| `ts` | 时间戳 |
| `tool` | 调用的工具名称 |
| `query_hash` | 查询的 SHA256 哈希（截断至 16 字符） |
| `n_results` | 返回结果数 |
| `latency_ms` | 延迟（毫秒） |
| `client_id_if_known` | 客户端标识（已知时） |

> **隐私保护**：审计日志不包含文档内容、chunk 内容或明文查询。

## 工具调用流程

```mermaid
sequenceDiagram
    participant Client as LLM 客户端
    participant MCP as FastMCP 服务器
    participant Engine as 搜索引擎
    participant DB as 元数据存储
    participant Ollama as Ollama LLM

    Client->>MCP: search_memory(query, top_k)
    MCP->>Engine: 混合检索
    Engine->>DB: 查询向量 + BM25
    DB-->>Engine: SearchHit 列表
    Engine-->>MCP: SearchResponse
    MCP-->>Client: hits + duration_ms

    Client->>MCP: ask_memory(question)
    MCP->>MCP: search_memory(question, top_k)
    MCP->>Ollama: generate(RAG_prompt)
    Ollama-->>MCP: answer
    MCP-->>Client: AskMemoryResponse

    Note over Client,DB: 写操作（index_now、pin_memory 等）
    Client->>MCP: index_now(path)
    MCP->>DB: 验证路径有效性
    MCP->>Engine: 重新索引
    Engine->>DB: 更新元数据
    DB-->>MCP: IndexResponse
    MCP-->>Client: 处理统计
```

## 访问控制与审计

### 认证守卫

工具注册时通过 `check_access(ctx, operation)` 检查访问权限：

```python
from memorymesh.server.auth_guard import check_access

if (err := check_access(ctx, "index")) is not None:
    return err
```

### 审计日志

每次工具调用都会记录到 `~/.memorymesh/audit.jsonl`：

```json
{"ts": 1703001234.567, "tool": "search_memory", "query_hash": "a1b2c3d4e5f6g7h8", "n_results": 5, "latency_ms": 42.3}
```

## 配置与扩展

### 配置来源优先级

```python
_DEFAULT_SEARCH_PATHS = [
    Path.cwd() / "config.yaml",           # 1. 当前工作目录
    Path.home() / ".memorymesh" / "config.yaml",  # 2. 用户配置目录
]
```

### 必需配置示例

```yaml
sources:
  - name: documents
    path: ~/Documents
    recursive: true
    extensions: [.txt, .md, .pdf]

embeddings:
  model: "sentence-transformers/all-MiniLM-L6-v2"

ollama:
  enabled: true
  model: "llama2"
```

## 错误处理规范

| 错误类型 | 返回方式 | 说明 |
|----------|----------|------|
| 配置错误 | 抛出 `ConfigError` | YAML 解析或验证失败 |
| 文档未找到 | 返回 `DocumentNotFoundError` | 路径不在任何源中 |
| 文档过大 | 返回部分内容 + `DocumentTooLargeError` | 包含开头和摘要 |
| Ollama 不可用 | 返回 `hint` | `ask_memory` 的容错机制 |
| 访问被拒 | 返回错误字典 | `check_access` 拦截 |

## 工具元数据速查

| 工具名称 | 返回类型 | 异步 | LLM 依赖 |
|----------|----------|------|----------|
| `search_memory` | `SearchResponse` | ✅ | ❌ |
| `ask_memory` | `AskMemoryResponse` | ✅ | Ollama |
| `list_sources` | `SourcesReport` | ❌ | ❌ |
| `get_document` | `DocumentResponse` | ✅ | ❌ |
| `index_now` | `IndexResponse` | ✅ | ❌ |
| `pin_memory` | `dict` | ❌ | ❌ |
| `unpin_memory` | `dict` | ❌ | ❌ |
| `forget_memory` | `dict` | ❌ | ❌ |
| `graph_memory` | `dict` | ❌ | ❌ |
| `get_entity` | `dict` | ❌ | ❌ |
| `query_timeline` | `dict` | ❌ | ❌ |
| `search_by_date` | `SearchResponse` | ❌ | ❌ |
| `related_documents` | `list[SearchHit]` | ❌ | ❌ |
| `summarize_source` | `dict` | ❌ | ❌ |
| `sync_source` | `dict` | ❌ | ❌ |

资料来源：[src/memorymesh/server/app.py:36-52]()

---

---

## Doramagic 踩坑日志

项目：kilhubprojects/memory-mesh

摘要：发现 6 个潜在踩坑项，其中 0 个为 high/blocking；最高优先级：能力坑 - 能力判断依赖假设。

## 1. 能力坑 · 能力判断依赖假设

- 严重度：medium
- 证据强度：source_linked
- 发现：README/documentation is current enough for a first validation pass.
- 对用户的影响：假设不成立时，用户拿不到承诺的能力。
- 建议检查：将假设转成下游验证清单。
- 防护动作：假设必须转成验证项；没有验证结果前不能写成事实。
- 证据：capability.assumptions | github_repo:1238654023 | https://github.com/kilhubprojects/memory-mesh | README/documentation is current enough for a first validation pass.

## 2. 维护坑 · 维护活跃度未知

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

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

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

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

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

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

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

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

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

<!-- canonical_name: kilhubprojects/memory-mesh; human_manual_source: deepwiki_human_wiki -->
