三只貓
Rich Mindset Zone
richmindsetzone.com
← All posts

搶票系統源碼分析:Tickets Hunter 教你 agent 開發 5 個 pattern

我成日覺得,香港程式開發者對「AI agent」呢個詞有個認知陷阱。打開 Medium,你見到的係一堆 flow chart、RAG 架構圖、LangChain 嘅 chain 同 tool 嘅抽象概念——但好少人真係俾一個 production-grade、行咗超過半年、處理過真實流量嘅系統你睇。Tickets Hunter 唔同。呢個 GitHub 上有 500+ stars 嘅 open source 搶票系統,唔單止係一個功能完整嘅多平台自動化工具,佢嘅源碼結構本身就係一本活生生嘅 AI agent design pattern 教科書。

我同 bouob(Tickets Hunter 作者)傾過,個 project 由頭到尾都係用 Claude Code 同 Codex 生成,接近 200 個 commits 無一行人手寫 code。但你以為咁代表 codebase 好亂?錯。正正因為開發過程係人機協作,每一個 pattern 都係被逼出來嘅——唔係理論先行,係為咗解決真實問題而自然演化出嚟。下面呢 5 個 pattern,係我讀完佢哋 source code 之後提煉出嚟,每個都可以直接套落你自己嘅 agent project。

Pattern 1:平台抽象層——用 Strategy Pattern 管好複雜度

Tickets Hunter 支援超過 15 個票務平台:TixCraft、KKTIX、TicketMaster、Cityline、HKTicketing、iBon、年代、TicketPlus……傳統做法係每個平台寫一個獨立 script,結果就係一堆重複嘅 boilerplate、各自為政嘅 error handling,最後變成 maintenance nightmare。

Tickets Hunter 嘅做法係每個平台一個 module,全部都繼承同一個 base class。呢個 base class 定義咗成個 ticket-buying 流程嘅 lifecycle:navigate_to_event()wait_for_tickets()select_seats()add_to_cart()checkout()handle_payment()。每個平台只需要 override 自己唔同嘅部分——比如 TixCraft 嘅 seat selection 同 TicketMaster 嘅完全唔同,但購物車同付款步驟可以重用。

呢種設計喺 agent 開發入面極之重要。你嘅 agent 唔應該係一個 monolithic 嘅「做晒所有嘢」嘅函數。你應該將每個能力(capability)抽象成一個 interface,然後為每個 specific domain 提供 implementation。例如你做一個電商 agent,唔同供應商(Amazon、Shopify、自建網站)各自有唔同嘅 DOM 結構同 API 行為,但你嘅核心 logic——search → compare → add to cart → checkout——係一樣嘅。將呢個 lifecycle 抽象化,係 agent 可以 scale 嘅第一步。

Pattern 2:事件驅動監控——Observer Pattern 係 agent 嘅感官系統

搶票最關鍵嘅唔係執行速度,而係感知能力。你需要知道個網頁「而家發生咩事」:係咪喺排隊?出咗 CAPTCHA?票已經賣完?定係 Cloudflare 嘅 Turnstile 彈咗出嚟?

Tickets Hunter 用咗一個好聰明嘅事件架構。佢唔係用 polling 不斷 check 狀態,而係用 zendriver(nodriver)嘅 DOM mutation observer,加上自定義嘅 event bus,將所有重要嘅狀態變更以事件方式廣播。例如當頁面出現「已售完」字樣時,selector match 會觸發 TICKET_SOLD_OUT 事件,成個系統會自動切換到下一個目標場次;當 Cloudflare Challenge 彈出時,CF_CHALLENGE_DETECTED 事件會激活專用嘅解題 handler。

呢個 pattern 對任何 agent 系統都係命脈。你嘅 agent 需要一個 sensor layer——唔係齋等 user prompt 先有反應,而係持續監控環境變化。喺 Tickets Hunter 嘅 codebase 入面,呢個 event bus 係用 Python 嘅 asyncio.Event 同 callback registry 實現,簡單但有效。你寫 agent 嘅時候,好應該由第一日就設計一個 event taxonomy:你關心嘅事件有邊幾類?每類事件嘅 handler 應該點樣註冊同取消註冊?呢個諗法唔係 selectors 嘅問題,係 architecture 嘅問題。

Pattern 3:錯誤回饋閉環——Error → Diagnosis → Patch 嘅自癒循環

呢個係 Tickets Hunter 最令我眼前一亮嘅 pattern,亦係成個 project 嘅靈魂。

傳統 software 嘅 debug 流程係:見到 error → 開 IDE → 睇 log → 搵 source code → 寫 fix → deploy。呢個 cycle 嘅 bottleneck 永遠係 developer 嘅 context switch 時間。Tickets Hunter 嘅做法完全唔同:當 error 發生嗰陣,系統會 capture 完整嘅 error context(traceback、DOM snapshot、network request log、browser console output),然後將呢個 context 直接 feed 俾 AI,由 AI 生成 patch。

呢個唔係一個 fancy 嘅自動修復工具——佢係一個工作流程嘅重新設計。你睇返 Tickets Hunter 嘅 git history,會發現大量 commit 嘅 message 結構係:「fix: [platform] [error type] — root cause: [analysis] — resolution: [approach]」。成個 diagnostic 過程都係 AI 做嘅,開發者只不過係做咗 verification gate。

呢個 pattern 你完全可以複製。你唔需要等 AI 識得自動修復先開始——你可以做得簡單好多:喺你嘅 agent 系統入面,每一個 error handler 都唔好剩係 print log,而係將 error context 格式化成一條清晰嘅 prompt,然後 call LLM 做 root cause analysis。然後你嚟決定 apply 唔 apply 個建議。就咁已經可以將你嘅 debug cycle 由幾粒鐘縮短到幾分鐘。

Pattern 4:非同步排程器——用 Task Queue 管理併發複雜性

搶票系統要同時做嘅嘢好多:監控多個場次、輪詢多個平台、處理 CAPTCHA 排隊、保持 WebSocket connection 唔斷。如果每個 task 都係 synchronous blocking,你根本 handle 唔到。

Tickets Hunter 用 asyncio 做底層排程,但佢仲多咗一層自定義嘅 task scheduler,而唔係就咁用 asyncio.gather()。呢個 scheduler 支援 priority queue(某個平台嘅熱門場次優先搶)、rate limiting(避免俾平台 ban IP)、timeout management(一個 task 超過 threshold 就自動 skip 去下一個),同埋 conditional chaining(搶到飛先做付款,否則 release)。

呢個 pattern 對 agent 開發嘅啟示好直接:你的 agent 唔應該一次淨係做一件事。佢應該有能力同時 maintain 多個「context window」——同多個 tool 互動、追蹤多個 sub-task 嘅進度、喺某個 sub-task 失敗時優雅地 fallback。你唔需要用 asyncio 照抄,但你需要思考你嘅 agent 嘅 concurrency model:係 sequential tool calling?係 parallel fan-out?係 pipeline?定係 dynamic DAG?唔同複雜度嘅 task 適合唔同嘅 model,但唔好 default 做 sequential——呢個係最常見嘅 bottleneck。

Pattern 5:自我測試沙箱——用 Headless Browser 做 Integration Test

Tickets Hunter 有一個好特別嘅做法:佢唔係用 unit test 嚟驗證正確性(因為 DOM-based automation 嘅 unit test 意義有限),而係用一套 headless browser 嘅 integration test sandbox。

每個平台嘅 handler 都有對應嘅 test script,會用真實嘅 browser instance 行一次完整嘅購票流程(當然係到付款前停低)。呢啲 test 唔係 mock 晒所有 network call,而係直接同 staging 或者公開嘅 test event 互動。成個 test 嘅 pass/fail 判斷唔係 assert 某個 function return value,而係觀察 DOM 嘅 state transition——「有冇去到下一步」、「error message 有冇出現」、「頁面有冇 crash」。

對 AI agent 開發者嚟講,呢個 pattern 係 gold dust。你嘅 agent 要同真實世界嘅系統互動,mock test 只能幫你到某個程度。你需要一個 sandbox environment,入面有真實嘅 API、真實嘅 browser、真實嘅 database——然後你嘅 agent 喺入面行完整嘅端到端流程。Tickets Hunter 嘅做法證實咗一件事:喺 AI-native 開發模式入面,integration test 嘅重要性遠遠大過 unit test。因為你唔係擔心 logic error,你擔心嘅係 environment 唔似、selector 過期、或者 DOM structure 變咗——呢啲嘢只有真實環境先捉得到。

行動點:由 fork Tickets Hunter 開始

五個 pattern,你可以逐個攞嚟用。但最快嘅學習方法永遠係直接睇 code。去 GitHub fork Tickets Hunter,用你部機行一次,睇下佢點樣 handle Cityline 嘅搶票流程、點樣 detect Cloudflare Challenge、點樣喺 Captcha 出現時 call OCR service。然後問自己一條問題:我下一個 agent project,可以點樣將呢五個 pattern embed 入去?

唔好等睇完所有 documentation 先開始。Tickets Hunter 成個 project 都係由「唔識寫 code」嘅 prompt 開始嘅。你嘅第一行 code 唔重要,你嘅第一個 architecture decision 先重要。