跳轉到主要內容
一句話結論:讓大模型一次產出上萬字(分集大綱、長篇小說、長翻譯、大段程式碼)時,用流式、不要用非流式;客戶端 read timeout 按「兩次資料事件之間的間隔」設(幾十秒即可,建議 90120 秒),不要按「整段生成的總時長」設;max_tokens 給足;拿到響應後先看 stop_reason 再用正文。做到這四點,長文場景就不會「拿不到結果」。輸出超過 23 萬字時,再加一條:拆成多次生成,別讓一次連線跑 20 分鐘。
本頁面向所有大模型通用(OpenAI、Claude、Gemini、Grok 等),程式碼示例以 Claude 原生 /v1/messages 為主,OpenAI 相容格式的差異單獨標註。

三個先知道的事實

  1. 出萬字長文,真實生成 10~20 分鐘是常態。模型要逐 token 產出上萬字,疊加推理/思考階段,端到端耗時本就很長。這不是閘道慢,是生成本身慢。
  2. 非流式要「整段攢齊」才回寫。非流式(stream 不傳或為 false)下,服務端必須等模型把整段生成完,再一次性把響應體回傳給你。這幾分鐘裡你的客戶端 read timeout 一直在和它賽跑,生成越久越容易在拿到結果前先斷開——斷開時異常資訊經常是空的(httpx.ReadError 的 str(e) 為空),看不出病因。
  3. 斷連仍然計費,盲目重試是重複計費。只要服務端已經產出,哪怕最後沒送達你,這次呼叫也照常計費。已經收到部分正文再斷開的情況,重試等於讓模型再跑一遍、再付一次錢。

用流式,不要用非流式

流式(stream: true)下,首位元組幾秒內就到,之後每隔幾十秒必有一個數據事件。你的 read timeout 只需覆蓋「兩次事件之間的間隔」,而不是覆蓋長達十幾分鐘的整段生成——這是流式能穩定拿到長文結果的根本原因。 兩種協議的結束訊號不同,別混用: Claude 原生開啟自適應思考時,會先出一個 type: "thinking" 的思考塊(增量是 thinking_delta),再出 text 正文塊。渲染時把 thinking_delta 和 text_delta 分流即可,思考增量不拼進正文。 Claude 原生 /v1/messages 流式最小可用示例(純 httpx,逐行解析 SSE):
如果你用官方 anthropic SDK,把 base_url 指到 https://api.apiyi.com,再用 client.messages.stream(...).get_final_message() 即可一步到位——SDK 自帶了 SSE 解析、超時處理、stop_reason 判定。上面的 httpx 版本是給不想引 SDK 的場景。

read timeout 按事件間隔設,不是按總時長

很多人把 read timeout 設成一個能兜住整段生成的巨大值(比如 1800 秒),結果照樣超時——因為非流式下這個值要和整段生成競速,稍有波動就斷。正確做法是流式 + 按事件間隔設 read timeout。 實測參考(claude-opus-5 出約 2 萬字分集大綱,輸入約 1.5 萬字符): 所以 read timeout 設 90 ~ 120 秒足以覆蓋最大事件間隔並留餘量,不必設成十幾分鍾。三段式超時把三個階段拆開,各自設值:

各語言客戶端怎麼設

不少客戶端庫同時有「單次讀超時」和「總超時」兩個引數,名字還很像。長文場景要設的是前者,後者不設或設成不限:

流式也會卡住:連線中途停止接收

流式解決了「整段攢齊才回寫」的問題,但還有一種失敗方式要防:連線中途卡住。
  • 現象:開頭正常出字,之後再也收不到資料,連線卻既不報錯也不斷開。客戶端一直掛到自己的超時上限:設的是 1 小時,就整整等 1 小時,最後只拿到開頭一小段。
  • 原因:在跨地域、跨境的網路鏈路上,長時間不斷開的連線可能被中間的網路裝置卡住。服務端早已生成完畢並關閉連線,但關閉訊號沒能傳到你這邊。連線持續越久,越容易遇到:20 分鐘的長連線比 3 分鐘的更容易中招。
  • 計費:服務端照常生成完,照常計費(同「三個先知道的事實」第 3 條)。
應對辦法:
  1. read timeout 按事件間隔設(上一節)。同樣是卡住,讀超時 120 秒只白等 2 分鐘就能報錯重試,讀超時 1 小時就要白等 1 小時。這是最關鍵的一條。
  2. 縮短單次連線:超長輸出拆成多次生成,見下文「超長輸出拆成多次生成」。
  3. 斷流後從斷點續寫,見下文「重試策略」。
別把 read timeout 設成「整段生成時長 + 餘量」(比如 1800 秒、3600 秒)。正常時看不出區別,一旦連線卡住,你就要白等這麼久才知道失敗了。

max_tokens 給足,並檢查 stop_reason

長輸出容易撞到 max_tokens 上限被截斷。尤其是 Claude 這類開了思考的模型,思考本身也佔 max_tokens 預算,一份長文很容易把預算吃滿。
  • max_tokens 建議 64000 起步(開高 effort / 深度思考時更要給足;claude-opus-5 輸出上限 128K)。
  • 拿到響應先看 stop_reason:
    • end_turn——正常結束,正文完整,這才算成功。
    • max_tokens——被截斷,正文可能不完整甚至為空。這是被截斷不是「空結果」,把 max_tokens 調大後重試即可。
    • refusal——被安全策略拒絕,單獨處理。
只用 str(e) 或「正文為空」來判斷成敗會誤導——空正文的真實原因往往是 max_tokens 截斷。

超長輸出拆成多次生成

一次讓模型出 5 萬字、跑 20 分鐘,即使用了流式也是最脆弱的用法:中途任何一次網路波動,整段作廢、整段計費。輸出量超過 2~3 萬字時,建議拆開生成:
  1. 先生成大綱 / 分集列表 / 章節目錄,這是個短請求。
  2. 再按章節或分集逐段生成,每次控制在 1~2 萬字以內。每次請求都帶上大綱和必要的前文資訊(人物設定、上一段結尾),保證前後連貫。
  3. 大綱定下來之後,各段相互獨立,可以並行發出。

重試策略

長文場景的重試要剋制,別讓「失敗重試」變成「重複計費 + 重複長跑」:
  • 只對「拿到響應頭之前的失敗」和 5xx / 429 重試(退避、最多 2 次)。這類是建連/瞬時問題,重試有意義。
  • 已經收到部分正文再斷流的,從斷點續寫,不要從頭重來。服務端已經產出並計費,從頭重試是讓它再跑一遍、再付一次錢。把已收到的正文保留下來,在新請求裡作為已寫內容附上,讓模型接著寫,只為剩下的部分付費。
  • read timeout 觸發(連線卡住)也按斷流處理:已有不少正文就續寫;幾乎沒收到正文,再整段重試。
  • 記錄響應頭裡的 request id,方便對賬和排查。
續寫請求的寫法示例(各家模型通用):

場景速查

單篇超過 3 萬字的,建議按章節或分集拆成多次生成(見「超長輸出拆成多次生成」)。全部走流式;節點用 api.apiyi.com(或備用 b.apiyi.com),不要用 api-cf.apiyi.com(CDN 節點約 100 秒就 524,扛不住長請求)。

相關連結

如何避免介面超時

分場景的 timeout 推薦值

流式 vs 非流式

兩種模式的差異與選型

Claude 思考與 effort

自適應思考、effort 檔位、max_tokens 與截斷

Claude 響應處理

原生響應結構、SSE 事件、stop_reason