把 M10 這輪三平台 build 踩的雷整理成 troubleshooting 文件,供未來 build 安裝包時參考。 涵蓋 9 條逐項 troubleshooting(統一格式:症狀 → 根因 → 為什麼發生 → 解法 → 如何根治)、快速症狀索引表、5 條橫向教訓、KneronPLUS 2.0.0 vs 3.1.2 版本相容附錄、build 驗收 checklist。 核心教訓:症狀常不指向根因(Error 12 是 input size、pip 秒退是 wheels 多版本、中文亂碼是 stdio code page),macOS 開發環境測不到大量 Windows-only 問題(編碼、DLL 路徑、SDK 版本差異)。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
26 KiB
Build Troubleshooting — visionA-local
這份文件的用途:記錄 visionA-local 打包安裝檔(macOS / Windows / Linux)時實際踩過的雷, 讓下次遇到同樣症狀能快速定位,而不是重新 debug 一輪。
目標讀者:未來要在 Windows / Linux build 這個專案安裝包的開發者(可能是你自己,也可能是團隊成員)。
這不是 build 教學。build 流程本身看
build-pipeline.md(Makefile 骨架、vendor 目錄、CI 策略)。 這份是它的 troubleshooting 補充:症狀 → 根因 → 為什麼會發生 → 解法 → 如何預防/根治。紀錄來源:2026-07 這輪(M10 classification + 特規打包 + 三平台實機 build)踩的雷, 每條都對到 progress.md 或實際 code 的
檔案:行號。若與現況不符,以 code 為準。
快速症狀索引表
先在這張表找你看到的症狀,跳到對應章節。症狀常常不指向真正的根因——這正是這份文件存在的理由。
| 你看到的症狀 | 可能的雷 | 跳到 |
|---|---|---|
裝置 reset 後 load_model Error code 24、停在 KDP2 Loader |
開發模式 dist/scripts/ 缺 firmware/ |
§1 |
前端顯示「載入模型失敗」、terminal 出現 darwin_usb.c:584 / SIGABRT |
除錯時 curl 與 UI 搶同一顆 USB | §2 |
Windows build:go: command not found / wails: command not found / pnpm not found(明明裝了) |
MSYS2 login shell 重建 PATH | §3 |
| Build 後置檢查失敗「預期 2 個 .nef,實際 8 個」 | copy_bundled_data 沒清空目標、殘留舊 .nef |
§4 |
Windows 推論 KP_ERROR_INVALID_PARAM_12(Error 12) |
input size 用了使用者亂填的 declared 值 | §5 |
| 每次啟動都「Python 相依未通過」但又不重裝,怎樣都好不了 | venv 半套安裝、只檢查 python.exe 存在就跳過 | §6 |
| 明明環境是好的,卻被判「Python 相依驗證失敗」擋住啟動 | 健康檢查 probe 沒補 Windows DLL 搜尋路徑 | §7 |
App 一啟動 pip 就秒退 ResolutionImpossible(certifi ×3 之類) |
vendor wheels 累積多版本 | §8 |
Windows 中文標籤亂碼(「布」→「撣<E3808C>」、log 出現 <EFBFBD>) |
Python stdio 綁 cp950 而非 UTF-8 | §9 |
如果症狀不在表上,先讀 §10 共通教訓——很多雷的「表面症狀」都不指向根因。
環境前置需求(三平台)
打包前的一次性環境安裝,用 bootstrap 腳本,不要手動裝:
| 平台 | 腳本 | 裝什麼 |
|---|---|---|
| Windows | scripts/bootstrap-windows.ps1 |
winget 裝 git / go / node / pnpm / python / MSYS2(提供 bash + make)/ Inno Setup + wails |
| Linux | scripts/bootstrap-linux.sh |
apt 裝 go 1.22.5 / node 20 / pnpm / wails + GTK/WebKit/libusb dev headers |
| macOS | (手動) | go / node / pnpm / wails / brew install create-dmg(DMG 美化,選用) |
三平台都需要 make vendor-sync 先把第三方二進位(Python runtime / wheels / ffmpeg)下載到 vendor/。
⚠️ Windows 特別注意:make 在 Windows 上是透過 C:\msys64\usr\bin\bash.exe 執行的(Windows 沒有原生 make),
這帶來 §3 的 PATH 坑。詳見該節。
逐條 Troubleshooting
§1 開發模式資源不同步 → 裝置 reset 後 load_model Error 24
症狀
- 裝置首次連線、reset 後,
load_model回Error code 24。 - Python bridge 卡在
KDP2 Loader狀態、進不到KDP2 Comp。 - 只在手動開發模式(
dist/scripts/)發生,打包出來的安裝包沒這問題。
根因
- 開發模式下
dist/scripts/需要同時含kneron_bridge.py+firmware/+drivers/,dist/data/需含models.json與.nef。 - 曾經只手動複製了
kneron_bridge.py、漏掉firmware/→ 裝置 reset 後 bridge 重啟時找不到 firmware → 停在 Loader →load_model Error 24。
為什麼會發生
- 手動同步「就複製那個我改到的檔案」很直覺,但 bridge 執行期會去讀
firmware/、drivers/這些不會每次都動、容易被忘記的相依資源。 - 打包流程之所以沒事,是因為 Makefile 三平台都用整包搬(
cp -R server/scripts/*/find | cp整包),不是逐檔挑。
解法
- 開發模式同步時,
dist/scripts/一律帶齊kneron_bridge.py+firmware/+drivers/,dist/data/帶齊models.json+.nef。不要只複製「這次改到的那個檔」。
如何預防 / 根治
- 走打包流程驗證而不是手動同步:
make payload-macos(progress.md L413 實跑驗證過 firmware/drivers 都在)。 - 已寫入 memory:
~/.claude/projects/-Users-jimchen-visionA/memory/project_local_tool_dev_env.md。 - 來源:progress.md L409-414。
§2 除錯時 curl 戳 flash 與 UI 搶同一顆 USB → SIGABRT
症狀
- 使用者端顯示「載入模型失敗」。
- terminal 出現 libusb 的 assert:
darwin_usb.c:584,程式 SIGABRT 直接掛掉。
根因
- 除錯時用
curl觸發 flash(load model),同時使用者還在用 UI 操作同一顆裝置 → 兩個行程同時對同一個 USB endpoint 下命令 → libusb 在 macOS 上直接 assert / abort。
為什麼會發生
- USB 裝置不是可多路複用的資源。KneronPLUS SDK / libusb 沒有替你做互斥;兩個 client 同時搶就炸。
解法 / 預防
- 除錯期間不要碰裝置——要嘛用 curl 手動測、要嘛用 UI 測,不要兩個同時來。
- 這不是 code bug,是除錯操作紀律。記住這個 assert 訊息(
darwin_usb.c:584),下次看到就知道是雙頭搶 USB,不用往 code 裡挖。 - 來源:progress.md L412。
§3 bootstrap-windows 的 MSYS2 PATH → Go / wails / node / pnpm 找不到
症狀
- Windows build 時,
go/wails/node/pnpm明明用 winget 裝好了,跑 make 卻報command not found。
根因
- Windows 沒有原生 make,本專案透過
C:\msys64\usr\bin\bash.exe -l(login shell)來跑 Makefile。 - login shell 啟動時會重跑
/etc/profile,把 PATH 整個重建成 MSYS2 自己的一套,Windows 上用 winget 裝的工具目錄就這樣被洗掉了。 MSYS2_PATH_TYPE=inherit(bootstrap 有設,bootstrap-windows.ps1:74)只影響 MSYS2 自己的 shell 啟動器(msys2.exe/mingw64.exe);直接呼叫bash.exe -l時它不生效。
為什麼會發生
inherit的作用範圍與「直接呼叫 bash.exe -l」的實際入口不重疊,是一個很容易誤解的設定。這也是為什麼 Inno Setup 呼叫、Python 呼叫本來就必須各自手動 export PATH。
解法
- 跟 Inno Setup 一樣,明確把工具目錄轉成 MSYS2 路徑格式(
C:\foo→/c/foo)後再 export,補在$PATH之前。 - 實作見
bootstrap-windows.ps1:73-113(註解完整說明)、:200(去重合併成單一 export,避免多行 export 互相覆蓋)、:284-294。
如何預防 / 根治
- 任何要在 MSYS2
bash.exe -l下被找到的工具,都不能依賴inherit,一律顯式 export 轉譯後的 MSYS2 路徑。 - 來源:
bootstrap-windows.ps1:73-113、progress.md L1401(M7 同型坑的前身)。
§4 copy_bundled_data 不冪等 → 「預期 2 個,實際 8 個」
症狀
- Build 後置檢查失敗:
!! ERROR: 預期 2 個 .nef,實際 8 個 !!,build 中止。
根因
payload-windows/payload-linux刻意不rm -rf整個payload/<os>/(因為build-server-*已先把 binary 放進bin/),所以前次 build 的data/殘留會留著。- 白名單機制(M5-a、
BUNDLED_NEFS只留 2 個 .nef)上線前,舊 build 會把 8 個 .nef 全複製進去。升級到白名單版本後再 build,就變成「新複製 2 個 + 殘留 6 個 = 8 個」,被後置檢查擋下。 payload-macos沒踩到,只是因為它有rm -rf payload/darwin。
為什麼這個後置檢查是「對的」
- installer(
installer/windows/visiona-local.iss)是用data\* + recursesubdirs整包收,殘留什麼就出貨什麼。所以「數 .nef 個數不符就 fail」是防止安裝包偷偷多帶不該帶的模型——這個 fail-loud 檢查要保留。
解法
copy_bundled_datahelper 先清空整個目標 data 目錄再複製(步驟 (a)),確保重複執行結果一致、不受既有內容影響。- 為什麼清整包而不是只清
nef/:目標目錄內容 100% 由這個 helper 產生(Makefile 中只有這裡寫入payload/<os>/data/),沒有其他來源需要保留;只清nef/的話,未來從server/data/移除的其他檔案殘留仍會被 installer 整包打包出貨。清整包才是真正冪等。 - 實作 + 完整註解見
Makefile:39-118(define copy_bundled_data)。
如何預防 / 根治
- helper 內建 fail-loud 後置檢查:白名單缺檔直接 fail(
Makefile:104-108)、複製後驗models.json存在(:101-103)+ .nef 數量 == 白名單長度(:113-116)。 - 不用 rsync:Windows CI 跑在 Git Bash(
windows-2022+shell: bash),該環境沒有 rsync → 一律用 POSIXfind/cp(Makefile:71-72)。 - 來源:
Makefile:39-118、progress.md L112-124。
§5 input size 優先序錯 → Windows 推論 Error 12
症狀
- Windows 上推論回
KP_ERROR_INVALID_PARAM_12(Error 12)。 - 同一個模型在 macOS 上正常。
根因
- input size 的來源可信度排序,declared(使用者在上傳表單手填的值)不能排在檔名解析之前。
- 上傳表單的
inputSize欄位長期沒有實際作用,使用者是「隨手填」的(實際案例:填 640×640,模型其實是 224×224)。 - KneronPLUS 3.1.2(Windows)不再提供 2.0.0(macOS)的
shape_onnx屬性,SDK 這層在 Windows 直接落空 → 於是垃圾 declared 值成為實際採用值,送進 NPU 得到 Error 12。 - 檔名的
wNNNhNNN是模型編譯工具鏈產生的,沒有人為亂填空間,明確解析出來時比 declared 可信。
為什麼是 Windows 才炸
- 見 §附錄「KneronPLUS 版本相容性」:macOS 用 2.0.0、Windows 用 3.1.2,
shape欄位在 3.x 搬進巢狀 union(TensorDescriptor.tensor_shape_info.data),舊寫法getattr(node, "shape_onnx")在 3.1.2 拋 AttributeError 被靜默吃掉 → SDK 來源落空 → 掉到 declared。
解法
- input size 可信度排序改為:SDK(0) → filename(1) → declared(2) → known-model-id(3) → default(4)。declared 降到第 3。
- 常數與完整根因註解見
kneron_bridge.py:351-371(INPUT_SIZE_SOURCE_RANK)。 - 逐軸解析(不再沿用單一純量
_model_input_size,因為模型輸入不保證正方形):kneron_bridge.py:159-193。 - 相容兩版 SDK 的 shape 讀取(先試 3.x 巢狀
tensor_shape_info、再退平鋪欄位):kneron_bridge.py:479-523。
如何預防 / 根治
- 實機驗收時 grep log 印出的 input size source(
kneron_bridge.py:347-349說明這是唯一能一眼看出尺寸怎麼來的線索)——尺寸錯掉時 NPU 不一定報錯,可能只是安靜給錯結果。 - ⚠️ 這是 §10「湊巧正確」教訓的實例:舊版檔名猜 224 湊巧對,改成「更可信」的 declared 反而錯。
- 來源:
kneron_bridge.py:345-376, 479-523。
§6 venv 半套安裝 → 永久卡住、怎樣都好不了
症狀
- 每次啟動都跑「Python 相依驗證未通過」,但又不重裝、也沒有提示,怎樣都好不了。
- 只能手動刪掉
runtime/venv才能恢復。
根因
- 舊邏輯只檢查
python.exe(venv/Scripts/python.exe或venv/bin/python3)存在就跳過安裝。 - 但「python 執行檔存在」不等於「相依裝好了」:pip install 中途失敗(斷網 / 磁碟滿 / 防毒攔截)會留下 venv 與 python.exe 都在、但
import kp失敗的半套環境。 - 於是每次啟動都「看到 python.exe → 跳過安裝 → 但 import 失敗」,永久卡死且無提示。
解法
- venv 已存在的日常啟動路徑改為「驗健康、必要時嘗試修復」:
reuseExistingVenv(app.go:1078-1103)。 - venv 在但相依看起來壞了 → 只補裝 wheels、不整個重建 venv(重建要重解壓 ~100MB tarball,而失敗幾乎都出在 pip 階段):
app.go:1091-1093。 - 修復失敗時記錄 warning 但不阻斷啟動(見 §7),改以現有 venv 繼續:
app.go:1096-1101。
如何預防 / 根治
- 狀態檢查要驗「真的能用」而非「檔案在」——這是 §10 的橫向教訓。
- 快路徑用標記檔
venv-ready.txt記錄「wheels 已成功裝完 + 當前 wheels 指紋」,指紋不符才真的跑一次 import 驗證(app.go:1105-1152)。 - 來源:
app.go:995-1103、progress.md(M4 之後的 fix)。
§7 健康檢查阻斷啟動(自造 regression)→ 健康的 venv 被判壞、擋住啟動
症狀
- 環境明明是好的(bridge 實際能跑、能掃到裝置),app 卻因「Python 相依驗證失敗」擋住啟動。
根因(這是修 §6 時自己造成的 regression)
- §6 的健康檢查 probe 裸跑
python -c "import kp",沒有補 Windows 的 DLL 搜尋路徑。 kp在 import 時就會ctypes.CDLL載入kp/lib下的 native DLL(libkplus / libusb-1.0 / libwdi + MinGW runtime,共 6 個)。Windows 上這些 DLL 不在預設搜尋路徑、必須先add_dll_directory。- 真正跑 bridge 時
kl720_driver.go的startPython()與platform_windows.go的 driver 安裝腳本有做這件事,但 probe 沒做 → 健康的環境也 import 失敗 → 被判壞掉 → 擋住啟動。
解法
- probe 的環境要盡量貼近「真正跑 bridge 的環境」:
pythonProbeScript加一段 preamble,先把site-packages/*/lib掛進PATH+os.add_dll_directory再 import(app.go:1182-1205)。 - 更重要的原則:健康檢查絕不可以成為啟動的阻斷點。 完整理由見
app.go:999-1016:- 這個 probe 會誤判(環境貼合度永遠不可能 100%)。
- 就算真的壞了,讓 bridge 自己回報「掃不到裝置」這類具體錯誤,比在啟動前用一個間接的 probe 攔死更好——kneron_bridge.py 本來就把 import kp 失敗當可降級的情況處理。
- 型別設計落地這個原則:
reuseExistingVenv沒有 error 回傳值(app.go:1078-1081)——型別本身就保證了「健康檢查不會阻斷啟動」。
如何預防 / 根治
- 加任何「啟動前健康檢查」時,先問:檢查失敗會不會擋住啟動?如果會,它就有能力誤殺健康環境。健康檢查應該是「發警告 + 嘗試修復」,不是 gate。
- 來源:
app.go:999-1016, 1078-1103, 1154-1205。
§8 wheels 多版本 → pip ResolutionImpossible、app 一啟動就秒退
症狀
- App 首次啟動安裝依賴時,pip 在 ~2 秒內
ResolutionImpossible失敗,使用者完全無法啟動。 - vendor 目錄裡同一套件有多顆(如
certifi ×3、numpy ×2、idna ×2)。
根因
vendor-wheels*用pip download --dest,而pip download只「補下載缺的」、不移除舊版。- upstream 每發一次新版,
vendor/wheels/<os>就多留一顆 whl → 實機累積成 16 顆(正常應為 9 顆)。 - 這些多版本原封不動被
payload-*複製進安裝包 → app 啟動pip install a.whl b.whl ...同時收到certifi 2026.2.25與2026.6.17→ 直接 ResolutionImpossible。 - debug 成本放大:這個 pip 錯誤還被 Makefile 的 Auto 分支吞掉(
|| echo WARN),導致三輪來回都拿不到線索。
解法(兩層都要)
- 源頭:
clean_wheels_dirhelper 在vendor-wheels*前先清空並重建vendor/wheels/<os>/,確保冪等、不累積多版本(Makefile:143-166,完整事故迴歸註解在:121-142)。 - 救援:app 端
selectLatestWheelPerPackage對每個套件只保留版本最高的一顆再交給 pip(app.go:1314-1325+),能救「已出貨」的舊安裝包。 - 兩層都要有:源頭杜絕讓新安裝包乾淨、救援讓舊安裝包也能自癒。
如何預防 / 根治
- 版本比較用逐段整數比較的簡化 PEP 440(
compareWheelVersions,app.go:1282-1312);套件名依 PEP 503 正規化,讓opencv_python_headless與opencv-python-headless視為同套件(normalizeDistName,app.go:1255-1271)。 - 錯誤不要被吞掉:這條的三輪 debug 成本就是 pip 錯誤被
|| echo WARN吞掉造成的。詳見 §10。 - 來源:
Makefile:121-166、app.go:1207-1325、progress.md L135-136。
§9 Windows 中文亂碼 → 標籤「布」變「撣<E3808C>」
症狀
- Windows(繁中)上 classification 標籤亂碼:「布」變「撣<E3808C>」。
- stderr log 的中文與 em dash(U+2014)出現
<EFBFBD>(如<EFBFBD>X SDK did not report)。
根因
- Windows 的 Python 把 stdio 綁到「系統 ANSI code page」而非 UTF-8。繁中 Windows 的 ANSI code page 是 cp950。
- bridge 的 JSON-RPC 兩個方向不對稱:
- Go → Python (stdin):Go 的
encoding/json不 escape 非 ASCII,{"labels":["布"]}在 wire 上是 raw UTF-8e5 b8 83。以 cp950 解碼得到「撣」+ U+FFFD(截圖的亂碼);嚴格模式下直接 UnicodeDecodeError 讓整個 bridge 掛掉。 - Python → Go (stdout):
json.dumps預設ensure_ascii=True,中文被 escape 成\uXXXX純 ASCII,所以這條「目前剛好沒壞」——但那是隱性依賴,任何人加上ensure_ascii=False就會壞。 - stderr:
_log()的中文與 em dash 現在就會壞。
- Go → Python (stdin):Go 的
解法
_force_utf8_stdio()把 stdin / stdout / stderr 一律reconfigure(encoding="utf-8", errors="replace")(kneron_bridge.py:22-71),不理會系統預設編碼。- 在 module import 時就呼叫(
kneron_bridge.py:71),不是在main()裡——必須早於任何 I/O(main()會os.dup()stdout、import 期間的例外也走 stderr)。 - 用
errors="replace"而非strict:這是診斷 log 通道與協定通道,遇到極端無效位元組寧可看到一個 U+FFFD 也不要讓整個 bridge 因一行 log 而崩潰(bridge 掛掉 = 裝置失聯,比壞字元嚴重)。
如何預防 / 根治
- 把「stdout 是 UTF-8」變成顯式契約而非巧合(連目前沒壞的 stdout 方向也一併綁定)。
- ⚠️
PYTHONUTF8與PYTHONIOENCODING管的範圍不同:前者是整個 Python 的 UTF-8 mode(含檔案系統編碼等)、後者只管 stdio 的編碼。這裡用程式內reconfigure是最直接、不依賴環境變數是否被正確傳入的做法。 - 測試釘死:
server/scripts/test_kneron_bridge_encoding.py。 - 來源:
kneron_bridge.py:22-71。
§10 共通教訓(橫向 pattern)
這節比逐條 bug 更有價值——上面 9 個雷裡反覆出現的幾個 pattern,下次寫 code / debug 時記住這些,能少踩一半。
10.1 macOS 開發 ≠ Windows 實機
好幾個雷都是「macOS 有、Windows 沒有」或「兩邊行為不同」造成的。macOS 上測不到、只有 Windows 實機才會爆的類別:
| 類別 | macOS | Windows | 踩到的雷 |
|---|---|---|---|
| stdio 編碼 | 預設 UTF-8 | 預設 cp950(繁中 ANSI code page) | §9 中文亂碼 |
| native DLL 搜尋路徑 | dyld(可用 ctypes 絕對路徑預載) | 需 add_dll_directory、不在預設路徑 |
§7 健康檢查誤殺 |
| KneronPLUS SDK 版本 | 2.0.0(有 shape_onnx) |
3.1.2(shape 搬進巢狀 union) | §5 input size Error 12 |
| shell / make | 原生 bash + make | MSYS2 login shell 重建 PATH | §3 工具找不到 |
| 既有環境 | 開發機常有現成工具 | 乾淨機、什麼都要 bootstrap | §3 / §4 |
原則:任何「編碼 / DLL 路徑 / SDK 版本 / code page / shell」相關的東西,不能只在 macOS 驗,一定要 Windows 實機或至少想清楚兩邊差異。
10.2 「檔案存在」≠「可用」
§6(venv 半套安裝)和 §7(健康檢查)都栽在這。
- venv 只檢查
python.exe存在就跳過安裝 → 半套環境永久卡死。 - 狀態檢查要驗**「真的能用」**(實際 import / 實際跑一次),而非「檔案在」。
- 但驗「能用」時要注意 §7 的教訓:驗證環境要貼近真實執行環境,否則會誤殺健康的環境;而且健康檢查不能是啟動阻斷點。
10.3 錯誤被吞掉會讓 debug 成本爆炸
§8(wheels 多版本)的三輪來回,根因是 pip 錯誤被 Makefile 的 || echo WARN 分支吞掉,拿不到真正的錯誤訊息。
- 吞錯誤 = 把「一次就能定位」變成「三輪還在猜」。
- fail-loud 優於 fail-silent。§4 的後置檢查(數 .nef 個數不符就直接 fail)就是正面教材——它讓「安裝包偷偷多帶模型」在 build 期就爆,而不是等出貨後使用者才發現。
- 對照 §5:input size 錯掉時 NPU 不報錯只給錯結果——這種「靜默失敗」最貴,所以要靠 log 印出 source 當唯一線索。
10.4 「湊巧正確」的行為改動要格外小心
§5(input size 優先序)是經典案例:
- 舊版用檔名猜測,某些模型湊巧猜到 224、剛好對。
- 改成「看起來更可信」的 declared(使用者手填值)反而錯——因為使用者是隨手填的。
- 教訓:當你把一個「能動但你覺得不夠嚴謹」的邏輯改成「更正確」的版本時,先確認新來源真的更可信。「更正式的欄位」不代表「更可信的值」——declared 是正式欄位、但值是垃圾。
10.5 兩層防護(源頭 + 救援)
§8 的解法是兩層都做:clean_wheels_dir 從源頭杜絕(新安裝包乾淨)+ selectLatestWheelPerPackage 救援(舊安裝包自癒)。
- 只做源頭 → 已出貨的舊安裝包救不了。
- 只做救援 → 每個新安裝包都帶著髒 vendor 出貨、依賴 app 端補救。
- 涉及「已出貨產物」的問題,通常源頭與救援都要有。
§附錄 A:KneronPLUS 版本相容性
三平台的 KneronPLUS wheel 版本不一致,這是好幾個雷的隱形根因。寫任何碰 SDK 的 code 時必讀。
| 平台 | KneronPLUS wheel 版本 | 影響 |
|---|---|---|
| macOS | 2.0.0 | TensorDescriptor 有平鋪的 shape_onnx / shape_npu 屬性 |
| Linux | 2.0.0 | 同上 |
| Windows | 3.1.2 | 無 shape_onnx 屬性;shape 搬進巢狀 tensor_shape_info.data(V1/V2 union);DLL 需求更嚴 |
具體差異與注意事項:
-
shape 欄位位置不同(→ §5 Error 12)
- 2.0.0:
node.shape_onnx/node.shape_npu直接可讀。 - 3.1.2:
node.tensor_shape_info.version(ModelTensorShapeInformationVersion)+.data(TensorShapeInfoV1有shape_onnx/shape_npu;TensorShapeInfoV2只有.shape,docstring 明寫是 ONNX shape)。 - 舊寫法
getattr(node, "shape_onnx")在 3.1.2 拋 AttributeError → 被 except 靜默吃掉 → SDK 這層以為「模型沒帶 shape」,其實是讀錯欄位。 - 相容兩版的讀法見
kneron_bridge.py:479-523(先試巢狀、再退平鋪)。
- 2.0.0:
-
native DLL 需求(→ §7 健康檢查誤殺)
import kp在 Windows 會載入kp/lib下的 native DLL(libkplus / libusb-1.0 / libwdi + MinGW runtime,共 6 個),不在預設搜尋路徑 → 需add_dll_directory。- macOS 走 dyld,可用 ctypes 絕對路徑預載(
_preload_kneron_dylibs_macos,kneron_bridge.py:74+)。
-
wheel 三平台版本不一致本身是風險(progress.md M9-6 findings L587)
- 若未來要加 KL630/KL730 等新晶片支援,macOS/Linux 的 2.0.0 wheel 沒有對應 enum,必須先升 wheel。
update_kdp_firmware_from_files在 3.1.2 Python wrapper 中不存在(warrenchen 是 ctypes 直打 .so C symbol),這類 API 差異在跨版本時要逐一確認。
原則:任何讀 SDK 結構(shape / enum / API 簽章)的 code,都要同時對 2.0.0 與 3.1.2 驗,或明確寫成「先試新版結構、失敗再退舊版」的相容寫法。
§附錄 B:Build 完驗收 Checklist
Build 完一個安裝包後,至少驗這些(每項標了對應的雷,避免重蹈覆轍):
- .nef 數量正確:打包版(不是開發模式)確認只帶白名單的 2 個
.nef(FCOS Detection/Tiny YOLOv3),不是 8 個。→ §4 (開發模式驗不出來:server/data/nef/8 個都在、過濾器只濾「檔案不存在」,開發模式會顯示 7 個模型。M5 必須用打包版驗、progress.md L206。) - models.json 有進安裝包:啟動後
/api/models回非空、log 印Loaded N built-in models(不是 0)。 - 中文顯示正常(Windows 繁中機):classification 標籤、log 的中文都不亂碼。→ §9
- input size source 正確:實機推論後 grep log 的 input size source,確認不是掉到 declared / default 撿到垃圾值;Windows 上尤其要看。→ §5
- 推論不報 Error 12 / Error 24:Windows 推論不 Error 12(§5)、裝置 reset 後 load_model 不 Error 24(§1)。
- Python venv 健康:全新機器首次啟動能自動裝好 wheels(不 ResolutionImpossible §8);且啟動不被健康檢查誤擋(§7)。
- driver 綁定:Windows 上 KneronPLUS native DLL 能被載入(
import kp成功、掃得到裝置)。→ §7 / 附錄 A - Wails 視窗確認:開 app window 確認主 UI 是 Next.js 而非 splash / installer wizard / 白畫面(progress.md L1602 的歷史教訓:M1 只用瀏覽器連 localhost 驗、沒開 window,讓 wizard 殘留混過 M1-M6)。
驗收原則:不要只驗「server 有回應」——很多雷(§1 / §4 / §5 / §9)在 /api/health 200 的情況下照樣存在。要驗到「真的能推論 + 顯示正確」。
相關文件
build-pipeline.md— Makefile 骨架、vendor 目錄結構、CI 策略、版本號管理(build 流程本體)。- progress.md(
.autoflow/progress.md)— M10 各段開發紀錄與踩坑細節的一手來源。 - memory:
~/.claude/projects/-Users-jimchen-visionA/memory/project_local_tool_dev_env.md— 開發模式資源同步坑。