Jacky.Cheung
October 17, 2026Programming

花俏的展示品:評「香港智慧城市交通情報網」

「香港智慧城市交通情報網」(HK Traffic Intelligence)是一個賣相討好、能夠順利上線的展示品,但稱不上是工程典範,日常實用價值亦有限。以此作為招牌開辦「Agentic Engineering」課程,難免有點名不副實。

項目背景

這是 Keith Li 以 AI 輔助開發的開源網站,部署於 Cloudflare Workers。它將港鐵、輕鐵、九巴、城巴、專線小巴、新大嶼山巴士、渡輪、過海隧道行車時間、主幹道車速、口岸輪候時間及天文台警告,全部疊加在同一張地圖上。README 寫明,此項目是為 Agentic Engineer 課程、公開講座及客席教學而設。

本文的分析基於直接審視 GitHub 源碼,並在本機執行項目自帶的測試。全個項目約 2.8 萬行 TypeScript,設有 24 個 API 路由,接入約 20 個數據源。下文提及的問題均附有檔案路徑,讀者可自行核對。

值得肯定之處

先說公道話:這個項目比坊間大部分「AI 生成玩具」好得多。

  • 數據整合細緻。 作者熟悉各個政府部門及營運商數據源的格式與更新頻率,並據此設定相應的緩存時間(TTL)。
  • 後端代理架構合理。 src/lib/upstream.ts 採用了記憶體加 Cloudflare Cache API 的雙層緩存,同一 URL 的並發請求只會向上游發送一次;當上游故障時,亦懂得退回上一份成功抓取的數據(graceful fallback)。
  • 具備真正的領域邏輯(Domain Logic)。 港鐵官方 API 只提供「幾分鐘後到站」,mtr-estimate.ts 據此反推列車位置:以球面距離計算站距,按市區及郊區路段套用不同車速,更處理了停站時間及東鐵綫馬場支線的分流。代碼註釋清楚交代了背後的推算邏輯,質素不俗。
  • 類型紀律嚴格。 全個項目沒有出現過一處 any、@ts-ignore 或 eslint-disable。
  • 具備單元測試。 共有 79 個測試檔案。在未安裝第三方依賴的情況下直接用 Node 執行,有 74 個通過,其餘 5 個僅因缺少套件而失敗。
  • 兼顧安全與無障礙體驗。 街景閉路電視代理(CCTV Proxy)用嚴格的正則表達式將目標網址限制於 tdcctv.data.one.gov.hk,有效防止 SSRF 攻擊。前端介面有 73 處 aria-* 和 role 屬性,亦支援系統的「減少動態效果」(reduced motion)設定。

由此可見,作者懂得為 AI 訂立開發規範,而非放任它胡亂生成代碼。項目有 151 條更新日誌,足見其執行力相當強。

重複造輪子,也重複自己

項目最明顯的弱點,在於 AI 習慣每次都在當前檔案「就地解決問題」,而開發者沒有做好把關與重構。問題主要分兩類:重新發明外部已有的成熟套件,以及在項目內重複編寫相同的邏輯。

問題檔案位置評價
手寫 PNG 編解碼(含濾波、CRC32)src/lib/terrain-tile.ts(306 行)package.json 已安裝 pngjs,全項目卻從未 import,是最說不過去的一項。
用正則表達式解析 XMLapi/traffic/route.ts、journey-times.ts、incidents.ts、speed-cam.ts上游一旦調換欄位次序或加入屬性,就會無聲無息地解析失敗。
自寫前端輪詢與緩存 Hookcomponents/use-live-json.ts重新實作了 SWR 或 TanStack Query 的基本功能。
並發限流寫了兩套polite-fetch.ts、pool.ts兩者功能重疊,且均依賴每 20 毫秒輪詢(polling)一次來等待。
球面距離公式寫了至少 3 次mtr-estimate.ts、corridors.ts、ev-chargers.ts另有 4 至 5 個近似版本,換算常數一時用 111,000,一時用 111,320。
同一段 User-Agent 字串複製約 10 次kmb-routes.ts、mtr-feed.ts 等連作者個人網域也寫死(hardcode)在內,別人 fork 後仍會以他的名義發送請求。

平心而論,Cloudflare Workers 對打包體積(bundle size)非常敏感,手寫一個 54 行的輕量 CSV 解析器尚算合理;但手寫 PNG 編解碼器、將同一條數學公式複製貼上多次,就無法以此作解釋了。此外,項目從 npm 安裝了一個名為 cn 的套件,而非按 shadcn 慣例在本地建立工具函數(utility function),建議核實該套件的安全性與來源。

工程短板

這個項目處於「做得出來,卻管不住」的狀態:系統能夠運行,但出事時無人知曉,其他人亦難以接手維護。

靜默吞掉錯誤,關閉可觀測性。 項目有 60 處完全不記錄錯誤的空白 catch {},cloudflare.config.ts 中的 observability.enabled 被設為 false,亦無接入任何錯誤追蹤服務。對於一個依賴 20 個外部數據源的系統而言,只要上游稍微更改格式,前端頁面就會靜悄悄地少了一層數據,維護者卻毫不知情。

訪客計數存在競態條件(Race Condition)。 src/lib/visits.ts 每次在用戶打開頁面時,都會讀取 Cloudflare KV 的同一個 key,加 1 後再寫回。只要有兩個人同時打開頁面,其中一次計數就會被覆蓋。況且 KV 本身屬於最終一致性(eventually consistent)儲存,同一 key 每秒寫入上限為一次,根本不適合用作即時去重計數器。諷刺的是,同一段代碼同時將紀錄寫入了 Analytics Engine,那邊的統計方式反而是準確的。

README 誇大緩存效果。 README 宣稱「全城共用一份緩存」。但實際上,記憶體緩存和請求合併(request coalescing)只在單一 Worker 實例(isolate)內有效,而 Cache API 亦僅在單一數據中心內共享。當緩存過期時,多個實例仍有機會同時向政府伺服器發起請求。

環境無法重現,缺乏 CI/CD。 package.json 引用的部署腳本,以及負責生成 data/ 目錄下約 4.4MB 靜態數據的 build-*.mjs,通通被 .gitignore 排除在外。其他人 clone 專案後,根本無法重新生成路線和站點數據。項目既沒有定義 npm test 指令,也沒有設置任何 CI 流程。

巨型組件與前端測試缺位。 city-map.tsx 長達 1,534 行,單一組件內塞入了約 60 個 React Hook;map-draw.ts、ops-hud.tsx、map-cards.ts 亦各自超過一千行。現有的測試幾乎全數集中在 lib/ 目錄,最核心的地圖互動前端反而毫無測試保護。

依賴版本過於激進。 項目採用了 vinext 1.0、Vite 8,以及尚處於 beta 階段的 Cloudflare Vite 插件。在只有一位維護者的情況下,這類前沿依賴會帶來頗高的長期維護風險。

部分數據源不合規或不穩定。 主幹道飽和度直接調用了香港出行易(HKeMobility)網站內部的 WFS 接口,並非官方正式開放的 API;富裕小輪的船期表被直接寫死在代碼中;衛星底圖則直接調用 Esri 的公開圖磚端點(tile endpoint),並未使用 API key,在服務條款上屬於灰色地帶。

實用價值何在?

對日常出行的市民來說,這個網站很難取代現有工具。一般人關心的是「由 A 去 B 怎樣搭車最快」,而 README 已表明系統不設路線規劃功能。

出行需求現有主流工具
點對點路線規劃Google Maps、Citymapper、香港出行易(HKeMobility)
巴士到站時間hkbus.app、App1933、城巴 App
港鐵班次與車務MTR Mobile
陸路口岸過關入境處網頁或 App
隧道行車時間、路況快拍香港出行易(HKeMobility)

網站的數據幾乎全數取自上述機構的開放數據,只是將它們重新包裝、放到同一張地圖上。

視覺上的花俏成分亦不少。列車在路軌上移動、渡輪沿航道滑行、衛星底圖配搭 3D 地形,無疑營造出滿滿的「控制中心」科技感。但既然列車位置只是靠到站時間反推算出來,看著「列車在兩站之間移動」,資訊量其實與「3 分鐘後到站」完全一樣。況且將二十多個圖層疊加在一起,在手機細小的屏幕上操作也相當吃力。

當然,它仍能應付幾個小眾場景:例如司機想在同一個畫面上比較三條過海隧道的車流;跨境旅客想同時查看口岸輪候時間與連接路的車速;又或者在打風日子,市民想一眼睇晒全港海陸交通概況。不過,這些需求大部分其實已被官方工具覆蓋。

公道點說,這個項目本來就是為了課程和講座而生的。作為技術展示品(Demo),視覺衝擊力確實比日常實用性更重要,而它亦成功吸引了媒體報導。真正的問題在於「智慧城市交通情報網」這個龐大的名字,容易令人誤以為它是一個成熟的民生工具。

以此開班,定位尷尬

作者以這個項目作為生招牌,開辦了「Agentic Coding 精讀班 with Grok & Cursor」。課程定於 2026 年 11 月 21 日舉行,為期一天,學費 HK$4,800(早鳥價 HK$3,840)。學員在堂上會製作一個「教學基礎版」交通網站,而非完整的開源項目。

平心而論,其招生頁面的寫法已比坊間不少「AI 割韭菜課程」克制:它列明學員需具備基本 AI 編程經驗,亦事先聲明需自費訂閱 Cursor,以及免費雲端部署有額度限制。然而,當中的問題依然明顯:

  • 名不副實。 課程與項目均以「Engineering(工程)」掛帥,但這個招牌項目最欠缺的恰恰是軟件工程的核心:審查 AI 產出、代碼重構、系統可觀測性(Observability),以及對數據準確性的要求。
  • 受眾定位極窄。 對編程新手而言,一日內消化這套技術棧門檻太高;對有經驗的開發者來說,一眼就能看出源碼的結構問題,而且 Cursor、GitHub 與 Cloudflare 部署在網上已有大量免費教學。真正能從中受惠的,大概只有「寫過簡單網頁,但從未試過將項目完整部署上線」的一群人。
  • 工具鏈言行不一。 課程主打 Cursor 配搭 Grok,但項目的 .gitignore 卻同時排除了 CLAUDE.md、AGENTS.md 和 .cursor/,反映作者在開發過程中很大機會混用了 Claude Code 等多種工具,並非單靠課堂所教的組合。
  • 資歷背景含糊。 宣傳頁面提及的「逾 30 項 IT 大獎」並未列明具體獎項名稱;所謂的媒體報導多數只是科技網站轉載介紹這個開源項目;頁面上亦未見任何往屆學員的評價或作品。

在決定付費報名前,不妨先向導師查詢三個問題:課堂會否涵蓋代碼審查(Code Review)、重構與自動化測試?如何避免 AI 在開發過程中不斷重複造輪子?能否提供往屆學員的實作成果作參考?

作者的強項在於產品觸覺與執行力:他清楚什麼畫面能吸引眼球,亦懂得指揮 AI 快速將構思轉化為上線產品。但他的弱項同樣明顯,就是傳統軟件工程底子不足:代碼架構失控、對數據一致性缺乏警覺、欠缺系統維運(Operations)意識。若以產品原型(Prototype)的標準衡量,它在香港同類 AI 輔助開發項目中確屬前列;但若以生產環境的工程標準衡量,這只算中規中矩,放在任何有嚴格 Code Review 的工程團隊裡,都會被要求退回重構。

這個項目正好成為當代 AI 輔助開發的絕佳縮影:凡是有「人」定下明確規範的地方(如類型檢查、單元測試、上游限流),AI 都交出了漂亮功課;凡是「人」沒有把關的地方(如邏輯複用、組件拆分、錯誤告警),代碼庫就會迅速失控。

AI 確實很擅長把東西「做出來」,但要把系統「做得好」,始終需要懂工程的人來掌舵。將這個項目當作展示品,它非常稱職;但若將它奉為工程方法論的教材,學員最終學到的,恐怕只是如何指揮 AI 不斷堆砌功能而已。

參考資料