Compaction API 实战:让你的 Agent 不再撞上下文墙
做过 Agent 的人都碰过这个问题:跑着跑着,上下文满了。
模型返回一个错误,或者开始"遗忘"前面说过的话。你要么让用户开一个新会话,要么自己写逻辑去裁剪历史消息。两种方案都不好——前者用户体验差,后者你得决定砍掉哪些内容,砍错了 Agent 就跑偏。
Opus 4.6 跟着一起发布了 Compaction API,用来解决这个问题。原理很直接:快撞窗口了,服务端自动把前面的对话压缩成一段摘要,腾出空间继续跑。
基本用法
请求里加一个 context_management 字段就行:
import anthropic
client = anthropic.Anthropic()
response = client.beta.messages.create(
betas=["compact-2026-01-12"],
model="claude-opus-4-6",
max_tokens=4096,
messages=messages,
context_management={
"edits": [{
"type": "compact_20260112",
"trigger": {"type": "input_tokens", "value": 150000}
}]
}
)
trigger 设的是触发阈值——输入 token 超过 150K 时自动压缩。最小值是 50K。
压缩触发后,API 返回的响应里会多一个 compaction 类型的 content block,里面就是摘要。下次请求时把这个 block 传回去,API 会自动丢掉摘要之前的所有旧消息,只保留摘要和后续内容。
你不需要自己管"哪些消息要删"——API 替你干了。
几个关键细节
1. 压缩也要花钱
这是最容易忽略的点。Compaction 本质上是让模型做了一次额外的"摘要生成"。这次生成有独立的输入和输出 token 消耗,算在你的账单里。
API 响应的 usage 字段里,会出现一个 iterations 数组:
{
"usage": {
"input_tokens": 23000,
"output_tokens": 1000,
"iterations": [
{"type": "compaction", "input_tokens": 180000, "output_tokens": 3500},
{"type": "message", "input_tokens": 23000, "output_tokens": 1000}
]
}
}
注意:顶层的 input_tokens 和 output_tokens 不包含 compaction 的消耗。要算真实花费,得遍历 iterations 数组累加。如果你的成本监控只看顶层字段,会严重低估实际支出。
2. 压缩用的是同一个模型
当前没有选项让你用一个便宜的模型做摘要、用 Opus 做正事。摘要就是 Opus 4.6 自己生成的。好处是摘要质量高,坏处是贵。一次 compaction 可能消耗几千个输出 token(按 $25/MTok 算,大概 $0.08-0.10)。
如果你的 Agent 频繁触发 compaction(比如每 10 分钟一次),这个成本不可忽视。
3. 自定义摘要指令
默认的摘要 prompt 是通用的:
请写一段对话摘要,包括当前状态、下一步、已有结论等,用于在后续上下文中替代原始历史。
你可以用 instructions 参数完全替换它:
context_management={
"edits": [{
"type": "compact_20260112",
"instructions": "重点保留:所有代码修改记录、文件路径、变量名。忽略:闲聊、确认性回复。"
}]
}
这个对特定任务很有用。比如你的 Agent 在做代码重构,摘要里最重要的是"改了哪些文件、改了什么",而不是中间那些"好的,我来看看"之类的对话。
但要注意:自定义指令会完全替换默认 prompt,不是追加。如果你写得太短或不够明确,摘要质量可能下降。
4. pause_after_compaction
这个参数让 compaction 触发后先暂停,返回摘要给你看,让你有机会在摘要之后、模型继续生成之前,插入额外的消息。
context_management={
"edits": [{
"type": "compact_20260112",
"pause_after_compaction": True
}]
}
触发后,API 返回 stop_reason: "compaction"。你可以:
- 把最后几轮对话原封不动地追加回去(避免最近的内容被压缩掉)
- 插入一段提醒消息(比如"你现在正在做 X 任务的第 Y 步")
- 检查摘要质量,决定要不要继续
这在对摘要质量敏感的场景里很实用。
控制总预算
长任务的另一个隐患是:模型一直跑一直跑,compaction 一次又一次,token 消耗无上限。
一个粗暴但有效的做法:用 compaction 次数乘以 trigger 阈值,估算累计消耗。
TRIGGER = 100_000
BUDGET = 3_000_000
n_compactions = 0
# ... 在处理循环里 ...
if response.stop_reason == "compaction":
n_compactions += 1
if n_compactions * TRIGGER >= BUDGET:
# 告诉模型:收尾吧
messages.append({
"role": "user",
"content": "请总结当前进展并结束任务。"
})
这个估算不精确——每次 compaction 后有效上下文会缩小,不是每次都消耗 TRIGGER 那么多 token。但作为安全阀够用了。
跟 Prompt Caching 配合
你可以在 compaction block 上加 cache_control:
{
"type": "compaction",
"content": "[摘要内容]",
"cache_control": {"type": "ephemeral"}
}
这样后续请求里,摘要部分可以被缓存复用。在多轮对话中,摘要在相当长时间内不会变,缓存命中率很高。
考虑到 Anthropic 的缓存命中价格是正常价的十分之一($0.50/MTok),这个组合能明显降低长对话的成本。
当前限制
- 只支持 Opus 4.6,Sonnet 和 Haiku 暂不支持
- 还是 beta 状态,需要加 beta header
- 摘要模型不能单独指定,只能用发请求的同一个模型
- 没有"选择性保留"功能——你不能标记某些消息"不许压缩"(但可以用 pause_after_compaction 变通)
什么时候该用,什么时候不该用
该用:Agent 任务可能跑很久(超过 20 轮工具调用)、多轮对话需要连续性、你不想自己写 context 管理逻辑。
不该用:短对话(10 轮以内)、对历史细节的精确保留有刚性要求(比如法律审计场景,每句话都不能丢)、成本敏感场景下频繁触发 compaction。
如果你的 Agent 之前因为上下文满了经常报错或者跑偏,Compaction 能直接解决这个问题。代价是多花一点 token 做摘要,以及需要适配 usage 统计的新口径。
参考链接
- Compaction API 文档:
https://platform.claude.com/docs/en/build-with-claude/compaction - 上下文窗口管理:
https://platform.claude.com/docs/en/build-with-claude/context-windows