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>
70 KiB
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)取得轉檔進度
- 轉檔完成後呼叫
promoteAPI 將結果搬進模型庫
- 以 OAuth2
- 一句話描述:「作為服務,我希望能用標準的 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.writescope 的 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 UIPOST /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_credentialsgrant 取得 token - 取得後用於:
- PUT 結果檔到 File Access Agent(scope=
files:upload.write,promote 時使用,見 US-10 / US-13)
- PUT 結果檔到 File Access Agent(scope=
- 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 fieldPOST /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,從設計文件確認)
以下為刻意的設計取捨,不是缺陷:
- 不做任務持久化 — Redis 重啟即清空所有任務
- 不做 Crash 後恢復 — 進行中的任務在 Crash 後消失
- 不做 exactly-once / at-least-once 保證 — 任務可能因 Crash 而遺失
- 不做 Scheduler HA — 單一 Scheduler instance
- 不做自動重試 — 失敗即 FAILED,由使用者手動重送
- 轉換流程固定 — 必須走完 ONNX → BIE → NEF,不支援跳過
7.2 技術假設
- 所有 Worker 需掛載相同的 Docker Volume 才能存取共享檔案
- Worker 需要 Kneron Toolchain Python 環境(或使用 Stub 模式)
- Redis 不開啟 persistence,符合「Crash 即 Reset」哲學
- [推測] 目標部署環境為 Linux Docker 環境
7.3 已知限制
- 前端 UI 的單階段 API 端點(
/api/onnx/upload、/api/bie/process等)在後端尚未實作,前後端 API 契約不一致 - Simulator 功能(浮點/定點/硬體模擬)旗標已定義但邏輯未接線
- 任務列表使用
redis.keys('job:*')掃描,任務量大時效能可能有問題 [推測] - 檔案上傳使用 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 /jobsp95 目標「< 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(當前 — 已實作 / 急需修復)
- 完整轉換流程(ONNX → BIE → NEF)
- Web UI 基本功能
- SSE 即時狀態推送
- Worker 水平擴展
- Stub Worker 開發模式
- 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
- 驗 token(作為 Resource Server):從
- 目前狀態:
- 核心 OAuth2 / OIDC 已完成(見
/tmp/member_center/docs/DESIGN.md §7.1) POST /file-access/download-tokens(Phase 2 需要)尚未實作
- 核心 OAuth2 / OIDC 已完成(見
- 本次 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 讀取任何東西)
- 註冊一個 resource audience:
- 風險:任何註冊、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 類的呼叫
- 僅 PUT 結果到模型庫:promote 時 Converter PUT 結果檔到 File Access Agent(帶 service token,scope=
- 目前狀態:
- 核心功能完成(見
/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 檔案流(已確認):
- 原始模型:
visionA-backend ──multipart──> Converter(不經 File Access Agent) - 轉檔結果(promote 時):
Converter ──PUT──> File Access Agent ──> NAS - 使用者下載結果(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 上線完成的判定標準:
- visionA-backend 能成功以 service token 呼叫所有四個對外 API
- 一個完整 E2E 流程跑通:VisionA 使用者上傳模型 → File Access Agent → 觸發轉檔 → polling 進度 → 完成後 promote 到模型庫
- 同使用者同時轉檔限制生效(回 409)
- Recovery 能查到 in-progress job
- OpenAPI 規格通過 visionA-backend 整合測試
- 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):
- Member Center 的
POST /file-access/download-tokens已實作並部署(目前:未實作) - Member Center owner 提供測試環境與 scope 授權
- 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 需使用者決定的產品問題
- Phase 1 的 Web UI 要不要也改走 OAuth 流程?
- 傾向不改(維持既有 multipart 行為),未來評估
- 若決定改,則 Phase 1 範圍會擴大(升級為 L+ 或拆兩個 L)
- 同使用者同時一個轉檔限制範圍確認
- 是否真的是「整個 Converter 服務」共用的 user_id 空間?還是不同
client_id(例如未來有 visionA-backend 以外的消費者)各自獨立? - 目前 PRD 以「整個服務內 user_id 唯一」設計(預期未來不會出現跨 client 的 user_id 衝突)
- 是否真的是「整個 Converter 服務」共用的 user_id 空間?還是不同
- tenant_id 策略
- Member Center 與 File Access Agent 都是多租戶設計,但 PRD 目前未處理「Converter 內部怎麼標記 tenant」
- 待 Architect Agent 評估:Converter 是否要在 job record 上記錄 tenant_id?還是只信任 File Access Agent 的 single-tenant-per-instance 保證?
- Phase 2 的 fallback 策略
- 若 Member Center 長期不實作 delegated token,VisionA 要不要做 proxy 下載作為折衷?
- 還是完全等 Member Center?
- API 採用度的 baseline 如何取得?
- §9.2.2 列的目標值(例如「每月 X 個 job」)目前沒有歷史資料
- 建議:Phase 1 上線後跑 1 個月 beta 再訂正式目標
- 既有 PRD 中的
[推測]標記要不要在此次順便確認?- 本次 PM 暫不動既有
[推測],保留給使用者決定 - 建議在使用者最終審核本版 PRD 時一併確認
- 本次 PM 暫不動既有
A.2 需跨團隊協調的問題(給 Orchestrator 記到 progress.md 未解決問題)
- Member Center owner 協調:註冊
kneron_converter_apiaudience、kneron_converterclient、設定 scope 授權 - File Access Agent owner 協調:確認 Converter 要連的 instance URL、tenant_id、objectKey 命名約定
- VisionA 團隊協調:確認 VisionA 的 Phase 1 OAuth 整合時程,對齊 Converter 整合測試時機
- Member Center
/file-access/download-tokens實作時程:影響 Phase 2 啟動
A.3 給 Architect Agent 的待確認項
- scope 命名:
converter:job.write/converter:job.read是否符合 Member Center 慣例?由 Architect 在 TDD 提案後跨團隊 review - Effort 估算:RICE 表中 Phase 1 Effort = 4 人週 為 PM 概估,需 Architect 在 TDD 後精確。注意:2026-04-25 變更後,Phase 1 移除「從 File Access Agent 取原始模型」這條路徑,相對減少 OAuth Client 的讀檔 scope 與整合測試複雜度,Architect 可重新估 Effort
- OpenAPI 規格的維護策略:自動生成還是手寫?版本變更流程?
- user_id 在 job record 的索引設計:Redis 現在用
redis.keys('job:*')掃描,加 user_id 過濾後效能策略? - (新增,2026-04-25)multipart 上傳的記憶體策略:既有 Web UI 用
multer.memoryStorage(),對外 API 接受相同路徑後,同時多個 visionA-backend 呼叫可能放大記憶體問題。Architect 需評估 Phase 1 是否同步改diskStorage,或是否需 Capacity Planning 加上明確的上限(例如同時 multipart 上傳數 × 500MB ≤ Node.js heap) - (新增,2026-04-25)
POST /api/v1/jobs與既有POST /jobs的路徑實作關係:兩者行為近似,Architect 需決定是「共享同一個 handler,前面加 OAuth middleware + user_id 驗證分支」還是「完全獨立兩個 handler」。這會影響未來維護性
A.4 給 Design Agent 的待確認項
- 本次 Phase 1 主要影響「API 層 + visionA-backend 串接」,Kneron Converter 自己的 Web UI 預期不改
- Design Agent 需確認:既有 Web UI 的「上傳模型」流程是否在 Phase 1 仍維持 multipart?若維持,則 Web UI 不受影響
- visionA-backend 端的 UI 設計(進度條、recovery 提示、promote 按鈕等)不在 Kneron Converter 的 Design Agent 範圍內,由 VisionA 團隊負責
A.5 本次變更(2026-04-25 第二次更新)新產生的 Open Questions
- 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 產品團隊對齊
- visionA-backend 在上傳前是否也存一份原始模型到自己:
- 由於 Phase 1 原始模型不進 File Access Agent,若轉檔失敗或使用者要重試,visionA-backend 是否需要自己暫存一份?
- 這是 visionA-backend 內部設計問題,不影響 Converter API 契約,但會影響 VisionA 使用者 UX(失敗後能不能一鍵重試)
- 既有
/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 用」兩套