這週的工作橫跨量化回測引擎、太陽能儲能通訊、自動駕駛縱向控制與現場部署,表面題材分散,卻有一條共同主軸:系統沒有崩潰、沒有報錯,但數字正在悄悄偏離現實。我們花了相當多時間設計「讓錯誤顯現」的機制,而不只是修掉看得見的問題。同時也在部署可靠性上做出了根本性的設計取捨——讓一包軟體在客戶網路完全不通的環境下也能一鍵安裝完成。
三個不讓系統崩潰的 bug,以及怎麼用手算逼它們現形 #
量化回測引擎持續運作、策略訊號正常產生,損益報告卻一直有點對不上直覺。這類「沉默錯誤」最難被察覺——它不會讓程式崩潰,只會讓你在分析策略表現時,無法分辨問題出在策略本身還是基礎設施。在量化系統中,一旦錯誤被當成「規格的一部分」沉澱下來,後續所有決策都會在偏移的基礎上進行。
我們採用「手算特定情境的期望損益,要求程式跑出一樣的結果」作為驗收方式,而非只看跑通沒報錯。這個做法讓三個長期並存的問題一次浮現:第一,訊號當根 K 棒收盤就成交,改為下根 K 棒開盤才符合真實交易邏輯;第二,歷史 K 棒與盤中合成 K 棒有系統性時間偏移,導致訊號發生在略微錯誤的時間點,修正後一致率從不到 1% 升至 99.8% 以上,並完成 2020 年起的歷史資料重建;第三,分批出場的最終平倉一直用最大口數計算而非實際剩餘口數,讓損益數字虛高,所有出場路徑(停損、強平、反手、期末平倉)均有此問題。三項修正後,重跑某一策略的結果與基準值完全吻合,驗收成立。此外,修正過程中發現過去對某個計算結果的陳述有誤,選擇主動承認並更正,而非等待被質疑。
量化系統乃至任何需要長期累積計算的系統中,「有結果」不等於「結果正確」。比擴大測試覆蓋率更根本的做法,是在開發初期就設計「已知正確基準值的 regression check」,把驗收錨定在可比較的具體數字上——沉默錯誤最怕的就是被拿來對比手算。
不要追精確車距:緩衝帶設計讓跟車每分鐘少了一次加減速 #
自適應跟車系統在設定車距後,只要前車有一點加減速就立即反應,導致每分鐘反覆加減速將近四次,乘客感受很不自然。這不是感測器精度的問題,而是控制邏輯本身把「維持精確車距」當成目標——而真實駕駛裡,合理的車距本來就有一段浮動範圍,沒必要每次都縮回精確值。
我們在 sunnypilot 的車距規劃層加入緩衝帶:只要當前車距比目標長、但在 60% 範圍以內,就視為「距離合理」不啟動追趕,緩衝只放在距離偏長的一側(晚加速、不晚煞車)。這個非對稱設計確保安全不妥協:距離不足時仍立即反應,只有「可以不急著縮近」時才按兵不動。模擬驗證顯示加減速次數從每分鐘 4.0 次降至 3.0 次,在 39 次前車重煞情境下車距均未異常縮近。同週也完成彎道煞車漸進化改版,讓煞車力道從「一格就到最重」改為每秒最多增加 1.5 m/s² 的斜率,模擬中「一開始就衝到最重」的比例從 85% 降至 6%。
這個設計思路對任何「閉迴路控制追目標值」的場景都適用:目標值不一定要精確命中,給合理範圍的容許帶,往往能大幅降低系統的振盪行為,而不影響最重要的安全邊界。「緩衝帶非對稱」這個細節尤其關鍵——安全邊界的方向不能有緩衝,只有舒適性方向才放。
Modbus 幀驗證的缺席:一個遲到的回應如何製造假電池告警 #
太陽能儲能系統在 WiFi 訊號不穩時,偶爾出現明顯不合理的電池告警——單體電壓數值出現在告警欄位裡。系統沒有崩潰,只是默默寫入了一筆假異常。問題發生在通訊層:上一個查詢的 Modbus 回應幀因網路延遲遲到,被下一個查詢的解析邏輯當成答案照單全收,不同語義的欄位就這樣對調了。
根因是通訊模組從未驗證回應的 slave id、function code、byte count 與 CRC16,只要 socket 有資料就解析。修法是新增幀提取函式,對收到的 bytes 從每個 offset 逐一掃描,找出同時通過四項驗證的合法幀;送出查詢前也先清掉 socket 殘留,避免前次遲到的回應污染新查詢。「逐 offset 掃描」而非「只從頭解析」是關鍵取捨——目的是應對幀黏著的情況,確保不論幀對齊與否都能命中正確資料。在掉包 33%、延遲最高 1310ms 的條件下,連續 14 筆讀取零亂碼,與修復前的對比明確。
序列埠與 TCP socket 通訊中,「socket 有資料」不等於「是對的資料」。在多設備輪詢的 Modbus 場景下,幀驗證是通訊層該做的基礎設施,不是留給業務邏輯去過濾。這條原則對任何透過 Modbus/RS485 串接設備的監控或控制系統都適用——驗證成本極低,收益是根絕整類假異常。
讓部署不再依賴客戶現場的網路:一包完全離線的安裝包 #
到客戶現場部署軟體時,最不可控的變數往往是網路環境。Python 套件下載失敗、Visual C++ Redistributable 缺失、企業防火牆過濾 PyPI——每個環節都可能讓安裝中途失敗,且失敗原因各不相同,現場工程師難以快速判斷,最終變成長時間的現場排障。
決定從根本解決:在有網路的環境預先備齊所有依賴,打成單一資料夾,讓客戶主機只需「複製資料夾 → 點 bat → 完成」。幾個設計取捨:Python 套件採用 wheel 檔(46 個)離線安裝,而非私有 PyPI 鏡像,理由是後者在網路管制環境仍可能失敗,wheel 包更確定;Chrome 採企業版 MSI 確保服務帳號可找到瀏覽器路徑;安裝前置資料夾(prerequirement)與程式本體分離,後續版本迭代只重新打包本體,共用安裝檔不重複下載,打包體積不隨版本線性增長。整包 431MB,驗證方式是逐檔 MD5 比對確認版本一致,三個安裝程式數位簽章均驗證為官方原檔。
對於需要在客戶機房部署的 B2B 軟體,離線安裝包是一次性工程投入、長期受益的基礎設施。客戶環境越不可控,「把依賴打進安裝包」的價值就越高。而「前置依賴與程式本體分離」的打包架構,讓日後的版本迭代不需要重新處理依賴,是這類工具的標準工法。
本週其他進展 #
- eMobile 現金抽屜三層根因全修復 — 追查出兩種訊號接法只處理一種、開啟時間僅 0.06 秒(延長至 0.1 秒)、失敗時無任何提示等三個根因,一併修復。新增首頁獨立「開抽屜」按鈕供手動觸發。
- eMobile 發票稅額精度修復,新增手動調整功能 — 修復逐行四捨五入造成的累計誤差(與螢幕顯示差 1 元同源),並新增稅額手動調整入口,讓操作者可在邊界情況下直接介入,不依賴程式自動計算。
- eMobile B2B 統編查詢三段式鏈路上線 — 查詢鏈路整合為本機快取→商店後台→財政部電子發票平台三段,每段約 0.14 秒,登入驗證碼自動辨識,全流程無須人工介入;同步改以設備身份區分版本授權,廢棄原對外暴露端點。
- eMobile 進退貨時間戳時區修正 — 進退貨時間戳原以 UTC 儲存但分日時未換算台灣時間,導致凌晨 0~8 點進貨被歸入前一天。修正後一律以台灣時間分日,PDF 印出日期同步修正。
- Solar Monitor 電費計算時間基準統一 — 抄表日有日期但無精確時間時,改以 09:00 為基準(對應台電實務上午抄表慣例),兩路計費路徑共用同一輔助函式,消除歷史用電漏算問題。
- fate.motoway.tw AdSense 手動廣告版位全面上線 — 通過 AdSense 審查後,廢棄自動廣告,改為手動建立廣告單元並埋入程式碼。在 14 個工具頁、首頁與全站頁尾完成佈建,首頁從 0 則升至 3 則,工具頁 2 則。
- fate.motoway.tw 獎勵廣告換問答額度機制上線 — 天機通書每日 AI 問答調整為 3 次,額度用盡後可觀看完整廣告再加次數(每日最多加 3 次)。採 Google Rewarded Ad 官方機制,廣告失敗時按鈕自動隱藏,不影響原有流程。
- 摩葳零售系統季末庫存逐項根因追查完成 — 15 個品項逐一倒推根因(廠商出貨未建進貨、建單數量有誤、款式分配被改等),逐項補建進退貨紀錄;季驗收報告(24 頁)採程式比對逐列確認,數字不一致時中止產生,確保報告與結帳表完全一致。
- 股票交易系統假日表架構重設計 — 固定假日改以 TWSE API 為主、本機快取為備(抓失敗不覆蓋舊快取);颱風等臨時休市改用開盤後即時成交日探測,不依賴人工維護清單。新增啟動時自動比對 API 與本機快取一致性,不一致即發 WARNING。
- 某製造業客戶施釉日報 VFP 介面修復完成 — 修復 MSSQL View 因 GROUP BY 與 SELECT 表達式不一致造成的分組錯誤,以及 VFP Remote View index key 因欄位型態繼承導致超過 240 bytes 限制的排序失敗問題。LG30I / LG31I 查詢介面完成交付。
- 某製造業客戶生產系統新功能上線 — 新增品檢缺點編輯功能,讓前端作業人員可直接修正已建記錄;烘胚室擴充至四間並改為 2×2 排列,支援跨日裝載批次連結,入室流程消除重複掃描步驟。
- 某零售客戶進貨單品項更正功能上線 — 支援原子式連動更正明細、入庫紀錄與雙向庫存,歷史異動前後庫存數字一併重算;四種攔截條件(已取消、商品重複、庫存不足、套組)保護稽核完整性,每筆更正留操作者與原因紀錄。
- 發票抽獎系統重構為四分頁單頁架構 — 登錄、查詢、辦法、獎項整合至單一頁面,切換分頁不重新載入元件,表單填寫進度完整保留;舊路徑全數設置轉址。同步修復獎項名稱重複顯示問題,後台補充說明文案防止再犯。
本週技術心得 #
這週最值得提煉的觀察是「沉默的錯誤比崩潰更難對付」。在中小企業 IT 環境裡,最讓人頭痛的問題往往不是系統掛掉——掛掉至少你知道出事了。更危險的是那些讓系統繼續跑、卻讓輸出數字悄悄偏離現實的問題:回測損益因口數算錯而虛高、BMS 因幀未驗證而寫入假異常、電費帳單因時間基準不一致而漏算歷史用電、假日表因優先序設計不當讓錯誤手填資料蓋掉正確 API 資料。它們的共同特徵是「靜悄悄地接受了錯誤的輸入,然後產出看起來合理的輸出」。對抗這類問題的有效做法,不是等問題被發現再修,而是在設計階段就內建「讓錯誤顯現」的機制:驗證放在通訊層而非業務邏輯層、回測用已知正確基準值做 regression check、資料層新增一致性比對告警。對資源有限的中小企業 IT 團隊而言,「在源頭設計防禦」比「事後建立觀測體系」更務實,成本也更低。
本文是 3Q 工程團隊的每週技術進度整理,由 Claude 協助編寫。內容聚焦技術類型與通用心得,不含客戶資訊。
