Responses API 與 Chat Completions 的選擇問題,本質上在於「誰擁有對話狀態」,而非哪個端點看起來比較新。Chat Completions 要求您的編排器(orchestrator)在每一輪對話中重新發送整個 messages 陣列;而 Responses 則可以從儲存的 response ID 繼續對話。我們於 2026-10-03 閱讀了 TokenLab 發布的 API 文件及線上模型 API,答案也取決於您的模型支援哪些格式。因此,我們從決策表開始。
| 代理程式需求 | 選擇 | 原因 |
|---|---|---|
| 現有的 OpenAI 相容聊天客戶端,需跨多個模型移植 | Chat Completions (/v1/chat/completions) |
根據 API 格式指南(觀察於 2026-10-03),模型相容性最廣 |
| 從儲存的伺服器端回應繼續對話 | Responses (/v1/responses) |
previous_response_id 和 store 是 Responses 的欄位 |
| 在對話輪次間進行任意歷史編輯、修剪或訊息遮蔽 | Chat Completions | 您擁有完整的 messages 陣列 |
| 背景回應或 Responses 事件 | Responses | 已針對支援這些功能的模型進行記錄 |
| 具備接續功能的持久化 WebSocket 連線 | Responses | wss://api.tokenlab.sh/v1/responses |
| 可移植的 JSON 物件輸出 | Chat Completions | response_format: {"type": "json_object"} |
模型未列出 openai_responses |
Chat Completions,或模型原生格式 | Responses 僅適用於列出該格式的模型 |
| Claude 思考區塊 (thinking blocks)、Claude 工具使用、prompt-cache 欄位 | Anthropic Messages (/v1/messages) |
Chat Completions 不保證這些欄位 |
Gemini contents、檔案、快取內容、Gemini 工具 |
Gemini (/v1beta/models/:model:generateContent) |
請在 Gemini 路由上保留 Gemini 原生欄位 |
重點摘要
- Chat Completions 是客戶端管理的狀態。Responses 可以透過
previous_response_id進行伺服器端參照。 - 工具呼叫(Tool calls)從巢狀的
tool_calls加上role: "tool"訊息,轉變為型別化的function_call和function_call_output項目。 - 串流(Streaming)從
choices[0].delta區塊變更為具名事件,且 Responses 客戶端必須監控response.failed和response.incomplete。 - 格式支援取決於模型。截至 2026-10-03,在我們三個範例模型中,僅
gpt-5.6-terra接受openai_responses。 - 切勿在同一個對話中混合格式。在發送下一個請求前,請先轉換並驗證已儲存的歷史紀錄。
Responses API 與 Chat Completions:相同的任務,兩種請求
以單輪任務為例:用兩句話解釋為什麼天空是藍色的。以下是使用 API 格式指南(觀察於 2026-10-03)中的客戶端設定所進行的 Chat Completions 請求:
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["TOKENLAB_API_KEY"],
base_url="https://api.tokenlab.sh/v1",
)
response = client.chat.completions.create(
model="gpt-5.6-terra",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Explain why the sky is blue in two sentences."},
],
max_tokens=1000,
)
print(response.choices[0].message.content)
以下是相同任務的 Responses 請求:
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["TOKENLAB_API_KEY"],
base_url="https://api.tokenlab.sh/v1",
)
response = client.responses.create(
model="gpt-5.6-terra",
instructions="You are a helpful assistant.",
input="Explain why the sky is blue in two sentences.",
max_output_tokens=1000,
)
print(response.output_text)
在這個簡單案例中,欄位是一對一對應的。系統訊息變成了頂層的 instructions。messages 變成了 input,它接受字串或項目陣列。max_tokens 變成了 max_output_tokens。
回應主體(Response bodies)的差異較大。Chat Completions 回傳 choices[0].message 和 finish_reason。Responses 回傳一個型別化的 output 陣列和一個 status 欄位。Create Response 參考文件(觀察於 2026-10-03)列出了 queued、in_progress、completed、incomplete、failed 和 cancelled,並建議即使 HTTP 請求成功,也應檢查 status。使用量(Usage)鍵值也不同:一邊是 prompt_tokens 和 completion_tokens,另一邊是 input_tokens 和 output_tokens。參考範例分別顯示 20/9/29 和 10/12/22。這些是範例負載,而非實際測量值。
繼續對話
想像一個支援代理程式剛回答完一個問題,現在收到「那訂單 #4472 呢?」。使用 Chat Completions 時,您需要將新的使用者訊息附加到儲存的陣列中並重新發送所有內容。使用 Responses 時,您只需傳入前一個回應的 id 並發送新的輪次:
{
"model": "gpt-5.6-terra",
"previous_response_id": "resp_abc123",
"input": "What about order #4472?"
}
store 預設為 true,因此除非您將其關閉,否則前一個回應會被保留以供後續檢索。您的應用程式仍需在各個請求間持久化儲存回傳的 id。如果您需要自訂修剪或訊息遮蔽,無狀態格式(stateless format)會更為合適。
粗略估算顯示了為什麼無狀態重新發送在代理程式規模下很重要。假設每次 20 次呼叫中都重新發送 10,000 個 token 的歷史紀錄。這就是 200,000 個輸入 token。以 gpt-5.6-terra 每 100 萬個 token 0.60 美元的輸入價格計算,總計為 200,000 × 0.60 / 1,000,000 = 0.12 美元(估算值;假設 token 數量,無快取)。該價格來自 線上模型 API,觀察於 2026-10-03,價格更新於 2026-10-02T16:53:30.068Z。
有兩個注意事項。我們閱讀的文件並未說明伺服器持有的上下文是否計入輸入 token,因此請自行比較流量中的 usage。此外,超過 272K 輸入 token 的請求,其完整請求價格為輸入 2 倍、輸出 1.5 倍:每 100 萬個 token 分別為 1.20 美元和 5.40 美元,而非 0.60 美元和 3.60 美元。長篇的無狀態歷史紀錄可能會超過該門檻。
工具呼叫:請求與回應形狀
兩種格式都遵循 Structured Outputs & Tool Calling 指南(觀察於 2026-10-03)中的迴圈。發送工具、讀取呼叫、在您自己的後端執行它、以相同格式回傳結果,並重複此過程直到獲得最終答案。它們的形狀有所不同。
Chat Completions。 工具宣告為 {"type": "function", "function": {...}}。模型以 choices[0].message 上的 tool_calls 回應,且 finish_reason 為 tool_calls。若要繼續,您需重新發送整個陣列,包括帶有 tool_calls 的助理訊息,以及帶有 tool_call_id 的 role: "tool" 訊息。以下數值僅供說明;lookup_customer 是指南中使用的工具名稱:
{
"model": "gpt-5.6-terra",
"messages": [
{"role": "user", "content": "Look up ana@example.com"},
{
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_xyz789",
"type": "function",
"function": {"name": "lookup_customer", "arguments": "{\"email\": \"ana@example.com\"}"}
}
]
},
{"role": "tool", "tool_call_id": "call_xyz789", "content": "{\"status\": \"active\"}"}
]
}
Responses。 模型在 output 內以 function_call 項目回應,每個項目帶有 call_id、name 和 arguments。您將結果作為 function_call_output 輸入項目回傳,並指向前一個回應:
{
"model": "gpt-5.6-terra",
"previous_response_id": "resp_abc123",
"input": [
{
"type": "function_call_output",
"call_id": "call_xyz789",
"output": "{\"status\": \"shipped\", \"tracking_number\": \"1Z999\"}"
}
]
}
您永遠不需要重建中間的助理工具訊息。parallel_tool_calls 在兩種格式中都存在。在 Create Response 參考文件中,它預設為 true。Chat 參考文件列出它時未提供預設值,並表示它適用於「選定模型支援時」。
我們發現了一個缺口。我們閱讀的頁面僅以一般術語描述 Responses 的 tools 和 tool_choice。在移植工具架構(tool schemas)之前,請閱讀 Create Response 參考文件中的工具定義形狀,並在您的目標模型上進行測試。同時請遵守指南中的這些規則:
- TokenLab 不會在格式之間轉換內建工具。
- 在執行任何副作用前,請先驗證工具參數。
- 使工具執行具備冪等性(idempotent),因為客戶端重試可能會重複相同的呼叫。
- 套用您自己的權限檢查。
串流:客戶端必須處理的事件
Chat Completions 串流 SSE 區塊。您的客戶端讀取 choices[0].delta.content,記錄 finish_reason,並跳過沒有 choices 的區塊。使用 stream_options={"include_usage": True} 時,使用量資訊會出現在此類區塊中。Streaming 指南(觀察於 2026-10-03)將 stop 視為完成,length 視為 token 限制,tool_calls 視為執行工具的請求。
Responses 串流具名事件。指南中的消費者處理以下事件:
response.output_text.delta:用於附加文字response.completed:成功標記response.failed、response.incomplete和error:終端問題
import os
from openai import OpenAI
with OpenAI(
api_key=os.environ["TOKENLAB_API_KEY"],
base_url="https://api.tokenlab.sh/v1",
timeout=30.0,
max_retries=0,
) as client:
completed = False
with client.responses.create(
model="gpt-5.6-terra",
input="Write a short poem.",
stream=True,
) as stream:
for event in stream:
if event.type == "response.output_text.delta":
print(event.delta, end="", flush=True)
elif event.type == "response.completed":
completed = True
elif event.type in {"response.failed", "response.incomplete", "error"}:
raise RuntimeError(f"Stream ended with {event.type}")
if not completed:
raise RuntimeError("Stream closed before response.completed")
根據指南,客戶端需遵守三項規則:
- 第一個事件抵達後,中斷的串流即為不完整,不會自動重新啟動。如果有所幫助,請保留部分輸出,但不要將其標記為完成。重複的請求可能會有所不同並再次產生費用。
- 使用 SDK 解析 SSE,因為一個網路區塊不一定是一個完整的事件。
- 當使用者停止或中斷連線時,請取消上游串流,並在您的伺服器上保留金鑰。
Responses 還在 wss://api.tokenlab.sh/v1/responses 提供 WebSocket。那裡的回應總是串流傳輸,不支援 background 和 response.cancel,每個連線一次執行一個活動回應,連線最長持續 60 分鐘。事件帶有回應範圍的 sequence_number。名為 error 的串流事件是扁平物件,而連線和協定失敗則使用巢狀的 error 物件,因此請處理這兩種形狀。
發送前檢查模型接受的格式
從模型頁面或 GET /v1/models/{model} 讀取 tokenlab.accepted_request_formats,如 Get a Model 參考文件(觀察於 2026-10-03)所述:
curl "https://api.tokenlab.sh/v1/models/gpt-5.6-terra"
回應包含一個 tokenlab 物件,其中包含 accepted_request_formats、pricing、限制和 lifecycle。這些值對應到端點,如 錯誤指南 所述:openai_chat_completions 對應 /v1/chat/completions,openai_responses 對應 /v1/responses,anthropic_messages 對應 /v1/messages,而 gemini_generate_content 對應 /v1beta/models/{model}:generateContent。接受的格式僅確認端點。個別工具和欄位仍可能因模型而異。
我們於 2026-10-03 針對本文引用的三個模型對照了線上模型 API:
| 模型 | 接受的格式 | 最大輸入 / 輸出 token | 每 100 萬個 token 輸入 / 輸出價格 (USD) | 來源 |
|---|---|---|---|---|
gpt-5.6-terra |
openai_chat_completions, openai_responses |
1,050,000 / 128,000 | 0.60 / 3.60 (輸入最高 272K) | 線上 API |
claude-sonnet-5 |
anthropic_messages, openai_chat_completions |
1,000,000 / 128,000 | 0.90 / 4.50 | 線上 API |
gemini-3.5-flash |
gemini_generate_content, openai_chat_completions |
1,048,576 / 65,536 | 0.75 / 4.50 | 線上 API |
這三個模型皆處於活躍生命週期階段,且無替代模型,價格更新於 2026-10-02T16:53:30.068Z。因此,目前僅 gpt-5.6-terra 接受 Responses 請求。另外兩個模型透過 Chat Completions 或其原生路由運作。在發布前請務必重新檢查,因為生命週期和價格可能會變動。
錯誤處理在這裡也很重要。在 create 呼叫中拼錯模型會回傳 400 model_not_found,並可能包含 did_you_mean。對未知 ID 詢問 GET /v1/models/{model} 會回傳 404 model_not_found。帶有 retryable: false 的 503 all_channels_failed 意味著重複請求將無濟於事。除非您的產品已獲得授權,否則請勿自動切換模型。
遷移檢查清單:Responses API 與 Chat Completions
將代理程式從 Chat Completions 遷移到 Responses 時,請依照此順序進行。
- 確認模型是否列出
openai_responses。 如果沒有,請在此停止。繼續使用 Chat Completions 是受支援的路徑。 - 選擇切換邊界。 在 Responses 上開始新的對話。不要在對話中途切換,因為這兩種格式對狀態和工具呼叫的表示方式不同。
- 謹慎轉換已儲存的歷史紀錄。 如果必須遷移舊的對話串,請在發送下一個請求前,於您的應用程式中轉換並驗證它們。
- 重新命名核心欄位。
messages變為input,系統或開發者訊息變為instructions,max_tokens或max_completion_tokens變為max_output_tokens。 - 重寫工具迴圈。 將
choices[0].message.tool_calls解析替換為function_call項目,並將role: "tool"訊息替換為以call_id為鍵的function_call_output項目。 - 持久化回應 ID。 儲存每個
id以便傳入previous_response_id。預先決定store和保留期限,並檢查 TokenLab 保留已儲存回應的時間,因為我們閱讀的頁面並未說明。 - 重寫串流消費者。 處理
response.output_text.delta、response.completed、response.failed、response.incomplete和error。將沒有response.completed的關閉串流視為失敗。 - 檢查
status。 HTTP 成功仍可能帶有incomplete或failed。 - 審核可能無法攜帶的參數。 Create Response 頁面列出了
temperature、top_p、tools、parallel_tool_calls、reasoning和text。它未列出n、logprobs、logit_bias、frequency_penalty、presence_penalty、seed、top_k、stop、user或stream_options。在依賴它們之前,請在您的模型上驗證每一個參數。TokenLab 可能會傳遞未知欄位,但這並不代表模型接受它們。 - 對應 JSON 輸出。 Chat 使用
response_format。Responses 使用text物件,且text.format的支援取決於模型。 - 規劃缺少端點的情況。 目前尚無 Cancel、input-items 和 input-tokens 端點。刪除已儲存的回應不會取消生成。
- 關閉重試進行重播測試。 保持
max_retries=0,並在您自己的程式碼中決定何時重試是安全的。逾時的生成不應自動重播。
常見問題
我可以發送 Responses 請求給 Claude Sonnet 5 或 Gemini 3.5 Flash 嗎?
根據 2026-10-03 的線上模型 API,不行。claude-sonnet-5 列出 anthropic_messages 和 openai_chat_completions。gemini-3.5-flash 列出 gemini_generate_content 和 openai_chat_completions。請使用 Chat Completions 或原生路由,並在發布前再次檢查 accepted_request_formats。
當我使用 previous_response_id 時,我是否停止為之前的輪次付費?
我們閱讀的頁面並未說明。它們記錄了伺服器可以從儲存的回應繼續,但未說明如何計費已還原的上下文。在規劃節省成本前,請執行幾次多輪呼叫,並將 usage 欄位與您的無狀態基準進行比較。
我可以在對話中途切換格式嗎?
不行。TokenLab 的指南建議每個對話保持一種格式,因為每種格式對狀態和工具呼叫的表示方式不同。如果您必須遷移已儲存的歷史紀錄,請在發送下一個請求前,於您的應用程式中轉換並驗證它。
我該如何取消正在執行的 Responses 請求?
目前尚無取消端點。刪除已儲存的回應不會取消生成,且 WebSocket 回應不支援 response.cancel。對於串流,當使用者停止或中斷連線時,請從您的伺服器關閉上游串流。
在更改端點之前,請開啟 TokenLab 模型目錄 並確認您代理程式所呼叫之確切模型的 accepted_request_formats。
來源
價格觀測於 2026-10-03
- TokenLab Docs: API formats觀測於 2026-10-03
- TokenLab Docs: Create Response觀測於 2026-10-03
- TokenLab Docs: Create Chat Completion觀測於 2026-10-03
- TokenLab Docs: Structured Outputs & Tool Calling觀測於 2026-10-03
- TokenLab Docs: Streaming觀測於 2026-10-03
- TokenLab Docs: Errors agents can act on觀測於 2026-10-03
- TokenLab Docs: Migration Guides觀測於 2026-10-03
- TokenLab Docs: Get a Model觀測於 2026-10-03
