Skip to content

掌柜问数 —— 项目全景

学习理念:本文档是整个 21 篇课件集合的总览和导航。先读这篇,知道整个项目长什么样、每篇文档该花多少精力,再按优先级逐篇深入。

海外对标:掌柜智库对标 Google Vertex AI Search + Neo4J GraphRAG 的企业级知识库方案。

本节 AI 替代率:~80% | 人工干预率:~20%

角色能力范围
🤖 AI 擅长解释架构图、对比技术选型、生成目录结构
👤 人类需理解哪些是新知识(P0)、哪些是已学技术(P1)、哪些是一次性配置(P2)

21 篇文档优先级总表

优先级编号文档行数代码段阅读建议
🔥 P0 必须要学01项目全景(本文)7492先读,建立全局认知
03导入骨架代码117511BaseNode/State/Graph 基石
04入口+PDF转MD8586第一个业务节点
06文档切分节点117722RAG 核心策略
07商品名识别119613LLM + Milvus 结合
10知识图谱构建138425🔴 最大新知识(Neo4J/GraphRAG)
11查询骨架代码125010查询流程基石
12商品名确认114816查询侧核心节点
14HyDE检索78316🔴 新知识
15知识图谱查询113922🔴 新知识
17RRF融合74416🔴 新知识
18Rerank重排序102420🔴 新知识
🟡 P1 看注释就行05图片处理+MinIO11519VLM 调用套路固定
08切片向量化62912bge-m3 在 Ch16 已学透
09向量入库81311Milvus 在 Ch16/17 已学透
13向量检索94323Milvus 检索,同上
19答案生成96821LLM 调用套路固定
🟢 P2 后面可以查20Web层与前端111531前端代码量大,需要时再查
02环境配置部署11004一次性配置,跑通后不用再看
🔵 P3 一目而过16网络搜索MCP64816Ch16 已学 MCP
21项目总结3211略读即可

1. 项目概述

1.1 项目定位与目标

项目定位:

掌柜问数是一个企业级智能知识库系统,结合了 RAG(检索增强生成)知识图谱 技术,旨在为垂直领域(如电子产品手册、维修指南、技术文档等)提供精准、智能的知识检索与问答服务。

核心目标:

  • 将非结构化文档(PDF、Markdown)转化为可检索的结构化知识
  • 通过多路召回策略提升检索准确率
  • 利用知识图谱实现实体关系推理
  • 提供流畅的流式问答交互体验

1.2 核心功能特性

功能模块描述
文档智能导入支持 PDF/Markdown 文件上传,自动解析、切分、向量化
知识图谱构建LLM 自动抽取实体和关系,构建领域知识图谱
混合向量检索稠密向量 + 稀疏向量(BM25)混合检索
多路召回融合向量检索 + 知识图谱查询 + HyDE + Web 搜索
智能重排序Reranker 模型重排序,断崖检测动态截断
流式问答SSE 实时推送,逐字输出答案
会话历史管理MongoDB 存储对话历史,支持上下文连续对话

1.3 适用场景

  • 产品手册问答:电子产品使用说明、维修手册等
  • 技术文档检索:API 文档、开发指南、FAQ 等
  • 企业知识库:内部制度、操作规范、培训资料等
  • 售后客服支持:产品故障排查、使用指导等

2. 系统架构

2.1 整体架构图

2.2 核心模块说明

模块职责技术实现
API 层HTTP 接口暴露、请求路由FastAPI + Uvicorn
Processor 层业务流程编排、节点调度LangGraph
Tools 层工具函数封装、外部服务调用Python 模块
数据层数据持久化、检索Milvus / Neo4j / MongoDB / MinIO

2.3 数据流向图

2.3.1 导入流程数据流

2.3.2 查询流程数据流

2.4 技术栈选型

类别技术选型版本/说明
后端框架FastAPI + Uvicorn异步高性能 HTTP 服务
工作流引擎LangGraph有状态图编排框架
大语言模型阿里云 DashScope (Qwen)qwen-flash / qwen3-vl-flash
向量嵌入OpenAI API (text-embedding-v4) + BGE-M31536维 / 1024维+稀疏
重排序模型BGE-Reranker-Large本地部署
向量数据库Milvus混合检索(稠密+稀疏)
图数据库Neo4j Community知识图谱存储与查询
文档数据库MongoDB对话历史存储
对象存储MinIO文件与图片存储
PDF解析MineRUPDF 转 Markdown
前端HTML5 + JS无框架,轻量实现

3. 核心技术原理

3.1 知识图谱构建原理

3.1.1 抽取流程

3.1.2 实体与关系类型

实体类型:

类型描述示例
Device设备/产品万用表、示波器
Part部件/组件探针、表盘、电池仓
Operation操作/功能测量电压、校准
Step操作步骤步骤1-连接探针
Warning警告/注意警告-请勿超量程
Condition条件/状态低电量、超载
Tool工具/配件探针、电池

关系类型:

关系描述示例
HAS_OPERATION拥有操作万用表 → HAS_OPERATION → 测量电压
HAS_PART拥有部件万用表 → HAS_PART → 探针
HAS_STEP包含步骤测量电压 → HAS_STEP → 步骤1
USES_TOOL使用工具测量电压 → USES_TOOL → 红黑探针
HAS_WARNING相关警告测量电压 → HAS_WARNING → 警告-超量程
NEXT_STEP下一步骤步骤1 → NEXT_STEP → 步骤2
AFFECTS影响低电量 → AFFECTS → 测量精度
REQUIRES需要条件测量电压 → REQUIRES → 正确档位

3.2 RAG 工作机制

RAG (Retrieval-Augmented Generation) 是一种结合检索与生成的技术范式:

3.3 向量检索

混合向量 (Dense + Sparse)

本项目采用 BGE-M3 模型实现混合向量检索:

向量类型维度检索方式优势
稠密向量 (Dense)1024维HNSW 近似最近邻语义相似性强
稀疏向量 (Sparse)动态维度BM25 倒排索引关键词精确匹配

检索流程:

python
# 混合检索示例
reqs = build_hybrid_search_requests(
    dense_vector=query_dense,      # 稠密向量
    sparse_vector=query_sparse,    # 稀疏向量
    dense_search_params={"metric_type": "COSINE"},
    sparse_search_params={"metric_type": "IP"},
    top_k=10
)

# 融合排序(权重可调)
results = execute_hybrid_search(
    search_requests=reqs,
    ranker_weights=(0.5, 0.5)  # 50% 稠密 + 50% 稀疏
)

3.4 多路召回策略

本项目实现了 四路并行召回

RRF (Reciprocal Rank Fusion) 公式:

$$ RRF_score(d) = \sum_{r \in R} \frac{1}{k + rank_r(d)} $$ 其中:

  • R 是所有召回来源
  • rank_r(d) 是文档 d 在来源 r 中的排名
  • k 是平滑参数(通常取 60)

断崖检测算法:

python
for i in range(min_topk - 1, max_topk - 1):
    gap = score[i] - score[i + 1]
    relative_gap = gap / (abs(score[i]) + 1e-6)

    # 满足任一条件则截断
    if gap >= gap_abs_threshold or relative_gap >= gap_ratio_threshold:
        return documents[:i + 1]

4. 项目目录结构说明

4.1 各模块职责

knowledge/
├── api/                              # API 路由层
│   ├── query_router.py              # 查询服务路由 (port 8001)
│   │   ├── POST /query              # 发起查询
│   │   ├── GET /stream/{session_id} # SSE 流式获取
│   │   ├── GET /history/{session_id}# 获取历史
│   │   └── DELETE /history/...      # 清除历史
│   └── import_router.py             # 导入服务路由 (port 8000)
│       ├── POST /upload             # 上传文件
│       └── GET /status/{task_id}    # 查询任务状态

├── core/                             # 核心配置
│   ├── deps.py                      # 依赖注入(单例管理)
│   └── paths.py                     # 路径常量配置

├── processor/                        # 业务处理流程(LangGraph)
│   ├── import_process/              # 导入流程
│   │   ├── main_graph.py           # 导入流程图定义
│   │   ├── state.py                # 状态类型定义
│   │   └── nodes/                  # 处理节点
│   │       ├── entry.py            # 入口节点
│   │       ├── pdf_to_md.py        # PDF 转 MD
│   │       ├── md_img.py           # 图片处理
│   │       ├── document_split.py   # 文档切分
│   │       ├── item_name_recognition.py  # 商品识别
│   │       ├── bge_embedding.py    # 向量嵌入
│   │       ├── import_milvus.py    # Milvus 存储
│   │       └── knowledge_graph.py  # 知识图谱构建
│   │
│   └── query_process/               # 查询流程
│       ├── main_graph.py           # 查询流程图定义
│       ├── state.py                # 状态类型定义
│       ├── prompt.py               # 提示词模板
│       └── nodes/                  # 处理节点
│           ├── item_name_confirm.py    # 商品确认
│           ├── search_embedding.py     # 向量检索
│           ├── search_embedding_hyde.py# HyDE 检索
│           ├── query_kg.py             # 知识图谱查询
│           ├── web_search_mcp.py       # Web 搜索
│           ├── rrf.py                  # RRF 融合
│           ├── rerank.py               # 重排序
│           └── answer_output.py        # 答案生成

├── schemas/                          # 数据模型定义
│   ├── query_schema.py              # 查询请求/响应模型
│   ├── upload_schema.py             # 上传响应模型
│   └── task_schema.py               # 任务状态模型

├── services/                         # 业务服务层
│   ├── file_import_service.py       # 文件导入服务
│   └── task_service.py              # 任务管理服务

├── tools/                            # 工具函数库
│   ├── milvus_utils.py              # Milvus 向量库操作
│   ├── neo4j_utils.py               # Neo4j 图数据库操作
│   ├── embedding_utils.py           # 向量嵌入工具
│   ├── llm_utils.py                 # LLM 客户端封装
│   ├── reranker_utils.py            # Reranker 模型
│   ├── mongo_history_utils.py       # MongoDB 历史记录
│   ├── sse_utils.py                 # SSE 流式推送
│   ├── task_utils.py                # 任务状态管理
│   ├── minio_utils.py               # MinIO 对象存储
│   └── normalize_sparse_vector.py   # 稀疏向量规范化

├── front/                            # 前端页面
│   ├── chat.html                    # 聊天界面
│   └── import.html                  # 导入界面

├── test/                             # 测试代码
├── docs/                             # 文档目录
├── temp_data/                        # 临时数据目录
├── .env                              # 环境配置文件
└── requirements.txt                  # Python 依赖声明

4.2 配置文件说明

.env 环境配置

ini
# ====== 模型缓存配置 ======
MINERU_MODEL_SOURCE=modelscope          # MineRU 模型来源
MODELSCOPE_OFFLINE=1                     # 离线模式
MODELSCOPE_CACHE=/path/to/cache          # ModelScope 缓存路径
HF_HOME=/path/to/huggingface             # HuggingFace 缓存路径

# ====== LLM API 配置 ======
OPENAI_API_KEY=sk-xxx                    # API 密钥
OPENAI_API_BASE=https://dashscope...     # API 基础地址
LLM_DEFAULT_MODEL=qwen-flash             # 默认 LLM 模型
LLM_DEFAULT_TEMPERATURE=0.1              # 温度参数
VL_MODEL=qwen3-vl-flash                  # 视觉语言模型
ITEM_MODEL=qwen-flash                    # 商品识别模型
KG_MODEL=qwen-flash                      # 知识图谱模型

# ====== BGE 模型配置 ======
BGE_M3_PATH=/path/to/bge-m3              # BGE-M3 本地路径
BGE_DEVICE=cuda:0                        # GPU 设备
BGE_FP16=True                            # 半精度推理
BGE_RERANKER_LARGE=/path/to/reranker     # Reranker 路径
BGE_RERANKER_DEVICE=cuda:0               # Reranker 设备

# ====== 向量配置 ======
EMBEDDING_DIM=1536                       # 嵌入维度
EMBEDDING_MODEL=text-embedding-v4        # 嵌入模型

# ====== Milvus 配置 ======
MILVUS_URL=http://localhost:19530        # Milvus 服务地址
CHUNKS_COLLECTION=kb_chunks              # 切片集合名
ENTITY_NAME_COLLECTION=kb_entity_names   # 实体名集合
ITEM_NAME_COLLECTION=kb_item_names       # 商品名集合
MILVUS_METRIC_TYPE=COSINE                # 距离度量
MILVUS_MIN_COSINE_SCORE=0.75             # 最小相似度

# ====== Neo4j 配置 ======
NEO4J_URI=bolt://localhost:7687          # Neo4j URI
NEO4J_DATABASE=neo4j                     # 数据库名
NEO4J_USERNAME=neo4j                     # 用户名
NEO4J_PASSWORD=password                  # 密码

# ====== MongoDB 配置 ======
MONGO_URL=mongodb://localhost:27017      # MongoDB 连接
MONGO_DB_NAME=kb001                      # 数据库名

# ====== MinIO 配置 ======
MINIO_ENDPOINT=localhost:9000            # MinIO 端点
MINIO_ACCESS_KEY=minioadmin              # 访问密钥
MINIO_SECRET_KEY=minioadmin              # 私有密钥
MINIO_BUCKET_NAME=knowledge-base         # 存储桶名

5. 数据处理流程

5.1 文档导入流程

5.2 知识抽取过程

LLM 提示词设计要点:

你是一个知识图谱构建专家,请从以下文本中抽取实体和关系。

实体类型:
- Device(设备/产品)
- Part(部件/组件)
- Operation(操作/功能)
- Step(操作步骤,格式:步骤N-动作短语)
- Warning(警告,格式:警告-内容)
- Condition(条件/状态)
- Tool(工具/配件)

关系类型:
- HAS_OPERATION(拥有操作)
- HAS_PART(拥有部件)
- HAS_STEP(包含步骤)
- USES_TOOL(使用工具)
- HAS_WARNING(相关警告)
- NEXT_STEP(下一步骤)
- AFFECTS(影响)
- REQUIRES(需要条件)

输出要求:
- 实体名称简短(≤15字)
- 输出纯 JSON(无 Markdown 围栏)
- 格式:{"entities": [...], "relations": [...]}

5.3 图谱构建步骤

5.4 检索增强流程


6. 前后端数据交互

6.1 主要 API 接口概览

6.1.1 导入服务 (Port 8000)

方法路径描述
POST/upload上传文件(支持多文件)
GET/status/{task_id}查询任务处理状态
GET/health健康检查

6.1.2 查询服务 (Port 8001)

方法路径描述
POST/query发起查询(流式/非流式)
GET/stream/{session_id}SSE 流式获取答案
GET/history/{session_id}获取会话历史
DELETE/history/{session_id}清除会话历史
GET/health健康检查

6.2 请求/响应格式

6.2.1 文件上传

请求:

http
POST /upload
Content-Type: multipart/form-data

files: [file1.pdf, file2.md, ...]

响应:

json
{
  "message": "Files uploaded successfully",
  "task_ids": ["task_001", "task_002"]
}

6.2.2 任务状态查询

请求:

http
GET /status/task_001

响应:

json
{
  "task_id": "task_001",
  "status": "processing",    // pending | processing | completed | failed
  "progress": 45,            // 0-100
  "message": "正在构建知识图谱...",
  "file_name": "万用表使用手册.pdf",
  "created_at": "2026-02-23T10:00:00"
}

6.2.3 知识查询(非流式)

请求:

http
POST /query
Content-Type: application/json

{
  "query": "万用表如何测量直流电压?",
  "session_id": "sess_001",   // 可选,留空自动生成
  "is_stream": false
}

响应:

json
{
  "message": "处理完成",
  "session_id": "sess_001",
  "answer": "测量直流电压的步骤如下:\n1. 将旋钮调至 V= 档位...",
  "done_list": []
}

6.2.4 知识查询(流式)

请求:

http
POST /query
Content-Type: application/json

{
  "query": "万用表如何测量直流电压?",
  "session_id": "sess_001",
  "is_stream": true
}

响应(建立 SSE 连接):

http
GET /stream/sess_001
Accept: text/event-stream

SSE 事件流:

data: {"type": "delta", "data": {"delta": "测"}}
data: {"type": "delta", "data": {"delta": "量"}}
data: {"type": "delta", "data": {"delta": "直"}}
...
data: {"type": "final", "data": {"answer": "测量直流电压...", "status": "completed"}}

6.2.5 历史查询

请求:

http
GET /history/sess_001?limit=10

响应:

json
{
  "session_id": "sess_001",
  "items": [
    {
      "_id": "65d1a2b3...",
      "session_id": "sess_001",
      "role": "user",
      "text": "万用表如何测量电压?",
      "rewritten_query": "万用表测量直流电压的步骤",
      "item_names": ["万用表"],
      "ts": 1708756800
    },
    {
      "_id": "65d1a2c4...",
      "session_id": "sess_001",
      "role": "assistant",
      "text": "测量直流电压的步骤如下...",
      "ts": 1708756805
    }
  ]
}

6.3 前端交互流程

6.3.1 导入界面交互

javascript
// 1. 发送查询
async function sendQuery(query) {
  const response = await fetch('/query', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      query: query,
      session_id: currentSessionId,
      is_stream: true
    })
  });

  const data = await response.json();
  currentSessionId = data.session_id;

  // 2. 建立 SSE 连接
  const eventSource = new EventSource(`/stream/${currentSessionId}`);

  eventSource.onmessage = (event) => {
    const msg = JSON.parse(event.data);

    if (msg.type === 'delta') {
      // 3. 逐字渲染
      appendToAnswer(msg.data.delta);
    } else if (msg.type === 'final') {
      // 4. 完成处理
      eventSource.close();
      finalizeAnswer(msg.data.answer);
    }
  };
}

6.3.2 聊天界面交互

javascript
// 1. 上传文件
async function uploadFiles(files) {
  const formData = new FormData();
  files.forEach(file => formData.append('files', file));

  const response = await fetch('/upload', {
    method: 'POST',
    body: formData
  });

  const data = await response.json();

  // 2. 轮询任务状态
  data.task_ids.forEach(taskId => {
    pollTaskStatus(taskId);
  });
}

// 3. 状态轮询
async function pollTaskStatus(taskId) {
  const interval = setInterval(async () => {
    const response = await fetch(`/status/${taskId}`);
    const status = await response.json();

    updateProgressBar(taskId, status.progress);

    if (status.status === 'completed' || status.status === 'failed') {
      clearInterval(interval);
      showResult(status);
    }
  }, 2000);  // 每2秒轮询
}

7. 快速开始

7.1 环境要求

项目要求
Python>= 3.10
CUDA>= 自己机器适配的版本(GPU 推理需要)
内存>= 16GB(建议 32GB)
显存>= 8GB(BGE-M3 + Reranker)
存储>= 50GB(模型缓存)

依赖服务:

  • Milvus(向量数据库)
  • Neo4j(图数据库)
  • MongoDB(文档数据库)
  • MinIO(对象存储)

7.2 安装步骤

bash
# 1. 创建虚拟环境
python -m venv .venv
.venv\Scripts\activate  # Windows
# source .venv/bin/activate  # Linux/Mac

# 2. 安装依赖(使用国内镜像)
pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple

# 3. 配置环境变量
copy .env.example .env
# 编辑 .env 文件,填入正确的配置

7.3 基础配置

  1. 启动依赖服务
bash
# Docker Compose 方式(推荐)
docker-compose up -d milvus neo4j mongodb minio
  1. 下载模型
bash
# BGE-M3 模型(通过 ModelScope)
python -c "from modelscope import snapshot_download; snapshot_download('BAAI/bge-m3')"

# BGE-Reranker-Large
python -c "from modelscope import snapshot_download; snapshot_download('BAAI/bge-reranker-large')"
  1. 初始化数据库
bash
# 运行初始化脚本(如有)
python scripts/init_db.py

7.4 运行示例

bash
# 启动导入服务 (端口 8000)
uvicorn api.import_router:app --host 0.0.0.0 --port 8000 --reload

# 启动查询服务 (端口 8001)
uvicorn api.query_router:app --host 0.0.0.0 --port 8001 --reload

访问前端页面:

8. 附录

A. Milvus 集合 Schema

文档切片

字段类型描述
pkINT64主键,自增
chunk_idINT64切片 ID
contentVARCHAR(65535)切片内容
titleVARCHAR章节标题
dense_vectorFLOAT_VECTOR(1024)稠密向量
sparse_vectorSPARSE_FLOAT_VECTOR稀疏向量
item_nameVARCHAR商品名称
created_atVARCHAR创建时间

图谱实体

字段类型描述
pkINT64主键,自增
entity_nameVARCHAR实体名称
dense_vectorFLOAT_VECTOR(1024)稠密向量
sparse_vectorSPARSE_FLOAT_VECTOR稀疏向量
source_chunk_idVARCHAR来源切片 ID
contextVARCHAR上下文描述
item_nameVARCHAR所属商品

B. Neo4j 图模型

(Entity {name, item_name, types[], description})

    ├── [:HAS_OPERATION] ──→ (Entity:Operation)
    ├── [:HAS_PART] ──→ (Entity:Part)
    ├── [:HAS_STEP] ──→ (Entity:Step)
    ├── [:HAS_WARNING] ──→ (Entity:Warning)
    ├── [:USES_TOOL] ──→ (Entity:Tool)
    ├── [:NEXT_STEP] ──→ (Entity:Step)
    ├── [:AFFECTS] ──→ (Entity)
    ├── [:REQUIRES] ──→ (Entity:Condition)
    └── [:MENTIONED_IN] ──→ (Chunk {id, item_name})

C. 关键文件速查表

功能文件路径
导入 APIapi/import_router.py
查询 APIapi/query_router.py
导入流程图processor/import_process/main_graph.py
查询流程图processor/query_process/main_graph.py
知识图谱构建processor/import_process/nodes/knowledge_graph.py
知识图谱查询processor/query_process/nodes/query_kg.py
向量检索processor/query_process/nodes/search_embedding.py
重排序processor/query_process/nodes/rerank.py
答案生成processor/query_process/nodes/answer_output.py
提示词模板processor/query_process/prompt.py
Milvus 工具tools/milvus_utils.py
Neo4j 工具tools/neo4j_utils.py
LLM 客户端tools/llm_utils.py
SSE 推送tools/sse_utils.py

OPC 超级个体实战指南