對話中途的系統訊息與工具變更
在對話進行到一半時變更系統指令或工具可用性,而不會使其之前的快取前綴失效。
系統指令通常位於頂層的 system 欄位中,排在對話中所有訊息之前。這個位置非常適合「prompt caching」(提示快取):提示快取會將系統提示視為穩定前綴的一部分,因此後續輪次都能命中快取。但對於您在工作階段進行到一半才發現需要的指令而言,這個位置並不理想,因為編輯頂層 system 欄位會改變提示的最開頭,並使其後所有內容的快取失效。
對話中途的系統訊息(mid-conversation system messages)填補了這個缺口。您可以在對話中新指令開始相關的位置附加一則 {"role": "system"} 訊息,而不是編輯頂層的 system 欄位。快取前綴保持不變,因此下一個請求仍會從快取中讀取它,而新指令仍會以系統指令的身分套用,而非被當作一般的使用者文字。
對話中途的工具變更
tools 陣列在經過雜湊的請求前綴中的位置甚至比頂層 system 欄位更靠前,因此編輯它會使整個對話的提示快取失效。對話中途的工具變更是對話中途系統訊息在工具方面的對應功能。您不必在對話的整個生命週期中固定工具清單,而是可以在輪次之間變更提供給模型的工具:先在 tools 中宣告完整的工具集,然後使用 tool_addition 與 tool_removal 區塊,從對話中的特定位置起向模型提供某個工具或將其撤回。tools 陣列本身永遠不會改變,因此快取前綴保持完整。
tool_addition 與 tool_removal 是 role: "system" 訊息之 content 陣列中的內容區塊,並且可以在同一則訊息中與 text 區塊混用。該訊息遵循與任何對話中途系統訊息相同的放置規則(請參閱限制),且變更會從對話中的該位置起生效。每個區塊的 tool 欄位是參照一個工具而非定義一個工具:{"type": "tool_reference", "name": "..."} 指名請求之 tools 陣列中宣告的工具,而 MCP 連接器工具可以使用 mcp_tool_reference(server_name 與 name)個別參照,或使用 mcp_toolset_reference(server_name)參照整個工具集。參照未在 tools 中宣告的名稱會傳回 400 錯誤。
在 tools 中宣告的每個工具都會從對話一開始就提供給模型,除非它是以 defer_loading: true 宣告的;這會讓該工具保持保留狀態,直到某個 tool_addition 區塊將其顯露出來。tool_addition 也可以重新提供先前被 tool_removal 撤回的工具。
client = anthropic.Anthropic()
response = client.beta.messages.create(
model="claude-opus-5",
max_tokens=1024,
betas=["mid-conversation-tool-changes-2026-07-01"],
# 完整的工具集在一開始就宣告且永不變更,因此
# 快取的前綴保持完整。
tools=[
{
"name": "get_weather",
"description": "Get the current weather for a location.",
"input_schema": {
"type": "object",
"properties": {
"location": {"type": "string", "description": "City name"},
},
"required": ["location"],
},
},
],
messages=[
{
"role": "user",
"content": "Say OK.",
},
# 從此處起撤回 get_weather。此區塊以名稱參照
# 該工具而非編輯 `tools`,因此先前的輪次保持
# 位元組完全相同,快取仍然命中。
{
"role": "system",
"content": [
{
"type": "tool_removal",
"tool": {"type": "tool_reference", "name": "get_weather"},
},
],
},
],
)
for block in response.content:
if block.type == "text":
print(block.text)對話中途的工具變更目前為 beta 版。若要使用,請在您的請求中加入 beta 標頭 mid-conversation-tool-changes-2026-07-01。
何時使用對話中途的系統訊息
提示快取會依序對請求前綴進行雜湊:先是 tools,接著是 system,然後是 messages。快取命中要求前綴在快取斷點之前與最近的某個請求逐位元組完全相符。
這個順序意味著頂層 system 欄位位於雜湊前綴的最開頭附近。對它的任何變更,即使只是附加一個句子,都會產生不同的雜湊值,而該請求對於系統提示以及其後每一則已快取的訊息都會錯失快取。
對話中途的系統訊息讓您可以改為在訊息歷史的末端加入指令。新指令之前的所有內容都保持不變,因此現有的快取項目仍然相符,只有新訊息會被當作新的輸入處理。
以下是幾個這一點很重要的情境:
- 工作階段中途的政策或角色變更。 一個長時間的代理工作階段在數十個已快取的輪次之後需要一項新的限制(「從現在起,所有 SQL 都寫成參數化查詢」)。將它加入頂層
system欄位會重新處理整個歷史。 - 必須具有權威性的逐輪次上下文。 您想要以系統層級的權重注入一則時效性備註、工作階段截止時間或工具可用性變更,而它變動得太頻繁,不適合放在快取前綴中。
- 不應堆積的逐輪次提醒。 某個執行框架(harness)在每批工具結果之後提醒模型(「將獨立的讀取請求一起發出」、「使用者已經有一段時間沒有收到您的回覆了」),並希望模型只看到最新的那一份。輪次範圍的系統訊息只會在一個輪次中呈現,之後不耗費任何成本,且不需要從歷史中刪除任何內容。
- 您的應用程式觀察到的狀態變更。 您的應用程式注意到某件 Claude 應視為操作者層級事實的事情:磁碟上的檔案已變更、使用者切換了自動核准設定、可用工具已變更,或剩餘的 token 預算降到某個門檻以下。
- 不應中斷代理迴圈的使用者輸入。 使用者在 Claude 仍在為前一個請求執行工具時輸入了後續內容。在下一個工具結果之後以系統訊息轉達它,可讓 Claude 將新輸入納入它正在進行的工作中,而不是將其視為需要切換過去的全新請求。請參閱放置於工具結果之後。
- 授予常設權限的模式切換。 工作階段層級的模式可以使用對話中途的系統訊息,對某項昂貴的能力(例如自動啟動多代理工作流程)授予常設同意,每隔數個輪次附上簡短的提醒,並在模式關閉時發出退出通知。如需完整範例,請參閱建構編排模式。
在上述所有情況中,您都可以將指令放在一般的 user 訊息中,而 Claude 確實會遵循在使用者輪次中送達的指令。差別在於優先順序:user 訊息被視為來自終端使用者,而 system 訊息被視為來自您,也就是應用程式操作者。當兩者衝突時,系統指令優先,因此對於即使終端使用者要求不同內容也應成立的操作者層級事實與限制,請使用 system 角色。對話中途的系統訊息保有這種操作者層級的優先順序,而不必付出編輯頂層 system 欄位所造成的快取錯失成本。
運作方式
在 messages 陣列中加入一則 "role": "system" 的訊息。content 可使用純字串或內容區塊,與 user 或 assistant 輪次相同。該指令從對話中的該位置起生效。當指令衝突時,較晚的系統訊息優先於較早的系統訊息,而對話中途的系統訊息對於其後的輪次優先於頂層 system 欄位。
您仍然可以為應套用於整個對話的指令設定頂層 system 欄位。請將對話中途的系統訊息保留給那些稍後才變得相關、或您想在不使快取前綴失效的情況下加入的指令。
role: "system" 訊息也可以攜帶 output_config.effort,以從下一個 user 輪次起變更 effort(努力程度)等級。此功能在 Claude API 上的 Claude Fable 5.1、Claude Mythos 5.1 與 Claude Opus 5 為 beta 版,需要 mid-conversation-output-config-2026-07-01 beta 標頭。請參閱逐訊息 effort。
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-opus-5",
max_tokens=1024,
# 自動提示快取:每個請求都會快取目前為止的對話,
# 而下一個請求會從快取中讀取未變更的前綴。
cache_control={"type": "ephemeral"},
system="You are a code review assistant. Be concise.",
messages=[
{
"role": "user",
"content": "Review process() in utils.py for performance issues.",
},
{
"role": "assistant",
"content": "The list comprehension is fine for small inputs. For large inputs, consider a generator to avoid materializing the full list.",
},
{
"role": "user",
"content": "Now review the calling code that invokes process().",
},
# 審查者在工作階段中途意識到所有建議也必須
# 通過團隊嚴格的型別政策。將指令附加在此處
# 可讓先前的輪次保持位元組完全相同,因此
# 前一個請求所快取的前綴仍可從快取中讀取。
{
"role": "system",
"content": "From now on, every suggestion must include explicit type annotations.",
},
],
)
for block in response.content:
if block.type == "text":
print(block.text)此範例透過頂層 cache_control 欄位啟用自動快取。提示快取是選擇性啟用的:如果請求沒有 cache_control 欄位(自動快取或明確斷點),就不會快取任何內容,且每個請求都要為整個對話支付一般的輸入 token 價格。啟用快取後,附加系統訊息會讓已快取的輪次保持不變,因此攜帶新指令的請求仍會從快取中讀取它們,而不是重新處理。快取也要求對話達到最小可快取提示長度;像這個範例這麼短的對話低於該長度,因此在對話增長之前,cache_creation_input_tokens 與 cache_read_input_tokens 會維持為 0。
對話中途的系統訊息必須緊接在 user 輪次(或以伺服器工具結果結尾的 assistant 輪次)之後,並且必須是 messages 中的最後一個項目,或緊接著一個 assistant 輪次。攜帶 tool_result 區塊的 user 訊息也算在內:在代理迴圈中,您可以將系統訊息放在工具結果之後、Claude 的下一個輪次之前。任何其他位置,包括在 assistant 的 tool_use 區塊與回應它的 tool_result 之間,都會傳回 400 錯誤。
放置於工具結果之後
在代理迴圈中,系統訊息放在傳遞工具結果的 user 訊息之後。這也是您的應用程式可以轉達使用者在 Claude 工作期間所輸入內容的位置,如此新的上下文便能被吸收,而不必重新開始該輪次:
[
{ "role": "user", "content": "Run the test suite and fix any failures." },
{
"role": "assistant",
"content": [{ "type": "tool_use", "id": "toolu_01", "name": "run_tests", "input": {} }]
},
{
"role": "user",
"content": [
{ "type": "tool_result", "tool_use_id": "toolu_01", "content": "12 passed, 0 failed" }
]
},
{
"role": "system",
"content": "The user sent the following message while you were working: also update the changelog before you finish."
}
]請將系統內容表述為上下文,而非覆寫使用者的命令。陳述事實(「收到來自使用者的新輸入:X」、「剩餘的 token 預算現在是 Y」),並讓 Claude 據此行動。Claude 經過訓練會抗拒看似與使用者作對的指令,而這項保護同樣適用於系統角色,因此像「忽略使用者所說的話」這類措辭,效果不如直接陳述發生了什麼變化。
此模式用於轉達來自對話本身終端使用者的輸入。請勿用它來傳遞工具輸出、擷取的文件或其他第三方內容;請將這類內容保留在 tool_result 區塊中(請參閱限制)。
輪次範圍的系統訊息
若要將 role: "system" 訊息的範圍限定在目前輪次,請設定其 clear_at 欄位。它接受以下兩個值之一:
"never"(預設值):該訊息在每個包含它的請求中都會在其位置呈現。省略此欄位的效果相同。"next_user_message":該訊息為輪次範圍(turn-scoped)。只有當messages中在它之後沒有任何role: "user"訊息時,其文字才會呈現。在此處,僅攜帶tool_result區塊的使用者訊息也算作使用者訊息。一旦存在較晚的使用者訊息,該訊息即被清除(cleared):它仍留在陣列中,但不呈現任何內容,也不耗費任何輸入 token,在該請求及其後的每個請求中皆是如此。
輪次範圍的系統訊息目前為 beta 版。請加入 beta 標頭 mid-conversation-system-clear-at-2026-08-21。若沒有它,clear_at 會被當作未知欄位而遭拒絕。
{
"role": "system",
"clear_at": "next_user_message",
"content": "First privately list what you need next; then request every item that doesn't depend on another's result in this one response."
}主要用途是工具迴圈中的逐輪次提醒。每次您希望模型看到提醒時,就在 tool_result 訊息之後附加該提醒,並將每一份較早的副本留在原處。模型只會看到位於最後一則使用者訊息之後的副本,因此提醒永遠不會堆積。messages 中較早的內容都不會改變,因此提示快取持續相符。在 Claude Fable 5.1 上,這也能讓後續的思考區塊保持有效:刪除較早的提醒會改變那些區塊之前的對話並導致對話檢查失敗,而被清除的訊息仍留在陣列中,使該段對話保持不變。
以下請求是代理迴圈的較後步驟。messages[3] 在較早的請求中曾經呈現,當時它是陣列中的最後一則訊息。一旦 messages[5](較晚的使用者訊息)存在,messages[3] 即被清除:被清除的訊息仍留在陣列中,因此 messages[4] 中思考區塊之前的對話保持不變,但模型不再看到其文字。messages[6] 與 messages[7] 都會依序呈現。
{
"model": "claude-fable-5-1",
"max_tokens": 16000,
"messages": [
{ "role": "user", "content": "Fix the failing test." },
{
"role": "assistant",
"content": [
{ "type": "thinking", "thinking": "", "signature": "..." },
{
"type": "tool_use",
"id": "toolu_01",
"name": "read_file",
"input": { "path": "test_auth.py" }
}
]
},
{
"role": "user",
"content": [{ "type": "tool_result", "tool_use_id": "toolu_01", "content": "..." }]
},
{
"role": "system",
"clear_at": "next_user_message",
"content": "Request independent reads in one turn."
},
{
"role": "assistant",
"content": [
{ "type": "thinking", "thinking": "", "signature": "..." },
{
"type": "tool_use",
"id": "toolu_02",
"name": "read_file",
"input": { "path": "auth.py" }
},
{
"type": "tool_use",
"id": "toolu_03",
"name": "read_file",
"input": { "path": "tokens.py" }
}
]
},
{
"role": "user",
"content": [
{ "type": "tool_result", "tool_use_id": "toolu_02", "content": "..." },
{
"type": "tool_result",
"tool_use_id": "toolu_03",
"content": "...",
"cache_control": { "type": "ephemeral" }
}
]
},
{
"role": "system",
"clear_at": "next_user_message",
"content": "Request independent reads in one turn."
},
{
"role": "system",
"clear_at": "next_user_message",
"content": "The shell exited with status 137."
}
]
}輪次範圍訊息的規則:
- 逐字重新傳送被清除的訊息。 被清除的訊息仍是對話歷史的一部分。根據目前狀態重建它(新的 token 計數、時間戳記)、將其視為多餘而捨棄,或變更其
clear_at值,都屬於對較早訊息的編輯。提示快取會從該位置起錯失,而在 Claude Fable 5.1 上,在它之後產生的每個思考區塊都會無法通過對話檢查。 - 僅限文字。
content為一個或多個text區塊(或一個字串)。tool_addition與tool_removal區塊在輪次範圍訊息上會傳回 400 錯誤,output_config亦然。請為這些用途使用另一則不帶clear_at的role: "system"訊息。 - 其區塊上不可有
cache_control。 被清除的訊息永遠不會成為快取鍵的一部分,因此放在它上面的斷點永遠無法相符。請改為將斷點放在前一個使用者輪次的最後一個區塊上,如範例所示。頂層自動快取欄位在挑選斷點時會跳過輪次範圍訊息。在清除某則訊息的請求中,可重複使用的快取前綴結束於它之前的使用者輪次,因此只有該訊息與新使用者訊息之間的那一個 assistant 輪次會被重新處理。 - 放置規則仍然適用,無論是否被清除。輪次範圍訊息必須接在
user輪次(或以伺服器工具結果結尾的assistant輪次)之後,並位於assistant輪次之前或結束陣列,與任何對話中途的系統訊息相同。結束陣列的訊息一定會呈現。緊接著另一則user訊息的訊息會是 400 錯誤,而非被清除的訊息:請將一輪工具的所有結果放在一則使用者訊息中,並將提醒放在其後。 - Assistant 輪次不會清除它。 在該訊息之後的預填或暫停的 assistant 輪次,或伺服器端工具迴圈,都不會新增使用者訊息,因此該訊息在該延續中仍會呈現。若要讓提醒在用戶端工具迴圈中持續可見,請在每則
tool_result訊息之後再次附加它。 - Token 計數依呈現內容而定。 被清除的訊息不會增加
usage.input_tokens,也不會增加 token 計數。 - 匯入的歷史。 在您一次建構完成的對話記錄中(少樣本範例、遷移過來的對話),若某則輪次範圍訊息之後已經有一個 assistant 輪次與一則使用者訊息,它從第一個請求起就被清除,永遠不會呈現。對於您要沿用的逐輪次提醒而言,這是正確的狀態。只有在模型應於每個請求中都看到的訊息上,才不設定
clear_at。
驗證錯誤如下:
messages.3.clear_at: Extra inputs are not permitted
messages.3.clear_at: clear_at is only permitted on role 'system' messages
messages.3.clear_at: Input should be 'next_user_message' or 'never'
messages.3: a turn-scoped system message supports text blocks only (clear_at: 'next_user_message')
messages.3: output_config is not permitted on a turn-scoped system message (clear_at: 'next_user_message')
messages.3.content.0: cache_control is not permitted on a turn-scoped system message (clear_at: 'next_user_message')第一個是未附 beta 標頭時傳回的錯誤。在 Amazon Bedrock 與 Google Cloud 上,請依照 Beta 標頭中的說明傳遞 beta 值。
透過 SDK 時,請在 messages 中的 role: "system" 項目上設定 clear_at 並傳送 beta 標頭。以下範例在使用者輪次之後附加一則輪次範圍的提醒;在下一個請求中,一旦存在較晚的使用者訊息,該提醒仍留在陣列中但不再呈現:
client = anthropic.Anthropic()
response = client.beta.messages.create(
model="claude-fable-5-1",
max_tokens=4096,
messages=[
{
"role": "user",
"content": "Draft a short status update on the database migration for the team channel.",
},
# 回合範圍的提醒:於本回合呈現,待之後出現使用者訊息時即清除。
{
"role": "system",
"clear_at": "next_user_message",
"content": "The reader is on call: keep this reply under 50 words.",
},
],
betas=["mid-conversation-system-clear-at-2026-08-21"],
)
for block in response.content:
if block.type == "text":
print(block.text)與提示快取結合使用
對話中途的系統訊息與提示快取是設計來搭配使用的:
- 明確啟用快取。 只有當請求包含
cache_control時才會進行快取,無論是頂層自動快取欄位,或是內容區塊上的明確斷點。對話中途的系統訊息本身不會建立快取項目,而若未啟用快取,就沒有可保留的節省。 - 照常快取穩定前綴。 將
cache_control放在跨請求保持不變的最後一個區塊上,無論那是頂層system欄位的末端、工具定義的末端,或訊息歷史中的某個穩定位置。 - 在斷點之後附加系統訊息。 由於它位於快取前綴之後,不會改變前綴雜湊,快取仍會命中。
- 對話中途的系統訊息本身也可快取。 一旦它進入對話,就成為穩定歷史的一部分。在下一個輪次中,您可以將快取斷點移到它之後(或依靠自動快取來做到),該系統訊息便會像任何其他輪次一樣從快取中讀取。
請避免編輯或移除已經傳送過的對話中途系統訊息。與對較早訊息的任何其他變更一樣,這會使從該位置起的快取失效。在 Claude Fable 5.1 上,它也會使其後每個 assistant 輪次中的思考區塊失效。對於只應套用於一個輪次的指引,請使用輪次範圍的系統訊息並將其留在原處。如果指令需要演進,請附加一則新的系統訊息,而不是重寫舊的。連續的系統訊息是被接受的,並被視為單一系統區段,整體遵循相同的放置規則。
限制
- 不可作為第一則訊息。 攜帶內容的
system訊息不能是messages中的第一個項目。對於從一開始就適用的指令,請使用頂層system欄位。 - 放置位置受限。 攜帶內容(
text、tool_addition或tool_removal區塊)的system訊息必須緊接在user輪次(包括攜帶tool_result區塊的user輪次)或以伺服器工具結果結尾的assistant輪次之後,並且必須位於assistant輪次之前或結束陣列。它不能位於tool_use區塊與其tool_result之間。放在其他位置會傳回 400 錯誤。content為空且僅設定output_config.effort的訊息在其位置不呈現任何內容,可放在messages中的任何位置,包括第一個位置或assistant輪次與user輪次之間。連續的system訊息會一起判定,因此在僅設定 effort 的訊息旁加入攜帶文字的訊息,會使整組訊息都遵循內容規則。 - 輪次範圍訊息僅限文字且須逐字重新傳送。
clear_at: "next_user_message"訊息不攜帶tool_addition、tool_removal、output_config或cache_control,且一旦被清除,它在後續請求中必須逐位元組地保留在messages中。請參閱輪次範圍的系統訊息。 - 不是放置不受信任內容的地方。 Claude 將系統內容視為操作者指令並加以遵循。請勿將來自對話外部的文字(例如原始工具輸出、擷取的文件或網頁內容)直接放入系統訊息中;這樣做會賦予該文字操作者層級的權限。請將這類資料保留在
tool_result區塊中,並繼續遵循減輕越獄與提示注入。
相關內容
快取的運作方式、斷點的放置位置,以及如何解讀快取用量欄位。
當您預期的快取命中沒有發生時,找出兩個請求究竟在哪裡產生分歧。
訊息結構、多輪對話,以及 system 欄位。
撰寫有效的提示與系統指令。
tool_use 與 tool_result 區塊在 messages 陣列中的結構方式。
Was this page helpful?