保留最近輪次的壓縮
使用隨需壓縮來摘要對話中較早的輪次,並在摘要之後逐字傳送最近的輪次。
「Keep-tail compaction」(保留尾端壓縮)會在摘要之後逐字保留對話的最後幾個輪次。它會改變「compaction loop」(壓縮迴圈)中的兩件事:哪些訊息會進入壓縮請求,以及您在區塊之後傳送的內容。從摘要繼續中的所有內容皆照常適用。
選擇要保留的輪次
沒有任何參數可設定要保留哪些輪次。您需要在歷史記錄中選擇一個「cut point」(切分點):切分點之前的訊息會進入壓縮請求,而從切分點開始的訊息則會被保留。
保留的輪次會以完整長度傳回給 Claude,因此您保留得越多,壓縮所釋放的空間就越少。
請將切分點放在沒有任何工具呼叫處於未完成狀態的位置,讓每個工具呼叫與其結果位於同一側。如果您傳送的訊息以一個 assistant 輪次結尾,且該輪次的工具呼叫尚未有結果,API 會拒絕該壓縮請求。
壓縮較早的輪次,並在區塊之後傳送其餘輪次
若要逐字保留最近輪次的尾端,請將這些輪次排除在壓縮請求之外。API 會摘要它收到的每一則訊息,因此請只傳送較早的輪次,然後將區塊放在您保留的輪次之前。
請完全依照歷史記錄中的原樣傳送保留的輪次,包括「thinking blocks」(思考區塊)。兩個請求都帶有「beta header」(beta 標頭),如同請求摘要中所述。
在以下範例中,歷史記錄包含兩個輪次,而切分點保留了第二個輪次。壓縮請求帶有第一個輪次:
{
"model": "claude-opus-5-5",
"max_tokens": 4096,
"messages": [
{
"role": "user",
"content": "I am building a recipe app. Help me name the main entities in the data model."
},
{
"role": "assistant",
"content": "Start with Recipe, Ingredient, and Step. Add a RecipeIngredient entry that holds the quantity and unit for each ingredient in a recipe."
}
],
"compaction": { "type": "summarize" }
}下一個請求會先傳送傳回的區塊,接著是完全保持原樣的保留輪次,然後是新的 user 訊息。從摘要繼續展示了一個以區塊開頭的請求。
以下程式是在迴圈中壓縮中的迴圈,經修改以保留最後兩個輪次。醒目標示的行顯示了它與該迴圈的不同之處。
from anthropic.types.beta import BetaMessageParam
client = anthropic.Anthropic()
# 請將此值設為接近您實際的輸入預算。此處設得較低,讓簡短對話也會觸發壓縮。
COMPACT_AT_TOKENS = 2500
SYSTEM = "You help design a recipe app's data model. Keep answers short."
KEEP_TURNS = 2
QUESTIONS = [
"What are the main entities in the data model?",
"Which fields should Recipe have?",
"Which fields should Ingredient have?",
"Which fields should RecipeIngredient have?",
"Which fields should Step have?",
"Which indexes should these tables have?",
"Which fields should be required?",
"Which fields should have default values?",
]
history: list[BetaMessageParam] = []
for turn, question in enumerate(QUESTIONS, start=1):
history.append({"role": "user", "content": question})
response = client.beta.messages.create(
model="claude-opus-5-5",
max_tokens=8192,
system=SYSTEM,
betas=["compact-2026-09-04"],
messages=history,
)
history.append({"role": "assistant", "content": response.content})
# 下一個請求也會送出這則回覆,因此要將其計入。
conversation_tokens = response.usage.input_tokens + response.usage.output_tokens
if conversation_tokens > COMPACT_AT_TOKENS and KEEP_TURNS < turn < len(QUESTIONS):
# 一個回合包含一則使用者訊息與一則助理回覆,
# 因此保留的回合會以使用者訊息開頭。
split = -2 * KEEP_TURNS
older, recent = history[:split], history[split:]
summary = client.beta.messages.create(
model="claude-opus-5-5",
max_tokens=4096,
system=SYSTEM,
betas=["compact-2026-09-04"],
messages=older,
compaction={"type": "summarize"},
)
if summary.stop_reason == "compaction":
history = [{"role": "assistant", "content": summary.content}, *recent]
print(f"Kept {len(recent) // 2} turns after the block")- 選擇切分點: 此程式保留最後兩個輪次,其中一個輪次是指一則
user訊息及對它的回覆。它在距離結尾四則訊息處分割歷史記錄,因此保留的輪次會以一則user訊息開頭。 - 決定何時壓縮: 大小檢查還要求對話的輪次數多於程式所保留的輪次數,因此較早的部分永遠不會是空的。
- 壓縮請求: 迴圈會傳送整個歷史記錄,而此版本只傳送較早的訊息。
- 替換: 迴圈會以傳回的訊息取代整個歷史記錄,而此版本的新歷史記錄則是傳回的訊息,後面接著保留的輪次。
stop_reason 檢查以及替換之後的每個請求,都與迴圈中的相同。
讓保留輪次中的思考保持有效
如果您在具有「preserved thinking」(保留思考)的模型上傳回思考區塊,保留輪次中的思考只有在保留的思考維持有效的條件成立時才會保持有效,而其中一項條件限制了切分點可以落在的位置。
此程式的切分點位於一則回覆與下一則 user 訊息之間,符合該條件。在您已發出的請求結尾處切分也同樣符合:請精確壓縮該請求的 messages,並保留您的歷史記錄自那之後新增的所有內容。
Compatibility
| Supported models |
|
|---|---|
| Supported platforms |
|
Was this page helpful?