一个支持多用户的知识图谱系统,整合 Neo4j 图数据库和 ChromaDB 向量数据库,实现文档知识管理和可视化检索。
本项目的
.env(根目录与backend/)包含真实 API 密钥和 JWT 签名密钥。任何 fork、镜像或截图前必须:
- 在硅基流动 / Moonshot / 阿里云百炼控制台**轮换(撤销并重新签发)**这些 API 密钥
- 用
python -c "import secrets; print(secrets.token_urlsafe(48))"生成新JWT_SECRET并替换- 永远不要把
.env提交到 git(已在.gitignore中,但仍请小心处理历史记录)
详见 安全配置 一节。
- 文档知识库:支持上传 PDF/Word/TXT/MD 格式,自动转换为 Markdown 并按层级切块
- 混合检索:基于硅基流动 Qwen3-Embedding-8B 向量检索 + BM25 关键词 + Qwen3-Reranker 重排序 + RRF 融合
- 知识图谱可视化:d3 + Vue 3 实现的交互式力导向图谱,支持节点拖拽和关系探索
- 大模型对话:基于 Kimi / 百炼 (qwen-flash) 的 RAG 问答,结合向量检索、图谱上下文与查询改写
- 用户隔离:JWT 账号密码认证,SQLite 存储用户数据,Neo4j/ChromaDB 通过
user_id标签隔离 - 健壮性:统一 logging、批量写入(Neo4j UNWIND)、输入校验、4xx 不重试、防 401 重定向循环
| 层级 | 技术 |
|---|---|
| 前端 | Vue 3.5 + Vite 7 + Pinia + Vue Router + d3.js · 学术雅致派双主题(Fraunces + Plus Jakarta Sans + JetBrains Mono) |
| 后端 API | FastAPI 0.115 + Python 3.11 + uvicorn |
| 图数据库 | Neo4j 5.14 (Docker) |
| 向量数据库 | ChromaDB 0.4.18 (Docker) |
| 用户数据 | SQLite + aiosqlite (单文件) |
| 嵌入模型 | 硅基流动 Qwen3-Embedding-8B (API) |
| 重排序 | 硅基流动 Qwen3-Reranker-8B (API) |
| 大模型 | Kimi API (Moonshot) / 百炼 qwen-flash (阿里云 DashScope) |
| 密码哈希 | bcrypt (原生) |
| 日志 | Python logging + RotatingFileHandler(统一在 app/logger.py) |
D:/NC/
├── docker-compose.yml # Neo4j + ChromaDB 服务定义
├── .env / .env.example # 部署环境变量(example 为模板)
├── backend/
│ ├── .env / .env.example # 后端实际加载的 .env
│ ├── app/
│ │ ├── api/ # API 端点
│ │ │ ├── auth.py # 注册/登录/me
│ │ │ ├── documents.py # 文档上传/列表/删除/切块
│ │ │ ├── chat.py # RAG 对话(流式 + 非流式)
│ │ │ ├── graph.py # 实体列表/图谱查询/可视化
│ │ │ ├── search.py # 语义检索
│ │ │ └── progress.py # 文档处理进度(SSE)
│ │ ├── auth/ # JWT 鉴权与 bcrypt 密码哈希
│ │ ├── models/ # Pydantic 数据模型(含字段校验)
│ │ ├── services/ # 核心服务
│ │ │ ├── embedding.py # 硅基流动嵌入(限流 + JSON 缓存)
│ │ │ ├── llm.py # 百炼 / Kimi 双 LLM
│ │ │ ├── chunker.py # Markdown 层级切块
│ │ │ ├── entity_extractor.py # 实体 + 关系提取(规则 + LLM)
│ │ │ ├── neo4j_client.py # Neo4j 封装(含 UNWIND 批量)
│ │ │ ├── chroma_client.py # ChromaDB 封装
│ │ │ ├── bm25.py # BM25 关键词检索(per-user 索引)
│ │ │ ├── fusion.py # RRF / 加权融合
│ │ │ ├── reranker.py # 硅基流动 Rerank
│ │ │ ├── query_processor.py # 查询改写 / 变体 / 实体抽取
│ │ │ └── progress_tracker.py # SSE 进度跟踪
│ │ ├── utils/md_parser.py # Markdown 解析(markitdown 防御性封装)
│ │ ├── config.py # 配置管理(含 CORS 白名单 + 生产校验)
│ │ ├── database.py # SQLite 初始化
│ │ ├── logger.py # 统一 logging 配置
│ │ └── main.py # FastAPI 入口
│ ├── requirements.txt
│ └── Dockerfile
├── frontend/ # Vue 3 + d3 前端(学术雅致派双主题)
│ ├── src/
│ │ ├── components/ # GraphPanel.vue 等
│ │ │ └── layout/ # Sidebar / Layout
│ │ ├── views/ # 页面:Home/Documents/Graph/Chat/Search
│ │ ├── composables/ # useTheme.js — 亮/暗主题切换 + localStorage 持久化
│ │ ├── api/ # axios 客户端(含 401 防重入 + 4xx 不重试)
│ │ ├── router/
│ │ ├── store/ # Pinia stores
│ │ └── styles/ # variables.css — 学术雅致派设计令牌(墨蓝+琥珀双主题)
│ ├── index.html
│ ├── package.json
│ └── vite.config.js
└── data/ # 数据目录 (gitignore)
├── sqlite/ # SQLite 数据库
├── uploads/ # 上传的原文件
├── logs/ # 应用日志(RotatingFileHandler)
├── neo4j/ # Neo4j 数据卷
└── chromadb/ # ChromaDB 数据卷
docker-compose up -d这将启动:
- Neo4j: http://localhost:7474 (浏览器界面), bolt://localhost:7687
- ChromaDB: http://localhost:8000
# 根目录(用于 IDE / 工具)
cp .env.example .env
# 后端实际加载的 .env
cd backend
cp .env.example .env必填项:
SILICON_FLOW_API_KEY— 硅基流动 API 密钥(用于 Embedding + Rerank)BAILIAN_API_KEY— 阿里云百炼 API 密钥(用于 LLM)KIMI_API_KEY— Moonshot Kimi API 密钥(备用 LLM)JWT_SECRET— 生产环境必须用python -c "import secrets; print(secrets.token_urlsafe(48))"生成
可选调整:
CORS_ALLOWED_ORIGINS— 逗号分隔的允许来源(默认http://localhost:5173)APP_ENV—development(默认)或production(生产环境会拒绝默认 JWT_SECRET 启动)UPLOAD_DIR/SQLITE_PATH/LOG_DIR— 数据与日志目录
# 推荐:使用根目录 .venv
cd ..
.venv/Scripts/python.exe -m pip install -r backend/requirements.txt
.venv/Scripts/python.exe -m spacy download zh_core_web_smcd backend
../.venv/Scripts/python.exe -m uvicorn app.main:app --host 0.0.0.0 --port 8001 --reload或使用一键启动脚本(Windows / Bash 双版本):
# Windows
start-dev.bat
# Bash (Git Bash / WSL)
./start-dev.shAPI 文档地址:http://localhost:8001/docs 健康检查: http://localhost:8001/health
cd frontend
npm install
npm run dev前端访问地址:http://localhost:5173
Vite 已配置 /api 代理到 http://localhost:8001。
所有需要鉴权的接口都要求 Authorization: Bearer <jwt> header。SSE 进度接口也通过 header 鉴权,不接受 URL ?token= 参数。
POST /api/auth/register— 用户注册(用户名 3-50 字符[A-Za-z0-9_.-]、密码 ≥ 8 字符且必须含字母+数字)POST /api/auth/login— 用户登录(OAuth2 form-data,返回 JWT)GET /api/auth/me— 获取当前用户信息
POST /api/documents/upload— 上传文档(multipart/form-data,支持 .pdf/.docx/.doc/.txt/.md/.markdown,≤ 10MB)GET /api/documents— 列出用户文档(分页:?skip=0&limit=100)DELETE /api/documents/{id}— 删除文档(联动清理 SQLite + ChromaDB + Neo4j)GET /api/documents/{id}/chunks— 获取文档切块
POST /api/search— 语义检索(向量 + BM25 + Rerank + 图谱关联)
GET /api/graph/entities?query=xxx— 实体名称模糊搜索POST /api/graph/query— 语义图谱查询(按query在向量空间找相关 chunk,再展开图谱)GET /api/graph/visualization— 获取当前用户的全量图谱可视化数据
POST /api/chat— 发送消息(非流式 RAG 问答)POST /api/chat/stream— 发送消息(Server-Sent Events 流式)GET /api/chat/conversations— 获取对话列表GET /api/chat/conversations/{id}/messages— 获取对话历史DELETE /api/chat/conversations/{id}— 删除对话
GET /api/progress/{doc_id}— SSE 流式进度事件(30 秒 keepalive,完成/错误自动关闭)GET /api/progress/{doc_id}/history— 历史进度事件列表
GET /health— 返回{"status": "healthy"}GET /— 返回 API 元信息
PDF/Word/TXT/MD → markitdown → Markdown → 层级解析 → 语义切块
→ 硅基流动 Embedding (Qwen3-Embedding-8B) → ChromaDB 存储
→ Neo4j 实体关系提取 (BM25 索引同步) → SSE 进度推送
用户 Query → 查询改写 (LLM) → Embedding
→ 向量检索 + BM25 → RRF 融合 → Qwen3-Reranker
→ 上下文扩展 (前/后 chunk) → Neo4j 图谱关联
→ 构建 Prompt → Kimi / 百炼 LLM → 流式返回结果
{
"chunk_id": "uuid",
"document_id": "doc_uuid",
"user_id": "user_uuid",
"content": "文本内容",
"hierarchy": {
"level": 2, # 标题层级
"path": ["标题1", "标题1.1"], # 层级路径
"parent_id": "parent_chunk_id"
},
"position": {
"start_line": 10,
"end_line": 25,
"prev_chunk_id": "uuid", # 前一块(用于上下文召回)
"next_chunk_id": "uuid" # 后一块
}
}// 节点
(:User {user_id, username, password_hash, created_at})
(:Document {doc_id, title, user_id, file_path, created_at})
(:Chunk {chunk_id, content, embedding_id, user_id, position, hierarchy_path})
(:Entity {name, type, description, user_id}) // 从文本提取
// 关系
(:User)-[:OWNS]->(:Document)
(:Document)-[:CONTAINS]->(:Chunk)
(:Chunk)-[:NEXT]->(:Chunk) // 文档顺序
(:Chunk)-[:MENTIONS]->(:Entity) // 提及实体
(:Entity)-[:RELATES_TO {relation_type}]->(:Entity) // 实体关系| 项 | 状态 | 备注 |
|---|---|---|
| JWT 签名 | 必须替换 | python -c "import secrets; print(secrets.token_urlsafe(48))" |
| CORS 来源 | 白名单 | 通过 CORS_ALLOWED_ORIGINS 配置,禁用通配符 |
| 密码哈希 | bcrypt | 72 字节硬截断;不 mutate 调用方入参 |
| API 密钥 | 环境变量 | 勿硬编码到代码;.env 已 gitignore |
| 生产模式 | APP_ENV=production |
默认 JWT_SECRET 启动时直接 RuntimeError |
| 401 处理 | 拦截器去重 | 防重入 + 派发 auth:logout 事件 |
| 进度 SSE | Authorization header | 不接受 ?token= URL 参数(避免日志泄露) |
| 嵌入缓存 | JSON 序列化 | 取代 pickle(防反序列化漏洞) |
| 注册校验 | 强校验 | 用户名 [A-Za-z0-9_.-]、密码 ≥ 8 字符含字母+数字 |
| Neo4j 删除 | 跨用户隔离 | delete_document step 4 强制 user_id 过滤 |
| 批量写入 | UNWIND | 实体/关系/MENTIONS 由 N 次往返降为 1 次 |
| 变量名 | 说明 | 默认值 | 必填 |
|---|---|---|---|
APP_ENV |
运行环境 | development |
否 |
NEO4J_URI |
Neo4j 连接地址 | bolt://localhost:7687 |
否 |
NEO4J_USER |
Neo4j 用户名 | neo4j |
否 |
NEO4J_PASSWORD |
Neo4j 密码 | 12345678 |
否 |
CHROMA_HOST / CHROMA_PORT |
ChromaDB 主机端口 | localhost:8000 |
否 |
SQLITE_PATH |
SQLite 数据库路径 | ./data/sqlite/app.db |
否 |
SILICON_FLOW_API_KEY |
硅基流动 API 密钥(Embedding + Rerank) | - | 是 |
SILICON_FLOW_BASE_URL |
硅基流动 base URL | https://api.siliconflow.cn/v1 |
否 |
BAILIAN_API_KEY |
阿里云百炼 LLM 密钥 | - | 是 |
BAILIAN_MODEL |
百炼模型 | qwen-flash |
否 |
KIMI_API_KEY |
Moonshot Kimi 密钥(备用) | - | 否 |
JWT_SECRET |
JWT 签名密钥 | 占位符(生产必须替换) | 是 |
JWT_ALGORITHM |
JWT 算法 | HS256 |
否 |
ACCESS_TOKEN_EXPIRE_MINUTES |
Token 有效期(分钟) | 60 |
否 |
UPLOAD_DIR |
上传文件目录 | ./data/uploads |
否 |
MAX_FILE_SIZE |
最大文件大小(字节) | 10485760(10MB) |
否 |
EMBEDDING_MODEL |
嵌入模型名 | Qwen/Qwen3-Embedding-8B |
否 |
EMBEDDING_DIM |
嵌入维度 | 1024 |
否 |
RERANK_MODEL |
Rerank 模型 | Qwen/Qwen3-Reranker-8B |
否 |
CORS_ALLOWED_ORIGINS |
允许的 CORS 来源(逗号分隔) | localhost 开发地址 | 否 |
ENTITY_BATCH_SIZE |
实体提取批大小 | 200 |
否 |
LOG_DIR / LOG_LEVEL |
日志目录与级别 | ./data/logs / INFO |
否 |
- Python 3.11+
- Node.js 18+
- Docker & Docker Compose
# 冒烟测试(无需 Neo4j/ChromaDB)
cd backend
../.venv/Scripts/python.exe -c "
from app.main import app
from fastapi.testclient import TestClient
c = TestClient(app)
assert c.get('/health').status_code == 200
print('OK')
"
# 集成测试(需启动 Docker 服务)
docker-compose up -d
../.venv/Scripts/python.exe -m pytest backend/tests# 构建并运行所有服务
docker-compose up -d
# 单独构建后端镜像
cd backend
docker build -t kg-backend .
docker run -p 8001:8001 --env-file .env kg-backendfastapi==0.115.0
uvicorn==0.32.0
python-jose[cryptography]==3.3.0
bcrypt==3.2.2
neo4j==6.1.0
chromadb==0.4.18
numpy==1.26.4
httpx==0.27.0
markitdown==0.0.1a3
markdown-it-py==3.0.0
jieba==0.42.1
spacy==3.7.5
rank-bm25==0.2.2
python-dotenv==1.0.0
pydantic==2.9.2
pydantic-settings==2.6.0
aiosqlite==0.20.0
注意:原
passlib[bcrypt]==1.7.4已移除,改为原生bcrypt==3.2.2(passlib 与新版 bcrypt 存在兼容问题)。
- API 密钥保护:
.env中的密钥若已泄露,立即在控制台轮换 - JWT_SECRET:生产环境 (
APP_ENV=production) 拒绝默认占位符启动 - 硅基流动限速:嵌入服务实现了批量处理、异步队列和并发控制(Semaphore=5)
- NumPy 版本:必须使用 NumPy 1.x(<2.0)以保证 ChromaDB 兼容性
- ChromaDB 版本:客户端和服务端必须都使用 0.4.18 版本
- Docker 内存:Neo4j 需要充足内存,建议 4GB+
- markitdown 防御:
utils/md_parser.py兼容新旧 API(text_content/markdown/title),失败时回退到txt解析
MIT