在導入 Claude 3.6 Sonnet 進行自動化長文生成(Article Generation)時,許多開發者都會遇到一個共同的夢魘:「cURL error 28: Operation timed out」

明明 Prompts 都對了,費用也花了,但程式跑了 300 秒後卻回傳一場空。今天我們來拆解這個問題的根因與兩階段解決方案。

一、為什麼 5 分鐘(300s)不夠用?

隨著 AI 模型能力增強,我們對輸出的要求也更高(例如 16,384 tokens、品牌 DNA、SERP 內容分析)。當 Claude 處理複雜任務時,思考與輸出的時間常會突破 5 分鐘。

傳統的「阻塞式請求 (Blocking Request)」 就像在等外送,外送員沒把菜送到你面前,你永遠拿不到資料。而這 300 秒內若沒有任何位元組(0 bytes received)傳輸,中間的網路設備(如 Cloudflare 或 Proxy)就會以為連線已掛斷,直接切斷連線。


二、第一階段:拉長耐性(Timeout 優化)

在不改動架構的前提下,我們首先要「放寬限制」。

  1. 拉長 HTTP Timeout:將原有的 300s 提升至 600s(Anthropic 官方建議的上限)。

  2. 加入 Connect Timeout:設定 connectTimeout(10)。如果連線一開始就失敗(如 DNS 錯誤),10 秒內就該放棄,不要白等 10 分鐘。

  3. 同步調整背景任務 (Queue Job):如果你的 PHP Worker 或 Horizon 設定的超時時間短於 HTTP 請求時間,Job 會被強行 Kill 掉。請確保 Job Timeout 大於 HTTP Timeout 的兩倍。


三、第二階段:終極方案 —— 導入 Streaming (串流模式)

拉長 Timeout 只是治標,Streaming 才是治本

將 API 請求設定為 stream => true,後端改用 SSE (Server-Sent Events) 協定來接收資料。

  • 為什麼 Streaming 能解決超時? 串流模式下,AI 每寫出一個字就會傳回一個數據包(Chunk)。連線始終保持活躍,網路設備就不會判定為「閒置超時」。

  • 後端的挑戰: 你必須撰寫 SSE Parser 來解析每一行的 data: {...},並手動拼接字串,最後在 message_stop 事件中抓取 Token 統計資訊。


四、開發者的告誡:為什麼不直接 Retry?

在處理 AI API 時,「失敗即重試」是危險的。 因為超時往往發生在「回傳階段」,AI 其實已經運算完了。如果直接重試($tries > 1),等於是再付一次錢去跑重複的任務,這在大量產文的情境下會造成巨大的預算浪費。修復 Timeout 邏輯,遠比增加重試次數更重要。