Move PRD, design specs, architecture docs, and TDD from .autoflow/ (personal/per-branch layer) to docs/autoflow/ (shared layer that goes into git) per the new Autoflow workspace layout. Files moved: - 02-prd/PRD.md - 03-design/design-review.md - 03-design/user-flow-cross-system.md - 04-architecture/TDD.md - 04-architecture/design-doc.md - 04-architecture/security.md The originals were never tracked, so git mv reduced to a filesystem rename with no history to preserve. .autoflow/ remains for personal notes (progress.md, review reports, testing logs). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1135 lines
70 KiB
Markdown
1135 lines
70 KiB
Markdown
# Kneron Model Converter - 產品需求文件 (PRD)
|
||
|
||
> **文件性質**:此 PRD 為從既有程式碼反向整理,尚待產品負責人確認。
|
||
> 標記 `[推測]` 的部分為從程式碼推斷但無法確認的內容,請使用者審閱時特別留意。
|
||
>
|
||
> **最後更新**:2026-04-25(原始模型上傳路徑變更:visionA-backend 直接 multipart 上傳到 Converter,不經過 File Access Agent)
|
||
>
|
||
> ## 變更歷程
|
||
>
|
||
> ### 2026-04-25(第二次更新):原始模型上傳路徑變更
|
||
>
|
||
> - **變更內容**:原始模型的上傳路徑由「visionA-backend → File Access Agent(使用者模型庫)→ Converter 用 S2S 從 File Access Agent 拉下來」改為「visionA-backend 直接把原始模型以 multipart 上傳到 Converter(跟現有 Web UI 一樣)」。
|
||
> - **變更原因**:先前 PRD 基於誤解,把使用者模型庫設計為「原始模型的來源」;使用者已澄清,正確設計是「模型庫只在使用者按『加進模型庫』後才存入轉檔結果」。原始模型上傳是從 visionA-backend 直接推給 Converter。
|
||
> - **影響章節**:
|
||
> - §4.3(F-28 刪除、F-23 描述重寫)
|
||
> - §4.4(US-08 前置條件與驗收標準重寫)
|
||
> - §5.5(POST /api/v1/jobs 描述改為 multipart)
|
||
> - §5.6(OAuth2 Client 讀檔相關 scope 移除)
|
||
> - §9.2.1(POST /jobs 的 p95 目標調整,標註大檔上傳時間不計入)
|
||
> - §10(路線圖移除「從 File Access Agent 取原始模型」)
|
||
> - §14(Phase 1 對 File Access Agent 只剩 PUT(promote),不需要 GET、HEAD)
|
||
> - §15(Phase 1 Scope 表移除「從 File Access Agent 取原始模型」)
|
||
> - §12.2(大檔 promote 風險表述維持;新增 multipart 上傳相關風險)
|
||
> - 附錄 A(補充本次變更造成的新問題)
|
||
> - **不影響章節**:
|
||
> - 既有 Persona A / B 定義
|
||
> - 既有 US-01 ~ US-07
|
||
> - 既有 `[推測]` 標記
|
||
> - US-13(promote 流程)
|
||
> - US-14(Phase 2 delegated download)
|
||
> - 既有「Crash 即 Reset」設計哲學
|
||
>
|
||
> ### 2026-04-25(首次更新):新增 L 級功能(對外 API)
|
||
>
|
||
> 將 Kneron Model Converter 從「僅有 Web UI 的內部工具」擴展為「對外提供 OAuth2 保護 REST API 的服務」,讓 Innovedus 生態中的其他服務(首個消費者為 VisionA)能以程式化方式呼叫轉檔能力。
|
||
>
|
||
> 新增章節:
|
||
> - §1.2 新增 **Persona C — 服務消費者(visionA-backend)**
|
||
> - §4.3 **API 消費者功能總覽**(Phase 1 / Phase 2 切分)
|
||
> - §4.4 **新增的 User Stories(US-08 ~ US-14)**
|
||
> - §5.5 **新增 API 端點預告(對外 API / v1)**
|
||
> - §8.1 **RICE 新增項目:API 對外開放**
|
||
> - §9.1 **新增成功指標(API SLA、採用度、錯誤率)**
|
||
> - §14 **相依服務(新增章節)**
|
||
> - §15 **Phase 1 / Phase 2 Scope 切分(新增章節)**
|
||
>
|
||
> 保留不變:
|
||
> - 既有 Persona A / B、既有 User Stories US-01 ~ US-07
|
||
> - 既有 Web UI 行為(Phase 1 不改 Web UI 流程)
|
||
> - 既有「Crash 即 Reset」設計哲學
|
||
> - 既有 `[推測]` 標記(本次不清除,留待使用者決定)
|
||
|
||
---
|
||
|
||
## 1. 產品策略
|
||
|
||
### 1.1 產品願景
|
||
|
||
**一句話描述**:讓 AI 工程師能透過 Web 介面,輕鬆地將 AI 模型轉換為可部署到 Kneron AI 晶片的格式,並透過任務佇列機制解決高併發下的效能瓶頸。
|
||
|
||
**背景問題**:Kneron Toolchain 的模型轉換流程(ONNX → BIE → NEF)在單一 VM / 單一 Toolchain instance 運行時,高併發場景下會造成 CPU 爆滿與 Crash。現有的轉換方式需要工程師手動操作 CLI 或 Python API,缺乏視覺化介面與任務管理能力。
|
||
|
||
**解決方案**:建構一個 Web-based 的模型轉換服務,採用「Crash 即 Reset」的設計哲學,將轉換流程拆分為可水平擴充的 Worker Pool,由 Task Scheduler 統一派工與狀態管理,提供即時任務追蹤與結果下載。
|
||
|
||
### 1.2 目標用戶(Persona)
|
||
|
||
#### Persona A:AI 應用工程師 — 小明
|
||
|
||
- **角色**:AI 應用開發工程師,負責將訓練好的模型部署到 Kneron 晶片
|
||
- **背景**:熟悉 Python、ONNX 模型格式,但不一定熟悉 Kneron Toolchain 的底層細節
|
||
- **目標**:快速將 ONNX/TFLite 模型轉換為 NEF 格式,部署到 Kneron KDP 系列晶片
|
||
- **痛點**:
|
||
- 手動使用 Toolchain CLI 操作繁瑣,容易出錯
|
||
- 多人同時轉換時系統容易當機
|
||
- 轉換過程耗時,無法即時掌握進度
|
||
- **技術素養**:高
|
||
- **一句話描述**:「我希望能一鍵上傳模型就自動完成轉換,這樣我就可以專注在模型調校而非部署工具的操作」
|
||
|
||
#### Persona B:[推測] 團隊主管 / 技術經理 — 大華
|
||
|
||
- **角色**:管理多位 AI 工程師的技術主管
|
||
- **目標**:提供團隊穩定的模型轉換服務,減少因工具問題導致的開發阻塞
|
||
- **痛點**:
|
||
- 單人佔用 Toolchain 時其他人無法使用
|
||
- Crash 後需要 IT 介入重啟
|
||
- 缺乏任務可見性,無法掌握團隊的轉換排隊情況
|
||
- **技術素養**:高
|
||
- **一句話描述**:「我希望團隊能同時使用轉換服務不互相干擾,這樣就不會因為工具問題拖延專案進度」
|
||
|
||
#### Persona C:服務消費者 — visionA-backend(非人類 Persona)
|
||
|
||
> **注意:這不是一個「使用者」,而是一個「服務」。** Persona C 代表所有以程式化方式呼叫 Kneron Model Converter API 的下游服務。首個消費者為 Innovedus 旗下的 **VisionA**(`visionA-backend`,Go 服務,路徑:`~/visionA/visionA-backend/`)。未來可擴展至 Innovedus 生態的其他 vertical 應用。
|
||
|
||
- **角色**:Innovedus 生態中需要「模型轉檔」能力的下游後端服務
|
||
- **當前代表**:visionA-backend(Go / Gin),目前處於 Phase 0 雛形,近期進入 Phase 1 將導入 OAuth2/OIDC
|
||
- **目標**:
|
||
- 讓 VisionA 的終端使用者(Edge AI 應用開發者)能在 VisionA 平台內直接觸發模型轉檔,無需離開平台
|
||
- 把轉檔結果自動納入使用者的 VisionA 模型庫(長期儲存於 NAS)
|
||
- 不需要自己重新實作 Kneron Toolchain 的封裝
|
||
- **痛點**:
|
||
- 目前 Kneron Model Converter 只有 Web UI,無法以程式化方式整合
|
||
- 沒有標準的 auth 機制,無法對齊 Innovedus 統一的 Member Center OAuth2 體系
|
||
- 沒有檔案搬運 API,下游服務無法把轉檔結果搬到自己的長期儲存
|
||
- 缺乏「同使用者同時一個轉檔」的保護,容易讓使用者搞混
|
||
- 沒有 job recovery 能力,使用者離開頁面後回來看不到未完成的任務
|
||
- **技術素養**:不適用(服務對服務)
|
||
- **關鍵特性**:
|
||
- 以 OAuth2 `client_credentials` 取得 service token 呼叫 Converter API
|
||
- 在 request 中帶 `user_id`(VisionA 端的使用者 ID,Converter 信任不驗證;僅用於業務邏輯,非授權邊界);建 job 時 `user_id` 作為 multipart field,查詢 API 作為 query string
|
||
- **直接將原始模型以 multipart 上傳給 Converter**(不經過任何中間檔案庫)
|
||
- 透過 polling(非 webhook)取得轉檔進度
|
||
- 轉檔完成後呼叫 `promote` API 將結果搬進模型庫
|
||
- **一句話描述**:「作為服務,我希望能用標準的 OAuth2 service token 呼叫 Converter API,讓我的使用者能在我的平台內完成模型轉檔,同時不用自己處理 Kneron Toolchain 的複雜度」
|
||
|
||
#### 間接使用者:VisionA 終端使用者
|
||
|
||
雖然他們不直接接觸 Converter API,但他們是最終受益者:
|
||
- **角色**:VisionA 平台上的 Edge AI 應用開發者
|
||
- **感受到的能力**:在 VisionA 模型庫內可以「把模型送去轉檔」、「看進度」、「把結果加進模型庫」
|
||
- **他們不會知道**:背後是另一個服務(Kneron Model Converter)在處理,也不會直接和它溝通
|
||
- **關鍵體驗要求**:
|
||
- 同時只能有一個轉檔進行中(避免搞混)
|
||
- 離開頁面再回來能看到未完成的任務
|
||
- 轉檔失敗時能看到具體原因
|
||
|
||
### 1.3 核心問題與價值主張
|
||
|
||
| 核心問題 | 價值主張 |
|
||
|---------|---------|
|
||
| 單一 Toolchain instance 無法承受高併發 | Worker Pool 水平擴展,多任務平行處理 |
|
||
| 模型轉換操作繁瑣(CLI / Python API) | Web UI 提供視覺化操作介面 |
|
||
| 轉換進度不透明 | SSE 即時推送任務狀態 |
|
||
| Crash 後恢復困難 | 「Crash 即 Reset」哲學,無狀態設計,重啟即恢復服務 |
|
||
| 多人共用時互相干擾 | 任務佇列隔離,每個 Worker 獨立處理 |
|
||
|
||
### 1.4 OKR [推測]
|
||
|
||
**Objective:提供穩定、高效的 AI 模型轉換服務**
|
||
|
||
- KR1:系統可同時處理 N 個轉換任務(透過 Worker 水平擴展)
|
||
- KR2:單一任務的轉換成功率 > 95%(排除模型本身問題)
|
||
- KR3:系統 Crash 後 < 30 秒恢復服務能力
|
||
|
||
### 1.5 北極星指標與指標體系 [推測]
|
||
|
||
```
|
||
北極星指標:每日成功轉換任務數
|
||
├── 驅動指標:任務提交數、轉換成功率、平均轉換時間
|
||
│ ├── 輸入指標:Web UI 使用率、API 呼叫次數
|
||
│ ├── 輸入指標:各階段(ONNX/BIE/NEF)失敗率
|
||
│ └── 輸入指標:Worker 利用率
|
||
└── 護欄指標:Worker Crash 率、Redis 記憶體使用量、佇列堆積長度
|
||
```
|
||
|
||
---
|
||
|
||
## 2. 市場分析 [推測]
|
||
|
||
### 2.1 市場定位
|
||
|
||
此產品為 **內部工具 / 企業內部服務**,主要服務 Kneron 內部或其客戶的 AI 工程團隊。非面向公開市場的 SaaS 產品。
|
||
|
||
### 2.2 競品對照
|
||
|
||
| 方案 | 類型 | 優勢 | 劣勢 | 與本產品差異 |
|
||
|------|------|------|------|------------|
|
||
| Kneron Toolchain CLI | 原生 CLI 工具 | 功能完整、官方支援 | 無 GUI、不支援併發、操作門檻高 | 本產品是其 Web 化包裝 |
|
||
| Kneron Toolchain Web GUI(原版) | 官方 Web GUI | 有介面 | 單一 instance、Crash 問題 | 本產品解決了其效能與穩定性瓶頸 |
|
||
| Edge Impulse | 雲端 ML 平台 | 完整 MLOps 流程 | 不支援 Kneron 特定格式 | 本產品專注 Kneron 晶片生態 |
|
||
| TensorFlow Lite Converter | Google 官方工具 | 生態完整 | 只支援 TFLite 格式 | 本產品支援 Kneron 特有的 BIE/NEF 格式 |
|
||
|
||
### 2.3 差異化策略
|
||
|
||
- **唯一性**:唯一支援 Kneron KDP 系列晶片完整轉換流程(ONNX → BIE → NEF)的 Web 服務
|
||
- **護城河**:與 Kneron Toolchain 深度整合,封裝其 Python API
|
||
- **關鍵優勢**:Worker Pool 架構解決了原生 Toolchain 的併發瓶頸
|
||
|
||
---
|
||
|
||
## 3. 用戶研究
|
||
|
||
### 3.1 用戶旅程地圖
|
||
|
||
| 階段 | 用戶行為 | 想法/感受 | 痛點 | 機會點 |
|
||
|------|----------|----------|------|--------|
|
||
| 模型準備 | 訓練好模型,匯出 ONNX/TFLite | 「模型訓練完成,該部署了」 | 需要確認模型格式相容性 | [推測] 提供模型格式驗證 |
|
||
| 上傳模型 | 透過 Web UI 上傳模型檔 + 參考圖片 | 「介面還算直覺」 | 大檔案上傳可能較慢(上限 500MB) | 上傳進度顯示 |
|
||
| 設定參數 | 選擇平台、填寫 Model ID / Version | 「這些參數是什麼意思?」 | 參數含義不夠直覺 | [推測] 提供參數說明 / 預設值 |
|
||
| 等待轉換 | 觀察 SSE 即時進度更新 | 「大概還要多久?」 | 只有階段進度,無時間預估 | [推測] 加入預估剩餘時間 |
|
||
| 下載結果 | 下載 BIE/NEF 產出檔 | 「轉換完成,可以部署了」 | - | - |
|
||
| 失敗處理 | 看到失敗訊息,需要重新提交 | 「為什麼失敗?該怎麼修?」 | 錯誤訊息可能不夠友善 | [推測] 提供更詳細的錯誤診斷 |
|
||
|
||
---
|
||
|
||
## 4. 功能需求
|
||
|
||
### 4.1 功能總覽與狀態
|
||
|
||
| # | 功能 | 狀態 | 說明 |
|
||
|---|------|------|------|
|
||
| F-01 | 模型檔案上傳 | 已實作 | 支援 ONNX、TFLite 格式,上限 500MB |
|
||
| F-02 | 參考圖片上傳 | 已實作 | BIE 量化用的參考圖片(最多 100 張) |
|
||
| F-03 | 完整轉換流程(ONNX → BIE → NEF) | 已實作 | 固定三階段序列化流程 |
|
||
| F-04 | 單階段轉換(ONNX 優化) | UI 已實作,後端部分實作 | Web UI 有獨立 ONNX 表單,但後端 API 僅有完整流程端點 |
|
||
| F-05 | 單階段轉換(BIE 量化) | UI 已實作,後端部分實作 | 同上 |
|
||
| F-06 | 單階段轉換(NEF 編譯) | UI 已實作,後端部分實作 | 同上 |
|
||
| F-07 | 任務狀態即時更新(SSE) | 已實作 | Server-Sent Events + Polling 備援 |
|
||
| F-08 | 任務狀態查詢(REST API) | 已實作 | GET /jobs/:jobId |
|
||
| F-09 | 任務列表查詢 | 已實作 | GET /jobs |
|
||
| F-10 | 結果檔案下載 | 已實作 | GET /jobs/:jobId/download/:filename |
|
||
| F-11 | Worker 水平擴展 | 已實作 | docker-compose --scale |
|
||
| F-12 | Stub Worker 開發模式 | 已實作 | WORKER_MODE=stub 模擬處理 |
|
||
| F-13 | IP 評估(可選) | 已實作 | enable_evaluate 旗標 |
|
||
| F-14 | 浮點 E2E 模擬 | 未完成 | enable_sim_fp 旗標已定義,邏輯未接線 |
|
||
| F-15 | 定點 E2E 模擬 | 未完成 | enable_sim_fixed 旗標已定義,邏輯未接線 |
|
||
| F-16 | 硬體 E2E 模擬 | 未完成 | enable_sim_hw 旗標已定義,邏輯未接線 |
|
||
| F-17 | 健康檢查 API | 已實作 | GET /health |
|
||
| F-18 | [推測] 任務取消 | 未實作 | 目前無法中途取消進行中的任務 |
|
||
| F-19 | [推測] 任務重試 | 未實作 | 符合「Crash 即 Reset」哲學,失敗需手動重送 |
|
||
| F-20 | [推測] 歷史任務持久化 | 未實作 | Redis 重啟即清空,無持久化 |
|
||
|
||
### 4.2 User Stories
|
||
|
||
#### US-01:上傳模型並執行完整轉換
|
||
|
||
> **作為** AI 應用工程師,
|
||
> **我希望** 上傳 ONNX/TFLite 模型檔和參考圖片,設定目標平台後一鍵啟動轉換,
|
||
> **以便** 自動完成 ONNX 優化 → BIE 量化 → NEF 編譯的完整流程,取得可部署到 Kneron 晶片的 NEF 檔。
|
||
|
||
**驗收標準**:
|
||
- 支援上傳 .onnx 和 .tflite 格式檔案
|
||
- 必填參數:model_id、version、platform
|
||
- 支援平台:KDP520、KDP720、KDP530、KDP630、KDP730
|
||
- 上傳成功後自動進入 ONNX → BIE → NEF 流程
|
||
- 狀態:**已實作**
|
||
|
||
#### US-02:即時追蹤轉換進度
|
||
|
||
> **作為** AI 應用工程師,
|
||
> **我希望** 在提交任務後能即時看到目前處於哪個階段(ONNX/BIE/NEF)以及進度百分比,
|
||
> **以便** 掌握任務狀態,不需要反覆手動刷新。
|
||
|
||
**驗收標準**:
|
||
- 透過 SSE 即時推送狀態更新
|
||
- SSE 斷線時自動降級為每 3 秒 Polling
|
||
- 顯示當前階段名稱與進度百分比
|
||
- 任務完成或失敗時顯示對應通知
|
||
- 狀態:**已實作**
|
||
|
||
#### US-03:下載轉換結果
|
||
|
||
> **作為** AI 應用工程師,
|
||
> **我希望** 轉換完成後能直接從 Web UI 下載產出的 NEF 檔(或中間產物 BIE),
|
||
> **以便** 取得可部署的模型檔案。
|
||
|
||
**驗收標準**:
|
||
- 任務 COMPLETED 後提供下載按鈕
|
||
- 支援下載 out.onnx、out.bie、out.nef
|
||
- 狀態:**已實作**
|
||
|
||
#### US-04:選擇單階段處理
|
||
|
||
> **作為** AI 應用工程師,
|
||
> **我希望** 能選擇只執行某一個階段(例如只做 ONNX 優化,或只做 BIE 量化),
|
||
> **以便** 在除錯時逐步確認每個階段的輸出正確性。
|
||
|
||
**驗收標準**:
|
||
- Web UI 提供四種工作流程選擇:ONNX 優化 / BIE 量化 / NEF 編譯 / 完整流程
|
||
- 各流程有獨立的參數表單
|
||
- 狀態:**UI 已實作,後端 API 部分實作**(Web UI 的前端表單呼叫的 API 端點如 `/api/onnx/upload`、`/api/bie/process` 尚未在 Task Scheduler 中實作,後端目前僅支援 POST /jobs 建立完整流程任務)
|
||
|
||
#### US-05:水平擴展 Worker
|
||
|
||
> **作為** 系統管理員,
|
||
> **我希望** 能透過簡單的指令增加 Worker 數量,
|
||
> **以便** 在任務量大時提升系統處理能力。
|
||
|
||
**驗收標準**:
|
||
- 透過 `docker-compose up --scale bie-worker=N` 即可擴展
|
||
- 新 Worker 自動加入 Consumer Group 分配任務
|
||
- 不需修改任何設定檔或重啟其他服務
|
||
- 狀態:**已實作**
|
||
|
||
#### US-06:[推測] 查看失敗原因
|
||
|
||
> **作為** AI 應用工程師,
|
||
> **我希望** 任務失敗時能看到具體的錯誤原因與失敗階段,
|
||
> **以便** 判斷是模型問題還是系統問題,並採取對應措施。
|
||
|
||
**驗收標準**:
|
||
- 失敗任務顯示失敗的階段(ONNX/BIE/NEF)
|
||
- 顯示錯誤原因文字
|
||
- 狀態:**已實作**(job record 中有 error.step 和 error.reason)
|
||
|
||
#### US-07:開發與測試用 Stub 模式
|
||
|
||
> **作為** 開發人員,
|
||
> **我希望** 能在不安裝 Kneron Toolchain 的情況下啟動整套系統進行開發測試,
|
||
> **以便** 快速迭代 Scheduler、Web UI 和佇列邏輯。
|
||
|
||
**驗收標準**:
|
||
- 設定 WORKER_MODE=stub 即可啟用
|
||
- Stub Worker 模擬處理時間(2-3 秒)並產生假輸出檔
|
||
- 完整流程可走通,SSE 通知正常運作
|
||
- 狀態:**已實作**
|
||
|
||
---
|
||
|
||
### 4.3 API 消費者功能總覽(新增,2026-04-25)
|
||
|
||
本節說明本次 L 級更新的新功能範圍。所有新功能都是針對 **Persona C(服務消費者)** 設計,並以「讓 VisionA 終端使用者獲得完整模型轉檔體驗」為最終目標。
|
||
|
||
| # | 功能 | 狀態 | Phase | 說明 |
|
||
|---|------|------|-------|------|
|
||
| F-21 | OAuth2 Resource Server(驗 visionA-backend 的 service token) | 未實作 | Phase 1 | 以 Member Center JWKS 驗簽 JWT,檢查 `aud=kneron_converter_api` 與 scope |
|
||
| F-22 | OAuth2 Client(Converter 自己取 service token) | 未實作 | Phase 1 | 用 `client_credentials` 向 Member Center 取 token,供 PUT 檔案到 File Access Agent(promote 時使用) |
|
||
| F-23 | 對外 API: 建立轉檔 job(`POST /api/v1/jobs`) | 未實作 | Phase 1 | **multipart/form-data** 格式(跟現有 Web UI 一致),visionA-backend 直接把原始模型上傳到 Converter,body 帶 `user_id` + `model`(原始模型檔)+ `ref_images[]`(可選)+ 參數 |
|
||
| F-24 | 對外 API: 查詢 job 進度(`GET /api/v1/jobs/:id`) | 未實作 | Phase 1 | Polling 模式,回傳 status、stage、progress、error |
|
||
| F-25 | 對外 API: 查詢 job 列表(`GET /api/v1/jobs?user_id=...&status=...`) | 未實作 | Phase 1 | 支援 recovery 場景(使用者離開頁面回來) |
|
||
| F-26 | 對外 API: 搬檔到模型庫(`POST /api/v1/jobs/:id/promote`) | 未實作 | Phase 1 | Converter 自己用 service token PUT 結果檔到 File Access Agent |
|
||
| F-27 | 同使用者同時一個轉檔限制 | 未實作 | Phase 1 | 建 job 時檢查 `user_id` 是否有 in-progress job,有則拒絕 |
|
||
| F-29 | OpenAPI 規格(對外 API 契約) | 未實作 | Phase 1 | 產出 OpenAPI 3.0 spec,方便下游服務整合與測試 |
|
||
| F-30 | 使用者下載模型(delegated token 直連 File Access Agent) | 未實作 | **Phase 2** | 阻塞:Member Center `POST /file-access/download-tokens` 尚未實作 |
|
||
|
||
> **註(2026-04-25 變更)**:原 F-28「從 File Access Agent 取 input 模型」已刪除。Phase 1 的原始模型上傳改為由 visionA-backend 直接 multipart 上傳到 Converter(見 F-23),不再經過 File Access Agent。
|
||
|
||
**Phase 1 / Phase 2 切分原因**:Phase 2 的「使用者下載」依賴 Member Center 的 delegated token endpoint,但該 endpoint 目前尚未實作。為避免阻塞 Phase 1 整體上線,Phase 1 先讓 VisionA 能完成「上傳 → 轉檔 → 搬進模型庫」閉環,下載則等 Member Center 補完後再做。詳見 §15。
|
||
|
||
### 4.4 新增 User Stories(2026-04-25)
|
||
|
||
#### US-08:visionA-backend 以 service token 建立轉檔 job
|
||
|
||
> **作為** visionA-backend(服務消費者),
|
||
> **我希望** 用 OAuth2 service token 呼叫 Converter API 建立轉檔 job,
|
||
> **以便** 讓我的使用者能在 VisionA 平台內觸發模型轉檔,而不用跳到另一個系統。
|
||
|
||
**前置條件**:
|
||
- visionA-backend 已取得終端使用者要轉檔的原始模型檔案(由 VisionA 自己的上傳流程收到,保存在 visionA-backend 自己可存取的位置)
|
||
- visionA-backend 已向 Member Center 取得 service token(`aud=kneron_converter_api`, scope=`converter:job.write`)
|
||
|
||
**驗收標準**:
|
||
- `POST /api/v1/jobs`,Content-Type: `multipart/form-data`,Header: `Authorization: Bearer <service_token>`
|
||
- **multipart files**:
|
||
- `model`(必填,原始模型檔,支援 `.onnx` / `.tflite`,單檔 ≤ 500MB)
|
||
- `ref_images[]`(可選,BIE 量化用參考圖片,最多 100 個)
|
||
- **multipart fields**:
|
||
- `user_id`(必填,VisionA 使用者 ID,字串)
|
||
- `model_id`(必填,Integer,1–65535)
|
||
- `version`(必填,字串,如 `"0001"`)
|
||
- `platform`(必填,字串,`"520"` / `"720"` / `"530"` / `"630"` / `"730"`)
|
||
- `enable_evaluate`(可選,Boolean,預設 false)
|
||
- `enable_sim_fp`(可選,Boolean,預設 false,未接線)
|
||
- `enable_sim_fixed`(可選,Boolean,預設 false,未接線)
|
||
- `enable_sim_hw`(可選,Boolean,預設 false,未接線)
|
||
- Converter 驗證 token 簽章、`aud`、`scope`,失敗則回 `401` / `403`
|
||
- 驗證通過後,Converter 把原始模型存到 Converter Bucket(例如 `jobs/{job_id}/input/{filename}`),由既有 Worker 流程處理(與現有 Web UI 走 `POST /jobs` 的儲存路徑一致)
|
||
- 建 job 成功回 `201 Created`,body 含 `job_id`、`status=created`
|
||
- 若該 `user_id` 已有進行中 job(`status ∈ {created, running}`),回 `409 Conflict`,body 含現有 job_id(詳見 US-11)
|
||
- 若 multipart 欄位缺漏、檔案超過 500MB、模型格式非 `.onnx` / `.tflite`、platform 不支援,回 `400 Bad Request`
|
||
- **設計備註**:此路徑刻意與既有 Web UI 的 `POST /jobs`(Phase 1 內部路徑)走同一份 multipart 上傳行為,以最大化重用既有上傳處理邏輯(multer memory storage、檔案大小限制、Worker 派工)。差異僅在:`/api/v1/jobs` 多驗 OAuth token、必填 `user_id`、多檢查 US-11 的同使用者同時限制。
|
||
- 狀態:**未實作(Phase 1 必做)**
|
||
|
||
#### US-09:追蹤轉檔進度(polling)
|
||
|
||
> **作為** VisionA 終端使用者(透過 visionA-backend),
|
||
> **我希望** 在觸發轉檔後能看到目前進度(哪個階段、百分比),
|
||
> **以便** 知道還要多久、是否成功。
|
||
|
||
**驗收標準**:
|
||
- visionA-backend 以固定間隔呼叫 `GET /api/v1/jobs/:id`(建議 2-5 秒一次)
|
||
- 回傳 body 含:`status`(created / running / completed / failed)、`stage`(onnx / bie / nef)、`progress`(0-100)、`error`(失敗時)、`result_object_keys`(完成時,各輸出檔在 Converter MinIO 的暫存 key)
|
||
- visionA-backend 將此資訊轉化為 VisionA UI 要顯示的進度條
|
||
- **不做** Webhook / SSE 對外推送(Phase 1 範圍內,polling 已足夠)
|
||
- 若 `job_id` 不存在或不屬於呼叫者的 tenant,回 `404`
|
||
- 狀態:**未實作(Phase 1 必做)**
|
||
|
||
#### US-10:轉檔完成後加進模型庫
|
||
|
||
> **作為** VisionA 終端使用者(透過 visionA-backend),
|
||
> **我希望** 轉檔完成後可以選擇「加進我的模型庫」,
|
||
> **以便** 結果被長期保存到 NAS,而不是留在 Converter 的暫存區等 7 天後被清掉。
|
||
|
||
**驗收標準**:
|
||
- visionA-backend 呼叫 `POST /api/v1/jobs/:id/promote`,body 帶目標 `object_key`(VisionA 端決定命名,例如 `visionA/models/{user_id}/{model_id}/v{version}/out.nef`)
|
||
- Converter 自己用 service token(scope=`files:upload.write`)PUT 檔案到 File Access Agent
|
||
- 檔案流只在 NAS 側流動(Converter → File Access Agent → NAS Bucket),不透過 visionA-backend 中轉
|
||
- 成功回 `200 OK`,body 含已搬檔的 object_key 列表
|
||
- 若 job 尚未 completed 或已 failed,回 `409 Conflict`
|
||
- 若 promote 過程失敗(File Access Agent 不可用、auth 問題等),回 `502 Bad Gateway`,並可重試
|
||
- Converter Bucket 的暫存檔仍保留直到 7 天 lifecycle 到期(不立即刪除,以利失敗重試)
|
||
- 狀態:**未實作(Phase 1 必做)**
|
||
|
||
#### US-11:同使用者同時一個轉檔
|
||
|
||
> **作為** VisionA 終端使用者(透過 visionA-backend),
|
||
> **我希望** 系統限制同一個使用者同時只能進行一個轉檔,
|
||
> **以便** 我不會被多個同時進行的轉檔搞混,也避免意外消耗 Worker 資源。
|
||
|
||
**驗收標準**:
|
||
- Converter 在建 job 時檢查該 `user_id` 是否已有 `status ∈ {created, running}` 的 job
|
||
- 若有,回 `409 Conflict`,body 範例:`{"error":"user_has_active_job","active_job_id":"..."}`
|
||
- 限制作用於 `user_id`(VisionA 使用者),**不是** `client_id`(同一個 VisionA backend 服務可以同時有多個不同使用者的轉檔)
|
||
- 此為「產品面軟限制」,非「授權邊界」:Converter 只是信任 visionA-backend 傳來的 user_id
|
||
- 狀態:**未實作(Phase 1 必做)**
|
||
|
||
#### US-12:離開頁面 recovery
|
||
|
||
> **作為** VisionA 終端使用者(透過 visionA-backend),
|
||
> **我希望** 離開轉檔頁面再回來時,能看到我之前未完成的 job,
|
||
> **以便** 不用重新送一次或擔心轉檔結果遺失。
|
||
|
||
**驗收標準**:
|
||
- visionA-backend 進入轉檔頁面時呼叫 `GET /api/v1/jobs?user_id=...&status=in_progress`(`in_progress` 為 `created` + `running` 的總稱)
|
||
- Converter 回傳該使用者所有進行中的 job 清單(Phase 1 同時至多 1 個,但 API 設計為 list 以保彈性)
|
||
- visionA-backend 根據清單決定是否顯示「有未完成的轉檔,是否繼續追蹤?」的 UI
|
||
- 同時支援 `status=completed` / `status=failed`(近期完成)、`limit`、`offset` 參數
|
||
- **注意**:Converter 本身仍遵循「Crash 即 Reset」哲學,Redis 重啟後 job 會消失。recovery 僅在 Converter 正常運行期間有效,不保證跨 Crash 可恢復
|
||
- 狀態:**未實作(Phase 1 必做)**
|
||
|
||
#### US-13:Converter 自己搬檔避免大檔跨網段傳輸
|
||
|
||
> **作為** visionA-backend,
|
||
> **我希望** 呼叫 Converter 搬檔時,Converter 能自己把檔案推到 File Access Agent,
|
||
> **以便** 避免大檔(可能數百 MB)跨 AWS ↔ NAS 來回傳輸(Converter → visionA-backend → File Access Agent 會慢且貴)。
|
||
|
||
**驗收標準**:
|
||
- `POST /api/v1/jobs/:id/promote` 的實作中,Converter 直接從自己的 MinIO 讀檔,然後 PUT 到 File Access Agent
|
||
- visionA-backend 不接觸檔案實體,只接收 promote API 的成功/失敗結果
|
||
- Converter 以自己的 OAuth2 `client_credentials` 向 Member Center 取得 `files:upload.write` scope 的 token(non-user-bound service token)
|
||
- File Access Agent 以 Member Center JWKS 驗該 token,檢查 `aud=file_access_api`、`scope=files:upload.write`、`tenant_id` 吻合
|
||
- 狀態:**未實作(Phase 1 必做)**
|
||
|
||
#### US-14:【Phase 2】使用者下載模型走 delegated token
|
||
|
||
> **作為** VisionA 終端使用者,
|
||
> **我希望** 從 VisionA 模型庫下載已搬進 NAS 的模型檔時,瀏覽器能直連 File Access Agent(帶短效 delegated token),
|
||
> **以便** 大檔不必經過 visionA-backend 中轉,下載快速且省流量。
|
||
|
||
**前置條件(阻塞)**:
|
||
- Member Center 已實作 `POST /file-access/download-tokens`(目前狀態:**未實作**)
|
||
|
||
**驗收標準(Phase 2)**:
|
||
- visionA-backend 呼叫 Member Center 的 `POST /file-access/download-tokens`(scope=`files:download.delegate`),傳入 `tenant_id`、`user_id`、`object_key`
|
||
- Member Center 回傳短效 opaque token(建議 `exp <= 5 分鐘`)
|
||
- visionA-backend 把 token 回給瀏覽器,瀏覽器直連 `GET https://<file-access-agent>/files/{object_key}?token=<delegated_token>`
|
||
- File Access Agent 呼叫 Member Center validation endpoint 線上驗 token,驗過才回檔案
|
||
- **此 User Story 不涉及 Converter API 的修改**,只是 VisionA ↔ Member Center ↔ File Access Agent 的串接
|
||
- 狀態:**未實作,Phase 2(等 Member Center 補完後啟動)**
|
||
|
||
**阻塞觸發條件**:
|
||
- Member Center owner 確認 `POST /file-access/download-tokens` 的實作時程,並提供測試環境
|
||
- 或者 VisionA 團隊決定自己暫時 proxy 下載(折衷方案,需另議)
|
||
|
||
---
|
||
|
||
## 5. 系統架構摘要(從程式碼確認)
|
||
|
||
### 5.1 服務元件
|
||
|
||
| 元件 | 技術 | 職責 |
|
||
|------|------|------|
|
||
| Web UI | Vue 3 + Vite + Element Plus | 使用者操作介面 |
|
||
| Nginx | Alpine | 反向代理、靜態檔案服務、SSE 轉發 |
|
||
| Task Scheduler | Node.js + Express | REST API、Job 狀態管理、Queue 派工、SSE 推送 |
|
||
| Redis | Redis 7 Alpine(不開 persistence) | Job 狀態儲存、任務佇列(Redis Stream) |
|
||
| ONNX Worker | Python | ONNX 優化 / TFLite 轉換 |
|
||
| BIE Worker | Python | 量化分析 |
|
||
| NEF Worker | Python | NEF 編譯 |
|
||
| Shared Volume | Docker named volume | Worker 間的檔案交換 |
|
||
|
||
### 5.2 API 端點(已實作)
|
||
|
||
| 方法 | 路徑 | 說明 |
|
||
|------|------|------|
|
||
| GET | /health | 健康檢查 |
|
||
| POST | /jobs | 建立新任務(上傳模型 + 參考圖片 + 參數) |
|
||
| GET | /jobs | 列出所有任務 |
|
||
| GET | /jobs/:jobId | 查詢單一任務狀態 |
|
||
| GET | /jobs/:jobId/events | SSE 事件串流 |
|
||
| GET | /jobs/:jobId/download/:filename | 下載結果檔案 |
|
||
|
||
### 5.3 任務參數
|
||
|
||
| 參數 | 必填 | 類型 | 說明 |
|
||
|------|------|------|------|
|
||
| model(檔案) | 是 | File | ONNX 或 TFLite 模型檔 |
|
||
| ref_images(檔案) | 否 | File[] | 量化用參考圖片(最多 100 張) |
|
||
| model_id | 是 | Integer | 模型 ID(1-65535) |
|
||
| version | 是 | String | 模型版本(如 "0001") |
|
||
| platform | 是 | String | 目標平台("520"/"720"/"530"/"630"/"730") |
|
||
| enable_evaluate | 否 | Boolean | 是否執行 IP 評估(預設 false) |
|
||
| enable_sim_fp | 否 | Boolean | 是否執行浮點 E2E 模擬(預設 false,未接線) |
|
||
| enable_sim_fixed | 否 | Boolean | 是否執行定點 E2E 模擬(預設 false,未接線) |
|
||
| enable_sim_hw | 否 | Boolean | 是否執行硬體 E2E 模擬(預設 false,未接線) |
|
||
|
||
### 5.4 任務狀態機
|
||
|
||
```
|
||
建立 → ONNX → BIE → NEF → COMPLETED
|
||
↓ ↓ ↓
|
||
FAILED FAILED FAILED
|
||
```
|
||
|
||
- 流程固定:ONNX → BIE → NEF,不支援跳過或只跑部分(後端限制)
|
||
- 任何階段失敗即整體 FAILED,不自動重試
|
||
|
||
### 5.5 對外 API 端點預告(新增,2026-04-25,待 Architect 產出詳細規格)
|
||
|
||
本節只列出 **PRD 層級** 的功能與驗收要點,詳細 API 規格(request / response schema、錯誤碼、範例)由 Architect Agent 在 `04-architecture/TDD.md` 或 `04-architecture/api/api-external.md` 中定義。
|
||
|
||
**Base Path**:`/api/v1`(與既有內部 API 區隔,讓 Web UI 繼續用舊的 `/jobs`,對外走新版)
|
||
|
||
**Auth**:所有端點都需要 `Authorization: Bearer <service_token>`,token 需滿足:
|
||
- 簽發者:Innovedus Member Center(以 JWKS 驗簽)
|
||
- `aud=kneron_converter_api`
|
||
- 對應 scope(下表列出)
|
||
|
||
| 方法 | 路徑 | Content-Type | 用途 | 必要 scope | 對應 US |
|
||
|------|------|-------------|------|-----------|---------|
|
||
| POST | `/api/v1/jobs` | `multipart/form-data` | 建立轉檔 job(直接上傳原始模型) | `converter:job.write` | US-08, US-11 |
|
||
| GET | `/api/v1/jobs/:id` | — | 查詢單一 job(polling) | `converter:job.read` | US-09 |
|
||
| GET | `/api/v1/jobs` | — | 查詢 job 列表(recovery) | `converter:job.read` | US-12 |
|
||
| POST | `/api/v1/jobs/:id/promote` | `application/json` | 搬檔到模型庫 | `converter:job.write` | US-10, US-13 |
|
||
|
||
> **註**:`POST /api/v1/jobs` 採 multipart/form-data 是刻意選擇,與既有 Web UI `POST /jobs` 一致,讓 visionA-backend 直接把原始模型推給 Converter。**不使用**「body 帶 object_key,Converter 再去 File Access Agent 拉檔」的設計(詳見 §4.4 US-08、§14.2)。
|
||
|
||
**Phase 1 明確不做的端點**:
|
||
- Webhook 回呼(不做,polling 已足夠)
|
||
- Cancel job(延後到未來,既有專案本來就沒有)
|
||
- Delegated download 相關(Phase 2)
|
||
|
||
**scope 命名**:上述命名為 PM 建議,Architect 需與 Member Center owner 對齊最終名稱。若 Member Center 已有命名慣例則採用其慣例。
|
||
|
||
### 5.6 Auth / 身分識別模型(新增,2026-04-25)
|
||
|
||
本節定義 Converter 在新 API 中的雙重身分與 user_id 傳遞策略。
|
||
|
||
**Converter 作為 OAuth2 Resource Server**:
|
||
- 驗證 visionA-backend(或其他未來消費者)送來的 service token
|
||
- 驗證項目:JWT 簽章(Member Center JWKS)、`iss`、`aud=kneron_converter_api`、`exp`、必要 `scope`
|
||
- **不驗證使用者身分**:token 是 service-to-service(`client_credentials`),claim 裡沒有 `user_id`
|
||
|
||
**Converter 作為 OAuth2 Client**:
|
||
- 使用自己的 `client_id=kneron_converter`(需在 Member Center 註冊)
|
||
- 以 `client_credentials` grant 取得 token
|
||
- 取得後用於:
|
||
- PUT 結果檔到 File Access Agent(scope=`files:upload.write`,promote 時使用,見 US-10 / US-13)
|
||
- **Phase 1 Converter 完全不從 File Access Agent「讀」任何東西**(原始模型改由 visionA-backend 直接 multipart 上傳,見 US-08)。因此 Phase 1 **不需要** `files:download.read` 或 `files:metadata.read` 等讀取類 scope。
|
||
|
||
**user_id 傳遞策略(方式 A:request payload)**:
|
||
- visionA-backend 在對外 API 中以 **request payload**(非 JWT claim,非 HTTP header)傳遞 `user_id`:
|
||
- `POST /api/v1/jobs`:`user_id` 作為 **multipart form field**
|
||
- `POST /api/v1/jobs/:id/promote`:`user_id` 作為 JSON body 欄位(若 promote API body 需要;若不需要,由 `:id` 反查即可)
|
||
- `GET /api/v1/jobs?user_id=...`(list)與 `GET /api/v1/jobs/:id`(single,Converter 會在內部比對 job 的 user_id):`user_id` 作為 **query string**
|
||
- Converter **信任** visionA-backend 送的 user_id,**不驗證**
|
||
- user_id 的用途:
|
||
- 業務邏輯:同使用者同時一個轉檔的限制(US-11)
|
||
- recovery 的 job 列表過濾(US-12)
|
||
- user_id **不是授權邊界**:Converter 不負責判斷「某個 user 能不能做某件事」,授權邊界由 visionA-backend 自己管
|
||
- 選擇方式 A 而非「把 user_id 放 token claim」的原因:visionA-backend 是 service-to-service token(非 user-bound),硬塞 user_id 進 claim 會破壞 OAuth2 semantics
|
||
- 選擇方式 A 而非「自訂 header(如 X-User-Id)」的原因:delegation model 跟 payload 一起走、API 審計可讀性較好,且 multipart 本來就要帶其他欄位,user_id 放在一起語意一致
|
||
|
||
**重要:不做的事**:
|
||
- Converter **不**呼叫 Member Center 驗證 user_id 是否存在(相信 visionA-backend)
|
||
- Converter **不**在 job 上做 user 層級的 ACL(例如「user A 不能看到 user B 的 job」),這由 visionA-backend 自己管,Converter 只是按 user_id 過濾查詢結果
|
||
|
||
---
|
||
|
||
## 6. 非功能需求
|
||
|
||
### 6.1 效能需求
|
||
|
||
| 項目 | 需求 | 現況 |
|
||
|------|------|------|
|
||
| 併發任務數 | 取決於 Worker 數量(每 Worker 一次處理一個任務) | 已實作(水平擴展) |
|
||
| 檔案上傳上限 | 500 MB | 已實作 |
|
||
| API Rate Limit | 每 15 分鐘 200 次請求 | 已實作 |
|
||
| SSE 心跳 | 每 15 秒 | 已實作 |
|
||
|
||
### 6.2 安全性需求
|
||
|
||
| 項目 | 需求 | 現況 |
|
||
|------|------|------|
|
||
| HTTP 安全標頭 | X-Frame-Options, X-Content-Type-Options, X-XSS-Protection | 已實作(Nginx + Helmet) |
|
||
| 容器安全 | 非 root 用戶運行 | Task Scheduler 已實作 |
|
||
| API Key 認證 | [推測] 應有 API Key 或其他認證機制 | 未實作(開發環境硬編碼) |
|
||
| Redis 認證 | Redis 應有密碼保護 | 未實作 |
|
||
| HTTPS | 生產環境需 TLS | 未實作 |
|
||
| 輸入驗證 | 檔案類型/大小驗證 | 部分實作(大小有限制,類型由前端限制) |
|
||
|
||
### 6.3 可用性需求
|
||
|
||
| 項目 | 需求 | 現況 |
|
||
|------|------|------|
|
||
| Crash Recovery | 服務重啟後自動恢復可用 | 已實作(Crash 即 Reset) |
|
||
| 容器自動重啟 | 服務異常時自動重啟 | 已實作(restart: unless-stopped) |
|
||
| 健康檢查 | Redis 連線狀態監控 | 已實作(GET /health) |
|
||
| [推測] 監控告警 | 系統指標監控與告警 | 未實作 |
|
||
| [推測] 日誌收集 | 集中式日誌管理 | 未實作(僅 console 輸出) |
|
||
|
||
### 6.4 可擴展性
|
||
|
||
| 項目 | 需求 | 現況 |
|
||
|------|------|------|
|
||
| Worker 水平擴展 | 動態增減 Worker 數量 | 已實作 |
|
||
| [推測] 跨主機部署 | 多台主機分散 Worker | 未實作(目前用 Shared Volume,未來規劃 MinIO) |
|
||
| [推測] Scheduler HA | 多個 Scheduler instance | 明確列為 Non-goal |
|
||
|
||
---
|
||
|
||
## 7. 系統限制與假設
|
||
|
||
### 7.1 設計決策(Non-goals,從設計文件確認)
|
||
|
||
以下為刻意的設計取捨,**不是缺陷**:
|
||
|
||
1. **不做任務持久化** — Redis 重啟即清空所有任務
|
||
2. **不做 Crash 後恢復** — 進行中的任務在 Crash 後消失
|
||
3. **不做 exactly-once / at-least-once 保證** — 任務可能因 Crash 而遺失
|
||
4. **不做 Scheduler HA** — 單一 Scheduler instance
|
||
5. **不做自動重試** — 失敗即 FAILED,由使用者手動重送
|
||
6. **轉換流程固定** — 必須走完 ONNX → BIE → NEF,不支援跳過
|
||
|
||
### 7.2 技術假設
|
||
|
||
1. 所有 Worker 需掛載相同的 Docker Volume 才能存取共享檔案
|
||
2. Worker 需要 Kneron Toolchain Python 環境(或使用 Stub 模式)
|
||
3. Redis 不開啟 persistence,符合「Crash 即 Reset」哲學
|
||
4. [推測] 目標部署環境為 Linux Docker 環境
|
||
|
||
### 7.3 已知限制
|
||
|
||
1. 前端 UI 的單階段 API 端點(`/api/onnx/upload`、`/api/bie/process` 等)在後端尚未實作,前後端 API 契約不一致
|
||
2. Simulator 功能(浮點/定點/硬體模擬)旗標已定義但邏輯未接線
|
||
3. 任務列表使用 `redis.keys('job:*')` 掃描,任務量大時效能可能有問題 [推測]
|
||
4. 檔案上傳使用 memory storage(`multer.memoryStorage()`),大檔案可能導致記憶體壓力
|
||
|
||
---
|
||
|
||
## 8. 功能優先排序(RICE)
|
||
|
||
> 以下 RICE 評分為從程式碼推斷的優先級建議,Reach 與 Confidence 為推測值,Effort 需 Architect 確認。
|
||
|
||
### 8.1 RICE 評分表(含 2026-04-25 新增項目)
|
||
|
||
| # | 功能 | Reach | Impact | Confidence | Effort (人週) | RICE 分數 | 階段 |
|
||
|---|------|-------|--------|------------|--------------|----------|------|
|
||
| **F-21~29** | **API 對外開放 Phase 1(OAuth2 + 對外 API + promote + recovery)** | **100%** | **3** | **70%** | **4** | **53** | **本次 Phase 1** |
|
||
| F-30 | Phase 2 使用者下載(delegated token) | 100% | 2 | 40% | 1 | 80 | Phase 2(阻塞中)|
|
||
| F-14~16 | E2E 模擬(浮點/定點/硬體) | 80% | 2 | 60% | 3 | 32 | Phase 2 |
|
||
| F-04~06 | 單階段轉換 API(後端) | 70% | 2 | 80% | 1.5 | 75 | Phase 2 |
|
||
| - | 前後端 API 契約對齊 | 100% | 3 | 90% | 1 | 270 | 急迫 |
|
||
| - | Redis 認證 + HTTPS | 100% | 2 | 90% | 1 | 180 | Phase 1 |
|
||
| F-18 | 任務取消 [推測] | 50% | 1 | 50% | 2 | 13 | Phase 3 |
|
||
| F-20 | 歷史任務持久化 [推測] | 60% | 1.5 | 40% | 3 | 12 | Phase 3 |
|
||
| - | 跨主機部署(MinIO) | 30% | 2 | 70% | 4 | 11 | Later |
|
||
| - | 監控與告警 | 80% | 1.5 | 70% | 2 | 42 | Phase 2 |
|
||
| - | 錯誤訊息改善 [推測] | 80% | 1 | 60% | 0.5 | 96 | Phase 1 |
|
||
| - | 轉換時間預估 [推測] | 70% | 0.5 | 40% | 1 | 14 | Phase 3 |
|
||
|
||
### 8.2 API 對外開放(Phase 1)RICE 推論說明
|
||
|
||
- **Reach = 100%**:100% 指「所有未來要整合 Converter 的下游服務」都需要此能力,不是終端使用者數。Phase 1 首個消費者是 visionA-backend,但架構設計為可擴展(未來 Innovedus 其他 vertical)。
|
||
- **Impact = 3(最高)**:沒有 API,VisionA 就無法整合,整個合作關係無法成立。屬於「關鍵路徑」。
|
||
- **Confidence = 70%**:OAuth2 / File Access Agent(僅 upload 方向)/ Member Center 三邊整合有不確定性(特別是 scope 命名、client 註冊流程、tenant_id 策略),實作細節待與兩個服務 owner 對齊。
|
||
- **Effort = 4 人週**:涵蓋 OAuth middleware、client 實作、multipart 上傳整合對外 API、promote API、user_id 相關業務邏輯、recovery API、OpenAPI 規格產出、整合測試。待 Architect Agent 在 TDD 中精確估算(**2026-04-25 變更後,Phase 1 不含「從 File Access Agent 取原始模型」的整合工作,Architect 可視情況調低 Effort**)。
|
||
- **RICE = 53**:分數看起來不高是因為 Effort 較大,但此功能屬於「解鎖型」——不做就無法開始整個商業合作,性質上是 P0,RICE 分數在此僅作排序參考,不應作為 go/no-go 的唯一依據。
|
||
|
||
### 8.3 商業效益(預期)
|
||
|
||
| 指標 | Phase 1 上線前 | Phase 1 上線後(預期) | 備註 |
|
||
|------|---------------|---------------------|------|
|
||
| 下游服務整合可能性 | 0(無 API)| 1+(VisionA)| 未來可擴展 |
|
||
| VisionA 使用者轉檔路徑 | N/A(無法使用 Converter)| 平台內一站完成 | 降低切換成本 |
|
||
| 手動操作步驟(從模型到 NAS)| 5+ 步(上傳 Web UI → 轉檔 → 下載 → 上傳到 VisionA → 搬到 NAS)| 2 步(在 VisionA 選模型 → 按轉檔)| 使用者體驗大幅改善 |
|
||
| 服務耦合度 | 緊耦合(各服務自己做)| 鬆耦合(經 OAuth2 契約)| 可維護性 |
|
||
|
||
**注意**:上述「預期」為 PM 推論,實際採用率與整合價值需 Phase 1 上線後用 §9 的成功指標追蹤。
|
||
|
||
### RICE 公式
|
||
RICE = (Reach x Impact x Confidence) / Effort
|
||
|
||
---
|
||
|
||
## 9. 成功指標(KPI)
|
||
|
||
> 9.1 既有指標 [推測] 為建議性質,需與產品負責人確認是否適用。
|
||
> 9.2 新增指標(2026-04-25)專門針對 API 對外開放功能。
|
||
|
||
### 9.1 既有成功指標 [推測]
|
||
|
||
| 類別 | 指標 | 建議目標值 | 追蹤方式 |
|
||
|------|------|-----------|---------|
|
||
| 穩定性 | 系統 uptime | > 99%(工作時段) | 健康檢查 API 監控 |
|
||
| 效率 | 轉換成功率 | > 95% | Job COMPLETED / 總 Job |
|
||
| 效率 | 平均轉換時間 | 視模型大小而定 | Job created_at → completed_at |
|
||
| 容量 | 每日處理任務數 | 視團隊規模而定 | Job 計數 |
|
||
| 體驗 | 任務佇列等待時間 | < 5 分鐘 | 入 Queue 到 Worker 開始處理 |
|
||
| 可用性 | Crash 後恢復時間 | < 30 秒 | Docker restart 時間 |
|
||
|
||
### 9.2 API 對外開放 成功指標(新增,2026-04-25)
|
||
|
||
#### 9.2.1 API SLA(品質指標)
|
||
|
||
| 指標 | 目標值 | 護欄(不能低於) | 追蹤方式 |
|
||
|------|--------|---------------|---------|
|
||
| API 可用率(`/api/v1/*` 非 5xx 的比率) | > 99.5%(工作時段) | 99% | Nginx access log + 監控 |
|
||
| API p95 回應時間(GET /jobs/:id) | < 200ms | 500ms | APM / 自建時間戳 |
|
||
| API p95 server-side 處理時間(POST /jobs)| < 500ms(**不含 multipart 上傳時間**,計算從 Converter 收到整份 body 後的處理時間) | 2s | APM(server-side 埋點,從 body 完整接收到回 201 的時間)|
|
||
| 端到端回應時間(POST /jobs,含上傳)| 取決於檔案大小與網路;**大檔上傳時間不計入 API p95 SLA** | — | 由 visionA-backend 側觀測,作為 UX 指標而非服務 SLA |
|
||
| API p95 回應時間(POST /jobs/:id/promote) | < 3s(含 PUT 到 File Access Agent) | 10s | APM |
|
||
| OAuth token 驗證失敗率(401 / 403) | < 1%(排除 token 過期正常情況) | 5% | Nginx log 分類統計 |
|
||
|
||
> **註(2026-04-25 變更)**:原 `POST /jobs` p95 目標「< 2s(含從 File Access Agent 下載原始模型)」已調整。現行設計為 visionA-backend 直接 multipart 上傳原始模型,因此 API SLA 分兩層:
|
||
> - **server-side 處理時間**:Converter 收完 multipart body 後的處理邏輯(驗 token、存檔到 Bucket、建 job record、派工到 Queue)— 這是 Converter 可控的 SLA。
|
||
> - **端到端上傳時間**:包含大檔上傳網路傳輸時間(可能數百 MB),受限於 visionA-backend ↔ Converter 網路頻寬與檔案大小,不納入 API p95 SLA,改由 visionA-backend 側追蹤作為使用者體驗指標。
|
||
|
||
#### 9.2.2 API 採用度指標(成長指標)
|
||
|
||
| 指標 | 目標(Phase 1 上線後 3 個月)| 追蹤方式 |
|
||
|------|----------------------------|---------|
|
||
| 每月透過 API 建立的 job 數 | 由 visionA 的使用量決定,設 baseline | job 來源標記(API vs Web UI)|
|
||
| API job 占總 job 的比例 | > 30%(Phase 1)→ > 60%(6 個月)| 同上 |
|
||
| promote 成功率(搬進模型庫)| > 90% | `promote` API 成功/總呼叫 |
|
||
| 離開頁面 recovery 使用率(有 in-progress 時回來查看)| 不設硬目標,但要能觀測 | `GET /api/v1/jobs?status=in_progress` 呼叫次數 |
|
||
| 同使用者 409 Conflict 比率(US-11 觸發)| < 5%(表示大多數使用者理解限制)| Conflict 回應計數 / 總 POST /jobs |
|
||
|
||
#### 9.2.3 錯誤率護欄
|
||
|
||
| 指標 | 護欄(不能超過) | 觸發動作 |
|
||
|------|----------------|---------|
|
||
| Auth failure rate | 5% | 檢查 Member Center JWKS 是否可達、scope 設定 |
|
||
| Promote 失敗率(5xx 類)| 5% | 檢查 File Access Agent 連線、Converter service token 有效性 |
|
||
| File Access Agent 連線失敗率 | 2% | 跨服務網路問題警報 |
|
||
| Converter 自己的 service token 取用失敗率 | 1% | Member Center 連線問題 |
|
||
|
||
#### 9.2.4 使用者體驗指標(透過 visionA 間接觀察)
|
||
|
||
| 指標 | 目標 | 追蹤方式 |
|
||
|------|------|---------|
|
||
| 同使用者同時一個轉檔的限制被使用者理解率(不會重複嘗試)| 高 | 連續同 user_id 在短時間內的 409 次數 |
|
||
| recovery 成功率(使用者離開頁面回來能看到 job)| > 95%(Converter 正常運行期間)| visionA 側埋點 |
|
||
|
||
**追蹤工具建議(待 Architect 決定)**:
|
||
- API layer 埋點:Nginx access log + 自訂結構化 log
|
||
- 指標聚合:Prometheus + Grafana(與既有監控對齊,如有)
|
||
- 失敗類別拆分:在 Scheduler 層記錄 error code(auth_failed / promote_failed / input_fetch_failed 等)
|
||
|
||
**注意**:上述目標值為 PM 提案,具體數字需 Phase 1 上線前與 SRE / 監控負責人對齊。沒有歷史資料的指標(例如 API p95)需在 Phase 1 beta 期間收集 baseline 後再訂正式 SLA。
|
||
|
||
---
|
||
|
||
## 10. 策略性路線圖
|
||
|
||
### Now(當前 — 已實作 / 急需修復)
|
||
|
||
- [x] 完整轉換流程(ONNX → BIE → NEF)
|
||
- [x] Web UI 基本功能
|
||
- [x] SSE 即時狀態推送
|
||
- [x] Worker 水平擴展
|
||
- [x] Stub Worker 開發模式
|
||
- [x] Docker Compose 一鍵啟動
|
||
- [ ] **前後端 API 契約對齊**(Web UI 的單階段端點在後端未實作)
|
||
|
||
### Next(Phase 1 — 對外 API + 穩定化與安全性)
|
||
|
||
本次 L 級新功能主要工作:
|
||
|
||
- [ ] **API 對外開放 Phase 1(本次重點)**
|
||
- [ ] OAuth2 Resource Server(以 Member Center JWKS 驗 service token)
|
||
- [ ] OAuth2 Client(Converter 自己取 service token,promote 時 PUT 到 File Access Agent)
|
||
- [ ] 對外 API 路徑:`POST /api/v1/jobs`(multipart)、`GET /api/v1/jobs/:id`、`GET /api/v1/jobs`、`POST /api/v1/jobs/:id/promote`
|
||
- [ ] user_id 業務邏輯(同使用者同時一個轉檔、recovery)
|
||
- [ ] multipart 上傳流程(visionA-backend → Converter,與現有 Web UI 路徑重用儲存邏輯)
|
||
- [ ] 搬結果檔到 File Access Agent(promote)
|
||
- [ ] OpenAPI 3.0 規格產出與測試
|
||
- [ ] 安全性強化:Redis 認證、HTTPS(原 API Key 由 OAuth2 取代)
|
||
- [ ] 錯誤訊息改善(更友善的錯誤描述)
|
||
- [ ] 單階段轉換 API(後端實作 /api/onnx/process、/api/bie/process、/api/nef/process)— 延後至下一波
|
||
- [ ] 輸入驗證強化(後端檔案類型驗證)
|
||
|
||
### Later(Phase 2 — 功能擴展)
|
||
|
||
- [ ] **使用者下載模型走 delegated token**(本次 Phase 2,阻塞於 Member Center)
|
||
- [ ] E2E 模擬功能接線(浮點/定點/硬體)
|
||
- [ ] 監控與告警(系統指標、Worker 狀態、API SLA)
|
||
- [ ] 日誌收集與集中管理
|
||
- [ ] [推測] 批次轉換(多個模型一次提交)
|
||
- [ ] Web UI 是否也改走新 OAuth 流程(待決)
|
||
|
||
### Future(Phase 3 — 進階功能)
|
||
|
||
- [ ] [推測] 任務取消功能
|
||
- [ ] [推測] 歷史任務持久化(可選開啟)
|
||
- [ ] 跨主機部署(MinIO 替換 Shared Volume)
|
||
- [ ] [推測] 轉換時間預估
|
||
- [ ] [推測] 使用者認證與權限管理
|
||
|
||
---
|
||
|
||
## 11. 支援平台清單(從程式碼確認)
|
||
|
||
| 平台代號 | 平台名稱 | 備註 |
|
||
|---------|---------|------|
|
||
| 520 | KDP520 | - |
|
||
| 720 | KDP720 | - |
|
||
| 530 | KDP530 | - |
|
||
| 630 | KDP630 | - |
|
||
| 730 | KDP730 | - |
|
||
|
||
---
|
||
|
||
## 12. 風險與緩解
|
||
|
||
### 12.1 既有風險(延續)
|
||
|
||
| 風險 | 可能性 | 影響 | 緩解措施 |
|
||
|------|--------|------|----------|
|
||
| Redis Crash 導致所有任務遺失 | 中 | 中 | 符合設計哲學,使用者重送即可;未來可考慮 optional persistence |
|
||
| 大檔案上傳耗盡 Node.js 記憶體 | 中 | 高 | 改用 disk storage(multer.diskStorage)替代 memory storage |
|
||
| Worker 處理時間過長佔用資源 | 中 | 中 | [推測] 加入 timeout 機制 |
|
||
| 前後端 API 不一致造成功能無法使用 | 高 | 高 | 優先對齊前後端 API 契約 |
|
||
| 無認證機制導致未授權存取 | 中 | 高 | Phase 1 以 OAuth2 取代硬編碼 |
|
||
| Redis keys 掃描在大量任務時效能劣化 | 低 | 中 | [推測] 改用 Redis Sorted Set 管理任務索引 |
|
||
|
||
### 12.2 本次 L 級新功能風險(新增,2026-04-25)
|
||
|
||
| 風險 | 可能性 | 影響 | 緩解措施 |
|
||
|------|--------|------|----------|
|
||
| Member Center `POST /file-access/download-tokens` 長期不實作,Phase 2 無法啟動 | 中 | 中 | Phase 1 可獨立上線(不依賴此 endpoint);定期與 Member Center owner 同步;必要時 VisionA 做 proxy 下載作為 fallback |
|
||
| File Access Agent 部署位置 / tenant_id 未定,promote 整合測試被阻塞 | 中 | 中 | 盡早與 File Access Agent owner 對齊部署計畫;若必要 Converter 開發環境先接 Stub 做 promote 契約驗證(讀檔已不再依賴 File Access Agent)|
|
||
| Member Center OAuth client / audience 註冊延遲 | 中 | 高 | 盡早申請;開發初期可用 local Member Center 測試 |
|
||
| scope 命名與 Member Center 既有命名慣例衝突 | 低 | 中 | Architect 在 TDD 提案後,走跨團隊 review |
|
||
| visionA-backend 傳來的 user_id 被偽造(VisionA 被入侵或誤用)| 低 | 高 | 接受此風險:Converter 不做 user 層 ACL,責任邊界在 visionA-backend。可加日誌記錄 user_id 變更頻率作為監測 |
|
||
| 大檔 promote 時 File Access Agent 不可用 | 中 | 中 | Converter Bucket 7 天 lifecycle 保留,使用者可重試 promote;API 回清楚的 502 |
|
||
| **大檔 multipart 上傳失敗或 timeout**(visionA-backend ↔ Converter 之間) | 中 | 中 | 沿用既有 Web UI 的 500MB 上限;若未來需更大檔,與 Architect 討論改用 disk storage 或 chunked upload;API 回清楚的 `413 Payload Too Large` / `408 Request Timeout`;由 visionA-backend 做重試邏輯(Converter 無 resume upload 能力)|
|
||
| **multipart 上傳占用記憶體**(既有 `multer.memoryStorage()` 問題)| 中 | 高 | 此為既有既有風險(見 §12.1),L 級新功能後因 API 消費者數量增加可能加劇。建議 Architect 評估是否 Phase 1 同步改 `multer.diskStorage()`;若不改,需明確在 Capacity Planning 中計算記憶體上限 |
|
||
| Converter 的 service token 過期未正確刷新 | 低 | 中 | 實作 token cache + 主動 refresh(`exp-60s`)|
|
||
| 同使用者同時一個轉檔對「急用者」造成不便 | 中 | 低 | 以 409 + 現有 job_id 回應,讓 VisionA 引導使用者「繼續追蹤」而非重送 |
|
||
| 對外 API 穩定性承諾(OpenAPI)修改困難 | 低 | 中 | Phase 1 採保守設計,預留未來擴充欄位;API 走 `/api/v1` 版本化 |
|
||
| OAuth middleware 阻塞既有 Web UI 走的 `/jobs` 路徑 | 低 | 高 | API 分兩套:Web UI 維持原路徑無 OAuth,對外 API 走 `/api/v1/*` 新路徑 |
|
||
|
||
---
|
||
|
||
## 14. 相依服務(新增,2026-04-25)
|
||
|
||
本次 L 級新功能使 Kneron Model Converter 從「獨立工具」變為「依賴兩個外部服務 + 被一個外部服務呼叫」的生態成員。本章節說明三個相依關係。
|
||
|
||
### 14.1 Member Center(身分與權限中心)
|
||
|
||
- **專案位置**:`/tmp/member_center/`(Innovedus 旗下,C# .NET + OpenIddict + PostgreSQL)
|
||
- **負責範圍**:OAuth2 / OIDC authorization server、JWKS 發布、token 簽發、delegated token 簽發與驗證
|
||
- **Converter 對它的依賴**:
|
||
- **驗 token(作為 Resource Server)**:從 `GET /.well-known/openid-configuration` 與 JWKS 端點拉取公鑰,驗證 visionA-backend 送來的 service token
|
||
- **取 token(作為 Client)**:以 `client_credentials` 向 `POST /oauth/token` 取得 Converter 自己的 service token
|
||
- **目前狀態**:
|
||
- 核心 OAuth2 / OIDC 已完成(見 `/tmp/member_center/docs/DESIGN.md §7.1`)
|
||
- `POST /file-access/download-tokens`(Phase 2 需要)**尚未實作**
|
||
- **本次 Converter 需要 Member Center 做的事**(需跨團隊協調):
|
||
- 註冊一個 resource audience:`kneron_converter_api`(暫定名)
|
||
- 註冊一個 OAuth client:`kneron_converter`(暫定名,Converter 自己使用)
|
||
- 在 visionA-backend 的 OAuth client 設定中加入 `kneron_converter_api` 的 scope 授權(例如 `converter:job.write`, `converter:job.read`)
|
||
- 在 Converter 的 client 設定中加入 `file_access_api` 相關 scope 授權:**Phase 1 僅需 `files:upload.write`**(promote 時 PUT 檔案用);**不需要 `files:download.read` 或 `files:metadata.read`**(2026-04-25 變更後,Phase 1 Converter 完全不從 File Access Agent 讀取任何東西)
|
||
- **風險**:任何註冊、scope 命名、client_secret 發放都需要 Member Center owner 配合
|
||
|
||
### 14.2 File Access Agent(檔案閘道)
|
||
|
||
- **專案位置**:`/tmp/file_access_agent/`(Innovedus 旗下,C# / ASP.NET Core)
|
||
- **負責範圍**:
|
||
- 代表「tenant 邊界內的所有檔案」的統一存取閘道
|
||
- 所有檔案進出都 proxy 經過 File Access Agent(**無 presigned URL 模式**)
|
||
- 單一 tenant per instance(啟動時設定 `INSTANCE_TENANT_ID`)
|
||
- 驗 upload 的 JWT(向 Member Center JWKS)
|
||
- 驗 download 的 delegated token(向 Member Center 線上 validation endpoint)
|
||
- **Converter 對它的依賴(Phase 1 簡化版,2026-04-25 變更)**:
|
||
- **僅 PUT 結果到模型庫**:promote 時 Converter PUT 結果檔到 File Access Agent(帶 service token,scope=`files:upload.write`)
|
||
- **Phase 1 Converter 完全不從 File Access Agent「讀」任何東西**(原始模型改由 visionA-backend 直接 multipart 上傳到 Converter)
|
||
- Phase 1 **不需要** GET / HEAD / metadata 類的呼叫
|
||
- **目前狀態**:
|
||
- 核心功能完成(見 `/tmp/file_access_agent/docs/API.md`):upload (PUT)、download (GET with delegated token)、metadata、delete
|
||
- MinioFileStorage、MemberCenterDelegatedDownloadTokenValidator 已實作(約 1865 行 C#)
|
||
- **本次 Converter 需要 File Access Agent 做的事(Phase 1)**:
|
||
- 確認 deployment:哪個 instance 服務哪個 tenant、Converter 要連哪個 URL
|
||
- 約定 objectKey 命名(建議:`kneron-converter/{user_id}/{model_id}/v{version}/{filename}` 或類似結構,需與 VisionA 對齊)
|
||
- 只使用 PUT 端點(upload 類),不使用 GET / HEAD / metadata
|
||
- **設計選擇(已確認)**:沒有 presigned URL 模式 — 所有 **promote 流量** 都經過 File Access Agent,Converter 接受此設計,不爭取改變
|
||
- **Phase 2 可能新增的依賴**:無(Phase 2 的 delegated download 不經過 Converter,見 US-14)
|
||
|
||
### 14.3 visionA-backend(服務消費者)
|
||
|
||
- **專案位置**:`~/visionA/visionA-backend/`(Innovedus 旗下,Go + Gin)
|
||
- **負責範圍**:
|
||
- VisionA 平台的後端,管理其使用者、模型庫、應用設定
|
||
- Phase 0 雛形階段,近期進 Phase 1 導入 OAuth2/OIDC 與 JWT 認證
|
||
- **Converter 對它的關係**:
|
||
- 是 Converter 的 **第一個 API 消費者(Persona C 實例)**
|
||
- visionA-backend 會以 `client_credentials` 向 Member Center 取 service token(`aud=kneron_converter_api`),然後呼叫 Converter API
|
||
- **職責邊界(明確區分)**:
|
||
- **visionA-backend 的責任**:使用者認證、使用者 ACL(哪個使用者能看哪些模型)、模型庫 UX、將終端使用者的操作轉換為對 Converter API 的呼叫、處理 polling 與 UI 進度顯示、決定 promote 的目標 objectKey
|
||
- **Converter 的責任**:Kneron Toolchain 轉檔執行、job 狀態管理、以自己的 service token 讀寫 File Access Agent、同使用者同時一個轉檔的限制、job 查詢過濾
|
||
- **不能混淆的邊界**:Converter **不**驗 user_id 真偽、**不**做使用者層級 ACL、**不**管 VisionA 的模型庫命名規則
|
||
- **目前狀態**:Phase 0 雛形(static auth,無 DB,LocalFS)。Phase 1 將導入 JWT/OIDC 與真實使用者系統
|
||
- **協作時間表假設**:VisionA 進 Phase 1(OAuth2 完成)的時間需與 Converter Phase 1 的整合測試時程對齊
|
||
|
||
### 14.4 相依關係圖(PRD 層級,2026-04-25 更新)
|
||
|
||
```
|
||
[VisionA 終端使用者]
|
||
│
|
||
│ (web UI 操作)
|
||
▼
|
||
┌──────────────────┐
|
||
│ visionA-backend │ ← Persona C(Converter API 消費者)
|
||
└───┬──────┬───┬───┘
|
||
│ │ │
|
||
service token │ │ │ ① multipart 上傳原始模型
|
||
(client_cred.) │ │ │ (POST /api/v1/jobs, Phase 1)
|
||
│ │ │
|
||
▼ │ │ delegated token(Phase 2)
|
||
┌────────────────┐ │
|
||
│ Member Center │ │
|
||
│ (OAuth2, JWKS, │ │
|
||
│ delegated tok.)│ │
|
||
└────┬──────┬────┘ │
|
||
│ │ │
|
||
驗 token │ │ 驗 │
|
||
取 token │ │ │
|
||
▼ ▼ ▼
|
||
┌────────────────────────┐
|
||
│ Converter (本專案) │
|
||
│ - 收 multipart 上傳 │
|
||
│ - 驗 OAuth token │
|
||
│ - Worker 轉檔流程 │
|
||
│ - Bucket 暫存 (7天) │
|
||
└──────────────┬─────────┘
|
||
│
|
||
│ ② promote 時 PUT 結果檔
|
||
│ (Phase 1, scope=files:upload.write)
|
||
▼
|
||
┌──────────────────┐
|
||
│ File Access Agent │ ← Phase 1 只收寫入
|
||
│ (檔案閘道) │ (不處理 Converter 的讀檔)
|
||
│ 無 presigned URL │
|
||
└─────────┬────────┘
|
||
│
|
||
│ NAS(長期儲存)
|
||
▼
|
||
[模型庫]
|
||
```
|
||
|
||
**Phase 1 檔案流(已確認)**:
|
||
1. 原始模型:`visionA-backend ──multipart──> Converter`(不經 File Access Agent)
|
||
2. 轉檔結果(promote 時):`Converter ──PUT──> File Access Agent ──> NAS`
|
||
3. 使用者下載結果(Phase 1 UX 由 visionA-backend 決定,可選方案:VisionA proxy、VisionA 存自己的 copy、或等 Phase 2)
|
||
|
||
**Phase 2 新增的檔案流(阻塞於 Member Center)**:
|
||
4. 使用者下載:`瀏覽器 ──GET (delegated token)──> File Access Agent`(Converter 不參與)
|
||
|
||
---
|
||
|
||
## 15. Phase 1 / Phase 2 Scope 切分(新增,2026-04-25)
|
||
|
||
本章節明確界定本次 L 級功能的交付範圍,避免在實作時範圍蔓延或誤砍。
|
||
|
||
### 15.1 Phase 1(本次必做)
|
||
|
||
**目標**:讓 visionA-backend 能完成「上傳 → 轉檔 → 搬進模型庫」閉環,不需要使用者直接下載能力。
|
||
|
||
**必須交付**:
|
||
|
||
| 項目 | 說明 | 對應 US / F |
|
||
|------|------|------------|
|
||
| OAuth2 Resource Server | 驗 visionA-backend 的 service token(JWKS 驗簽、aud、scope) | F-21, US-08 |
|
||
| OAuth2 Client | Converter 自己取 service token(僅用於 promote 時呼叫 File Access Agent 的 PUT) | F-22, US-13 |
|
||
| `POST /api/v1/jobs`(multipart) | 建 job,multipart files:`model` + `ref_images[]`;multipart fields:`user_id` + `model_id` + `version` + `platform` + 旗標 | F-23, US-08 |
|
||
| `GET /api/v1/jobs/:id` | Polling 進度 | F-24, US-09 |
|
||
| `GET /api/v1/jobs?user_id=...&status=...` | Recovery 的 job 列表查詢 | F-25, US-12 |
|
||
| `POST /api/v1/jobs/:id/promote` | 搬結果到 File Access Agent(Converter 自己推) | F-26, US-10, US-13 |
|
||
| 同使用者同時一個轉檔限制 | 建 job 時檢查 user_id 有無 in-progress job | F-27, US-11 |
|
||
| OpenAPI 3.0 規格 | 對外 API 契約,visionA-backend 整合用 | F-29 |
|
||
|
||
> **註(2026-04-25 變更)**:原 Phase 1 Scope 中的「從 File Access Agent 取原始模型(F-28)」已移除。Phase 1 原始模型來源改為「visionA-backend 直接 multipart 上傳到 Converter」(見 F-23 / US-08)。
|
||
|
||
**明確不做**(Phase 1 不在範圍):
|
||
|
||
- ❌ 使用者下載模型的 delegated token 流程(移至 Phase 2)
|
||
- ❌ Web UI 改走新 OAuth 流程(維持既有 multipart 路徑,另外評估)
|
||
- ❌ Webhook / SSE 對外推送(polling 已足夠)
|
||
- ❌ Job 取消功能(既有專案本來就沒有,不在本次新增)
|
||
- ❌ Job 持久化 / Crash 恢復(維持「Crash 即 Reset」哲學)
|
||
- ❌ 單階段轉換 API(F-04~06)— 這是既有 backlog 項目,和本次 L 級功能獨立
|
||
|
||
**Phase 1 上線完成的判定標準**:
|
||
|
||
1. visionA-backend 能成功以 service token 呼叫所有四個對外 API
|
||
2. 一個完整 E2E 流程跑通:VisionA 使用者上傳模型 → File Access Agent → 觸發轉檔 → polling 進度 → 完成後 promote 到模型庫
|
||
3. 同使用者同時轉檔限制生效(回 409)
|
||
4. Recovery 能查到 in-progress job
|
||
5. OpenAPI 規格通過 visionA-backend 整合測試
|
||
6. API SLA 基本指標可觀測(可用率、p95 回應時間)
|
||
|
||
### 15.2 Phase 2(延後做)
|
||
|
||
**目標**:讓 VisionA 終端使用者能直接從瀏覽器下載 NAS 裡的模型檔,不經 visionA-backend 中轉。
|
||
|
||
**必須交付**:
|
||
|
||
| 項目 | 說明 | 對應 US / F |
|
||
|------|------|------------|
|
||
| visionA-backend 呼叫 Member Center 取 delegated token | scope=`files:download.delegate`,帶 tenant_id + user_id + object_key | F-30, US-14 |
|
||
| 瀏覽器直連 File Access Agent 下載 | `GET /files/{object_key}?token=<delegated>` | US-14 |
|
||
| Converter 無變更 | Phase 2 對 Converter 本身無直接改動 | — |
|
||
|
||
**阻塞條件(必須先解除才能啟動 Phase 2)**:
|
||
|
||
1. Member Center 的 `POST /file-access/download-tokens` 已實作並部署(目前:**未實作**)
|
||
2. Member Center owner 提供測試環境與 scope 授權
|
||
3. File Access Agent 的 `MemberCenterDelegatedDownloadTokenValidator` 已通過整合測試(目前:程式碼已有,待驗證)
|
||
|
||
**觸發 Phase 2 的條件**:
|
||
|
||
- Member Center owner 確認時程,或
|
||
- VisionA 業務需求強烈要求,此時可考慮折衷方案(VisionA 自己做 proxy 下載),但這是另一個討論
|
||
|
||
**Phase 2 的 US-14 風險**:
|
||
- 若 Member Center 長期不實作,VisionA 的終端使用者要下載自己的模型就只能「從 VisionA 下載介面(經 visionA-backend proxy)」或「連 Kneron Converter 舊的 Web UI(此時兩邊資料不同步,會混亂)」。需提前與 VisionA 產品團隊溝通 UX 取捨。
|
||
|
||
### 15.3 Phase 1 / Phase 2 決策原則
|
||
|
||
- **Phase 1 必須能獨立上線**:不能因為 Phase 2 阻塞就拖累 Phase 1。
|
||
- **Phase 1 / Phase 2 之間不會互相破壞**:Phase 2 只新增功能,不修改 Phase 1 的 API 契約。
|
||
- **阻塞透明化**:Phase 2 的阻塞原因(Member Center endpoint 未實作)必須明確記錄在 PRD,讓使用者知道是上游依賴不是本專案問題。
|
||
|
||
---
|
||
|
||
## 16. 附錄
|
||
|
||
> 註:本章原為 §13,因新增 §14(相依服務)與 §15(Phase 切分)而重編號為 §16。章節內容不變。
|
||
|
||
### 16.1 技術堆疊完整列表
|
||
|
||
| 層級 | 技術 | 版本 |
|
||
|------|------|------|
|
||
| 前端框架 | Vue 3 + Vite | Vue 3.3.4, Vite 4.4.5 |
|
||
| UI 元件庫 | Element Plus | - |
|
||
| 狀態管理 | Pinia | - |
|
||
| 後端(調度) | Node.js + Express | Node 18 |
|
||
| Worker 框架 | Python(同步) | Python 3.9 |
|
||
| 佇列 / 狀態 | Redis Stream | Redis 7 Alpine |
|
||
| 模型處理 | ONNX 1.14.1, TensorFlow 2.16.2 | - |
|
||
| 容器化 | Docker + docker-compose | - |
|
||
| 反向代理 | Nginx | Alpine |
|
||
| 測試框架 | pytest + pytest-asyncio | - |
|
||
|
||
### 16.2 後端介面層設計
|
||
|
||
程式碼採用 **Protocol + Factory 模式**,將 Kneron Toolchain 的呼叫封裝為可替換的後端介面:
|
||
|
||
- `QuantizationBackend`(`services/backends/quantization.py`)— 量化分析
|
||
- `CompilerBackend`(`services/backends/compiler.py`)— NEF 編譯
|
||
- `EvaluatorBackend`(`services/backends/evaluator.py`)— IP 評估
|
||
- `SimulatorBackend`(`services/backends/simulator.py`)— E2E 模擬(未完成)
|
||
|
||
此設計使得未來可以替換為不同版本的 Toolchain 後端,或在測試時注入 Mock。
|
||
|
||
### 16.3 程式碼品質觀察
|
||
|
||
- 模組化設計良好,Worker / Consumer / Backend 職責清晰
|
||
- 測試覆蓋:6 個測試檔涵蓋 ONNX/BIE/NEF 核心與 E2E 流程
|
||
- 使用 Helmet、Rate Limiting、Compression 等 Express 最佳實踐
|
||
- Graceful shutdown 處理(SIGTERM / SIGINT)
|
||
|
||
---
|
||
|
||
## 附錄 A:本次更新的 PM 疑問清單(2026-04-25)
|
||
|
||
撰寫本次 PRD 更新時遇到以下疑問,列出給 Orchestrator / 使用者裁決。**這些問題不阻塞三方交叉審閱,但需在使用者最終審核 PRD 前釐清**。
|
||
|
||
### A.1 需使用者決定的產品問題
|
||
|
||
1. **Phase 1 的 Web UI 要不要也改走 OAuth 流程?**
|
||
- 傾向不改(維持既有 multipart 行為),未來評估
|
||
- 若決定改,則 Phase 1 範圍會擴大(升級為 L+ 或拆兩個 L)
|
||
2. **同使用者同時一個轉檔**限制範圍確認
|
||
- 是否真的是「整個 Converter 服務」共用的 user_id 空間?還是不同 `client_id`(例如未來有 visionA-backend 以外的消費者)各自獨立?
|
||
- 目前 PRD 以「整個服務內 user_id 唯一」設計(預期未來不會出現跨 client 的 user_id 衝突)
|
||
3. **tenant_id 策略**
|
||
- Member Center 與 File Access Agent 都是多租戶設計,但 PRD 目前未處理「Converter 內部怎麼標記 tenant」
|
||
- 待 Architect Agent 評估:Converter 是否要在 job record 上記錄 tenant_id?還是只信任 File Access Agent 的 single-tenant-per-instance 保證?
|
||
4. **Phase 2 的 fallback 策略**
|
||
- 若 Member Center 長期不實作 delegated token,VisionA 要不要做 proxy 下載作為折衷?
|
||
- 還是完全等 Member Center?
|
||
5. **API 採用度的 baseline 如何取得?**
|
||
- §9.2.2 列的目標值(例如「每月 X 個 job」)目前沒有歷史資料
|
||
- 建議:Phase 1 上線後跑 1 個月 beta 再訂正式目標
|
||
6. **既有 PRD 中的 `[推測]` 標記要不要在此次順便確認?**
|
||
- 本次 PM 暫不動既有 `[推測]`,保留給使用者決定
|
||
- 建議在使用者最終審核本版 PRD 時一併確認
|
||
|
||
### A.2 需跨團隊協調的問題(給 Orchestrator 記到 progress.md 未解決問題)
|
||
|
||
1. **Member Center owner 協調**:註冊 `kneron_converter_api` audience、`kneron_converter` client、設定 scope 授權
|
||
2. **File Access Agent owner 協調**:確認 Converter 要連的 instance URL、tenant_id、objectKey 命名約定
|
||
3. **VisionA 團隊協調**:確認 VisionA 的 Phase 1 OAuth 整合時程,對齊 Converter 整合測試時機
|
||
4. **Member Center `/file-access/download-tokens` 實作時程**:影響 Phase 2 啟動
|
||
|
||
### A.3 給 Architect Agent 的待確認項
|
||
|
||
1. **scope 命名**:`converter:job.write` / `converter:job.read` 是否符合 Member Center 慣例?由 Architect 在 TDD 提案後跨團隊 review
|
||
2. **Effort 估算**:RICE 表中 Phase 1 Effort = 4 人週 為 PM 概估,需 Architect 在 TDD 後精確。**注意:2026-04-25 變更後,Phase 1 移除「從 File Access Agent 取原始模型」這條路徑,相對減少 OAuth Client 的讀檔 scope 與整合測試複雜度,Architect 可重新估 Effort**
|
||
3. **OpenAPI 規格的維護策略**:自動生成還是手寫?版本變更流程?
|
||
4. **user_id 在 job record 的索引設計**:Redis 現在用 `redis.keys('job:*')` 掃描,加 user_id 過濾後效能策略?
|
||
5. **(新增,2026-04-25)multipart 上傳的記憶體策略**:既有 Web UI 用 `multer.memoryStorage()`,對外 API 接受相同路徑後,同時多個 visionA-backend 呼叫可能放大記憶體問題。Architect 需評估 Phase 1 是否同步改 `diskStorage`,或是否需 Capacity Planning 加上明確的上限(例如同時 multipart 上傳數 × 500MB ≤ Node.js heap)
|
||
6. **(新增,2026-04-25)`POST /api/v1/jobs` 與既有 `POST /jobs` 的路徑實作關係**:兩者行為近似,Architect 需決定是「共享同一個 handler,前面加 OAuth middleware + user_id 驗證分支」還是「完全獨立兩個 handler」。這會影響未來維護性
|
||
|
||
### A.4 給 Design Agent 的待確認項
|
||
|
||
1. 本次 Phase 1 主要影響「API 層 + visionA-backend 串接」,**Kneron Converter 自己的 Web UI 預期不改**
|
||
2. Design Agent 需確認:既有 Web UI 的「上傳模型」流程是否在 Phase 1 仍維持 multipart?若維持,則 Web UI 不受影響
|
||
3. visionA-backend 端的 UI 設計(進度條、recovery 提示、promote 按鈕等)**不在 Kneron Converter 的 Design Agent 範圍內**,由 VisionA 團隊負責
|
||
|
||
### A.5 本次變更(2026-04-25 第二次更新)新產生的 Open Questions
|
||
|
||
1. **VisionA 終端使用者如何下載轉檔結果(Phase 1 期間)**:
|
||
- 由於 Converter 不再從 File Access Agent「讀」原始模型,而使用者要看 / 下載 **轉檔結果**(BIE、NEF)的流程在 Phase 1 就尚未有 end-to-end 設計
|
||
- 選項:(a) 使用者先等到 promote 完成後從 VisionA UI 下載(VisionA 自己 proxy),(b) Phase 1 只讓 VisionA 平台顯示「已加進模型庫」,不提供下載鍵,等 Phase 2 delegated token 再開放,(c) VisionA 先不呼叫 promote,從 Converter 的 `/jobs/:jobId/download/:filename` 既有路徑下載(此路徑目前無 OAuth)
|
||
- 需 PM + VisionA 產品團隊對齊
|
||
2. **visionA-backend 在上傳前是否也存一份原始模型到自己**:
|
||
- 由於 Phase 1 原始模型不進 File Access Agent,若轉檔失敗或使用者要重試,visionA-backend 是否需要自己暫存一份?
|
||
- 這是 visionA-backend 內部設計問題,不影響 Converter API 契約,但會影響 VisionA 使用者 UX(失敗後能不能一鍵重試)
|
||
3. **既有 `/jobs/:jobId/download/:filename` 端點的對外曝光問題**:
|
||
- Phase 1 visionA-backend 若走 promote 路徑,下載由 VisionA ↔ File Access Agent 處理,Converter 的下載端點不需對外
|
||
- 但若 VisionA 決定「先不 promote、直接從 Converter 拉結果」,此端點就需要加 OAuth 保護
|
||
- 需在 TDD 中決定:既有下載端點是否要區分「Web UI 內部用」vs「對外 API /api/v1 用」兩套
|