AI Agent系統 SA文件

2026-03-05




# AI Agent 系統

## 系統分析文件(SA Document)

| 欄位               | 內容           |
| ------------------ | -------------- |
| **文件版本** | v1.1.0         |
| **撰寫日期** | 2026-03-05     |
| **負責單位** | 機構設計整合部 |
| **系統代號** | MEC-AI         |
| **機密等級** | 機構內部文件   |

---

## 目錄

1. [專案背景與目標](#1-專案背景與目標)
2. [系統需求分析](#2-系統需求分析)
3. [技術選型分析](#3-技術選型分析)
   - [3.6 淘汰方案說明(AnythingLLM / MaxKB / Dify / Open-WebUI / RAGFlow)](#36-淘汰方案說明)
4. [系統架構設計](#4-系統架構設計)
5. [資料庫設計](#5-資料庫設計)
6. [API 規格設計](#6-api-規格設計)
7. [關鍵流程設計](#7-關鍵流程設計)
   - [7.3 RAG 上下文管理策略](#73-rag-上下文管理策略)
8. [前端設計規格](#8-前端設計規格)
9. [MCP 工具設計](#9-mcp-工具設計)
10. [安全設計](#10-安全設計)
11. [離線環境部署指南](#11-離線環境部署指南)
12. [專案結構與開發計畫](#12-專案結構與開發計畫)
13. [可替代/降級策略](#13-可替代降級策略)
14. [待調查事項與後續建議](#14-待調查事項與後續建議)
15. [附錄:Mermaid 圖例清單](#15-附錄mermaid-圖例清單)

---

## 1. 專案背景與目標

### 1.1 背景說明

機構設計整合部的研發同仁日常以 SolidWorks、CATIA 等 CAD 軟體進行機構設計作業,需頻繁查閱指令手冊、功能說明及教育訓練資料。現有資料散落於各處文件,查閱效率低落,且無法支援自然語言提問。

本系統目標是在**完全離線的內網環境**中,建構一套以 AI Agent 為核心的知識輔助系統,部署於機構設計整合部專用伺服器,研發同仁透過繪圖筆電的瀏覽器即可存取。

### 1.2 系統目標

| 目標              | 說明                                           |
| ----------------- | ---------------------------------------------- |
| 📖 CAD 知識問答   | 自然語言查詢 CAD 指令、快捷鍵、操作步驟        |
| 🖼️ 多模態支援   | 可上傳 CAD 截圖或圖片進行詢問                  |
| 📁 知識庫管理     | 批次匯入技術文件(PDF/Word/圖片)並自動向量化  |
| 🔧 MCP 工具整合   | 透過 MCP 協議整合 CAD 工具與專家知識           |
| 🔒 資料在地化     | 所有資料與運算皆留存於機構內網,不外傳         |
| 🛠️ 可維護可擴展 | 全開源技術棧,任何具備 Python 基礎的人員可維護 |

### 1.3 系統邊界

#### Client 端(研發繪圖筆電)

- 執行輕量前端 UI(Web Browser),透過內網存取系統服務
- **Local Agent Runtime**:管理 SQLite 快取、短期上下文記憶、MCP 工具清單 Metadata
- 資源限制:約 8GB RAM、獨立 GPU(推理能力有限),大型推理與批次向量化皆交由 Remote 端執行
- **可選本地 Runner**:若需完全本地推理或低延遲場景,可選擇性安裝輕量 LLM runner(量化模型 + llama.cpp server)

#### Remote 端(整合部專用伺服器)

- **推理引擎**:llama.cpp server(主力)/ Ollama(備援),提供 OpenAI 相容的 LLM 推理 API
- **資料層**:PostgreSQL 16 + pgvector,儲存向量與 Metadata;原始文件由 KM 系統匯入
- **API 服務**:FastAPI REST API,處理認證、對話路由、文件管理
- **文件向量化服務**:獨立的批次向量化匯入程式,與 AI Agent 核心邏輯分離運行,便於資源排程
- **MCP 工具**:在 Remote 端執行需存取內部系統或資料的 Skill(如 CAD 指令查詢)

#### 共同限制

- **離線環境**:系統完全在機構內網運作,不依賴任何外部雲端服務
- **不使用 Docker**:所有服務採系統服務、虛擬環境或原生套件安裝方式部署
- **可複製部署**:文件須讓任何具備基本權限與硬體的人員能依步驟完成部署

---

## 2. 系統需求分析

![1772529827099](image/SA文件_機構設計AI_Agent系統/1772529827099.png)

### 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 依賴、NVIDIA CUDA、離線完整運作、OpenAI 相容 API、GGUF 量化支援、Embedding API、多模態支援、使用者控制權、授權條款、商業化風險

#### 3.1.1 候選方案比較表

| 評估項目 | **LLaMA.cpp Server** ✅ | **Ollama** | **LM Studio CLI** | **Foundry Local** |
| -------- | :---: | :---: | :---: | :---: |
| Windows 原生安裝 | ✅ 單一執行檔 | ✅ `.exe` 安裝包 | ✅ GUI + CLI | ✅ 安裝包 |
| 無 Docker 依賴 | ✅ | ✅ | ✅ | ✅ |
| NVIDIA CUDA | ✅ | ✅ | ✅ | ✅ |
| GGUF 量化(4/8bit) | ✅ 完整原生 | ✅ | ✅ | ⚠️ 部分 |
| OpenAI 相容 API | ✅ `/v1/chat/completions` | ✅ | ✅ | ✅ |
| Embedding API | ✅ | ✅ | ❌ 無原生 | ❌ |
| 多模態(Vision) | ⚠️ 實驗支援(llava) | ✅ 成熟 | ✅ | ⚠️ 部分 |
| 推理參數完整控制 | ✅ 最高自由度 | ⚠️ 有封裝限制 | ⚠️ GUI 優先 | ⚠️ 有限 |
| 離線完整運作 | ✅ | ✅ | ✅ | ❌ 首次啟動需登入 |
| 程式化呼叫 | ✅ REST + CLI | ✅ REST + CLI | ⚠️ CLI 功能有限 | ⚠️ 有限 |
| 版本更新頻率 | ✅ 極活躍(每週迭代) | ✅ 活躍 | ⚠️ 中等 | ⚠️ 不定期 |
| 授權條款 | **MIT** | MIT | 商業收費版本存在 | **微軟條款** |
| 商業化風險 | **低** | 低(需持續關注) | 中(已有付費方案) | **高(微軟生態綁定)** |
| 社群成熟度 | ⭐⭐⭐⭐⭐ 極高 | ⭐⭐⭐⭐⭐ 極高 | ⭐⭐⭐ 中 | ⭐⭐ 低 |

---

#### 3.1.2 各方案深度分析

##### 🏆 LLaMA.cpp Server(主力選型)

> **定位**:以 C++ 實作的高效 LLM 推理引擎,提供完整的 HTTP Server 模式,支援所有 GGUF 格式模型

**優勢**:

1. **最高使用者控制權**:可直接設定 `--ctx-size`、`--n-gpu-layers`、`--threads`、`--rope-scaling` 等所有推理參數,無任何封裝限制
2. **輕量單一執行檔**:`llama-server.exe` 無外部依賴,可直接啟動;在離線環境最易部署
3. **MIT 授權**:完全無商業化風險,可自由修改與二次分發
4. **GGUF 量化最完整**:原生支援 Q2~Q8 所有量化等級,7B 模型在 4GB VRAM 即可流暢運行
5. **版本迭代最快**:GitHub 倉庫每週多次提交,問題修復迅速
6. **可完全離線**:模型下載後不再與任何外部服務通訊

**限制**:

- 多模態(Vision)支援尚在實驗階段,穩定性略低於 Ollama
- 無內建模型管理機制(需手動管理 `.gguf` 檔案)
- 初始設定需要較多 CLI 參數知識

**啟動範例**:

```powershell
# 啟動 llama-server(OpenAI 相容模式)
.\llama-server.exe `
  --model D:\models\qwen2.5-vl-7b-q4_k_m.gguf `
  --ctx-size 8192 `
  --n-gpu-layers 35 `
  --host 0.0.0.0 `
  --port 8080 `
  --parallel 4
```

---

##### Ollama(備援 + 開發階段)

> **定位**:封裝 llama.cpp 核心的一站式本地 LLM 管理工具,提供模型下載、管理與推理 API

**優勢**:

1. Windows `.exe` 一鍵安裝,開發者最低入門門檻
2. 多模態(Vision)支援最成熟:`qwen2.5-vl`、`llava` 等視覺模型開箱即用
3. 統一的模型版本管理(`ollama pull`、`ollama list`)
4. `Modelfile` 機制支援自訂系統提示與推理參數

**限制與風險**:

- 封裝層過多,部分推理參數無法直接控制(如精細的 `--rope-scaling`)
- 商業化趨勢需持續觀察:Ollama Inc. 已有融資記錄,授權變更風險雖目前為低,但須追蹤
- 若 Ollama 服務進程崩潰,模型同時失效(單點故障)
- API 回應格式在部分邊緣情況與標準 OpenAI 規範有細微差異

> ⚠️ **建議**:開發與驗證階段優先使用 Ollama(降低設定成本);生產環境切換至 llama.cpp server(獲得最高控制權),兩者 API 格式相容,切換無需修改業務程式碼。

---

##### LM Studio CLI(不採用)

> **定位**:以 GUI 為核心的桌面應用,提供 CLI 模式與本地 API Server 功能

| 限制面向 | 說明 |
| -------- | ---- |
| **CLI 功能有限** | 主要設計為 GUI 使用,CLI 介面為附屬功能,程式化自動化能力不足 |
| **無 Embedding API** | 官方 API Server 不提供 Embedding 端點,無法直接支援 RAG 向量化流程 |
| **商業化路徑明確** | LM Studio 已推出 Pro 付費版,免費版功能逐漸受限,長期維護風險中等 |
| **定位偏向個人開發** | 介面與功能設計以個人開發者為目標,不適合伺服器端無人值守部署 |

**結論**:LM Studio 在個人桌面快速試用場景有優勢,但缺乏 Embedding API 且商業化路徑不利於本系統長期維護,不採用。

---

##### Foundry Local(不採用)

> **定位**:微軟推出的本地 AI 模型推理工具,主打與 Azure AI 生態整合

| 限制面向 | 說明 |
| -------- | ---- |
| **微軟授權條款** | 受微軟服務條款約束,授權內容可能隨產品策略調整,商業化風險最高 |
| **首次啟動需登入** | 需要微軟帳號驗證方可啟動,無法在完全氣隔的離線環境中使用 |
| **生態系綁定風險** | 設計上深度整合 Azure AI Studio,切換至其他方案的遷移成本高 |
| **Embedding 缺失** | 官方文件無原生 Embedding API,須額外整合其他工具 |
| **社群規模小** | 社群活躍度遠低於 llama.cpp 和 Ollama,問題排查文件匱乏 |

**結論**:Foundry Local 的微軟授權綁定與離線限制,根本性地違反本系統「完全離線、無商業化風險」的核心需求,不採用。

---

#### 3.1.3 選型結論

**🏆 主力:LLaMA.cpp Server + 備援:Ollama**

| 環境 | 使用方案 | 原因 |
| ---- | -------- | ---- |
| 開發 / 驗證 | Ollama | 快速模型切換,最低設定成本 |
| 生產部署(Remote) | LLaMA.cpp Server | 最高控制權,MIT 授權,無商業風險 |
| Client 本地推理(可選) | LLaMA.cpp Server(輕量) | 單一執行檔,資源佔用可精確控制 |

> 💡 兩套方案 API 格式完全相容(OpenAI `/v1` 規範),切換時**無需修改任何業務程式碼**,只需變更 `INFERENCE_BASE_URL` 環境變數。

---

### 3.2 Agent 框架選型

> **評估基準**:授權條款與商業化風險、無 Docker 依賴、MCP 工具支援、現代 RAG 技術支援、可程式化程度、PostgreSQL+pgvector 整合、稽核能力、**上下文限制與 Memory 管理能力**、長期維護性

#### 3.2.1 候選框架總覽

本次評估九個候選工具,涵蓋文件結構提取庫、全程式化框架、低程式碼平台與 RAG 專用引擎四大類型:

| 框架 | 類型 | 核心定位 | 授權 | 商業化風險 |
| ---- | ---- | -------- | ---- | ---------- |
| **LangExtract** | 提取工具庫 | 文件結構化資料提取(LangChain 子項目) | MIT | 🟢 低 |
| **LangChain** | 程式化框架 | LLM 應用開發工具鏈基礎庫 | MIT | 🟢 低 |
| **LangGraph** ✅ | 程式化框架 | 顯式狀態機 Agent 編排引擎 | MIT | 🟢 低 |
| **Dify** | 低程式碼平台 | 視覺化 AI 應用開發平台 | Apache 2.0 + 附加條款 | 🟡 中高 |
| **MaxKB** | 低程式碼平台 | 中文優先知識庫問答系統 | Apache 2.0 | 🟡 中 |
| **AnythingLLM** | 一體式應用 | 桌面 / 伺服器端 RAG 應用 | MIT | 🟢 低(但封閉) |
| **Open-WebUI** | 前端介面 | LLM 聊天介面 + 輕量 RAG | MIT | 🟢 低 |
| **RAGFlow** | RAG 引擎 | 深度文件解析 RAG 平台 | Apache 2.0 | 🟢 低 |
| **GraphRAG** | RAG 方法論 | 知識圖譜輔助多跳推理 | MIT(微軟) | 🟡 中(微軟) |

---

#### 3.2.2 各框架深度分析

##### LangExtract(整合使用,非獨立 Agent 框架)

> **定位**:LangChain 生態的結構化資料提取子項目(`langchain-extract`),以 LLM 為驅動力,從非結構化文本 / PDF 中提取符合 JSON Schema 的結構化欄位

| 維度 | 評估 |
| ---- | ---- |
| **授權 / 商業化** | MIT,LangChain 核心生態的一部分,商業化風險極低 |
| **Docker 依賴** | 無,`pip install langchain langchain-core` 即可使用提取鏈 |
| **核心能力** | ✅ 以 `with_structured_output()` 或 `create_extraction_chain()` 從文件中提取標準化欄位(如 CAD 圖面標題欄:圖號、版本、材料清單、修訂歷史) |
| **與 LangGraph 整合** | ✅ 作為攝入 Pipeline 的前置節點,將 PDF 頁面解析為結構化 metadata 後存入 PostgreSQL `documents.metadata` JSONB 欄位 |
| **Context 限制** | ⚠️ 提取任務受 context window 限制,長文件需分頁提取後彙總(每頁獨立呼叫 LLM) |
| **長期維護** | ⭐⭐⭐⭐⭐ LangChain 核心維護 |

**結論**:LangExtract **不作為 Agent 框架**,而是**文件攝入 Pipeline 的結構化提取層**:
- 從 CAD PDF 標題欄提取:圖號、版本號、日期、負責人 → 存入 `metadata`
- 從技術規格書提取:材料牌號、尺寸公差、表面處理 → 作為 Metadata 過濾依據
- 提取結果驅動 Pre-retrieval 過濾,顯著縮小向量搜尋空間

---

##### LangChain(底層工具鏈)

> **定位**:LLM 應用開發的基礎工具鏈,提供 Chains、Retrievers、Memory、Agents 等模組化組件

| 維度 | 評估 |
| ---- | ---- |
| **授權 / 商業化** | MIT,LangChain Inc. 已有商業產品(LangSmith、LangServe)但核心庫保持開源;商業化風險低 |
| **Docker 依賴** | 無,`pip install langchain` 即用 |
| **MCP 支援** | 透過 `langchain-mcp-adapters`,需搭配 LangGraph 才能完整發揮 |
| **RAG 能力** | ✅ 完整的 Retriever、DocumentLoader、TextSplitter 生態 |
| **Context / Memory** | ✅ `ConversationBufferMemory`、`ConversationSummaryMemory`、`ConversationTokenBufferMemory` 多種策略;`trim_messages()` 精確控制 Token 上限 |
| **可程式化程度** | 高,但 LCEL 在複雜分支邏輯上表達能力不如 LangGraph 狀態機 |
| **長期維護** | ⭐⭐⭐⭐⭐ GitHub Star > 100K,社群最大,版本迭代快 |

**結論**:LangChain 是**底層工具鏈**,與 LangGraph 搭配使用;其 Memory 模組是上下文管理的核心依賴,不單獨作為 Agent 框架。

---

##### 🏆 LangGraph(選型)

> **定位**:基於 LangChain 生態的顯式狀態機 Agent 編排框架,每個節點為可測試、可稽核的 Python 函式

| 維度 | 評估 |
| ---- | ---- |
| **授權 / 商業化** | MIT,無任何附加條款;LangChain Inc. 的商業化方向(LangSmith 觀測平台)不影響 LangGraph 核心庫的免費使用 |
| **Docker 依賴** | 無,`pip install langgraph` 即用 |
| **MCP 支援** | ✅ `langchain-mcp-adapters` 原生整合,MCP Server 工具自動轉換為 LangChain BaseTool |
| **RAG 能力** | ✅ 完整支援現代 RAG 技術(詳見 3.2.5 節) |
| **可程式化程度** | 極高:每個節點為純 Python 函式,狀態完全透明可查 |
| **稽核能力** | 完整:每個節點的輸入/輸出皆可記錄,天然支援 Prompt Injection 稽核 |
| **pgvector 整合** | ✅ `langchain-postgres` 直接封裝 pgvector,支援 HNSW 索引與相似度搜尋 |
| **狀態持久化** | ✅ `AsyncPostgresSaver` 將對話 Checkpoint 存入 PostgreSQL |
| **Context / Memory 管理** | ✅ 狀態機天然支援多層記憶體策略;`manage_context` / `summarize_conversation` 節點可無縫嵌入;Token 計數精確可控(詳見 3.2.4) |
| **長期維護** | ⭐⭐⭐⭐⭐ 極活躍,LangChain 生態保護,Issue 響應快 |

---

##### Dify(不採用)

> **定位**:提供視覺化工作流編輯器的開源 LLM 應用開發平台,支援 RAG、Agent、Chatbot

| 維度 | 評估 |
| ---- | ---- |
| **授權 / 商業化** | ⚠️ Apache 2.0 + 自訂附加條款(Dify Additional Terms):SaaS 超過 50,000 月活用戶須商業授權;派生版本需保留 Dify 標識。授權模糊性不符合本部門完全開源要求 |
| **Docker 依賴** | ❌ 標準安裝為 `docker compose up`,含 Nginx / Worker / API / Web / PostgreSQL / Redis / Weaviate 等多個容器 |
| **Context / Memory** | ⚠️ 視覺化 Workflow 的 Memory 節點功能有限,無法程式化控制 Token 預算;長對話的 context 截斷策略不透明 |
| **MCP 支援** | 插件形式,非原生整合,穩定性不如 LangGraph |
| **RAG 深度客製** | 深度客製(如攝入時呼叫視覺模型描述圖片)必須退化為自訂 Code Node,失去平台優勢且除錯困難 |
| **升級相容性** | 版本間 API 與 DB Schema 變更頻繁,維護成本高 |

**結論**:功能完整,但授權附加條款、Docker 強依賴、Memory 不可程式化控制是根本性硬傷,不採用。

---

##### MaxKB(不採用)

> **定位**:飛致雲出品的中文優先開源知識庫問答平台,Django 後端 + Vue 前端

| 維度 | 評估 |
| ---- | ---- |
| **授權 / 商業化** | Apache 2.0,但飛致雲(商業公司)主導,有推出企業版付費功能的歷史 |
| **Docker 依賴** | ❌ 官方推薦 `docker-compose` 安裝,原生安裝路徑文件不完整 |
| **MCP 支援** | ❌ 無原生 MCP 整合,工具為平台自有生態 |
| **Context / Memory** | ❌ 封裝於平台內,對話歷史管理與 Token 截斷策略均不可程式化控制 |
| **RAG 深度客製** | 後端以 Django ORM 緊密耦合,插入自訂攝入步驟需深度修改框架核心 |
| **長期維護** | ⭐⭐⭐ GitHub Star 成長穩定,但社群規模遠低於 LangChain |

**結論**:Docker 依賴、封閉 Django 架構、MCP 不相容,不採用。

---

##### AnythingLLM(不採用)

> **定位**:一體式桌面 / 伺服器端 RAG 問答應用,支援多種 LLM 後端

| 維度 | 評估 |
| ---- | ---- |
| **授權 / 商業化** | MIT,但 Mintplex Labs 已推出企業版(AnythingLLM Cloud),核心庫雖開源但長期走向需觀察 |
| **Docker 依賴** | 伺服器端部署建議 Docker,原生安裝可行但文件支援有限 |
| **MCP 支援** | ⚠️ 部分支援,整合深度不及 LangGraph 原生 |
| **RAG Pipeline 客製** | ❌ Chunk 策略、Reranker、Prompt 模板封裝為黑盒,無法程式化介入 |
| **Context / Memory** | ❌ Workspace 記憶體管理為黑盒,Token 預算不可精確控制;長對話截斷策略固定,無法依場景調整 |
| **Agent 控制** | ❌ ReAct 固定迴圈,不支援顯式狀態機的多步驟複合流程 |

**結論**:Pipeline 黑盒化、Memory 不可控、Agent 控制不足,不採用。

---

##### Open-WebUI(不採用)

> **定位**:以 Docker 為主的開源 LLM 聊天介面,提供輕量 RAG 與 Tool Calling 功能

| 維度 | 評估 |
| ---- | ---- |
| **授權 / 商業化** | MIT,但 Open-WebUI 已有商業化趨勢(Enterprise 版),核心庫目前免費 |
| **Docker 依賴** | ❌ 官方安裝為 `docker run`,非 Docker 安裝社群支援有限 |
| **MCP 支援** | ⚠️ 自有 Function Calling 機制,與標準 MCP 規範不完全相容 |
| **RAG 客製** | ❌ 內建 RAG 為黑盒,Chunk / Reranker / Prompt 不可程式化控制 |
| **Context / Memory** | ⚠️ 對話歷史存入 SQLite,無法整合 PostgreSQL 多使用者 Memory;Token 截斷策略固定不可調,長對話時模型品質無保障 |

**結論**:優秀的個人 LLM 介面,Docker 依賴、封閉 RAG Pipeline 與 Memory 不可控不符合本系統需求。

---

##### RAGFlow(不採用,部分技術可借鏡)

> **定位**:專注於深度文件版面解析(Document Layout Analysis)的開源 RAG 引擎

| 維度 | 評估 |
| ---- | ---- |
| **授權 / 商業化** | Apache 2.0,InfiniFlow 商業公司主導,有企業版服務,但核心開源 |
| **Docker 依賴** | ❌ 需要 Docker Compose 啟動(Elasticsearch、Redis、MinIO 等多服務) |
| **技術棧相容性** | ❌ 使用 Elasticsearch 作為向量引擎,與本系統 PostgreSQL + pgvector 不相容 |
| **Agent 能力** | ⚠️ Agent 功能薄弱,主要設計為 RAG Pipeline,無法實作複雜意圖分類流程 |
| **MCP 支援** | ❌ 無 MCP 整合 |
| **值得借鏡** | ✅ 深度 PDF 版面解析(表格識別、多欄版面)技術可作為本系統 PDF 解析層的參考 |

**結論**:Docker 依賴與 Elasticsearch 技術棧不相容為根本性硬傷,不採用;文件解析方法論可日後參考。

---

##### GraphRAG(作為選用進階技術,非獨立框架)

> **定位**:微軟研究院開源的知識圖譜增強 RAG 方法論,將文件解析為知識圖以支援多跳推理

| 維度 | 評估 |
| ---- | ---- |
| **授權 / 商業化** | MIT,但微軟研究院主導,與 Azure AI 生態整合深度高,長期走向有商業化疑慮 |
| **獨立部署** | ⚠️ 需額外的知識圖譜建構流程(Indexing Pipeline),整合成本高 |
| **適用場景** | ✅ CAD 知識多跳推理(A 特徵 → 依賴 B 功能 → 需要 C 指令)有顯著優勢 |
| **Context 需求** | ⚠️ 圖查詢結果可能產生大量 context,必須搭配 3.2.4 的壓縮策略才能用於 8K 模型 |
| **與 LangGraph 整合** | ✅ 可作為 `graph_retrieve` 節點的選用擴充,搭配 NetworkX + pgvector |
| **當前成熟度** | ⚠️ 建構知識圖譜成本高,初期 MVP 先採 Standard RAG |

**結論**:不作為獨立框架,作為 LangGraph 的**選用進階 RAG 節點**,在系統成熟後(M5+)引入。

---

#### 3.2.3 選型結論:LangGraph + LangExtract(LangChain 生態)

| 套件 | 角色 | 安裝 |
| ---- | ---- | ---- |
| `langgraph` | Agent 編排引擎(顯式狀態機) | `pip install langgraph` |
| `langchain` | 工具鏈基礎庫(Retriever / Memory / Chain) | `pip install langchain` |
| `langchain-core` | 核心抽象層(BaseMessage / Runnable) | 隨 `langchain` 安裝 |
| `langchain-postgres` | pgvector 整合 + 對話 Checkpoint | `pip install langchain-postgres` |
| `langchain-mcp-adapters` | MCP Server 工具整合 | `pip install langchain-mcp-adapters` |
| LangExtract 功能 | 文件結構化提取(攝入 Pipeline) | `with_structured_output()` 內建於 LangChain |

**選型理由(8 點):**

1. **MIT 授權,零商業化風險**:核心庫完全免費,LangChain Inc. 的商業化(LangSmith)不影響本系統
2. **無 Docker 依賴**:五個套件皆 `pip install` 即用
3. **最高可程式化程度**:純 Python 函式節點,任何 Python 工程師皆可維護
4. **原生 MCP 整合**:自動將 MCP Server 工具轉換為 LangChain BaseTool
5. **完整稽核能力**:每個節點 I/O 記錄至 `audit_logs`,滿足資安需求
6. **PostgreSQL 深度整合**:pgvector HNSW + `AsyncPostgresSaver` 對話持久化共用同一 DB 實例
7. **精確 Context / Memory 控制**:顯式狀態機使 Token 預算管理完全可程式化(詳見 3.2.4)
8. **社群規模最大**:GitHub Star > 100K,Issue 響應快

---

#### 3.2.4 上下文限制與 Memory 架構設計

##### 問題陳述:Context Window 的硬性挑戰

本系統採用本地 LLM(Qwen2.5-14B / Llama-3.2-11B 等),**context window 通常為 4K–32K tokens**。一次完整請求的 Token 組成:

```
[System Prompt]  +  [對話歷史]  +  [RAG 召回文本]  +  [使用者問題]  +  [工具回傳]
   ≈ 500 tok        ≈ N tok        ≈ 2,000 tok         ≈ 200 tok        ≈ 500 tok
                                         ↓
              總和必須 < model_context_window(例如 8,192 tokens)
```

若不加控制,幾輪對話後即可能:
- **截斷早期重要對話** → 遺失使用者意圖與先前確認的設計參數
- **超出 context 限制** → API 報錯,系統崩潰
- **過多無關歷史** → LLM 注意力稀釋,生成品質下降
- **RAG chunks 被歷史擠壓** → 知識庫資訊無法有效注入

##### 三層 Memory 架構

```
┌─────────────────────────────────────────────────────────────┐
│  Layer 1 — Working Memory(工作記憶)                        │
│  位置:LangGraph State 的 messages 欄位(in-process)        │
│  內容:最近 N 輪對話,由 trim_messages 動態截斷              │
│  上限:Token Budget 動態計算(context_window × 75%)         │
│  持久:否(session 結束即消失)                              │
├─────────────────────────────────────────────────────────────┤
│  Layer 2 — Episodic Memory(片段記憶)                       │
│  位置:PostgreSQL `checkpoints` 表(AsyncPostgresSaver)     │
│  內容:LangGraph Checkpoint,含完整 state 快照               │
│  上限:無限(受磁碟限制)                                    │
│  持久:是(跨 session 恢復,使用者重連即接續上次對話)       │
├─────────────────────────────────────────────────────────────┤
│  Layer 3 — Semantic Memory(語意記憶)                       │
│  位置:PostgreSQL `documents` 表 + pgvector HNSW 索引        │
│  內容:所有攝入的 CAD 文件知識片段                           │
│  上限:無限(受磁碟限制)                                    │
│  持久:是(RAG 知識庫永久存在)                              │
└─────────────────────────────────────────────────────────────┘
```

##### 策略一:Token Budget 動態截斷(P1,M2)

在每輪 LLM 呼叫前,`manage_context` 節點使用 `trim_messages()` 精確裁剪對話歷史:

```python
from langchain_core.messages import trim_messages

def manage_context(state: AgentState) -> AgentState:
    """動態截斷對話歷史,確保不超出 context window"""
    trimmed = trim_messages(
        state["messages"],
        strategy="last",       # 優先保留最近的訊息
        token_counter=llm,     # 使用 LLM 自身的 tokenizer 精確計數
        max_tokens=6144,       # 保留 2K 給 RAG chunks + 回應生成
        start_on="human",      # 確保以 human 訊息開頭(避免孤立 AI 訊息)
        include_system=True,   # 永遠保留 system prompt
        allow_partial=False,   # 不截斷單一訊息的中間
    )
    return {**state, "messages": trimmed}
```

##### 策略二:對話摘要壓縮(P2,M3)

對話輪數超過閾值時,將舊對話壓縮為摘要,以 `SystemMessage` 形式替代詳細歷史,釋放大量 context 空間:

```python
def summarize_conversation(state: AgentState) -> AgentState:
    """將超出 N 輪的舊對話壓縮為摘要"""
    if len(state["messages"]) < SUMMARY_THRESHOLD:  # 預設 10 輪
        return state

    summary_prompt = [
        SystemMessage(content="請將以下對話歷史濃縮為 150 字以內的重點摘要,保留關鍵設計參數與決定:"),
        HumanMessage(content=format_messages(state["messages"][:-KEEP_RECENT]))
    ]
    summary = llm.invoke(summary_prompt)

    # 以摘要 SystemMessage + 最近 KEEP_RECENT 輪取代完整歷史
    new_messages = [
        SystemMessage(content=f"[對話摘要] {summary.content}"),
        *state["messages"][-KEEP_RECENT:]  # 保留最近 4 輪完整對話
    ]
    return {**state, "messages": new_messages, "has_summary": True}
```

##### 策略三:RAG Chunk Token 預算動態調整(P1,M2)

召回片段數量依剩餘 Token 預算動態計算,避免 RAG 內容擠爆 context:

```python
def rag_retrieve_with_budget(state: AgentState) -> AgentState:
    """根據剩餘 Token 預算動態決定召回片段數"""
    used_tokens = count_tokens(state["messages"])
    remaining = TOKEN_BUDGET - used_tokens - GENERATION_RESERVE  # 保留生成空間

    avg_chunk_tokens = 300  # 每片段平均 token 估算
    dynamic_top_k = max(1, min(MAX_TOP_K, remaining // avg_chunk_tokens))

    docs = retriever.invoke(
        state["rewritten_query"],
        k=dynamic_top_k,
        filter=state.get("metadata_filter", {})
    )
    return {**state, "retrieved_docs": docs, "used_top_k": dynamic_top_k}
```

##### 策略四:跨 Session 記憶體恢復(P2,M3)

`AsyncPostgresSaver` 以 `thread_id` 為鍵,使用者重連時自動恢復上次對話狀態:

```python
from langgraph.checkpoint.postgres.aio import AsyncPostgresSaver

async def create_agent():
    checkpointer = AsyncPostgresSaver.from_conn_string(DATABASE_URL)
    await checkpointer.setup()  # 自動建立 checkpoints 表
    return build_agent_graph().compile(checkpointer=checkpointer)

# 每次呼叫帶入相同 thread_id 即可恢復對話
config = {"configurable": {"thread_id": f"user_{user_id}"}}
result = await agent.ainvoke({"messages": [HumanMessage(content=query)]}, config)
```

##### Context 管理決策流

```
收到使用者輸入
  ↓
[manage_context]
  ├─ Token 使用率 > 80%?
  │    ├─ 是 → [summarize_conversation] ← 壓縮舊對話為摘要
  │    └─ 否 → [trim_messages]          ← 截斷最舊訊息至 60% 預算
  ↓
[rag_retrieve_with_budget]
  ├─ 計算剩餘 Token 預算
  └─ 動態決定 top_k(1 ≤ k ≤ MAX_TOP_K)
  ↓
[generate_response]        ← 傳入精確控制的 context
  ↓
[AsyncPostgresSaver]       ← 完整 State 持久化至 PostgreSQL
```

##### Context 管理參數建議(8K context window 基準)

| 參數 | 建議值 | 說明 |
| ---- | ------ | ---- |
| `TOKEN_BUDGET` | 6,144 | 為 RAG + 生成保留 2K |
| `GENERATION_RESERVE` | 1,024 | 預留 LLM 生成輸出空間 |
| `RAG_CHUNK_BUDGET` | 2,048 | RAG 召回文本最大 token 數 |
| `SUMMARY_THRESHOLD` | 10 輪 | 超過此輪數觸發摘要壓縮 |
| `KEEP_RECENT` | 4 輪 | 摘要後保留最近幾輪完整對話 |
| `avg_chunk_tokens` | 300 | 每個 RAG 片段平均 token 估算值 |
| `MAX_TOP_K` | 6 | RAG 召回片段數上限 |

> **升級路徑**:若未來換用 32K context window 模型(如 Qwen2.5-32B),只需調整 `TOKEN_BUDGET` 常數,所有動態計算邏輯自動適應,業務邏輯無需修改。

---

#### 3.2.5 LangGraph 現代 RAG 技術實作路徑

LangGraph 的顯式狀態機架構使每種現代 RAG 優化技術都能對應到一個獨立、可測試的節點,以下依**導入優先順序**排列:

| 優先 | RAG 技術 | 說明 | LangGraph 實作方式 | 導入時機 |
| :---: | -------- | ---- | ------------------ | -------- |
| 🔴 P1 | **Metadata 過濾(Pre-retrieval)** | 以 LangExtract 提取的文件欄位(圖號、類別、日期)縮小向量搜尋空間 | `rag_retrieve_with_budget` 節點內 pgvector `WHERE` 子句 | M2 |
| 🔴 P1 | **Hybrid Search(BM25 + 向量)** | 結合稀疏(關鍵字)與稠密(語意)搜尋,提升 CAD 指令名等專有名詞召回率 | `langchain_postgres` 配合 PostgreSQL `tsvector` 全文索引 | M2 |
| 🔴 P1 | **Token Budget 動態截斷** | 依剩餘 context 空間動態調整 top_k,保障 RAG 內容不被歷史擠出 | `manage_context` + `rag_retrieve_with_budget`(詳見 3.2.4) | M2 |
| 🟡 P2 | **Post-retrieval Rerank** | 以 Cross-encoder 對 top-k 片段重新排序,取最相關 N 個,降低 context 雜訊 | `rerank_node`,使用 BGE Reranker 或 Jina Reranker(本地模型) | M3 |
| 🟡 P2 | **Query Expansion / Rewriting** | 自動將簡短問句改寫為語意完整查詢,提升向量召回率 | `rewrite_query` 前置節點 | M3 |
| 🟡 P2 | **Contextual Compression** | 對過長召回文本萃取關鍵句,只保留與問題相關內容,釋放 context | `compress_context` 節點(LLMChainExtractor 或 extractive 方法) | M3 |
| 🟡 P2 | **對話摘要壓縮(Memory)** | 超過 N 輪後壓縮舊對話為摘要,釋放大量 context 空間供 RAG 使用 | `summarize_conversation` 節點(詳見 3.2.4) | M3 |
| 🟢 P3 | **Multi-turn / Iterative Retrieval** | 複雜問題採多輪迭代:第一輪召回後 Agent 決定是否需要補充查詢 | 狀態機條件迴圈邊 `retrieve → assess → retrieve` | M4 |
| 🟢 P3 | **Self-RAG** | Agent 自評召回品質(Relevance Score),低分時重新檢索 | `assess_retrieval` 節點,輸出 `sufficient / insufficient` 路由 | M4 |
| 🔵 P4 | **GraphRAG(選用)** | CAD 知識圖譜化,支援多跳推理;圖查詢結果需搭配壓縮策略 | `graph_retrieve` 節點,搭配 NetworkX + pgvector | M5 後 |

##### 完整狀態機節點圖

```
START
  ↓
[manage_context]           ← Token 計數 → 截斷 / 摘要壓縮(P1 Memory)
  ↓
[rewrite_query]            ← Query Rewriting(P2)
  ↓
[classify_intent]
  ↓ routing
  ├─ rag      → [rag_retrieve_with_budget]   ← metadata filter(P1)
  │                                              hybrid search(P1)
  │                                              動態 top_k(P1 Memory)
  │                 ↓
  │            [rerank_node]                 ← Cross-encoder rerank(P2)
  │                 ↓
  │            [compress_context]            ← Contextual Compression(P2)
  │                 ↓
  │            [assess_retrieval]            ← Self-RAG 評估(P3)
  │                 ├─ sufficient → [generate_response]
  │                 └─ insufficient → [rag_retrieve_with_budget](迭代,P3)
  │
  ├─ cad_tool → [call_cad_tool]             ← MCP Tool Call
  │                 ↓
  │            [generate_response]
  │
  ├─ vision   → [vision_analyze]
  │                 ↓
  │            [rag_retrieve_with_budget] → [generate_response]
  │
  └─ general  → [generate_response]
  ↓
[AsyncPostgresSaver]       ← Checkpoint 持久化至 PostgreSQL(Episodic Memory)
  ↓
END
```

---

| 維度 | 評估 |
| ---- | ---- |
| **授權 / 商業化** | MIT,完全開源,LangChain Inc. 已有商業產品(LangSmith、LangServe)但核心庫保持開源;商業化風險低 |
| **Docker 依賴** | 無,`pip install langchain` 即用 |
| **MCP 支援** | 透過 `langchain-mcp-adapters` 支援,但需搭配 LangGraph 才能完整發揮 |
| **RAG 能力** | 完整的 Retriever、DocumentLoader、TextSplitter 生態;但 Chain 模式為線性流程,複雜多步驟 RAG 需自行串接 |
| **可程式化程度** | 高,但 LCEL(LangChain Expression Language)在複雜分支邏輯上表達能力有限 |
| **長期維護** | ⭐⭐⭐⭐⭐ GitHub Star > 100K,社群最大,版本迭代快 |

**結論**:LangChain 是**底層工具鏈**,本身不直接作為 Agent 框架選型;LangGraph 以 LangChain 為基礎建構,兩者配合使用,單獨選用純 LangChain 在複雜 Agent 流程控制上不如 LangGraph。

---

##### 🏆 LangGraph(選型結論)

> **定位**:基於 LangChain 生態的顯式狀態機 Agent 編排框架,每個節點為可測試、可稽核的 Python 函式

| 維度 | 評估 |
| ---- | ---- |
| **授權 / 商業化** | MIT,無任何附加條款;LangChain Inc. 的商業化方向(LangSmith)不影響 LangGraph 核心庫的免費使用 |
| **Docker 依賴** | 無,`pip install langgraph` 即用 |
| **MCP 支援** | ✅ `langchain-mcp-adapters` 原生整合,MCP Server 工具自動轉換為 LangChain BaseTool |
| **RAG 能力** | ✅ 完整支援現代 RAG 技術(詳見 3.2.3 節) |
| **可程式化程度** | 極高:每個節點為純 Python 函式,狀態完全透明可查 |
| **稽核能力** | 完整:每個節點的輸入/輸出皆可記錄,天然支援 Prompt Injection 稽核 |
| **pgvector 整合** | ✅ `langchain-postgres` 直接封裝 pgvector,支援 HNSW 索引與相似度搜尋 |
| **狀態持久化** | ✅ `AsyncPostgresSaver` 將對話 Checkpoint 存入 PostgreSQL |
| **長期維護** | ⭐⭐⭐⭐⭐ 極活躍,LangChain 生態保護,問題響應快 |

---

##### Dify(不採用)

> **定位**:提供視覺化工作流編輯器的開源 LLM 應用開發平台,支援 RAG、Agent、Chatbot

| 維度 | 評估 |
| ---- | ---- |
| **授權 / 商業化** | ⚠️ Apache 2.0 + 自訂附加條款(Dify Additional Terms):SaaS 超過 50,000 月活用戶須商業授權;派生版本需保留 Dify 標識。授權模糊性不符合本部門完全開源要求 |
| **Docker 依賴** | ❌ 標準安裝為 `docker compose up`,含 Nginx/Worker/API/Web/PostgreSQL/Redis/Weaviate 等多個容器 |
| **MCP 支援** | 插件形式,非原生整合,穩定性不如 LangGraph |
| **RAG 深度客製** | 在深度客製場景(如攝入時呼叫視覺模型描述圖片)必須退化為自訂 Code Node,失去平台優勢且除錯困難 |
| **升級相容性** | 版本間 API 與 DB Schema 變更頻繁,維護成本高 |
| **長期維護** | ⭐⭐⭐⭐ 社群活躍,但授權附加條款為長期隱患 |

**結論**:功能完整但授權附加條款與 Docker 強依賴,是根本性的硬傷,不採用。

---

##### MaxKB(不採用)

> **定位**:飛致雲出品的中文優先開源知識庫問答平台,Django 後端 + Vue 前端

| 維度 | 評估 |
| ---- | ---- |
| **授權 / 商業化** | Apache 2.0,但飛致雲(商業公司)主導,有推出企業版付費功能的歷史 |
| **Docker 依賴** | ❌ 官方推薦 `docker-compose` 安裝,原生安裝路徑文件不完整 |
| **MCP 支援** | ❌ 無原生 MCP 整合,工具為平台自有生態 |
| **RAG 深度客製** | 後端以 Django ORM 緊密耦合,插入自訂攝入步驟需深度修改框架核心 |
| **多模態** | ⚠️ 圖片輸入支援處於實驗階段,穩定性不足 |
| **長期維護** | ⭐⭐⭐ GitHub Star 成長穩定,但社群規模遠低於 LangChain |

**結論**:Docker 依賴、封閉 Django 架構與 MCP 不相容,無法適用本系統。

---

##### AnythingLLM(不採用)

> **定位**:一體式桌面 / 伺服器端 RAG 問答應用,支援多種 LLM 後端

| 維度 | 評估 |
| ---- | ---- |
| **授權 / 商業化** | MIT,但 Mintplex Labs 已推出企業版(AnythingLLM Cloud),核心庫雖開源但長期走向需觀察 |
| **Docker 依賴** | 伺服器端部署建議 Docker,原生安裝可行但文件支援有限 |
| **MCP 支援** | ⚠️ 部分支援,整合深度不及 LangGraph 原生 |
| **RAG Pipeline 客製** | ❌ Chunk 策略、Reranker、Prompt 模板封裝為黑盒,無法程式化介入 |
| **Agent 控制** | ❌ ReAct 固定迴圈,不支援顯式狀態機的多步驟複合流程 |
| **多使用者企業** | ⚠️ Workspace 機制非企業多角色設計,稽核日誌薄弱 |

**結論**:適合個人 / 小團隊原型,Pipeline 黑盒化與 Agent 控制不足,無法滿足本系統需求。

---

##### Open-WebUI(不採用)

> **定位**:以 Docker 為主的開源 LLM 聊天介面,提供輕量 RAG 與 Tool Calling 功能

| 維度 | 評估 |
| ---- | ---- |
| **授權 / 商業化** | MIT,但 Open-WebUI 已有商業化趨勢(Enterprise 版),核心庫目前免費 |
| **Docker 依賴** | ❌ 官方安裝為 `docker run`,非 Docker 安裝社群支援有限 |
| **MCP 支援** | ⚠️ 自有 Function Calling 機制,與標準 MCP 規範不完全相容 |
| **RAG 客製** | ❌ 內建 RAG 為黑盒,Chunk / Reranker / Prompt 不可程式化控制 |
| **企業部署** | ⚠️ 設計目標為個人 / 小組使用,多角色存取控制與稽核日誌能力不足 |

**結論**:優秀的個人 LLM 介面,Docker 依賴與封閉 RAG Pipeline 不符合本系統需求。

---

##### RAGFlow(不採用,部分技術可借鏡)

> **定位**:專注於深度文件版面解析(Document Layout Analysis)的開源 RAG 引擎

| 維度 | 評估 |
| ---- | ---- |
| **授權 / 商業化** | Apache 2.0,InfiniFlow 商業公司主導,有企業版服務,但核心開源 |
| **Docker 依賴** | ❌ 需要 Docker Compose 啟動(Elasticsearch、Redis、MinIO 等多服務) |
| **技術棧相容性** | ❌ 使用 Elasticsearch 作為向量引擎,與本系統 PostgreSQL + pgvector 架構不相容 |
| **Agent 能力** | ⚠️ Agent 功能薄弱,主要設計為 RAG Pipeline,無法實作複雜意圖分類流程 |
| **MCP 支援** | ❌ 無 MCP 整合 |
| **值得借鏡** | ✅ 其深度 PDF 版面解析(表格識別、多欄版面)技術值得在本系統 PDF 解析層參考 |

**結論**:Docker 依賴與 Elasticsearch 技術棧不相容為根本性硬傷,不採用;但 RAGFlow 的文件解析方法論可作為日後優化 PDF 攝入品質的參考。

---

##### GraphRAG(不採用為獨立框架,作為選用優化技術)

> **定位**:微軟研究院開源的知識圖譜增強 RAG 方法論,將文件解析為知識圖以支援多跳推理

| 維度 | 評估 |
| ---- | ---- |
| **授權 / 商業化** | MIT,但微軟研究院主導,與 Azure AI 生態整合深度高,長期走向有商業化疑慮 |
| **獨立部署** | ⚠️ 需要額外的知識圖譜建構流程(Indexing Pipeline),整合成本高 |
| **適用場景** | ✅ 對於 CAD 知識的多跳推理(如「A 特徵依賴 B 功能,B 功能需要 C 指令」)有顯著優勢 |
| **與 LangGraph 整合** | ✅ 可作為 LangGraph `rag_retrieve` 節點的選用擴充,搭配 NetworkX + pgvector |
| **當前成熟度** | ⚠️ 建構知識圖譜成本高,初期 MVP 先採 Standard RAG,GraphRAG 作為 M4 後的進階選項 |

### 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        | 表格擷取最強           |
| **Tesseract OCR** ✅ | ✅ 掃描文件 |    ❌    |   ❌   | Apache 2.0 | 掃描 PDF/影像 OCR 首選 |

**🏆 選型結論:pymupdf4llm 為主,unstructured 為輔,Tesseract OCR 處理掃描文件**

- **pymupdf4llm**:將 PDF 轉為 Markdown,保留文字結構、表格、圖片位置資訊
- 圖片自動以 **Qwen2.5-VL** 視覺模型生成文字描述,描述結果納入向量索引
- **Tesseract OCR**:處理掃描式 PDF 或影像類文件,先 OCR 再進行向量化
- 對於複雜的多欄版面,額外引入 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 推理       │ llama.cpp server(主力)/ Ollama(備援)        │
│               │ Qwen2.5-VL:7b(對話+視覺)                    │
│               │ nomic-embed-text(向量嵌入)                   │
├───────────────┼─────────────────────────────────────────────┤
│ 向量儲存       │ PostgreSQL 16 + pgvector 擴充套件             │
│               │ langchain-postgres(PGVector)                │
├───────────────┼─────────────────────────────────────────────┤
│ 關聯式資料庫   │ PostgreSQL 16                                 │
│               │ SQLAlchemy 2.0 + Alembic(遷移管理)          │
├───────────────┼─────────────────────────────────────────────┤
│ PDF 解析       │ pymupdf4llm + unstructured + Tesseract OCR   │
│               │ Pillow(圖片處理)                             │
├───────────────┼─────────────────────────────────────────────┤
│ 作業系統       │ Windows 11(伺服器 + 客戶端)                  │
└───────────────┴─────────────────────────────────────────────┘
```

---

### 3.6 淘汰方案說明(AnythingLLM / MaxKB / Dify / Open-WebUI / RAGFlow)

本節說明在初步評估中曾列入考慮的五款「一體式 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。

---

#### 3.6.4 Open-WebUI

> **定位**:以 Docker 為主的開源 Web UI,支援 Ollama / OpenAI 等後端,提供聊天介面、RAG Pipeline、Tool Calling 等功能

| 限制面向                            | 說明                                                                                                     |
| ----------------------------------- | -------------------------------------------------------------------------------------------------------- |
| **強依賴 Docker**             | 官方安裝方式為 `docker run`,雖有非 Docker 安裝方式但社群支援有限,不符合本系統「不使用 Docker」的限制 |
| **RAG Pipeline 不可深度客製** | Open-WebUI 的 RAG 功能為內建黑盒,Chunk 策略、Reranker 與 Prompt 模板不開放程式化控制                    |
| **無 MCP 原生整合**           | Open-WebUI 的工具整合為自有函數呼叫機制,與標準 MCP 規範不完全相容                                       |
| **適合個人用戶**              | 設計定位為個人或小組的 UI 工具,企業級多角色存取控制與稽核日誌功能不足                                   |

**結論**:Open-WebUI 是優秀的個人/小組 LLM 前端,但 Docker 依賴、封閉的 RAG Pipeline 與 MCP 不相容,使其不適合作為本系統的核心框架。

---

#### 3.6.5 RAGFlow

> **定位**:專注於深度文件解析(Document Layout Analysis)的開源 RAG 引擎,以高精準度 PDF/圖片解析為核心賣點

| 限制面向                        | 說明                                                                                                |
| ------------------------------- | --------------------------------------------------------------------------------------------------- |
| **強依賴 Docker Compose** | 官方部署需要 Docker Compose 啟動多個服務(Elasticsearch、Redis、MinIO 等),無原生 Windows 安裝路徑 |
| **Elasticsearch 依賴**    | RAGFlow 使用 Elasticsearch 作為全文搜尋引擎,與本系統採用 PostgreSQL + pgvector 的技術棧不相容      |
| **Agent 功能有限**        | RAGFlow 以 RAG Pipeline 為核心,Agent 流程控制能力弱,無法實作多步驟意圖分類與 MCP 工具整合         |
| **社群生態**              | GitHub Star 成長快速但生態成熟度與 LangChain 相比仍有差距,長期維護風險需持續觀察                   |

**結論**:RAGFlow 的文件解析精準度値得借鑑,但 Docker 強依賴、Elasticsearch 架構與 Agent 功能不足,使其無法滿足本系統需求。RAGFlow 的版面分析技術可作為日後優化文件攝入品質的參考方向。

---

## 4. 系統架構設計

![1772508371735](image/SA文件_機構設計AI_Agent系統/1772508371735.png)

### 4.1 整體架構

```
┌──────────────────────────────────────────────────────────────────┐
│                    Client Layer(研發繪圖筆電)                     │
│   ┌────────────────────────────────────────────────────────┐    │
│   │         Web Browser(Chrome / Edge)                    │    │
│   │    React + TypeScript SPA(http://server-ip:5173)     │    │
│   └────────────────────────┬───────────────────────────────┘    │
│   ┌────────────────────────────────────────────────────────┐    │
│   │  Local Agent Runtime                                    │    │
│   │  SQLite 快取 │ MCP 工具清單 │ 短期上下文記憶             │    │
│   │  (可選:llama.cpp server 輕量本地推理)                  │    │
│   └────────────────────────────────────────────────────────┘    │
└────────────────────────────┼─────────────────────────────────────┘
                             │  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  |
| -------------------------------- | ----------------------------------------------------------------------------------- | ----- |
| **Local Agent Runtime**    | 客戶端本地 Agent,管理 SQLite 快取、MCP 工具清單、短期記憶;可選安裝輕量 LLM runner | -     |
| **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 呼叫透過 OpenAI 相容 API(llama.cpp server / Ollama),更換模型或推理引擎只需修改 `config.py` 中的選項
2. **工具熱插拔**:新增 MCP Server 無需修改 Agent 核心程式,只需在 `mcp_servers_config.json` 中登記
3. **前後端分離**:FastAPI 提供純 REST API,前端可由任何框架實作,亦可由第三方開發
4. **狀態持久化**:LangGraph 使用 `AsyncPostgresSaver` 將對話 Checkpoints 存入 PostgreSQL,重啟後可恢復對話
5. **降級容錯設計**:每個關鍵元件(推理引擎、Agent 框架、文件解析)均有文件化的替代方案,確保單一元件商業化或故障時可快速切換(詳見第 13 節)

---

## 5. 資料庫設計

> 資料庫引擎:**PostgreSQL 16** + **pgvector** 擴充套件
> ORM:**SQLAlchemy 2.0**(Async 模式)

![1772507814677](image/SA文件_機構設計AI_Agent系統/1772507814677.png)

### 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`

![1772507683463](image/SA文件_機構設計AI_Agent系統/1772507683463.png)

#### 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`

![1772507736257](image/SA文件_機構設計AI_Agent系統/1772507736257.png)

#### 流程概述

```
[使用者上傳檔案]
      ↓
[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)
```

---

### 7.3 RAG 上下文管理策略

> 📌 **背景**:部分推理引擎(含 llama.cpp server / Ollama)在超過上下文長度(context length)時會直接截斷或回傳錯誤,因此系統需要明確的上下文管理策略。

#### 核心策略

| 策略                                       | 說明                                                                         | 實作方式                                             |
| ------------------------------------------ | ---------------------------------------------------------------------------- | ---------------------------------------------------- |
| **Standard RAG(分塊檢索)**         | 對長文件進行 chunking,以向量搜尋擷取相關片段送入 LLM                        | `RecursiveCharacterTextSplitter` + pgvector        |
| **Pre-retrieval 篩選**               | 以 metadata(時間、類別、文件 ID、使用者權限)縮小檢索範圍,避免無關文件干擾 | `rag_retrieve` 節點前置條件                        |
| **Post-retrieval Rerank**            | 對 top-k 召回片段進行語意重排,取最相關的 N 個送入 LLM                       | 開源 Reranker 模型或 Cross-encoder 評分              |
| **Extractive Summarization**         | 對過長召回內容萃取摘要,減少送入 LLM 的 token 數量                           | 小型模型或 extractive 方法(`langextract` 類工具) |
| **Multi-turn / Iterative Retrieval** | 複雜問題採多輪迭代檢索與 query 重寫(Query Reformulation/Expansion)         | LangGraph 迴圈邊(conditional loop)                 |
| **Self-RAG**                         | Agent 自我評估召回結果品質,決定是否重新檢索或補充查詢                       | 新增評估節點 `assess_retrieval`                    |
| **GraphRAG(進階,選用)**           | 將知識整理為圖結構,支援多跳推理(複雜 CAD 流程關聯分析)                    | NetworkX 知識圖 + pgvector 混合搜尋                  |

#### RAG 執行順序

```
1. 接收 query 與使用者偏好;若為操作型請求,先檢查是否有相應 MCP Skill
2. Pre-retrieval:以 metadata 篩選(時間、類別、權限)縮小檢索範圍
3. 向量檢索 top-k
4. Post-retrieval:Rerank + Extractive 摘要(控制 token 總量)
5. (若需要)Multi-turn 檢索或 Query Expansion
6. 組裝 Prompt(萃取後片段 + MCP Skill 輸出),呼叫 LLM 生成答案
7. 回傳結果並記錄來源(文件名稱、頁碼)與信心度
```

---

## 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 資料隔離

- 每位使用者只能查看自己的對話記錄與上傳文件
- 管理員可查看所有紀錄
- 向量知識庫為全域共享(機構內部知識庫)

### 10.5 網路與 TLS 安全

| 機制                                | 說明                                                                                     |
| ----------------------------------- | ---------------------------------------------------------------------------------------- |
| **內網隔離**                  | FastAPI 服務僅監聽整合部內網網段,不對外開放                                             |
| **TLS(內部 CA)**            | 建議以機構內部 CA 簽發 HTTPS 憑證,加密 Client ↔ Server 通訊                            |
| **API Token / 任務 Token**    | 批次匯入及管理員 API 使用獨立的 Token 驗證,避免一般使用者誤觸                           |
| **Role-based Access Control** | `user` 角色僅可對話與上傳;`admin` 才能存取系統設定、使用者管理、批次匯入路徑        |
| **端點最小開放**              | 防火牆僅開放 Port 8000(API);Port 11434(Ollama)與 5432(PostgreSQL)限制為伺服器本機 |

### 10.6 備份與加密策略

| 項目                       | 策略                                                                          |
| -------------------------- | ----------------------------------------------------------------------------- |
| **資料庫備份**       | 每日排程執行 `pg_dump mechdesign_ai > backup_YYYYMMDD.sql`,保留 30 天      |
| **向量資料備份**     | `document_chunks` 向量欄位隨 `pg_dump` 一併備份,恢復時重新建立 HNSW 索引 |
| **原始文件備份**     | `D:\mechdesign-ai\storage\documents\` 目錄定期複製至備援硬碟                |
| **磁碟加密(選用)** | 視機構安全規範,可對伺服器磁碟啟用 BitLocker 加密                             |
| **欄位加密(選用)** | 高敏感欄位(如使用者密碼 hash 以外的個資)可加入 SQLAlchemy 欄位層加密        |

---

## 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 開發階段規劃

#### M1(第 0–2 週):需求確認與環境準備

- [ ] 明確 Client 與 Remote 的資源預算、network policy 與驗證方式
- [ ] 伺服器環境安裝:llama.cpp server(主力)+ Ollama(備援)+ PostgreSQL 16 + pgvector
- [ ] 評估並在測試環境安裝 Foundry Local / LM Studio CLI,比較推理效能與 API 相容性
- [ ] FastAPI 框架搭建:JWT 認證、骨架 API、Task Queue(DB table 實作)
- [ ] LangGraph Agent 基礎版(單輪問答,無 RAG)
- [ ] 資料庫 Schema 建立,Alembic 遷移管理
- [ ] **交付物**:可問答的基礎 API 服務

#### M2(第 3–6 週):文件匯入服務與批次上傳

- [ ] PDF 解析服務(pymupdf4llm + Tesseract OCR 掃描文件支援)
- [ ] 圖片視覺描述(Qwen2.5-VL),描述合併回 Markdown
- [ ] 文字分塊(RecursiveCharacterTextSplitter,chunk_size=512, overlap=64)
- [ ] Embedding 向量化(nomic-embed-text)並批次寫入 pgvector
- [ ] 完成 `POST /documents/upload` 與 `POST /documents/batch-import`
- [ ] 批次任務進度追蹤 `GET /documents/batch-jobs/{job_id}`
- [ ] **交付物**:可查詢內部文件的 RAG 問答 API(90% 批次成功率)

#### M3(第 7–10 週):RAG Pipeline 與 MCP/Skill 框架

- [ ] RAG 向量搜尋整合至 LangGraph(含 Pre-retrieval 篩選與 Post-retrieval Rerank)
- [ ] CAD Tools MCP Server 開發(SolidWorks 指令資料庫)
- [ ] CATIA、AutoCAD 指令資料庫建置
- [ ] LangGraph MCP 工具呼叫節點、意圖分類路由完整實作
- [ ] Client Local Agent Runtime 基礎版(SQLite 快取、MCP 工具清單 Metadata 管理)
- [ ] **交付物**:完整 Agent(RAG + MCP 工具選用)

#### M4(第 11–14 週):多模態支援與上下文策略

- [ ] 圖像 Embedding 支援(CLIP 或 Qwen2.5-VL 作為多模態 Encoder)
- [ ] React 對話介面、串流輸出顯示、圖片上傳功能
- [ ] 文件管理頁面(上傳、批次匯入、狀態追蹤)、系統管理頁面
- [ ] 上下文管理驗證(Pre/Post Retrieval、Iterative Retrieval、Self-RAG)
- [ ] 評估 `langextract` 類工具作為 token 濃縮步驟
- [ ] **交付物**:完整前後端整合版本

#### M5(第 15–18 週):安全性、備份與文件化

- [ ] TLS(內部 CA)設定、網路隔離確認
- [ ] 備份策略落地(pg_dump 排程、原始文件備份)
- [ ] 整合測試(各流程端到端)、效能調優
- [ ] Windows 一鍵部署腳本 `setup_windows.ps1`
- [ ] 使用者說明文件、部署手冊
- [ ] **交付物**:可交付的完整系統

### 12.3 里程碑概覽

| 里程碑           | 週次     | 說明                                              |
| ---------------- | -------- | ------------------------------------------------- |
| M1:環境就緒     | W0–W2   | llama.cpp server + PostgreSQL + pgvector 基礎問答 |
| M2:RAG 問答可用 | W3–W6   | 文件上傳、向量化、OCR、RAG 對話                   |
| M3:Agent 完整   | W7–W10  | MCP 工具整合、多模態支援、Local Agent Runtime     |
| M4:前端完整     | W11–W14 | UI 全功能、上下文管理策略驗證                     |
| M5:正式部署     | W15–W18 | 安全設定、備份、測試通過,離線環境部署完成        |

---

## 13. 可替代/降級策略

> 本節為各技術層的替代方案登記表,確保任何單一元件商業化、授權變更或故障時,可依以下路徑快速降級或切換,降低對整體系統的衝擊。

### 13.1 推理引擎層

| 主選方案                   | 觸發降級條件         | 替代方案                       | 降級成本                               |
| -------------------------- | -------------------- | ------------------------------ | -------------------------------------- |
| **llama.cpp server** | 授權變更、版本停更   | Ollama(備援)、LM Studio CLI  | 低:修改 `LLAMA_SERVER_URL` 環境變數 |
| **Ollama(備援)**   | 商業化或授權附加限制 | llama.cpp server 直接替換      | 低:更換 API endpoint                  |
| **Qwen2.5-VL:7b**    | 模型授權變更         | Gemma3:12b、LLaMA 量化衍生模型 | 低:修改 `CHAT_MODEL` 設定           |

### 13.2 Agent 框架層

| 主選方案                         | 觸發降級條件         | 替代方案                                             | 降級成本                                  |
| -------------------------------- | -------------------- | ---------------------------------------------------- | ----------------------------------------- |
| **LangGraph + LangChain**  | 商業化、授權附加條款 | 純 LangChain(無 Graph)、手寫 FastAPI + Prompt 流程 | 中:重寫狀態機邏輯,但 LLM 呼叫層不需變動 |
| **langchain-mcp-adapters** | MCP SDK 不相容       | 自行實作 HTTP 呼叫 MCP Server                        | 低:封裝為獨立 `mcp_client.py`          |

### 13.3 向量資料庫層

| 主選方案                        | 觸發降級條件      | 替代方案                                           | 降級成本                                             |
| ------------------------------- | ----------------- | -------------------------------------------------- | ---------------------------------------------------- |
| **PostgreSQL + pgvector** | pgvector 授權問題 | ChromaDB(本地檔案)、Qdrant(無 Docker 原生安裝) | 中:需更換 `langchain_postgres` 為對應 VectorStore |
| **nomic-embed-text**      | 模型授權問題      | mxbai-embed-large、bge-m3                          | 低:修改 `EMBED_MODEL` 設定,需重新向量化所有文件  |

### 13.4 文件解析層

| 主選方案                | 觸發降級條件                        | 替代方案                  | 降級成本                                 |
| ----------------------- | ----------------------------------- | ------------------------- | ---------------------------------------- |
| **pymupdf4llm**   | AGPL-3.0 授權問題(若未來商業部署) | pdfplumber + pdfminer.six | 低:替換 `pdf_processor.py` 的解析邏輯 |
| **Tesseract OCR** | 功能不足                            | PaddleOCR、EasyOCR        | 低:替換 OCR 呼叫封裝                    |

---

## 14. 待調查事項與後續建議

### 14.1 待調查清單

| 事項                                  | 說明                                                                                                                                           | 優先順序 |
| ------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| **LLM 推理引擎評估**            | 比較 llama.cpp server、Foundry Local、LM Studio CLI、Ollama 的資源需求、API 支援與版本更新頻率;在測試環境實際量測 TTFT(Time To First Token) | 🔴 高    |
| **Client/Remote 資源分配**      | 若使用者要求完全本地離線推理,需評估 Client(繪圖筆電)是否能承受量化模型 + storage;否則建議預設將推理放在 Remote                             | 🔴 高    |
| **上下文處理工具**              | 評估 `langextract`、開源 Reranker(BGE Reranker、Jina Reranker)作為 Post-retrieval 步驟                                                     | 🟡 中    |
| **GraphRAG 可行性**             | 評估 CAD 知識圖的建構成本與多跳推理收益;初期 Standard RAG 先行,GraphRAG 作為進階選項                                                         | 🟡 中    |
| **圖像 Embedding 策略**         | 確認 CLIP 或 Qwen2.5-VL 作為多模態 Encoder 的向量維度與 pgvector 整合方式                                                                      | 🟡 中    |
| **Client Local Agent 資源估算** | 評估 SQLite 本地快取與 Local Agent Runtime 在繪圖筆電上的實際 CPU/RAM 佔用                                                                     | 🟢 低    |

### 14.2 後續建議

1. **MVP 先行**:在初期實作階段鎖定「llama.cpp server + Qwen2.5-VL:7b + Standard RAG」的最小組合,完成 MVP 後再評估引入 Reranker、Self-RAG 或 GraphRAG 的成本效益。
2. **版本鎖定**:記錄所有外部套件的確切版本與授權細節(參考 `requirements.txt`),確保未來能以替代實作降低風險。
3. **分批引入 RAG 優化技術**:Pre-retrieval 篩選與 Post-retrieval Rerank 優先引入(投入產出比高);Self-RAG 與 GraphRAG 視 M3/M4 階段效果決定是否納入。
4. **定期評估推理引擎**:每季確認 llama.cpp server 版本更新狀況,若 Foundry Local 或 LM Studio CLI 的 API 相容性成熟,可作為替換候選。

---

## 15. 附錄:Mermaid 圖例清單

| 編號 | 檔案                                     | 說明                                |
| ---- | ---------------------------------------- | ----------------------------------- |
| 01   | `docs/diagrams/01_use_case.mmd`        | Use Case 圖(使用者角色與功能邊界) |
| 02   | `docs/diagrams/02_uml_class.mmd`       | UML Class 圖(核心類別關係)        |
| 03   | `docs/diagrams/03_database_schema.mmd` | 資料庫 Schema ER 圖                 |
| 04   | `docs/diagrams/04_sequence_rag.mmd`    | RAG 對話 Sequence 圖                |
| 05   | `docs/diagrams/05_sequence_upload.mmd` | 文件上傳/向量化 Sequence 圖         |
 







Login to like - 0 Likes



Comments...


No Comments Yet...



Add Comment...



shumin

A graduated biotechnology engineer. Now is a software engineer


Latest Posts



Footer with Icons