我們已針對 Claude 系列模型,對 OpenAI 相容介面進行更深入的最佳化。現在,你可以更精準、更方便地控制思考與快取。多輪對話中的交錯思考也變得更容易使用,無須額外參數即可無縫整合。此外,介面也支援啟用 Anthropic 提供的 Beta 功能。
1. 模型思考(延伸思考)
1.1 交錯思考的優勢
未啟用交錯思考時,模型只會在助理回合開始時思考一次;收到工具結果後,便會直接產生後續回覆,不會再產生新的思考區塊:
User → [Thinking] → Tool Call → Tool Result → Response
啟用交錯思考後,模型每次收到工具結果時都會插入新的思考區塊,形成推理鏈:
User → [Thinking] → Tool Call → Tool Result → [Thinking] → Response
↑ Interleaved Thinking
這讓模型能夠:
- 根據工具結果進行二次推理,而不是單純串接輸出。
- 在多次工具呼叫之間串接推理,每個決策都以先前步驟的分析為依據。
參考資料:Anthropic 交錯式思考
1.2 啟用思考
你可以透過以下四種方式啟用思考,任選一種即可:
| 方式 | 範例 | 說明 |
|---|---|---|
reasoning_effort |
"reasoning_effort": "low" |
OpenAI 標準參數,放在請求本文的頂層 |
reasoning.effort |
"reasoning": {"effort": "low"} |
與前一種方式等效,放在 reasoning 物件內 |
reasoning.max_tokens |
"reasoning": {"max_tokens": 1024} |
精確控制思考的 token 數上限 |
模型名稱加上 -think |
"model": "claude-sonnet-4-5-think" |
最簡單的方式,無須額外參數 |
優先順序(同時使用多種方式時):reasoning_effort>reasoning.max_tokens>reasoning.effort>-think後綴
可用的推理強度值:minimal / low / medium / high / xhigh
1.3 思考內容回傳
回應訊息會包含兩個新欄位:
reasoning_content:思考內容(字串),方便顯示。reasoning_details:思考內容的完整結構化資訊;在多輪對話中必須原樣回傳,不同供應商的內部結構可能有所不同。
非串流範例(省略無關欄位):
{
"choices": [{
"message": {
"role": "assistant",
"content": "Hello! How can I help you today?",
"reasoning_content": "The user is just saying hello...",
"reasoning_details": {
"type": "thinking",
"thinking": "The user is just saying hello...",
"signature": "Er8CCkYI..."
}
}
}]
}
串流回應中,思考內容會透過 delta.reasoning_content 和 delta.reasoning_details 分段傳送。完整的串流串接邏輯請參閱下方完整範例。
1.4 在多輪對話中保留思考內容(交錯思考為內建功能,無須額外參數)
若要讓模型在多輪對話中延續推理能力,只需將先前回傳的 reasoning_details原樣放入下一輪的 assistant 訊息中:
messages = [
{"role": "user", "content": "What's the weather like in Boston?"},
{
"role": "assistant",
"content": response.choices[0].message.content,
"tool_calls": response.choices[0].message.tool_calls,
"reasoning_details": response.choices[0].message.reasoning_details,
},
{
"role": "tool",
"tool_call_id": "toolu_xxx",
"content": '{"temperature": 45, "condition": "rainy"}',
}
]
AIHubMix 偵測到請求中包含歷史思考資訊時,會自動啟用交錯思考,讓模型收到工具呼叫結果後無須額外參數即可繼續深度推理。
1.5 完整範例
以下兩個範例展示完整的多輪 Tool Call + 交錯思考流程:使用者提問 → 模型思考並呼叫工具 → 注入工具結果(保留 reasoning_details)→ 模型透過交錯思考給出最終回覆。
非串流 · 交錯思考
import os
import json
from openai import OpenAI
client = OpenAI(
base_url="https://aihubmix.com/v1",
api_key=os.environ.get("AIHUBMIX_API_KEY", "sk-***"),
)
# ── Tool definition ───────────────────────────────────────────
tools = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get current weather for a location",
"parameters": {
"type": "object",
"properties": {"location": {"type": "string", "description": "City name"}},
"required": ["location"]
}
}
}]
# ── Mock tool execution ───────────────────────────────────────
WEATHER_DB = {
"boston": {"temperature": "45°F (7°C)", "condition": "rainy", "humidity": "85%", "wind": "15 mph NE"},
"tokyo": {"temperature": "72°F (22°C)", "condition": "sunny", "humidity": "45%", "wind": "5 mph S"},
}
def execute_tool(name: str, args: dict) -> str:
if name == "get_weather":
key = next((k for k in WEATHER_DB if k in args.get("location", "").lower()), None)
return json.dumps(WEATHER_DB.get(key, {"temperature": "65°F", "condition": "clear"}))
return "{}"
# ── Multi-turn conversation loop ─────────────────────────────
messages = [
{"role": "user", "content": "What's the weather like in Boston? Then recommend what to wear."}
]
turn = 0
while True:
turn += 1
print(f"\n── Turn {turn} ──")
response = client.chat.completions.create(
model="claude-sonnet-4-5",
messages=messages,
tools=tools,
extra_body={"reasoning": {"max_tokens": 2000}},
)
msg = response.choices[0].message
# Print thinking process
if msg.reasoning_content:
label = "Interleaved Thinking" if turn > 1 else "Thinking"
print(f"[{label}] {msg.reasoning_content}")
# Print response content
if msg.content:
print(f"[Response] {msg.content}")
# Print tool calls
if msg.tool_calls:
for tc in msg.tool_calls:
print(f"[Tool Call: {tc.function.name}] {tc.function.arguments}")
# Build assistant message, preserve reasoning_details (critical!)
assistant_msg = {"role": "assistant", "content": msg.content}
if msg.tool_calls:
assistant_msg["tool_calls"] = msg.tool_calls
if msg.reasoning_details:
assistant_msg["reasoning_details"] = msg.reasoning_details # pass back unmodified
messages.append(assistant_msg)
# No tool_calls means conversation is done
if not msg.tool_calls:
break
# Execute tools and append results to messages
for tc in msg.tool_calls:
args = json.loads(tc.function.arguments)
result = execute_tool(tc.function.name, args)
print(f"[Tool Result: {tc.function.name}] {result}")
messages.append({"role": "tool", "tool_call_id": tc.id, "content": result})
串流 · 交錯思考
import os
import sys
import json
from openai import OpenAI
client = OpenAI(
base_url="https://aihubmix.com/v1",
api_key=os.environ.get("AIHUBMIX_API_KEY", "sk-***"),
)
# ── Tool definition & mock execution ─────────────────────────
tools = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get current weather for a location",
"parameters": {
"type": "object",
"properties": {"location": {"type": "string", "description": "City name"}},
"required": ["location"]
}
}
}]
WEATHER_DB = {
"boston": {"temperature": "45°F (7°C)", "condition": "rainy", "humidity": "85%", "wind": "15 mph NE"},
"tokyo": {"temperature": "72°F (22°C)", "condition": "sunny", "humidity": "45%", "wind": "5 mph S"},
}
def execute_tool(name: str, args: dict) -> str:
if name == "get_weather":
key = next((k for k in WEATHER_DB if k in args.get("location", "").lower()), None)
return json.dumps(WEATHER_DB.get(key, {"temperature": "65°F", "condition": "clear"}))
return "{}"
# ── Stream response collector ────────────────────────────────
def stream_and_collect(turn: int, **kwargs):
"""Stream response, print thinking/content in real-time, accumulate reasoning_details/tool_calls."""
rd = {} # accumulated reasoning_details
content = "" # accumulated response text
tc_map = {} # accumulated tool_calls (by index)
cur = "none" # current output section: none / thinking / content
stream = client.chat.completions.create(stream=True, **kwargs)
for chunk in stream:
if not chunk.choices:
continue
delta = chunk.choices[0].delta
# ── Handle thinking ──
rd_delta = getattr(delta, "reasoning_details", None)
if rd_delta and isinstance(rd_delta, dict):
for k, v in rd_delta.items():
if k == "type":
rd[k] = v
elif isinstance(v, str):
rd[k] = rd.get(k, "") + v
elif v is not None:
rd[k] = v
# Print thinking chunks in real-time
thinking_chunk = rd_delta.get("thinking", "")
if thinking_chunk:
if cur != "thinking":
cur = "thinking"
label = "Interleaved Thinking" if turn > 1 else "Thinking"
sys.stdout.write(f"\n[{label}] ")
sys.stdout.write(thinking_chunk)
sys.stdout.flush()
# ── Handle content ──
if delta.content:
if cur != "content":
if cur == "thinking":
sys.stdout.write("\n")
cur = "content"
sys.stdout.write("\n[Response] ")
sys.stdout.write(delta.content)
sys.stdout.flush()
content += delta.content
# ── Handle tool_calls ──
for tc in delta.tool_calls or []:
i = tc.index
if i not in tc_map:
tc_map[i] = {"id": "", "type": "function",
"function": {"name": "", "arguments": ""}}
if tc.id:
tc_map[i]["id"] = tc.id
if tc.function:
tc_map[i]["function"]["name"] += tc.function.name or ""
tc_map[i]["function"]["arguments"] += tc.function.arguments or ""
# End current output section
if cur in ("thinking", "content"):
sys.stdout.write("\n")
tool_calls = [tc_map[i] for i in sorted(tc_map)] if tc_map else None
return {
"content": content or None,
"reasoning_details": rd or None,
"tool_calls": tool_calls,
}
# ── Multi-turn conversation loop ─────────────────────────────
messages = [
{"role": "user", "content": "What's the weather like in Boston? Then recommend what to wear."}
]
turn = 0
while True:
turn += 1
print(f"\n── Turn {turn} ──")
result = stream_and_collect(
turn,
model="claude-sonnet-4-5",
messages=messages,
tools=tools,
extra_body={"reasoning": {"max_tokens": 2000}},
)
# Print tool calls
if result["tool_calls"]:
for tc in result["tool_calls"]:
print(f"[Tool Call: {tc['function']['name']}] {tc['function']['arguments']}")
# Build assistant message, preserve reasoning_details (critical!)
assistant_msg = {"role": "assistant", "content": result["content"]}
if result["tool_calls"]:
assistant_msg["tool_calls"] = result["tool_calls"]
if result["reasoning_details"]:
assistant_msg["reasoning_details"] = result["reasoning_details"] # pass back unmodified
messages.append(assistant_msg)
# No tool_calls means conversation is done
if not result["tool_calls"]:
break
# Execute tools and append results to messages
for tc in result["tool_calls"]:
args = json.loads(tc["function"]["arguments"])
tool_result = execute_tool(tc["function"]["name"], args)
print(f"[Tool Result: {tc['function']['name']}] {tool_result}")
messages.append({"role": "tool", "tool_call_id": tc["id"], "content": tool_result})
1.6 思考強度對應規則
推理強度模式:
- Opus 4.6 / Sonnet 4.6 及以上版本:對應至 Anthropic 原生的 Adaptive Thinking 推理強度。
- 其他模型:使用
budget_tokens公式計算:
budget_tokens = max(min(max_tokens × effort_ratio, 128000), 1024)
| 推理強度 | 推理強度比例 |
|---|---|
| xhigh | 0.95 |
| high | 0.80 |
| medium | 0.50 |
| low | 0.20 |
| minimal | 0.10 |
Adaptive Thinking 推理強度對應:
| 傳入的推理強度 | Opus 4.6 | Sonnet 4.6 |
|---|---|---|
| xhigh | max | high |
| high | high | high |
| medium | medium | medium |
| low | low | low |
| minimal | low | low |
max_tokens 模式:直接指定為 Anthropic 的 budget_tokens。
-think 後綴:Opus/Sonnet 4.6+ 使用 adaptive thinking(effort=medium);其他模型則設定 budget_tokens = min(10240, max_tokens - 1),max_tokens 預設為 4096。
2. 提示詞快取
透過 Chat 介面向 Claude 模型發出請求時,可以使用提示詞快取。在訊息中設定 cache_control 快取斷點,即可快取大型文字區塊(例如角色卡、RAG 資料、書籍章節等)以供重複使用,讓後續請求直接命中快取,大幅降低成本。
Claude 官方文件:提示詞快取
2.1 快取費用
| 操作 | 價格倍率(相對於原始輸入價格) |
|---|---|
| 寫入快取(5 分鐘 TTL) | 1.25x |
| 寫入快取(1 小時 TTL) | 2x |
| 讀取快取 | 0.1x |
2.2 支援的模型與快取長度下限
| 模型 | 快取 token 數下限 |
|---|---|
| Claude Opus 4.8 | 1024 |
| Claude Opus 4.7 | 2048 |
| Claude Opus 4.6 / Opus 4.5 | 4096 |
| Claude Sonnet 4.6 / Sonnet 4.5 / Opus 4.1 / Opus 4 / Sonnet 4 / Sonnet 3.7(已棄用) | 1024 |
| Claude Haiku 4.5 | 4096 |
| Claude Haiku 3.5(已棄用)/ Haiku 3 | 2048 |
斷點數量限制:每個請求最多可設定 4 個 cache_control 斷點。2.3 快取 TTL
| TTL | 語法 | 適用情境 |
|---|---|---|
| 5 分鐘(預設) | "cache_control": {"type": "ephemeral"} |
短時間工作階段、一般請求 |
| 1 小時 | "cache_control": {"type": "ephemeral", "ttl": "1h"} |
長時間工作階段,避免重複寫入快取 |
1 小時 TTL 的寫入成本較高,但在長時間工作階段中,減少重複寫入即可節省整體費用。所有供應商(包括 Anthropic、Amazon Bedrock、Google Vertex AI)提供的 Claude 4.5 及後續版本模型,皆支援 1 小時 TTL。
2.4 使用方式
你可以在 system、user(包括圖片)和 tools 中使用 cache_control 欄位設定快取斷點。以下範例僅展示關鍵結構,省略大型文字區塊。
System 訊息快取(預設 5 分鐘 TTL):
{
"model": "claude-opus-4-5",
"messages": [
{
"role": "system",
"content": [
{"type": "text", "text": "You are an AI assistant"},
{
"type": "text",
"text": "(long context)",
"cache_control": {"type": "ephemeral"}
}
]
},
{
"role": "user",
"content": [{"type": "text", "text": "Hello"}]
}
]
}
User 訊息快取(1 小時 TTL):
{
"model": "claude-opus-4-5",
"messages": [
{
"role": "system",
"content": [{"type": "text", "text": "You are an AI assistant"}]
},
{
"role": "user",
"content": [
{
"type": "text",
"text": "(long context)",
"cache_control": {"type": "ephemeral", "ttl": "1h"}
},
{"type": "text", "text": "Hello"}
]
}
]
}
圖片訊息快取:
{
"role": "user",
"content": [
{
"type": "image_url",
"image_url": {"detail": "auto", "url": "data:image/jpeg;base64,/9j/4AAQ..."},
"cache_control": {"type": "ephemeral"}
},
{"type": "text", "text": "What's this?"}
]
}
工具定義快取:
cache_control 放在工具物件的頂層(與 type 和 function 同一層):
{
"tools": [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get current weather for a location",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"]
}
},
"cache_control": {"type": "ephemeral", "ttl": "1h"}
}]
}
2.5 查看快取狀態
回應中的 usage 會回傳 claude_cache_tokens_details,記錄快取的詳細資訊:
首次請求(建立快取):
{
"usage": {
"prompt_tokens": 22,
"completion_tokens": 890,
"total_tokens": 912,
"claude_cache_tokens_details": {
"cache_creation_input_tokens": 6266,
"cache_read_input_tokens": 0,
"cache_write_5_minutes_input_tokens": 6266,
"cache_write_1_hour_input_tokens": 0
}
}
}
後續請求(快取命中):
{
"usage": {
"prompt_tokens": 22,
"completion_tokens": 810,
"total_tokens": 832,
"prompt_tokens_details": {
"cached_tokens": 6266
},
"claude_cache_tokens_details": {
"cache_creation_input_tokens": 0,
"cache_read_input_tokens": 6266,
"cache_write_5_minutes_input_tokens": 0,
"cache_write_1_hour_input_tokens": 0
}
}
}
| 欄位 | 意義 |
|---|---|
cache_creation_input_tokens |
此請求寫入快取的 token 數 |
cache_read_input_tokens |
此請求從快取讀取的 token 數 |
cache_write_5_minutes_input_tokens |
寫入 5 分鐘 TTL 快取的 token 數 |
cache_write_1_hour_input_tokens |
寫入 1 小時 TTL 快取的 token 數 |
prompt_tokens_details.cached_tokens |
快取命中時的快取 token 數,與 OpenAI 格式相容 |
3. anthropic-beta 請求標頭
你可以透過 HTTP 標頭 anthropic-beta 啟用 Claude 模型的 Beta 功能,AIHubMix 會將此標頭轉送至 Anthropic API。
使用方式
在請求標頭中加入 anthropic-beta,並將值設為對應的 Beta 功能識別碼:
curl "https://aihubmix.com/v1/chat/completions" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $AIHUBMIX_API_KEY" \
-H "anthropic-beta: context-1m-2025-08-07" \
-d '{
"model": "claude-opus-4-5",
"messages": [
{
"role": "system",
"content": [
{"type": "text", "text": "You are an AI assistant"},
{
"type": "text",
"text": "(long context)",
"cache_control": {"type": "ephemeral"}
}
]
},
{"role": "user", "content": [{"type": "text", "text": "hello"}]}
]
}'
如需查詢可用的 Beta 識別碼,請參閱Anthropic API 文件。
最後更新:2026-06-01



