Files
md-vector-db/docs/superpowers/specs/2026-07-05-md-vector-db-design.md
T

269 lines
7.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# md-vector-db 设计文档
**日期**: 2026-07-05
**作者**: 刘航宇
**状态**: 已确认
## 1. 项目概述
构建一个 Markdown 文档向量数据库,支持文档入库、嵌入、检索,并通过 HTTP API 供其他项目调用。
### 核心目标
- 支持 ~1000 篇 Markdown 文档的存储与检索
- 混合嵌入方案:默认本地模型,可切换到 API
- HTTP API 对外暴露检索能力
- CLI 命令行管理工具
## 2. 技术栈
| 层 | 选型 | 理由 |
| --------- | -------------------------------------- | -------------------------------- |
| 语言 | Python 3.13 | 向量库生态最成熟 |
| 向量库 | ChromaDB | 嵌入式运行,也支持 HTTP 服务模式 |
| 嵌入模型 | `BAAI/bge-small-zh-v1.5`(本地默认) | 中文优化,仅 100MB |
| 嵌入 API | OpenAI 兼容协议 | 可切到 DashScope/硅基流动/OpenAI |
| HTTP 框架 | FastAPI + uvicorn | 轻量高性能 |
| 包管理 | uv | 用户标准工具链 |
## 3. 目录结构
```
md-vector-db/
├── pyproject.toml
├── config.yaml # 用户配置文件
├── src/
│ ├── core/
│ │ ├── __init__.py
│ │ ├── db.py # ChromaDB 初始化与配置
│ │ ├── embedder.py # 嵌入模型抽象(本地/API)
│ │ ├── ingest.py # Markdown 解析→分块→入库
│ │ └── search.py # 检索接口
│ ├── server/
│ │ ├── __init__.py
│ │ └── app.py # FastAPI 路由
│ └── cli/
│ ├── __init__.py
│ └── main.py # 命令行入口
├── data/ # ChromaDB 持久化目录
├── md_docs/ # 待入库的 Markdown 源文件
├── scripts/
│ └── serve.py # 启动 HTTP 服务
└── tests/
├── test_embedder.py
├── test_ingest.py
├── test_search.py
└── test_api.py
```
## 4. 核心模块设计
### 4.1 embedder.py — 嵌入层
```python
class Embedder:
def __init__(self, config: EmbedConfig):
if config.mode == "local":
self.model = SentenceTransformer(config.local_model)
elif config.mode == "api":
self.client = OpenAI(base_url=config.api_base, api_key=config.api_key)
def embed(self, texts: list[str]) -> list[list[float]]:
"""返回嵌入向量列表"""
@property
def dimension(self) -> int:
"""返回向量维度"""
```
- `local` 模式:首次运行自动下载 `BAAI/bge-small-zh-v1.5`
- `api` 模式:兼容 OpenAI/DashScope/硅基流动(OpenAI 协议)
- 切换方式:修改 `config.yaml` 中的 `embed.mode`
### 4.2 ingest.py — 文档入库
**分块策略(混合切分):**
1. 按 Markdown 标题(`#`/`##`/`###`)拆分章节
2. 若章节超过 1000 字符,按段落边界(`\n\n`)继续拆分
3. 每个 chunk 保留元数据:`source_file`, `section_title`, `heading_level`, `chunk_index`
**入库流程:**
```
Markdown 文件 → 读取 → 提取标题结构 → 分块
→ 逐块 embed → ChromaDB collection.add()
```
**去重:** 同一文件重复入库时,先删除旧 chunks 再重新插入(以 `source_file` 为键)。
### 4.3 search.py — 检索
```python
def search(query: str, top_k: int = 10, filters: dict | None = None) -> list[SearchResult]:
"""
- query 嵌入 → ChromaDB 相似度搜索
- 支持按 source_file、heading_level 过滤
- 返回: [(content, source_file, section_title, score), ...]
"""
```
### 4.4 db.py — 数据库层
```python
class VectorDB:
def __init__(self, persist_dir: str = "./data"):
self.client = chromadb.PersistentClient(path=persist_dir)
def get_or_create_collection(self, name: str) -> Collection:
...
```
- ChromaDB 数据持久化到 `data/` 目录
- 默认 collection 名称:`markdown_docs`
## 5. HTTP API
### 端点设计
| 方法 | 路径 | 说明 |
| ---------- | --------------------------------- | ------------------------------------- |
| `POST` | `/api/v1/ingest` | 入库 Markdown(传文件路径或原始内容) |
| `POST` | `/api/v1/search` | 语义检索 |
| `GET` | `/api/v1/collections` | 列出所有文档集合 |
| `DELETE` | `/api/v1/documents/{file_name}` | 删除指定文件的文档 |
| `GET` | `/api/v1/health` | 健康检查 |
### 请求/响应示例
**入库:**
```json
POST /api/v1/ingest
{
"file_path": "D:/docs/my-note.md"
}
// 或
{
"content": "# 标题\n正文内容...",
"file_name": "my-note.md"
}
{ "status": "ok", "chunks": 12, "file": "my-note.md" }
```
**检索:**
```json
POST /api/v1/search
{
"query": "如何配置向量数据库",
"top_k": 10
}
{
"results": [
{
"content": "...匹配片段...",
"source_file": "setup-guide.md",
"section_title": "向量数据库配置",
"heading_level": 2,
"score": 0.923
}
]
}
```
### 启动方式
```bash
# 嵌入式模式(直接调用 core 模块)
python -c "from src.core.search import search; print(search('关键词'))"
# HTTP 服务模式(供其他项目调用)
uv run scripts/serve.py --port 8000
```
## 6. CLI 工具
```bash
# 入库单个文件
uv run src/cli/main.py ingest path/to/file.md
# 入库整个目录
uv run src/cli/main.py ingest-dir ./md_docs/
# 命令行搜索
uv run src/cli/main.py search "关键词" --top-k 10
# 启动服务
uv run src/cli/main.py serve --port 8000
# 查看统计
uv run src/cli/main.py stats
```
## 7. 配置设计
```yaml
# config.yaml
chroma:
persist_dir: ./data
collection_name: markdown_docs
embed:
mode: local # local | api
local_model: BAAI/bge-small-zh-v1.5
api_base: "" # api 模式下填写
api_key: "" # api 模式下填写
chunk:
max_size: 1000 # 分块最大字符数
overlap: 100 # 相邻块重叠字符数
server:
host: 0.0.0.0
port: 8000
```
## 8. 依赖
```toml
[project]
name = "md-vector-db"
version = "0.1.0"
requires-python = ">=3.13"
dependencies = [
"chromadb>=0.5.0",
"sentence-transformers>=3.0.0",
"fastapi>=0.115.0",
"uvicorn[standard]>=0.30.0",
"pyyaml>=6.0",
"markdown-it-py>=3.0.0",
"typer>=0.12.0",
]
[project.optional-dependencies]
dev = [
"pytest>=8.0",
"httpx>=0.27.0",
]
```
## 9. 测试计划
| 测试 | 覆盖 |
| -------------------- | ------------------------------- |
| `test_embedder.py` | 本地/API 模式嵌入,维度验证 |
| `test_ingest.py` | Markdown 解析、分块、入库、去重 |
| `test_search.py` | 检索、元数据过滤 |
| `test_api.py` | FastAPI 端点集成测试 |
目标覆盖率:80%+
## 10. 自检清单
- [X] 无 TBD/TODO 占位符
- [X] 模块间接口定义清晰(core/server/cli 分层)
- [X] 功能范围明确(入库、检索、CLI、HTTP API
- [X] 无内部矛盾(本地模型+API 双模、嵌入+服务双模)
- [X] 已确定分块策略(混合切分:标题+段落)