# AI Agent 系統
## 系統分析文件(SA Document)
| 欄位 | 內容 |
| ------------------ | -------------- |
| **文件版本** | v1.0.0 |
| **撰寫日期** | 2026-03-03 |
| **負責單位** | 機構設計整合部 |
| **系統代號** | MEC-AI |
| **機密等級** | 機構內部文件 |
---
## 目錄
1. [專案背景與目標](#1-專案背景與目標)
2. [系統需求分析](#2-系統需求分析)
3. [技術選型分析](#3-技術選型分析)
- [3.6 淘汰方案說明(AnythingLLM / MaxKB / Dify)](#36-淘汰方案說明anythingllm--maxkb--dify)
4. [系統架構設計](#4-系統架構設計)
5. [資料庫設計](#5-資料庫設計)
6. [API 規格設計](#6-api-規格設計)
7. [關鍵流程設計](#7-關鍵流程設計)
8. [前端設計規格](#8-前端設計規格)
9. [MCP 工具設計](#9-mcp-工具設計)
10. [安全設計](#10-安全設計)
11. [離線環境部署指南](#11-離線環境部署指南)
12. [專案結構與開發計畫](#12-專案結構與開發計畫)
13. [附錄:Mermaid 圖例清單](#13-附錄mermaid-圖例清單)
---
## 1. 專案背景與目標
### 1.1 背景說明
機構設計整合部的研發同仁日常以 SolidWorks、CATIA 等 CAD 軟體進行機構設計作業,需頻繁查閱指令手冊、功能說明及教育訓練資料。現有資料散落於各處文件,查閱效率低落,且無法支援自然語言提問。
本系統目標是在**完全離線的內網環境**中,建構一套以 AI Agent 為核心的知識輔助系統,部署於機構設計整合部專用伺服器,研發同仁透過繪圖筆電的瀏覽器即可存取。
### 1.2 系統目標
| 目標 | 說明 |
| ----------------- | ---------------------------------------------- |
| 📖 CAD 知識問答 | 自然語言查詢 CAD 指令、快捷鍵、操作步驟 |
| 🖼️ 多模態支援 | 可上傳 CAD 截圖或圖片進行詢問 |
| 📁 知識庫管理 | 批次匯入技術文件(PDF/Word/圖片)並自動向量化 |
| 🔧 MCP 工具整合 | 透過 MCP 協議整合 CAD 工具與專家知識 |
| 🔒 資料在地化 | 所有資料與運算皆留存於機構內網,不外傳 |
| 🛠️ 可維護可擴展 | 全開源技術棧,任何具備 Python 基礎的人員可維護 |
### 1.3 系統邊界
- **後端服務** 部署於整合部專用伺服器(含 LLM、向量資料庫、API 服務)
- **客戶端** 為研發同仁的繪圖筆電,僅需瀏覽器即可使用
- **離線環境** 系統完全在機構內網運作,不依賴任何外部雲端服務
- **不使用 Docker**,所有服務採原生安裝方式部署
---
## 2. 系統需求分析

### 2.1 功能需求
#### FR-01:多輪對話問答
- 使用者可透過 Web 介面與 AI Agent 進行自然語言對話
- 支援上下文記憶(多輪對話保持脈絡)
- 支援串流輸出(逐字顯示回應,減少等待感)
#### FR-02:CAD 工具輔助(MCP 工具)
- Agent 可自動識別 CAD 相關查詢並呼叫 MCP 工具
- MCP 工具提供 CAD 指令查詢、功能說明等專業回應
#### FR-03:知識庫 RAG 問答
- 匯入的文件可透過向量搜尋供 Agent 引用
- 回答附帶引用來源(文件名稱、頁碼)
#### FR-04:多模態輸入
- 使用者可上傳圖片(CAD 截圖、工程圖)進行詢問
- Agent 可分析圖片內容並結合知識庫回答
#### FR-05:文件匯入與管理
- 支援 PDF(含圖片)、Word、Markdown、純文字格式
- 支援批次匯入整個資料夾
- PDF 中的圖片自動以視覺模型描述,納入向量索引
#### FR-06:使用者管理
- 支援帳號登入
- 角色分為一般使用者與管理員
#### FR-07:稽核日誌
- 所有操作(對話、上傳、刪除)皆記錄至稽核日誌
### 2.2 非功能需求
| 需求類別 | 要求 |
| ------------------ | ------------------------------------------------- |
| **效能** | 一般問答回應首字元 < 3 秒(取決於伺服器規格) |
| **可用性** | 系統在伺服器開機後自動啟動,無需手動介入 |
| **可擴展性** | 新增 MCP 工具或切換 AI 模型無需重寫核心程式 |
| **可維護性** | 全 Python 後端,程式碼模組化,有清楚文件 |
| **安全性** | JWT 認證、角色存取控制、Prompt 注入防護 |
| **離線性** | 100% 離線,不對外發出任何 HTTP 請求 |
| **資源限制** | 後端伺服器承擔 LLM 推理,客戶端繪圖筆電僅執行前端 |
---
## 3. 技術選型分析
### 3.1 AI 推理平台選型
> 評估基準:Windows 原生支援、無 Docker 依賴、CUDA/GPU 支援、離線能力、OpenAI 相容 API、GGUF 量化、授權條款
| 項目 | **Ollama** ✅ | vLLM | LLaMA.cpp Server | Foundry Local |
| ------------------ | :-----------------: | :------------: | :--------------: | :------------------: |
| Windows 原生 | ✅ 一鍵安裝 | ❌ Linux 為主 | ✅ | ✅ |
| 無 Docker 依賴 | ✅ | ❌ 建議 Docker | ✅ | ✅ |
| NVIDIA CUDA | ✅ | ✅ | ✅ | ✅ |
| GGUF 量化 (4/8bit) | ✅ | ❌ | ✅ | 部分 |
| OpenAI 相容 API | ✅ (`/v1`) | ✅ | ✅ | ✅ |
| 多模態 (Vision) | ✅ | ✅ | 部分 | 部分 |
| Embedding API | ✅ | ✅ | ✅ | ❌ |
| 模型管理 CLI | ✅ 完善 | 有限 | 有限 | 有限 |
| 離線完整運作 | ✅ | ✅ | ✅ | ⚠️ 需登入 |
| 授權 | MIT | Apache 2.0 | MIT | 微軟條款 |
| 社群成熟度 | **極高** | 高 | 極高 | 中 |
| 商業化風險 | **低** | 低 | 低 | **高(微軟)** |
**🏆 選型結論:Ollama**
理由:
1. Windows `.exe` 一鍵安裝,無任何外部依賴
2. GGUF 量化讓 7B 模型在 4~6GB VRAM 下可順暢運行
3. `ollama serve` 啟動後自動提供 OpenAI 相容的 REST API
4. `Modelfile` 機制支援模型自訂(系統提示、參數)
5. MIT 授權,無商業化風險
6. 可完全離線,模型下載完成後不再需要網路
---
### 3.2 Agent 框架選型
> 評估基準:授權條款、商業化風險、無 Docker 依賴、MCP 工具支援、RAG 能力、自訂前端 API、PostgreSQL+pgvector 整合
| 項目 | **LangGraph** ✅ | Dify | Langflow |
| -------------- | :---------------------: | :--------------------------: | :-------------------: |
| 授權 | **MIT** | Apache 2.0 + 附加條款¹ | MIT |
| 商業化風險 | **低** | **中高**(已有企業版) | 中(DataStax 商業化) |
| 無 Docker 依賴 | ✅`pip install` | ⚠️ 強烈建議 Docker | ⚠️ 建議 Docker |
| MCP 工具支援 | ✅ 原生 (langchain-mcp) | ✅ 插件 | ✅ 部分 |
| RAG Pipeline | ✅ 原生 LangChain | ✅ 內建完整 | ✅ 完整 |
| 自訂前端 API | ✅ FastAPI 包裝 | ✅ REST API | ✅ REST API |
| pgvector 整合 | ✅ langchain-postgres | ✅ | ✅ |
| 可程式化程度 | **極高** | 中 | 中 |
| 狀態機持久化 | ✅ PostgresSaver | ✅ 資料庫 | 有限 |
| 批次匯入自訂 | ✅ 完全可控 | ✅ 內建 | ✅ |
| 多模態 | ✅ | ✅ | ✅ |
| 授權可二次開發 | ✅ 無限制 | ⚠️ 有使用限制 | ✅ |
¹ **Dify 授權限制**:在 Apache 2.0 基礎上附加條款,若以 Dify 為基礎提供 SaaS 服務且超過 50,000 使用者,須取得商業授權;自行派生版本需特別標示。本系統雖屬內部使用,但商業化風險與程式碼控制限制不符合長期維護需求。
**🏆 選型結論:LangGraph(LangChain 生態)**
理由:
1. **MIT 授權**,完全無商業化風險,可自由二次開發
2. `pip install langgraph langchain-ollama langchain-postgres` 即完成安裝,無 Docker
3. **顯式狀態機**:每個節點(意圖分類→RAG 檢索→工具呼叫→生成)皆可測試與稽核
4. **原生 MCP 支援**:`langchain-mcp-adapters` 套件直接整合 MCP Server
5. `AsyncPostgresSaver` 將對話狀態持久化至 PostgreSQL,支援多工作階段恢復
6. 生態最廣:LangChain 社群 GitHub Star > 100K,持續快速迭代
7. 任何了解 Python 的人員皆能快速上手維護
---
### 3.3 模型選型
> 後端伺服器承擔所有 LLM 推理,客戶端繪圖筆電僅執行前端。
#### 3.3.1 主力對話模型(含多模態)
| 模型 | 量化 | VRAM 需求 | 特點 | 適用場景 |
| -------------------------- | ------ | --------- | ------------------------------------ | ------------------ |
| **Qwen2.5-VL:7b** ✅ | Q4_K_M | ~5 GB | 阿里巴巴出品,繁中優秀,支援圖片輸入 | 預設主力模型 |
| Qwen2.5-VL:32b | Q4_K_M | ~20 GB | 更強大的推理能力 | 高規格伺服器 |
| Gemma3:12b | Q4_K_M | ~8 GB | Google 出品,多模態,效能均衡 | 伺服器 VRAM 8~12GB |
| Gemma3:4b | Q4_K_M | ~3 GB | 輕量備援模型 | 資源緊張時 |
#### 3.3.2 Embedding 模型
| 模型 | VRAM 需求 | 向量維度 | 特點 |
| ----------------------------- | --------- | -------- | ------------------------------ |
| **nomic-embed-text** ✅ | ~0.3 GB | 768 | 高品質,繁中支援良好,MIT 授權 |
| mxbai-embed-large | ~0.6 GB | 1024 | 更高維度,精準度更高 |
> 💡 **伺服器 VRAM 建議**:
>
> - 最低需求:8 GB(Qwen2.5-VL:7b + nomic-embed-text)
> - 建議配置:16 GB(可同時載入多個模型)
> - 高效配置:24 GB(可使用 Qwen2.5-VL:32b)
---
### 3.4 文件解析工具選型
| 工具 | 文字擷取 | 圖片擷取 | 表格 | 授權 | 備註 |
| ------------------------ | :---------: | :-------: | :-----: | ---------- | ---------------------- |
| **pymupdf4llm** ✅ | ✅ Markdown | ✅ 像素圖 | ✅ | AGPL-3.0 | 內部使用無商業授權問題 |
| unstructured | ✅ | ✅ | ✅ | Apache 2.0 | 複雜版面分析較強 |
| pdfplumber | ✅ | ✅ 有限 | ✅ 精準 | MIT | 表格擷取最強 |
**🏆 選型結論:pymupdf4llm 為主,unstructured 為輔**
- **pymupdf4llm**:將 PDF 轉為 Markdown,保留文字結構、表格、圖片位置資訊
- 圖片自動以 **Qwen2.5-VL** 視覺模型生成文字描述,描述結果納入向量索引
- 對於複雜的多欄版面,額外引入 unstructured 處理
---
### 3.5 技術棧總覽
```
┌─────────────────────────────────────────────────────────────┐
│ 技術棧總覽 │
├───────────────┬─────────────────────────────────────────────┤
│ 層級 │ 選用技術 │
├───────────────┼─────────────────────────────────────────────┤
│ 前端介面 │ React 18 + TypeScript + Vite │
│ │ TailwindCSS + shadcn/ui │
├───────────────┼─────────────────────────────────────────────┤
│ 後端 API │ Python 3.11 + FastAPI + Uvicorn │
│ │ python-jose (JWT) + passlib (bcrypt) │
├───────────────┼─────────────────────────────────────────────┤
│ Agent 引擎 │ LangGraph 0.3+ + LangChain 0.3+ │
│ │ langchain-ollama + langchain-postgres │
├───────────────┼─────────────────────────────────────────────┤
│ MCP 整合 │ langchain-mcp-adapters + mcp SDK │
├───────────────┼─────────────────────────────────────────────┤
│ LLM 推理 │ Ollama(Windows 原生) │
│ │ Qwen2.5-VL:7b(對話+視覺) │
│ │ nomic-embed-text(向量嵌入) │
├───────────────┼─────────────────────────────────────────────┤
│ 向量儲存 │ PostgreSQL 16 + pgvector 擴充套件 │
│ │ langchain-postgres(PGVector) │
├───────────────┼─────────────────────────────────────────────┤
│ 關聯式資料庫 │ PostgreSQL 16 │
│ │ SQLAlchemy 2.0 + Alembic(遷移管理) │
├───────────────┼─────────────────────────────────────────────┤
│ PDF 解析 │ pymupdf4llm + unstructured │
│ │ Pillow(圖片處理) │
├───────────────┼─────────────────────────────────────────────┤
│ 作業系統 │ Windows 11(伺服器 + 客戶端) │
└───────────────┴─────────────────────────────────────────────┘
```
---
### 3.6 淘汰方案說明(AnythingLLM / MaxKB / Dify)
本節說明在初步評估中曾列入考慮的三款「一體式 AI 知識庫平台」最終未被採用的原因。這三款平台均以低程式碼(Low-code)或零程式碼(No-code)為賣點,適合快速建立 RAG 問答系統,但在本系統的需求下均存在不同程度的根本性限制。
---
#### 3.6.1 AnythingLLM
> **定位**:桌面 / 伺服器端一體式 RAG 問答應用,支援 Ollama、OpenAI 等多種 LLM 後端
| 限制面向 | 說明 |
| ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **黑盒系統,RAG Pipeline 不可客製** | AnythingLLM 將文件切割、向量化、檢索、生成等步驟封裝在內部實作中,使用者無法介入調整 Chunk 策略、Reranker 邏輯或 Prompt 模板,難以針對 CAD 技術文件的特殊版面進行優化。 |
| **Agent 流程無法程式化控制** | 其 Agent 模式採固定的 ReAct 迴圈,不支援 LangGraph 式的顯式狀態機,無法實作「意圖分類 → 分支路由 → 視覺分析 → RAG 檢索 → 生成」等多步驟複合流程。 |
| **文件攝入邏輯封閉** | 無法在 PDF 攝入時插入自訂步驟(例如:呼叫 Qwen2.5-VL 對圖片自動生成文字描述後一併向量化),此為本系統的核心需求之一。 |
| **多使用者企業部署能力有限** | 多工作區(Workspace)機制並非設計給企業多部門、多角色的存取控制場景,使用者管理與稽核日誌功能相對薄弱。 |
**結論**:AnythingLLM 適合個人或小型團隊快速建立 RAG 原型,但本系統需要完全可控的 Pipeline、深度 MCP 整合與 Python 可維護性,AnythingLLM 無法滿足。
---
#### 3.6.2 MaxKB
> **定位**:中文優先的開源知識庫問答平台(飛致雲出品),以 Django 後端 + Vue 前端構成
| 限制面向 | 說明 |
| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| **強依賴 Docker 部署** | 官方推薦以 `docker-compose` 安裝,無 Docker 的原生安裝路徑文件不完整、社群支援薄弱,與本系統「不使用 Docker」的硬性需求衝突。 |
| **Django 架構封閉,擴充困難** | 後端以 Django ORM 緊密耦合,若需在攝入流程中插入視覺模型描述步驟或客製 Chunk 策略,需深入改寫框架核心,維護成本極高。 |
| **無原生 MCP 工具整合** | MaxKB 的「工具」概念為平台自有生態,與 MCP 規範不相容,無法直接整合標準 MCP Server。 |
| **多模態支援有限** | 截至評估時(2026-Q1),MaxKB 對圖片輸入的支援仍處於實驗階段,無法穩定支援使用者上傳 CAD 截圖進行問答的場景。 |
| **Agent 推理流程不透明** | MaxKB 的 Agent 節點以 GUI 工作流設定為主,對複雜條件分支的程式化控制能力不足,中間步驟難以加入日誌稽核。 |
| **社群與迭代速度** | GitHub Star 數與 Issue 響應速度遠低於 LangChain 生態,長期維護風險較高。 |
**結論**:MaxKB 在純中文 RAG 場景有一定優勢,但 Docker 依賴、封閉架構與 MCP 不相容三項硬傷,使其無法適用於本系統的部署與擴充需求。
---
#### 3.6.3 Dify
> **定位**:開源 LLM 應用開發平台,提供視覺化工作流編輯器,支援 RAG、Agent、Chatbot 等多種應用模式
> ⚠️ Dify 已於 [3.2 Agent 框架選型](#32-agent-框架選型) 列入比較表,此處進一步展開說明淘汰原因。
| 限制面向 | 說明 |
| ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **授權附加條款,商業化風險** | Dify 採 Apache 2.0 + 自訂附加條款(Dify Additional Terms):若以 Dify 為基礎提供 SaaS 服務且月活躍使用者超過 50,000,須取得商業授權;自行 Fork 的衍生版本需保留 Dify 標識。雖然本系統為內部使用,但條款的模糊性與潛在的商業化風險不符合本部門對完全開源技術棧的要求。 |
| **強依賴 Docker Compose** | Dify 的標準安裝方式為 `docker compose up`,包含 Nginx、Worker、API、Web、PostgreSQL、Redis、Weaviate 等多個容器,不符合「不使用 Docker」的部署限制。雖有 `local` 分支可嘗試原生安裝,但官方不積極維護此路徑,生產環境穩定性存疑。 |
| **Low-code 介面靈活性不足** | Dify 的視覺化工作流(Workflow)對於常見的 RAG、Function Calling 場景操作便利,但當需要實作「攝入時呼叫視覺模型描述圖片並回寫至向量索引」這類深度客製邏輯時,必須依賴自訂代碼節點(Code Node),等同退化為手寫程式,失去平台優勢,且除錯困難。 |
| **升級相容性風險** | Dify 迭代速度快,但版本間 API 與資料庫 Schema 變更頻繁,升級需謹慎測試,對維護人力有限的內部團隊而言是額外負擔。 |
| **中間步驟稽核能力弱** | Dify 的 Workflow Trace 雖可查看節點輸入輸出,但對資安稽核所需的每步驟完整日誌(操作者、時間戳、資料雜湊)支援有限,需另行開發。 |
| **系統為黑盒,除錯困難** | 遇到非預期行為時,開發者難以快速定位是 Dify 平台層、LLM 呼叫層或工具層的問題,不如直接以 LangGraph 撰寫的程式碼透明可查。 |
**結論**:Dify 功能完整且介面友善,適合快速建立 AI 應用原型;但授權附加條款、Docker 強依賴、以及在本系統複雜需求下退化為「必須手寫 Code Node」的困境,使其無法成為本系統的長期技術基礎。LangGraph 在可程式化、可稽核、可維護三個面向均全面優於 Dify。
---
## 4. 系統架構設計

### 4.1 整體架構
```
┌──────────────────────────────────────────────────────────────────┐
│ Client Layer(研發繪圖筆電) │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ Web Browser(Chrome / Edge) │ │
│ │ React + TypeScript SPA(http://server-ip:5173) │ │
│ └────────────────────────┬───────────────────────────────┘ │
└────────────────────────────┼─────────────────────────────────────┘
│ RESTful API / SSE Stream(內網 HTTP)
│
┌────────────────────────────▼─────────────────────────────────────┐
│ Server Layer(整合部專用機器) │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ FastAPI Service (Port 8000) │ │
│ │ ┌───────────┐ ┌─────────────┐ ┌──────────────────┐ │ │
│ │ │ Chat API │ │ Document API│ │ Admin API │ │ │
│ │ │ /chat/* │ │ /documents/*│ │ /admin/* │ │ │
│ │ └─────┬─────┘ └──────┬──────┘ └────────┬─────────┘ │ │
│ │ └───────────────┼──────────────────┘ │ │
│ │ │ │ │
│ └────────────────────────┼────────────────────────────────┘ │
│ │ │
│ ┌────────────────────────▼────────────────────────────────┐ │
│ │ LangGraph Agent Engine │ │
│ │ │ │
│ │ START → [意圖分類] → { │ │
│ │ "rag" → [RAG 檢索] → [生成] │ │
│ │ "cad_tool" → [MCP 工具] → [生成] │ │
│ │ "vision" → [視覺分析] → [RAG] → [生成] │ │
│ │ "general" → [直接生成] │ │
│ │ } → END │ │
│ │ │ │
│ └──────┬────────────────┬──────────────────────────────────┘ │
│ │ │ │
│ ┌──────▼──────┐ ┌──────▼──────────────────────────────────┐ │
│ │ Ollama │ │ PostgreSQL 16 │ │
│ │ (Port 11434)│ │ ┌──────────────┐ ┌──────────────────┐ │ │
│ │ │ │ │ pgvector │ │ Relational DB │ │ │
│ │ Qwen2.5-VL │ │ │ (Embeddings) │ │ (Metadata, │ │ │
│ │ :7b │ │ │ document_ │ │ Users, Logs) │ │ │
│ │ nomic-embed │ │ │ chunks │ │ │ │ │
│ │ -text │ │ └──────────────┘ └──────────────────┘ │ │
│ └──────┬──────┘ └───────────────────────────────────────────┘ │
│ │ │
│ ┌──────▼──────────────────────────────────────────────────┐ │
│ │ MCP Servers │ │
│ │ ┌──────────────────────┐ ┌───────────────────────┐ │ │
│ │ │ CAD Tools MCP │ │ Knowledge MCP │ │ │
│ │ │ (指令查詢/功能說明) │ │ (專業知識擴充) │ │ │
│ │ └──────────────────────┘ └───────────────────────┘ │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ File Storage(本機檔案系統) │ │
│ │ D:\mechdesign-ai\storage\documents\ │ │
│ └────────────────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────────────┘
```
### 4.2 元件說明
| 元件 | 說明 | Port |
| -------------------------------- | ------------------------------------------------------ | ----- |
| **FastAPI** | 後端 REST API,處理所有客戶端請求,負責認證與路由 | 8000 |
| **LangGraph Agent Engine** | 核心 AI Agent,顯式狀態機,管理對話流程與工具呼叫 | - |
| **Ollama Service** | 本地 LLM 推理服務,提供 OpenAI 相容 API | 11434 |
| **PostgreSQL + pgvector** | 關聯式資料庫兼向量資料庫,儲存所有業務資料與向量索引 | 5432 |
| **MCP CAD Tools** | Model Context Protocol Server,提供 CAD 指令查詢等工具 | 8100 |
| **MCP Knowledge** | MCP Server,提供領域知識擴充工具 | 8101 |
| **React Frontend** | 以 Vite 建構的 SPA,透過 API 與後端溝通 | 5173 |
| **File Storage** | 本機目錄儲存上傳的原始文件 | - |
### 4.3 關鍵設計原則
1. **LLM 無感切換**:所有 LLM 呼叫透過 Ollama OpenAI 相容介面,更換模型只需修改 `config.py` 中的 `MODEL_NAME`
2. **工具熱插拔**:新增 MCP Server 無需修改 Agent 核心程式,只需在 `mcp_servers_config.json` 中登記
3. **前後端分離**:FastAPI 提供純 REST API,前端可由任何框架實作,亦可由第三方開發
4. **狀態持久化**:LangGraph 使用 `AsyncPostgresSaver` 將對話 Checkpoints 存入 PostgreSQL,重啟後可恢復對話
---
## 5. 資料庫設計
> 資料庫引擎:**PostgreSQL 16** + **pgvector** 擴充套件
> ORM:**SQLAlchemy 2.0**(Async 模式)

### 5.1 資料表清單
| 資料表 | 說明 |
| ------------------------- | --------------------------------------------- |
| `users` | 使用者帳號與角色管理 |
| `conversations` | 對話工作階段(Session)紀錄 |
| `messages` | 每則對話訊息(含 Agent 中間步驟) |
| `documents` | 匯入文件的元資料(檔名、狀態、統計) |
| `document_chunks` | 向量化後的文件段落(含 pgvector 向量欄位) |
| `mcp_tools` | 已登記的 MCP 工具清單 |
| `audit_logs` | 所有使用者操作的稽核紀錄 |
| `batch_jobs` | 批次匯入任務狀態追蹤 |
| `langgraph_checkpoints` | LangGraph 對話狀態 Checkpoint(框架自動管理) |
### 5.2 資料表詳細定義
#### `users`
```sql
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
username VARCHAR(64) UNIQUE NOT NULL,
email VARCHAR(128) UNIQUE NOT NULL,
password_hash VARCHAR(256) NOT NULL,
role VARCHAR(16) NOT NULL DEFAULT 'user', -- 'user' | 'admin'
is_active BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
last_login_at TIMESTAMPTZ
);
```
#### `conversations`
```sql
CREATE TABLE conversations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
title VARCHAR(256) NOT NULL DEFAULT '新對話',
system_prompt TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
```
#### `messages`
```sql
CREATE TABLE messages (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
conversation_id UUID NOT NULL REFERENCES conversations(id) ON DELETE CASCADE,
role VARCHAR(16) NOT NULL, -- 'user' | 'assistant' | 'system' | 'tool'
content TEXT NOT NULL,
metadata JSONB DEFAULT '{}', -- 含引用來源、工具呼叫結果
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_messages_conversation_id ON messages(conversation_id);
CREATE INDEX idx_messages_created_at ON messages(created_at);
```
#### `documents`
```sql
CREATE TABLE documents (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
uploaded_by UUID REFERENCES users(id),
filename VARCHAR(512) NOT NULL,
file_type VARCHAR(32) NOT NULL, -- 'pdf' | 'docx' | 'md' | 'txt' | 'image'
file_path TEXT NOT NULL,
file_size INTEGER NOT NULL, -- bytes
status VARCHAR(32) NOT NULL DEFAULT 'pending',
-- 'pending' | 'processing' | 'completed' | 'failed'
chunk_count INTEGER DEFAULT 0,
metadata JSONB DEFAULT '{}', -- 自訂標籤、分類等
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
```
#### `document_chunks`(核心向量表)
```sql
-- 需先啟用 pgvector:CREATE EXTENSION IF NOT EXISTS vector;
CREATE TABLE document_chunks (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
document_id UUID NOT NULL REFERENCES documents(id) ON DELETE CASCADE,
content TEXT NOT NULL,
embedding VECTOR(768), -- nomic-embed-text 維度為 768
chunk_index INTEGER NOT NULL,
page_number INTEGER,
chunk_type VARCHAR(32) DEFAULT 'text', -- 'text' | 'image_description' | 'table'
metadata JSONB DEFAULT '{}',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- 向量相似度索引(HNSW,適合中小型資料集)
CREATE INDEX idx_doc_chunks_embedding
ON document_chunks
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);
CREATE INDEX idx_doc_chunks_document_id ON document_chunks(document_id);
```
#### `audit_logs`
```sql
CREATE TABLE audit_logs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES users(id),
action VARCHAR(64) NOT NULL, -- 'chat', 'upload', 'delete', 'login', etc.
resource_type VARCHAR(64),
resource_id VARCHAR(256),
details JSONB DEFAULT '{}',
ip_address VARCHAR(64),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_audit_logs_user_id ON audit_logs(user_id);
CREATE INDEX idx_audit_logs_created_at ON audit_logs(created_at);
```
#### `batch_jobs`
```sql
CREATE TABLE batch_jobs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES users(id),
status VARCHAR(32) NOT NULL DEFAULT 'pending',
-- 'pending' | 'processing' | 'completed' | 'failed'
source_path TEXT NOT NULL,
total_files INTEGER NOT NULL DEFAULT 0,
processed_files INTEGER NOT NULL DEFAULT 0,
failed_files INTEGER NOT NULL DEFAULT 0,
error_log JSONB DEFAULT '[]',
started_at TIMESTAMPTZ,
completed_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
```
### 5.3 向量搜尋查詢範例
```sql
-- RAG 檢索:以 query_embedding 搜尋最相似的 5 個文件段落
SELECT
dc.content,
dc.metadata,
d.filename,
dc.page_number,
1 - (dc.embedding <=> $1::vector) AS similarity
FROM document_chunks dc
JOIN documents d ON dc.document_id = d.id
WHERE d.status = 'completed'
ORDER BY dc.embedding <=> $1::vector
LIMIT 5;
```
---
## 6. API 規格設計
> Base URL: `http://<server-ip>:8000/api/v1`
> 認證方式:`Authorization: Bearer <JWT Token>`
> 回應格式:`Content-Type: application/json`
### 6.1 認證 API
#### `POST /auth/login` — 使用者登入
```json
// Request
{
"username": "john.doe",
"password": "secret"
}
// Response 200
{
"access_token": "eyJhbGci...",
"token_type": "bearer",
"expires_in": 28800,
"user": {
"id": "550e8400-...",
"username": "john.doe",
"role": "user"
}
}
```
---
### 6.2 Chat API
#### `POST /chat/stream` — 串流對話(Server-Sent Events)
```json
// Request
{
"session_id": "550e8400-...", // 可選,不傳則建立新對話
"message": "SolidWorks 如何建立曲面特徵?",
"image_base64": null // 可選,含圖片時帶入 base64
}
// Response (SSE stream)
data: {"type": "token", "content": "要"}
data: {"type": "token", "content": "在"}
data: {"type": "token", "content": "SolidWorks"}
...
data: {"type": "sources", "documents": [{"filename": "SW手冊.pdf", "page": 42}]}
data: {"type": "done", "session_id": "550e8400-..."}
```
#### `GET /chat/conversations` — 取得對話列表
```json
// Response 200
{
"conversations": [
{
"id": "550e8400-...",
"title": "SolidWorks 曲面特徵詢問",
"updated_at": "2026-03-03T10:30:00Z",
"message_count": 5
}
],
"total": 12,
"page": 1
}
```
#### `GET /chat/conversations/{id}/messages` — 取得對話訊息
```json
// Response 200
{
"messages": [
{
"id": "...",
"role": "user",
"content": "SolidWorks 如何建立曲面特徵?",
"created_at": "2026-03-03T10:30:00Z"
},
{
"id": "...",
"role": "assistant",
"content": "要在 SolidWorks 建立曲面特徵...",
"metadata": {
"sources": [{"filename": "SW手冊.pdf", "page": 42}],
"tool_used": "rag"
},
"created_at": "2026-03-03T10:30:05Z"
}
]
}
```
---
### 6.3 Document API
#### `POST /documents/upload` — 單一文件上傳
```
// Request (multipart/form-data)
Content-Type: multipart/form-data
file: <binary>
metadata: {"category": "SolidWorks", "tags": ["曲面", "特徵"]}
// Response 202
{
"document_id": "550e8400-...",
"filename": "SW曲面特徵手冊.pdf",
"status": "processing",
"job_id": "job-uuid"
}
```
#### `POST /documents/batch-import` — 批次匯入(資料夾路徑,伺服器本地路徑)
```json
// Request
{
"source_path": "D:\\documents\\cad_manuals\\",
"file_extensions": ["pdf", "docx", "md"],
"metadata": {"category": "CAD手冊"}
}
// Response 202
{
"job_id": "batch-job-uuid",
"total_files": 23,
"status": "processing"
}
```
#### `GET /documents/batch-jobs/{job_id}` — 查詢批次任務狀態
```json
// Response 200
{
"job_id": "batch-job-uuid",
"status": "processing",
"total_files": 23,
"processed_files": 10,
"failed_files": 1,
"progress_percent": 43,
"estimated_completion": "2026-03-03T10:45:00Z"
}
```
---
### 6.4 Admin API
#### `GET /admin/system-status` — 系統狀態
```json
// Response 200
{
"ollama": {
"status": "running",
"models": [
{"name": "qwen2.5-vl:7b", "size_gb": 4.4, "loaded": true},
{"name": "nomic-embed-text", "size_gb": 0.3, "loaded": true}
]
},
"database": {
"status": "connected",
"document_count": 145,
"chunk_count": 8230
},
"mcp_tools": [
{"name": "cad_command_query", "status": "running"},
{"name": "knowledge_expert", "status": "running"}
]
}
```
#### `GET /admin/tools` — MCP 工具清單
```json
// Response 200
{
"tools": [
{
"name": "cad_command_query",
"description": "查詢 CAD 軟體的指令、快捷鍵與操作步驟",
"server_url": "http://localhost:8100",
"is_active": true,
"parameters": {
"software": "string (solidworks|catia|autocad)",
"keyword": "string"
}
}
]
}
```
---
## 7. 關鍵流程設計
### 7.1 RAG 對話流程(含 MCP 工具選用條件)
> 詳見 Mermaid 圖例:`docs/diagrams/04_sequence_rag.mmd`

#### LangGraph 狀態機節點說明
```
START
↓
[Node 1: classify_intent]
描述:呼叫 LLM 判斷使用者意圖
輸出 intent:
"rag" → 知識庫問答(需要查詢內部文件)
"cad_tool" → CAD 工具查詢(指令/快捷鍵/操作步驟)
"vision" → 視覺分析(使用者上傳了圖片)
"general" → 一般對話(不需要工具或 RAG)
↓
[條件路由]
↓ (rag) ↓ (cad_tool) ↓ (vision) ↓ (general)
[Node 2a: [Node 2b: [Node 2c: [Node 3:
rag_retrieve] call_cad_tool] vision_analyze] generate]
↓ RAG 結果 ↓ MCP 工具結果 ↓ 視覺描述
↓ ↓ (可選 RAG 補充) ↓ (RAG 補充)
[Node 3: generate_response]
描述:以上下文生成回答,串流輸出
↓
END
```
#### MCP 工具選用條件
| 意圖分類 | 觸發條件 | 使用工具 |
| ------------ | --------------------------------------------------------------------------- | ------------------------- |
| `cad_tool` | 問句包含「指令」「快捷鍵」「操作步驟」「功能」等關鍵詞,且指向特定 CAD 動作 | `cad_command_query` MCP |
| `rag` | 問句涉及「如何」「說明」「什麼是」「教學」等,需要文件知識 | pgvector 向量搜尋 |
| `vision` | 使用者上傳了圖片(`image_base64` 非空) | Qwen2.5-VL 視覺推理 + RAG |
| `general` | 一般問候、閒聊、簡單計算等,不需要外部資料 | 直接 LLM 回答 |
> **注意**:`cad_tool` 與 `rag` 可同時使用——MCP 工具取得結構化資料後,可進一步由 RAG 補充說明文件。
#### 核心程式碼概覽
```python
# backend/app/agent/state.py
from typing import Annotated, List, TypedDict
from langchain_core.messages import BaseMessage
from langgraph.graph.message import add_messages
class AgentState(TypedDict):
messages: Annotated[List[BaseMessage], add_messages]
intent: str # "rag" | "cad_tool" | "vision" | "general"
retrieved_docs: List[dict] # RAG 檢索到的文件段落
tool_results: List[dict] # MCP 工具呼叫結果
session_id: str
user_id: str
```
```python
# backend/app/agent/graph.py
from langgraph.graph import StateGraph, START, END
from langgraph.checkpoint.postgres.aio import AsyncPostgresSaver
def create_agent_graph(checkpointer: AsyncPostgresSaver):
graph = StateGraph(AgentState)
graph.add_node("classify_intent", classify_intent_node)
graph.add_node("rag_retrieve", rag_retrieve_node)
graph.add_node("call_cad_tool", call_cad_tool_node)
graph.add_node("vision_analyze", vision_analyze_node)
graph.add_node("generate_response", generate_response_node)
graph.add_edge(START, "classify_intent")
graph.add_conditional_edges(
"classify_intent",
lambda state: state["intent"],
{
"rag": "rag_retrieve",
"cad_tool": "call_cad_tool",
"vision": "vision_analyze",
"general": "generate_response",
}
)
graph.add_edge("rag_retrieve", "generate_response")
graph.add_edge("call_cad_tool", "generate_response")
graph.add_edge("vision_analyze", "generate_response")
graph.add_edge("generate_response", END)
return graph.compile(checkpointer=checkpointer)
```
---
### 7.2 文件上傳與向量化流程
> 詳見 Mermaid 圖例:`docs/diagrams/05_sequence_upload.mmd`

#### 流程概述
```
[使用者上傳檔案]
↓
[FastAPI 接收,建立 documents 紀錄,狀態 = "pending"]
↓
[Background Task 啟動 DocumentIngestionService]
↓
┌── PDF 檔案 ──┐
│ pymupdf4llm │
│ 轉 Markdown │
│ 擷取圖片 │→ 圖片 → Qwen2.5-VL 描述 → 合併回 Markdown
└──────────────┘
↓
[TextChunker:RecursiveCharacterTextSplitter]
chunk_size=512, chunk_overlap=64
↓
[Ollama nomic-embed-text 生成向量]
每個 chunk → 768 維向量
↓
[批次寫入 document_chunks (content + embedding)]
↓
[更新 documents.status = "completed"]
↓
[更新 batch_jobs 進度]
```
#### PDF 圖片處理細節
```python
# backend/app/ingestion/pdf_processor.py
import pymupdf4llm
import fitz # PyMuPDF
from app.services.ollama_service import OllamaService
class PDFProcessor:
def __init__(self, ollama: OllamaService):
self.ollama = ollama
async def process(self, pdf_path: str) -> str:
"""將 PDF 轉為含圖片描述的 Markdown"""
# 1. 轉換文字內容為 Markdown
md_text = pymupdf4llm.to_markdown(pdf_path)
# 2. 擷取所有圖片
doc = fitz.open(pdf_path)
image_descriptions = []
for page_num, page in enumerate(doc):
for img_index, img_info in enumerate(page.get_images()):
xref = img_info[0]
pix = fitz.Pixmap(doc, xref)
img_bytes = pix.tobytes("png")
# 3. 呼叫視覺模型描述圖片
description = await self.ollama.vision_chat(
prompt="請以繁體中文詳細描述這張工程圖片的內容,"
"包含尺寸、形狀、標注等資訊。",
image_bytes=img_bytes
)
image_descriptions.append(
f"\n[圖片說明 第{page_num+1}頁 圖{img_index+1}]:\n{description}\n"
)
# 4. 將圖片描述附加至 Markdown
return md_text + "\n\n" + "\n".join(image_descriptions)
```
---
## 8. 前端設計規格
### 8.1 頁面架構
```
/login 登入頁面
/ 主頁面(重新導向至 /chat)
/chat 對話主頁
/chat/:id 特定對話工作階段
/documents 文件管理頁
/documents/upload 上傳頁面
/admin 管理頁面(admin 角色才能存取)
/admin/system 系統狀態
/admin/users 使用者管理
/admin/tools MCP 工具管理
```
### 8.2 主要元件
| 元件 | 說明 |
| ----------------------- | ------------------------------------------ |
| `<ChatWindow />` | 對話主要介面,支援串流輸出顯示 |
| `<MessageItem />` | 單則訊息,支援 Markdown 渲染、引用來源顯示 |
| `<ImageUpload />` | 圖片上傳元件,支援拖放、預覽 |
| `<DocumentList />` | 文件列表,顯示向量化狀態 |
| `<BatchImportForm />` | 批次匯入表單,顯示進度條 |
| `<Sidebar />` | 對話歷史清單 |
| `<SystemStatus />` | Ollama 服務狀態、模型清單顯示 |
### 8.3 前端 API 呼叫範例
```typescript
// frontend/src/api/chat.ts
// 串流對話
export async function streamChat(
sessionId: string | null,
message: string,
imageBase64?: string,
onToken: (token: string) => void,
onDone: (sessionId: string) => void
) {
const response = await fetch('/api/v1/chat/stream', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${getToken()}`,
},
body: JSON.stringify({ session_id: sessionId, message, image_base64: imageBase64 }),
});
const reader = response.body!.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const lines = decoder.decode(value).split('\n');
for (const line of lines) {
if (!line.startsWith('data: ')) continue;
const data = JSON.parse(line.slice(6));
if (data.type === 'token') onToken(data.content);
if (data.type === 'done') onDone(data.session_id);
}
}
}
```
---
## 9. MCP 工具設計
### 9.1 MCP 架構說明
MCP(Model Context Protocol)是 Anthropic 制定的開放協議,用於讓 LLM 呼叫外部工具。LangGraph 透過 `langchain-mcp-adapters` 套件整合 MCP Server,使 Agent 可動態呼叫工具。
### 9.2 CAD Tools MCP Server(Port 8100)
```python
# backend/mcp_servers/cad_tools/server.py
from mcp.server import Server
from mcp.server.models import InitializationOptions
import mcp.types as types
server = Server("cad-tools")
@server.list_tools()
async def list_tools() -> list[types.Tool]:
return [
types.Tool(
name="cad_command_query",
description="查詢 CAD 軟體(SolidWorks/CATIA/AutoCAD)的"
"指令名稱、快捷鍵、操作步驟與功能說明",
inputSchema={
"type": "object",
"properties": {
"software": {
"type": "string",
"enum": ["solidworks", "catia", "autocad"],
"description": "目標 CAD 軟體名稱"
},
"keyword": {
"type": "string",
"description": "查詢的指令關鍵字,如「旋轉」「伸長」「曲面」"
}
},
"required": ["software", "keyword"]
}
),
types.Tool(
name="cad_shortcut_lookup",
description="查詢 CAD 軟體的鍵盤快捷鍵",
inputSchema={
"type": "object",
"properties": {
"software": {"type": "string", "enum": ["solidworks", "catia", "autocad"]},
"action": {"type": "string", "description": "想查詢的動作名稱"}
},
"required": ["software", "action"]
}
)
]
@server.call_tool()
async def call_tool(name: str, arguments: dict) -> list[types.TextContent]:
if name == "cad_command_query":
result = query_cad_database(arguments["software"], arguments["keyword"])
return [types.TextContent(type="text", text=result)]
# ...
```
#### CAD 指令資料庫格式(JSON)
```json
{
"solidworks": {
"伸長填料": {
"menu": "插入 → 填料/基材 → 伸長",
"shortcut": null,
"description": "沿指定方向伸長草圖輪廓以建立 3D 實體特徵",
"steps": [
"1. 選取草圖或草圖輪廓",
"2. 點選「插入 → 填料/基材 → 伸長」",
"3. 設定伸長方向與深度",
"4. 確認「√」完成特徵"
],
"tags": ["填料", "實體", "基材"]
}
}
}
```
### 9.3 LangGraph 中的 MCP 整合
```python
# backend/app/mcp/client.py
from langchain_mcp_adapters.client import MultiServerMCPClient
async def create_mcp_client() -> MultiServerMCPClient:
client = MultiServerMCPClient({
"cad_tools": {
"url": "http://localhost:8100/mcp",
"transport": "streamable_http"
},
"knowledge_tools": {
"url": "http://localhost:8101/mcp",
"transport": "streamable_http"
}
})
return client
# 在 AgentOrchestrator 初始化時
mcp_client = await create_mcp_client()
mcp_tools = await mcp_client.get_tools()
# mcp_tools 自動轉為 LangChain BaseTool 格式,可直接傳入 Agent
```
---
## 10. 安全設計
### 10.1 認證與授權
| 機制 | 說明 |
| ---------------------- | --------------------------------------------------------------------- |
| **JWT Token** | 登入後取得 JWT,每個 API 請求需帶入 `Authorization: Bearer <token>` |
| **Token 有效期** | 預設 8 小時,可在 `config.py` 中調整 |
| **密碼儲存** | 使用 `passlib[bcrypt]` 進行 hash,不儲存明文密碼 |
| **角色控制** | `user` 可對話與上傳文件;`admin` 額外可管理使用者與系統設定 |
### 10.2 輸入安全
| 威脅 | 防護措施 |
| -------------------------- | ----------------------------------------------------------- |
| **Prompt Injection** | System Prompt 明確限制 Agent 行為範圍;使用者輸入與指令分開 |
| **路徑穿越攻擊** | 批次匯入路徑僅允許管理員操作,且限制在白名單目錄內 |
| **超大檔案** | API 層限制上傳檔案大小(預設 50MB) |
| **惡意 PDF** | 使用 pymupdf 的安全模式解析,避免 PDF 注入 |
### 10.3 稽核日誌
所有以下操作都會寫入 `audit_logs` 資料表:
- 使用者登入/登出
- 對話建立、訊息傳送
- 文件上傳、刪除
- 批次匯入
- 管理員操作(使用者管理、系統設定)
### 10.4 資料隔離
- 每位使用者只能查看自己的對話記錄與上傳文件
- 管理員可查看所有紀錄
- 向量知識庫為全域共享(機構內部知識庫)
---
## 11. 離線環境部署指南
> 📌 所有軟體需預先下載至安裝媒介(USB 隨身碟),在離線環境中安裝。
> 📌 本指南假設作業系統為 **Windows 11**(伺服器端)。
### 11.1 伺服器端安裝步驟
#### Step 1:安裝 PostgreSQL 16
1. 下載 [PostgreSQL 16 Windows 安裝檔](https://www.postgresql.org/download/windows/)(`.exe`)
2. 安裝時設定:
- Port: `5432`
- 超級使用者密碼:建議使用強密碼
3. 安裝完成後,以 psql 啟用 pgvector:
```sql
-- 以 postgres 超級使用者連入
CREATE DATABASE mechdesign_ai;
\c mechdesign_ai
CREATE EXTENSION IF NOT EXISTS vector;
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
```
4. 安裝 pgvector Windows 版本:下載 [pgvector releases](https://github.com/pgvector/pgvector/releases) 的 Windows 二進位包,複製 `.dll` 至 PostgreSQL 的 `lib` 目錄,複製 `.control` 和 `.sql` 至 `share/extension` 目錄。
#### Step 2:安裝 Python 3.11
1. 下載 [Python 3.11 Windows 安裝檔](https://www.python.org/downloads/windows/)
2. 安裝時勾選「Add Python to PATH」
3. 確認安裝:`python --version`
#### Step 3:安裝 Ollama
1. 下載 [Ollama Windows 安裝檔](https://ollama.ai/download/windows)(`OllamaSetup.exe`)
2. 安裝後,Ollama 服務自動在背景執行
3. 匯入模型(需在有網路的機器預先下載):
```powershell
# 有網路環境下載模型
ollama pull qwen2.5-vl:7b
ollama pull nomic-embed-text
# 找到模型儲存目錄(通常在 %USERPROFILE%\.ollama\models)
# 複製整個 models 目錄至離線機器相同路徑
```
4. 設定 Ollama 監聽所有 IP(讓客戶端可存取):
```powershell
# 在系統環境變數中新增
OLLAMA_HOST = 0.0.0.0:11434
```
#### Step 4:安裝 Node.js(前端建構用)
1. 下載 [Node.js LTS](https://nodejs.org/)(v20+)
2. 確認安裝:`node --version`
#### Step 5:安裝後端 Python 依賴
```powershell
# 在有網路的環境先下載所有套件
pip download -r requirements.txt -d ./offline_packages
# 在離線環境安裝
pip install --no-index --find-links=./offline_packages -r requirements.txt
```
**`requirements.txt`**:
```
fastapi>=0.115.0
uvicorn[standard]>=0.30.0
langchain>=0.3.0
langgraph>=0.3.0
langchain-community>=0.3.0
langchain-ollama>=0.2.0
langchain-postgres>=0.0.9
langchain-mcp-adapters>=0.1.0
mcp>=1.0.0
psycopg[binary,pool]>=3.2.0
pgvector>=0.3.0
sqlalchemy>=2.0.0
alembic>=1.13.0
pymupdf4llm>=0.0.17
unstructured[pdf]>=0.15.0
pillow>=11.0.0
python-multipart>=0.0.9
python-jose[cryptography]>=3.3.0
passlib[bcrypt]>=1.7.4
pydantic-settings>=2.0.0
httpx>=0.27.0
python-dotenv>=1.0.0
```
#### Step 6:初始化資料庫
```powershell
# 設定環境變數 .env
DATABASE_URL=postgresql+psycopg://postgres:yourpassword@localhost:5432/mechdesign_ai
OLLAMA_BASE_URL=http://localhost:11434
SECRET_KEY=your-32-char-secret-key-here
CHAT_MODEL=qwen2.5-vl:7b
EMBED_MODEL=nomic-embed-text
STORAGE_PATH=D:\mechdesign-ai\storage
# 執行資料庫初始化
python scripts/init_db.py
```
#### Step 7:設定 Windows 服務自動啟動
使用 NSSM(Non-Sucking Service Manager)將後端服務設定為 Windows 服務:
```powershell
# 下載 NSSM,然後:
nssm install MechDesignAI-Backend "python" "-m uvicorn app.main:app --host 0.0.0.0 --port 8000"
nssm set MechDesignAI-Backend AppDirectory "D:\mechdesign-ai\backend"
nssm start MechDesignAI-Backend
# MCP Servers 同理
nssm install MechDesignAI-CAD-MCP "python" "mcp_servers/cad_tools/server.py"
nssm start MechDesignAI-CAD-MCP
```
#### Step 8:建構前端
```powershell
cd D:\mechdesign-ai\frontend
# 離線安裝前端依賴(需預先下載 node_modules)
npm install --offline
# 建構生產版本
npm run build
# dist/ 目錄即為靜態網頁,可由 FastAPI 提供靜態服務
# 或設定 Nginx 提供服務
```
---
### 11.2 客戶端(繪圖筆電)使用方式
客戶端**無需安裝任何軟體**,僅需開啟瀏覽器:
```
http://<伺服器IP>:8000
```
> 建議使用 Chrome 或 Edge 最新版本。
---
### 11.3 設定防火牆
在伺服器的 Windows 防火牆中開放:
| Port | 用途 |
| ----- | ------------------------------------------------ |
| 8000 | FastAPI(主要 API 服務) |
| 11434 | Ollama(若需直接存取) |
| 5432 | PostgreSQL(僅限內部存取,**不對外開放**) |
---
## 12. 專案結構與開發計畫
### 12.1 專案目錄結構
```
mechdesign-ai/
├── backend/
│ ├── app/
│ │ ├── __init__.py
│ │ ├── main.py # FastAPI 應用入口
│ │ ├── config.py # 設定(從 .env 讀取)
│ │ ├── api/
│ │ │ ├── deps.py # 依賴注入(JWT 驗證、DB Session)
│ │ │ └── v1/
│ │ │ ├── auth.py # 認證 API
│ │ │ ├── chat.py # 對話 API(含 SSE 串流)
│ │ │ ├── documents.py # 文件管理 API
│ │ │ └── admin.py # 管理 API
│ │ ├── agent/
│ │ │ ├── graph.py # LangGraph 狀態機定義
│ │ │ ├── nodes.py # 各節點函數實作
│ │ │ ├── state.py # AgentState TypedDict
│ │ │ └── prompts.py # System Prompts
│ │ ├── rag/
│ │ │ ├── retriever.py # pgvector 向量搜尋
│ │ │ └── chunker.py # 文字分塊邏輯
│ │ ├── ingestion/
│ │ │ ├── pdf_processor.py # PDF 解析(含視覺描述)
│ │ │ └── batch_importer.py # 批次匯入排程
│ │ ├── mcp/
│ │ │ └── client.py # MCP Client 初始化
│ │ ├── services/
│ │ │ └── ollama_service.py # Ollama API 封裝
│ │ └── models/
│ │ ├── database.py # SQLAlchemy ORM 模型
│ │ └── schemas.py # Pydantic Request/Response
│ ├── mcp_servers/
│ │ ├── cad_tools/
│ │ │ ├── server.py # CAD Tools MCP Server
│ │ │ └── cad_data/
│ │ │ ├── solidworks.json # SolidWorks 指令資料庫
│ │ │ ├── catia.json
│ │ │ └── autocad.json
│ │ └── knowledge_tools/
│ │ └── server.py # Knowledge MCP Server
│ ├── migrations/
│ │ └── init.sql # 初始化 SQL 腳本
│ ├── scripts/
│ │ ├── setup_windows.ps1 # Windows 一鍵環境設定腳本
│ │ ├── init_db.py # 資料庫初始化
│ │ └── batch_import.py # CLI 批次匯入工具
│ ├── .env.example # 環境變數範本
│ └── requirements.txt
├── frontend/
│ ├── src/
│ │ ├── App.tsx
│ │ ├── components/
│ │ │ ├── ChatWindow.tsx
│ │ │ ├── MessageItem.tsx
│ │ │ ├── ImageUpload.tsx
│ │ │ ├── DocumentList.tsx
│ │ │ ├── BatchImportForm.tsx
│ │ │ └── Sidebar.tsx
│ │ ├── pages/
│ │ │ ├── Chat.tsx
│ │ │ ├── Documents.tsx
│ │ │ └── Admin.tsx
│ │ └── api/
│ │ ├── client.ts # axios/fetch 基礎設定
│ │ ├── chat.ts
│ │ └── documents.ts
│ ├── package.json
│ └── vite.config.ts
└── docs/
├── SA文件_機構設計AI_Agent系統.md ← 本文件
└── diagrams/
├── 01_use_case.mmd
├── 02_uml_class.mmd
├── 03_database_schema.mmd
├── 04_sequence_rag.mmd
└── 05_sequence_upload.mmd
```
### 12.2 開發階段規劃
#### Phase 1:基礎建設
- [ ] 伺服器環境安裝:Ollama + PostgreSQL 16 + pgvector
- [ ] FastAPI 框架搭建,JWT 認證
- [ ] LangGraph Agent 基礎版(單輪問答,無 RAG)
- [ ] 資料庫 Schema 建立,Alembic 遷移管理
- [ ] Ollama API 呼叫服務封裝
- [ ] **交付物**:可問答的基礎 API 服務
#### Phase 2:RAG Pipeline
- [ ] PDF 解析服務(含圖片視覺描述)
- [ ] 文字分塊(RecursiveCharacterTextSplitter)
- [ ] Embedding 向量化並寫入 pgvector
- [ ] RAG 向量搜尋整合至 LangGraph
- [ ] 單一文件上傳 API
- [ ] 批次文件匯入(背景任務)
- [ ] **交付物**:可查詢內部文件的 RAG 問答 API
#### Phase 3:MCP 工具整
- [ ] CAD Tools MCP Server 開發(SolidWorks 指令資料庫)
- [ ] CATIA、AutoCAD 指令資料庫建置
- [ ] LangGraph MCP 工具呼叫節點
- [ ] 意圖分類路由完整實作
- [ ] **交付物**:完整 Agent(RAG + MCP 工具選用)
#### Phase 4:前端 UI
- [ ] React 對話介面
- [ ] 串流輸出顯示
- [ ] 圖片上傳功能
- [ ] 文件管理頁面(上傳、批次匯入、狀態追蹤)
- [ ] 系統管理頁面
- [ ] **交付物**:完整前後端整合版本
#### Phase 5:測試與部署
- [ ] 整合測試(各流程端到端測試)
- [ ] 效能調優(Ollama 並行請求、pgvector 索引調整)
- [ ] Windows 一鍵部署腳本 `setup_windows.ps1`
- [ ] 使用者說明文件
- [ ] 正式上線
- [ ] **交付物**:可交付的完整系統
### 12.3 里程碑概覽
| 里程碑 | 週次 | 說明 |
| ---------------- | ---- | ------------------------------------- |
| M1:API 服務可用 | W4 | FastAPI + LangGraph + Ollama 基礎問答 |
| M2:RAG 問答可用 | W8 | 文件上傳、向量化、RAG 對話 |
| M3:Agent 完整 | W11 | MCP 工具整合、多模態支援 |
| M4:前端完整 | W14 | UI 全功能上線 |
| M5:正式部署 | W16 | 測試通過,離線環境部署完成 |
---
Comments...
No Comments Yet...