内容
# 小智機器人 MCP 知識庫查詢系統 v2.1
## 項目概述
本項目實現小智機器人與多個本地 PostgreSQL 知識庫的橋接,透過小智官方 MCP 服務(WebSocket)讓 ESP32 語音設備能以自然語言查詢工程文件。
> 本版本(-OK)為生產穩定版,相較原始版新增連線池、LRU 快取、Ollama retry 與多資料庫支援,並整合完整的文件重新 ingest 與 OCR 維護工具組。
---
## 系統架構
```
ESP32 語音設備
↓ 語音→文字
小智機器人(官方服務)
↓ WebSocket (wss://api.xiaozhi.me/mcp/)
mcp_server_multi.py ← 多資料庫 MCP Server(本地常駐)
↓ psycopg2(連線池 ThreadedConnectionPool)
PostgreSQL(pgvector)
├── ahow_db AHOW 內部文件(施工安全、品管查驗、扣點項目)
├── ahow_rag_pcc 公共工程委員會(PCC)法規函示
└── mrt_knowledge_rag 捷運技術文件
query_server_enhanced.py ← 獨立 Flask 查詢服務(ahow_db,port 11451)
management_tools/ ← 文件向量化管理 GUI(三庫版)
```
---
## 項目結構
```
2-MCP - (介面) -OK/
├── mcp_server_multi.py # 多資料庫 MCP Server v2.1(推薦使用)
├── query_server_enhanced.py # 增強型 Flask 查詢服務(ahow_db,port 11451)
├── create_hnsw_indexes.sql # HNSW 向量索引建立 SQL(效能優化)
├── start_all_services.bat # 統一服務管理器(互動選單)
├── set_env.bat # 環境變量設置腳本
│
├── management_tools/
│ ├── file_manager_gui.py # 三資料庫文件向量化 GUI v2.1(深色主題)
│ ├── main_menu.bat # 工具選單
│ └── start_file_manager.bat # 快速啟動 GUI
│
├── _reingest_with_ocr.py # 含 OCR 的完整重新 ingest 工具
├── _reingest_missing_pdfs.py # 補充重新 ingest 遺漏 PDF
├── _match_pdfs.py # PDF 比對工具
├── _ocr_poc.py # OCR 概念驗證腳本
├── _reingest_skipped.tsv # 跳過的文件清單
│
├── downloads/ # 已下載 PDF / MD 文件
├── .env # 環境變量(不納入版控)
└── README.md # 本文件
```
---
## 快速啟動
### 方式一:多資料庫 MCP Server(推薦)
```bash
# 確保 Ollama 已啟動、.env 已設定 MCP_WS_URL
python mcp_server_multi.py
```
### 方式二:統一服務管理器
```bat
# 以管理員身份執行
start_all_services.bat
```
選單選項:
| 選項 | 功能 |
|------|------|
| 1 | 啟動增強型查詢服務器(Flask port 11451) |
| 2 | 啟動多資料庫 MCP Server(推薦) |
| 3 | 啟動完整服務(查詢服務器 + MCP Server) |
| 4 | 重啟所有服務 |
| 5 | 停止所有服務 |
| 6 | 查看狀態 |
### 方式三:文件管理 GUI
```bat
management_tools\start_file_manager.bat
```
---
## MCP Server v2.1 核心功能
### 三個知識庫與 MCP 工具
| 資料庫 | MCP 工具名稱 | 說明 | 表結構 |
|--------|-------------|------|--------|
| `ahow_db` | `query_ahow_knowledge` | AHOW 內部工程文件 | `pdf_chunks` |
| `ahow_rag_pcc` | `query_pcc_documents` | PCC 公共工程法規函示 | `document_chunks` |
| `mrt_knowledge_rag` | `query_mrt_knowledge` | 捷運技術文件 | `chunks` |
### v2.1 效能改善項目
1. **ThreadedConnectionPool** — 每庫 2–5 常駐連線,取代每次建新連線
2. **Embedding LRU + TTL 快取** — 避免重複呼叫 Ollama(TTL 預設 30 分鐘)
3. **Ollama retry** — 最多 3 次,指數退避(1s / 2s)
4. **score 門檻過濾** — `SCORE_MIN = 1.3`,低分結果不回傳
5. **啟動預熱** — Ollama 空查詢 + 各庫筆數統計
6. **run_in_executor** — 查詢改為非同步,不阻塞事件迴圈
7. **友善錯誤提示** — 失敗時回傳中文提示,而非原始例外訊息
### Embedding 模型
```
來源:本地 Ollama(零 API 費用)
模型:qwen3-embedding:4b
端點:http://localhost:11434/api/embed
相似度算子:<#> negative inner product
值域:高相關 ~1.58–1.67,不相關 ~1.21–1.22
```
### 訊息長度限制
```python
CHUNK_TEXT_MAX = 1500 # 單一 chunk 截斷上限(字元)
RESPONSE_TEXT_MAX = 12000 # 整個回應上限(字元)
```
---
## 環境變量(.env)
```env
PYTHONIOENCODING=utf-8
# PostgreSQL
PG_HOST=localhost
PG_PORT=5432
PG_DATABASE=ahow_db
PG_USER=<你的使用者名稱>
PG_PASSWORD=<你的密碼>
# 小智 MCP WebSocket(需至小智平台取得 token)
MCP_WS_URL=wss://api.xiaozhi.me/mcp/?token=<YOUR_TOKEN>
# Flask 查詢服務
QUERY_SERVER_URL=http://localhost:11451/query
```
---
## 向量索引建立(首次部署)
```sql
-- 執行 create_hnsw_indexes.sql 以建立 HNSW 索引
\i create_hnsw_indexes.sql
```
HNSW 索引可大幅提升向量相似度查詢效能,建議在資料匯入完成後執行。
---
## 維護工具組(下劃線前綴腳本)
| 腳本 | 用途 |
|------|------|
| `_reingest_with_ocr.py` | 含 OCR 的完整重新向量化(處理掃描 PDF) |
| `_reingest_missing_pdfs.py` | 比對 downloads/ 找出未向量化的 PDF 並補充 ingest |
| `_match_pdfs.py` | 比對本地 PDF 與資料庫中已有的文件 |
| `_ocr_poc.py` | OCR 功能驗證腳本(概念驗證) |
| `_reingest_skipped.tsv` | 記錄跳過的檔案清單(檔名、跳過原因) |
---
## query_server_enhanced.py 功能說明
提供 REST API 供 MCP Server 或外部程式查詢 `ahow_db`:
- **連線池**:psycopg2 連線池(2–20 連線)
- **熔斷器模式**:防止級聯故障,自動恢復
- **中文編碼處理**:自動偵測 GBK / Big5 / UTF-8
- **Embedding 快取**:LRU 策略快取 Ollama 嵌入結果(TTL 7200 秒)
- **效能監控**:P95 / P99 延遲統計、快取命中率
**API 端點**:
```
POST http://localhost:11451/query
Content-Type: application/json
{ "query": "施工圍籬的設置規範" }
```
---
## 系統需求
| 元件 | 版本 / 說明 |
|------|-------------|
| Python | 3.8+ |
| PostgreSQL | 16,含 pgvector 擴充 |
| Ollama | 本地運行,已下載 `qwen3-embedding:4b` |
| psycopg2 | `pip install psycopg2-binary` |
| websockets | `pip install websockets` |
| python-dotenv | `pip install python-dotenv` |
| PyMuPDF(fitz)| `pip install pymupdf`(file_manager_gui 需要) |
| tiktoken | `pip install tiktoken`(file_manager_gui 需要) |