Coder-Priyan/VectorDB
GitHub: Coder-Priyan/VectorDB
一个用 C++ 从零实现的向量数据库,集成了三种最近邻搜索算法和基于 Ollama 的本地 RAG 管线,用于探索和演示语义搜索的底层原理。
Stars: 0 | Forks: 0
# VectorDB
### 语义搜索引擎
*一个使用 C++ 从第一性原理开始实现的向量数据库 —— 包含三种搜索算法、一个本地 embedding pipeline,以及一个检索增强生成系统,不依赖任何外部向量数据库。*
[](#)
[](#)
[](#)
[](#)
[](#)
## 目录
- [概述](#overview)
- [项目存在的原因](#why-this-project-exists)
- [核心特性](#feature-highlights)
- [架构概览](#architecture-overview)
- [搜索算法对比](#search-algorithm-comparison)
- [核心组件](#core-components)
- [Embedding Pipeline](#embedding-pipeline)
- [本地 RAG Pipeline](#local-rag-pipeline)
- [截图](#screenshots)
- [性能表现](#performance)
- [技术栈](#tech-stack)
- [项目结构](#project-structure)
- [未来路线图](#future-roadmap)
- [文档](#documentation)
- [安装说明](#installation)
- [许可协议](#license)
## 概述
VectorDB 是一个完全使用 C++ 从零构建的语义搜索引擎。它在一个统一的 REST API 背后实现了三种最近邻搜索算法 —— Brute Force、KD-Tree 和 HNSW,在浏览器中实时渲染向量空间,并通过 Ollama 在本地托管的 LLM 上运行完整的检索增强生成 (RAG) pipeline。
本系统中的任何部分都没有封装现有的向量数据库。索引、搜索算法、embedding pipeline 以及 RAG 编排全部直接在此代码库中实现。
## 项目存在的原因
向量搜索是几乎所有现代语义搜索和 RAG 系统背后的检索层,但它几乎总是以托管 API 的形式被调用。本项目旨在通过实际运行的代码(而非文档)来回答那些通常没有被解答的问题:
- HNSW 图究竟长什么样?为什么它在规模化时能超越更简单的结构?
- 随着维度的增加,经典的空间索引 (KD-Tree) 在什么情况下会失去效用?
- 当 RAG pipeline 检索上下文并生成答案时,它实际上一步一步做了什么?
要回答这些问题,需要在相同的数据上并行实现这三种算法,需要一种直接检查其内部结构和性能的方法,还需要在其之上构建一个真实的应用程序 —— RAG —— 以证明该索引是可用的,而不仅仅是理论上正确的。
## 核心特性
| | |
|---|---|
| 🔍 **三种搜索算法** | 在同一个 API 后实现 Brute Force、KD-Tree 和 HNSW,支持按请求切换 |
| 📐 **三种距离度量** | Cosine、Euclidean 和 Manhattan —— 可独立于算法进行选择 |
| 🕸️ **真正的 HNSW 实现** | 具备贪婪下降、beam search 和双向链接的多层图结构 |
| 📊 **实时向量空间可视化** | PCA 降维投影的 2D 散点图,实时更新 |
| 🧠 **真实的 Embedding** | 通过 Ollama 的 `nomic-embed-text` 将任意文本转换为 768 维向量 |
| 🤖 **本地 RAG Pipeline** | 通过 Ollama 的 `llama3.2` 实现完全离线的检索与生成 |
| ⚡ **内置性能基准测试** | 一个 endpoint 即可在相同查询上运行全部三种算法,便于直接对比 |
## 架构概览
```
graph TD
UI[Browser UI] -->|HTTP| SRV[C++ Server — cpp-httplib]
SRV --> VDB[VectorDB]
SRV --> DDB[DocumentDB]
SRV --> OC[OllamaClient]
VDB --> BF[Brute Force]
VDB --> KD[KD-Tree]
VDB --> HN[HNSW]
DDB --> HN2[HNSW — 768D Index]
OC -->|HTTP| OL[Ollama Runtime]
OL --> EMB[nomic-embed-text]
OL --> GEN[llama3.2]
```
`VectorDB` 负责提供 16 维的演示数据集,并将查询分发给所请求的算法。`DocumentDB` 是一个独立的、仅使用 HNSW 的索引,专用于真实的 768 维 embedding。`OllamaClient` 是唯一存在进程外部依赖的组件 —— 它会向运行中的 Ollama 实例发起本地 HTTP 调用。
完整的组件拆解详情请见[技术需求文档](2_TRD.md)。
## 搜索算法对比
| | Brute Force | KD-Tree | HNSW |
|---|---|---|---|
| 类型 | 精确 | 精确 | 近似 |
| 时间复杂度 | O(N·d) | 平均 O(log N) | 平均 O(log N) |
| 16 维 (演示) | 准确,慢 | 准确,快 | 准确,快 |
| 768 维 (真实 embedding) | 准确,慢 | 性能退化至接近暴力搜索 | 不受影响 |
| 用于 | 真值基准 | 仅限 16 维对比 | 16 维 **及** 768 维索引 |
关于该表格的完整推理过程 —— 以及为什么 KD-Tree 被刻意排除在 768 维索引之外 —— 已在下方的[核心组件](#core-components)和 TRD 中详细说明。
## 核心组件
**HNSW (Hierarchical Navigable Small World)** —— 一种多层图结构,其中每个节点被随机分配一个最大层级;第 0 层包含所有节点且密集连接,较高层包含的节点数量呈指数级减少,充当远程快捷方式。搜索从顶层开始贪婪下降,然后在第 0 层执行 beam search。这与 Pinecone、Weaviate、Chroma 和 Milvus 所使用的算法族相同。
**KD-Tree** —— 一种二叉空间划分树,每次沿一个维度进行切分,并按深度循环。搜索利用超球体与超平面的边界来剪枝子树。在低维度下精确且快速;但其剪枝效果在高维度下会崩溃(即维度灾难),这就是为什么它被保留用于 16 维演示索引,但从未用于 768 维的真实 embedding 索引。
**Brute Force** —— 线性 O(N·d) 扫描,用作验证其他所有算法正确性的基准。
各组件的设计原理和数据结构记录在[后端架构](5_BackendSchema.md)中。
## Embedding Pipeline
长篇输入文本会被切分为约 250 词的重叠块,这样检索就能返回特定的相关段落,而不是整篇文档。每个文本块都会被发送到 Ollama 的 `nomic-embed-text` 模型,并作为 768 维向量存储在 `DocumentDB` 的 HNSW 索引中。
## 本地 RAG Pipeline
用户的问题会以与文档相同的方式进行 embedding,HNSW 检索出最相关的文本块,这些文本块随后被组装成 prompt 发送给 `llama3.2`。生成的答案基于检索到的文本,并且检索到的文本块会在 UI 中展示而非隐藏起来 —— 检索步骤是可审计的,而不是一个黑盒。
该 pipeline 完整的逐请求序列图详见[应用程序流程](3_AppFlow.md)。
## 截图
Search tab — algorithm/metric selection, results, live scatter plot
Ask AI tab — question, streamed answer, expandable retrieved-context chips
故障排除与完整 REST API 参考文档
| 问题 | 解决方法 | |---|---| | 页头显示 `Ollama: OFFLINE` | 运行 `ollama serve` | | 提示 `g++: command not found` | 将 `C:\msys64\ucrt64\bin` 添加到 PATH 环境变量 | | 8080 端口被占用 | 执行 `netstat -ano \| findstr 8080` → `taskkill /PID
**许可协议:** MIT
标签:AI风险缓解, C++, HNSW, LLM评估, Ollama, RAG, 向量数据库, 数据擦除, 语义搜索