内容
<p align="center">
<img src="https://img.shields.io/badge/python-3.10+-blue?logo=python&logoColor=white" />
<img src="https://img.shields.io/badge/license-MIT-green" />
<img src="https://img.shields.io/badge/Ollama-ready-orange?logo=ollama&logoColor=white" />
<img src="https://img.shields.io/badge/MCP-server-purple" />
<img src="https://img.shields.io/badge/LanceDB-vector--db-brightgreen" />
</p>
<p align="center">
<img src="docs/banner.jpeg" alt="Roowet Semantic Vault Search" width="75%" />
</p>
# 语义保险库 MCP
**适用于 Obsidian 保险库的本地 RAG 语义搜索,由 Ollama + LanceDB + MCP 提供支持。**
通过**含义**(而非关键词匹配)搜索你的 Markdown 保险库。完全本地运行 — 零 API 成本,零数据离开你的机器。
```
用户查询 → Ollama 嵌入 → LanceDB 向量搜索 → 相关片段 → LLM 上下文
```
## 功能
- 🔍 **语义搜索** — 按概念而非关键词查找笔记
- 🚀 **批量嵌入** — 比串行快 30-50 倍(每次 HTTP 调用 50 个片段)
- 👁️ **自动文件监视器** — 文件更改时重新索引(通过 watchdog)
- 🧩 **MCP 服务器** — Claude Desktop / Claude Code / Hermes 的即插即用工具
- 💾 **持久哈希存储** — 增量索引,仅重新索引更改的内容
- 🔄 **崩溃安全** — Ollama 的断路器,批量写入 LanceDB
## 快速开始
### 先决条件
- Python 3.10+
- [Ollama](https://ollama.com) 在本地运行
- Obsidian 保险库(或任意 Markdown 文件夹)
### 1. 安装
```bash
# 克隆
git clone https://github.com/brodewa369/roowet-semantic-vault-search.git
cd semantic-vault-mcp
# Windows
setup.bat
# Linux/Mac
chmod +x setup.sh && ./setup.sh
```
### 2. 配置
编辑 `.env`:
```env
VAULT_ROOT=C:/Users/you/your-obsidian-vault
OLLAMA_BASE_URL=http://localhost:11434
EMBED_MODEL=bge-m3
```
### 3. 索引你的保险库
```bash
python indexer/vault_indexer.py --once
```
### 4. 将 MCP 添加到 Claude Desktop / Hermes
```json
{
"mcpServers": {
"semantic-vault": {
"command": "python",
"args": ["-m", "mcp_server.server"],
"env": {
"VAULT_ROOT": "C:/Users/you/your-vault",
"LANCEDB_PATH": "./data/lancedb",
"OLLAMA_BASE_URL": "http://localhost:11434",
"EMBED_MODEL": "bge-m3"
}
}
}
}
```
重启 Claude Desktop。现在你已经在代理工具栏中拥有了 `search_vault()`、`read_vault_file()` 和 `vault_stats()`。
## 架构
```
┌──────────────┐ ┌─────────────────────┐ ┌──────────────────────┐
│ │ │ vault_indexer.py │ │ semantic_search_ │
│ Obsidian │───▶│ │───▶│ mcp.py (MCP server) │
│ Vault (.md) │ │ - 扫描保险库 │ │ │
│ │ │ - 按 ## 分段 │ │ 工具: │
└──────────────┘ │ - 嵌入(Ollama) │ │ - search_vault() │
│ - 存储(LanceDB) │ │ - read_vault_file() │
└──────────┬──────────┘ │ - vault_stats() │
│ │ - get_chunk() │
▼ │ - reindex_file() │
┌─────────────────────┐ │ - index_stats() │
│ LanceDB │ └──────────────────────┘
│ vault_chunks.lance │ │
│ (向量存储) │ ▼
└─────────────────────┘ ┌──────────────────────┐
│ Claude Desktop / │
│ Hermes / Claude Code│
│ (MCP 客户端) │
└──────────────────────┘
```
## 命令
| 命令 | 描述 |
|---------|-------------|
| `python indexer/vault_indexer.py --once` | 索引所有保险库文件一次 |
| `python indexer/vault_indexer.py --watch` | 作为文件监视器守护进程运行 |
| `python indexer/vault_indexer.py --reindex` | 清除并重新索引所有内容 |
| `python -m mcp_server.server` | 启动 MCP 服务器(stdio 传输) |
## MCP 工具
| 工具 | 描述 |
|------|-------------|
| `search_vault(query, top_k=5)` | 按含义进行语义搜索 |
| `read_vault_file(filepath)` | 读取完整文件内容 |
| `vault_stats()` | 索引统计信息 |
| `get_chunk(source)` | 获取文件的所有片段 |
| `reindex_file(filepath)` | 重新索引特定文件 |
| `index_stats()` | 哈希存储统计信息 |
## 环境变量
| 变量 | 必需 | 默认值 | 描述 |
|----------|----------|---------|-------------|
| `VAULT_ROOT` | ✅ | `./vault` | Markdown 保险库路径 |
| `LANCEDB_PATH` | ✅ | `./data/lancedb` | 向量存储路径 |
| `OLLAMA_BASE_URL` | ✅ | `http://localhost:11434` | Ollama 端点 |
| `EMBED_MODEL` | ✅ | `bge-m3` | 嵌入模型 |
| `EMBED_DIM` | ❌ | `1024` | 嵌入维度 |
| `CHUNK_SIZE` | ❌ | `512` | 分段大小(字符) |
| `OVERLAP` | ❌ | `64` | 分段重叠 |
| `BATCH_SIZE` | ❌ | `50` | 嵌入批次大小 |
| `EXCLUDE_DIRS` | ❌ | `.obsidian,.trash,.git` | 跳过的文件夹 |
| `MAX_BACKUPS` | ❌ | `2` | 备份保留 |
## 项目结构
```
semantic-vault-mcp/
├── README.md # 快速开始 + MCP 配置
├── CLAUDE.md # 代理指南(Claude Code/Desktop)
├── AGENTS.md # 代理指南(Hermes 集成)
├── SOUL.md # 代理身份模板(RAG 集成)
├── LICENSE # MIT
├── pyproject.toml # pip install .
├── requirements.txt
├── .env.example # 所有 12 个环境变量文档
├── .gitignore
├── setup.bat # Windows 一键设置
├── setup.sh # Linux/Mac 一键设置
├── indexer/
│ ├── __init__.py
│ └── vault_indexer.py # 扫描 → 分段 → 嵌入 → 存储
├── mcp_server/
│ ├── __init__.py
│ └── server.py # MCP 协议服务器
├── vault-structure/ # 示例保险库布局
│ ├── README.md # 文件夹结构解释
│ ├── obsidian-setup.md # 推荐的 Obsidian 插件
│ ├── 00-NOTES/ … 08-DOCS/ # 30+ 个空文件夹
│ ├── 06-SYSTEM/rules/ # 命名、路由、MOC 创建
│ └── 06-SYSTEM/templates/ # 28 个笔记模板
└── docs/
└── ARCHITECTURE.md # 数据流 + 设计决策
```
## 需求
- **Ollama**,任意嵌入模型(测试:`bge-m3`、`nomic-embed-text`)
- Python 包:`lancedb`、`pyarrow`、`requests`、`watchdog`
- ~2GB RAM 用于 LanceDB(取决于保险库大小)
## 保持索引新鲜
**为什么定期索引很重要:**
RAG 搜索的质量取决于索引的质量。如果你添加/编辑了 50 个文件但没有重新索引,搜索将返回**过时的片段** — 或者完全忽略新的内容。
索引器使用 MD5 内容哈希来检测更改,因此重新索引速度很快:
```bash
# 增量 — 仅处理更改的文件(通常 <1 秒)
python indexer/vault_indexer.py --once
```
**推荐频率:**
- **手动:** 在任何重要的保险库编辑会话后运行 `--once`
- **Cron:** 每 6 小时自动索引(索引器是幂等的)
- **监视模式:** `--watch` 用于实时索引(作为守护进程运行)
当有疑问时:**在每次 AI 代理会话前重新索引。** 1 秒的重新索引可以避免基于过时保险库内容的答案。
## 常见问题
**问:初始索引需要多长时间?**
答:~30-60 秒,用于 100 个文件,bge-m3 嵌入。批量嵌入每次调用 50 个片段。
**问:我可以使用其他嵌入模型吗?**
答:是的。在 `.env` 中设置 `EMBED_MODEL` 和 `EMBED_DIM`。测试了 `bge-m3`(1024d)和 `nomic-embed-text`(768d)。
**问:它支持增量更新吗?**
答:是的。索引器跟踪文件内容哈希(MD5)。重新运行 `--once` 以仅索引更改的文件。
**问:我可以在没有 Obsidian 的情况下使用它吗?**
答:是的。任何包含 `.md` 文件的文件夹都可以使用。 将 `VAULT_ROOT` 设置为任意 Markdown 目录。
## 许可证
MIT