簡短回答
三句話講完:
- 流式還是非流式,完全由你的程式碼決定——請求體裡的
stream引數。同一個 Key、同一個模型、同一個端點,一會流式一會非流式,一定是客戶端程式碼(或你用的 SDK / 上層框架)在切換,閘道不會隨機改。 - 兩者拿到的最終內容一致、計費口徑也完全一致。差別只在「什麼時候拿到」和「怎麼解析」。
- 怎麼選:有人盯著螢幕等輸出 → 流式;程式自己吃結果(解析 JSON、批處理、工具呼叫)→ 非流式。
一張表看清差別
為什麼我的請求一會流式一會非流式?
這是最常見的疑問,答案是:在你自己這一側被改掉了。按下面幾條從上到下排查,基本能命中:① 程式碼裡的 stream 是變數或配置項
① 程式碼裡的 stream 是變數或配置項
最典型的情況:
stream=config.get("stream", False)、stream=is_web_request 這類寫法。不同入口走到同一個函式,傳進去的值不一樣,日誌上看就是”一會流式一會非流式”。排查:把實際發出去的請求體打印出來,看 stream 欄位到底是什麼。② 不同 SDK / 框架的預設值不一樣
② 不同 SDK / 框架的預設值不一樣
同一份業務程式碼,換個客戶端就變了:
- 直接用 OpenAI SDK 的
chat.completions.create():預設 非流式 - 用
client.chat.completions.stream()或with_streaming_response:流式 - LangChain / LlamaIndex 之類的封裝:是否流式取決於你調的是
invoke還是stream,以及構造模型物件時有沒有傳streaming=True - 各類桌面客戶端、Agent 工具、工作流平臺:一般在設定裡有「流式輸出」開關,預設值各不相同
③ 同一個 Key 被多個應用共用
③ 同一個 Key 被多個應用共用
一個 Key 同時給「網頁聊天介面」和「後臺定時任務」用,前者流式、後者非流式,日誌混在一起看就像是隨機的。排查:給不同用途建不同的令牌,日誌一眼就分得開。做法見 令牌管理。
④ 中間層代理把流式「壓平」了
④ 中間層代理把流式「壓平」了
你確實發了
stream: true,但請求經過 Nginx、企業閘道、某些代理軟體時被緩衝了——服務端是一塊塊發的,代理攢夠了才一次性給你,體感上就變成了非流式。排查:繞過代理直連測一次;Nginx 側關掉緩衝(proxy_buffering off;)。注意這種情況下控制台日誌的 is_stream 仍然是 true,因為閘道這邊確實是流式發出去的。怎麼選:按場景對號入座
用流式
- 聊天介面、客服機器人——使用者需要立刻看到反應
- IDE 外掛 / 程式設計助手(Claude Code、Cursor 等)
- 長文本生成(萬字文章、長翻譯、大段程式碼)
- 推理型模型的長任務——至少能看到進度,不至於”完全沒動靜”
- 需要中途打斷(使用者點「停止」)的場景
用非流式
- 結構化輸出:要拿完整 JSON 去
json.loads() - Function Calling / 工具呼叫的引數解析
- 批處理、離線跑批、定時任務
- 只要最終結果、沒有人在等的後臺流程
- 快速驗證、除錯、寫測試用例
接入複雜度對比:同一件事的兩種寫法
- Python 非流式
- Python 流式
- Node.js 流式
- cURL 對照
Claude 原生格式(
/v1/messages)的流式協議不一樣:它用的是 Anthropic 的具名事件 SSE(message_start / content_block_delta / message_delta 等),不是 OpenAI 那種統一的 data: chunk,usage 也分散在 message_start 和 message_delta 兩個事件裡。完整解析方法見 Claude 原生格式:流式與非流式響應。計費與用量:兩者完全一樣
關於usage 的兩個坑:
- 流式預設不返回 usage。OpenAI 相容端點要顯式傳
stream_options: {"include_usage": true},用量會出現在最後一個 chunk 裡(那個 chunk 的choices是空陣列,解析時要先判空)。本站多個模型已實測可用。 - 不要用 API 回顯的 usage 去核對賬單,尤其是快取相關欄位。回顯值和實際計費不總是一致,快取是否命中以控制台日誌的「快取計費詳情」為準。詳見 快取計費說明。
六個常見誤區
誤區①:開了流式就不會超時了
誤區①:開了流式就不會超時了
不成立。 流式只是讓”第一個 token”來得早,它不縮短總生成時間,也不保證中途一直有資料。推理型模型(
gemini-3.1-pro-preview、gpt-5.6-sol、gpt-5.5-pro 等)在思考階段可能長時間不吐任何 token,客戶端的 read timeout 一樣會被觸發。正確做法是按場景分檔設定 timeout,見 如何避免介面超時。誤區②:流式比非流式快
誤區②:流式比非流式快
快的是首位元組,不是總耗時。 同一個模型、同一段提示詞,流式和非流式跑完的總時間基本一致。流式的價值是體感:使用者 1 秒就看到有東西在動,而不是盯著轉圈等 30 秒。如果沒人在看螢幕,這份價值等於零。
誤區③:流式更省錢 / 只按實際收到的部分計費
誤區③:流式更省錢 / 只按實際收到的部分計費
不是。 見上方「計費與用量」一節:計費口徑完全相同,中途斷開也照常扣費。
誤區④:所有模型和端點都支援流式
誤區④:所有模型和端點都支援流式
不是。 文本對話類模型基本都支援;圖片生成、Embedding、Rerank 這類端點沒有流式概念,傳
stream 要麼被忽略要麼直接報錯。個別模型對流式下的某些引數組合有額外限制,不確定時先用非流式跑通,再加 stream: true。誤區⑤:非流式一定更穩
誤區⑤:非流式一定更穩
各有各的坑。
- 非流式的風險:整段生成期間連線是”靜默”的,中間的代理、CDN、企業閘道容易按空閒超時把連線掐掉。另外響應體很大時(出圖返回 base64 動輒十幾 MB)還可能遇到收尾卡住,見 請求收尾卡住 和 日誌顯示已完成卻收不到響應。
- 流式的風險:對不支援 SSE 或強制緩衝的中間層不友好;客戶端解析邏輯更復雜,容易漏掉邊界情況。
api-cf.apiyi.com(CDN 節點)有約 100 秒的請求上限,流式和非流式都受影響,長請求請改用 api.apiyi.com 或 vip.apiyi.com,見 Base URL 配置指南。誤區⑥:流式響應裡拿不到完整答案
誤區⑥:流式響應裡拿不到完整答案
能拿到,只是要自己拼。 把每個 chunk 的
delta.content 按順序累加起來,就是非流式那個 message.content。如果你發現拼出來的內容不完整,先查這三點:是否漏處理了 finish_reason、是否在收到 data: [DONE] 前就退出了迴圈、是否被中間層截斷。流式接不通?按這四步查
1
確認請求體真的帶了 stream: true
列印實際發出的 JSON。用了封裝庫時,“你以為傳了”和”真的傳了”經常不是一回事。
2
用 curl -N 直連測一次
繞開你自己的程式碼和代理,直接用上面「cURL 對照」裡的命令跑。如果 curl 能看到一塊塊吐出來,說明服務端側沒問題,問題在客戶端或中間層。
3
檢查中間層緩衝
Nginx 加
proxy_buffering off;;企業閘道 / 安全裝置可能對 text/event-stream 做整包掃描,需要聯絡網路管理員放行。4
核對解析邏輯
按行讀 SSE,跳過空行和
: 開頭的註釋行,遇到 data: [DONE] 結束;最後一個帶 usage 的 chunk 裡 choices 是空陣列,別在這裡下標越界。相關文件
如何避免介面超時
分場景的 timeout 推薦值,以及流式為什麼救不了超時
Base URL 配置指南
各介面地址的差異,CDN 節點的 100 秒限制
日誌顯示已完成卻收不到響應
非流式大響應的經典問題,含分段計時方法
Claude 流式與非流式響應
Anthropic 原生格式的具名事件 SSE 協議解析
文本生成介面說明
完整引數列表與呼叫示例
日誌計費明細怎麼看
控制台日誌各欄位含義,含 is_stream