先说结论

Claude Messages API 的按需 compaction 不是“让模型写一段摘要,然后把旧消息删掉”。API 会返回一个签名的 compaction block;后续请求应把这个 block 放在消息历史最前面,用它替代已经被压缩的旧消息。

如果应用只保存 block 里的可读文本、修改 block、把它放错位置,或者在并发分支之间混用,恢复结果就不再可靠。

这项能力解决的是长任务 Agent 的上下文增长问题,但不会自动解决业务状态恢复、工具幂等、并发写入和审计。

它与普通摘要有什么不同

普通摘要通常由应用自己生成和保存:

Text
任务目标:修复登录回调。
已修改:auth.ts。
剩余:补充刷新令牌测试。

这种文本可以人工编辑,也可以换模型重写。signed compaction block 则是 API 返回的结构化历史状态。应用应把它视为不可修改的模型输入工件。

两者可以同时存在:

  • compaction block 用于模型继续推理。
  • 业务 checkpoint 用于人和程序恢复任务。

不要只保留前者。若工具已经修改文件、创建 issue 或写入数据库,模型摘要并不能证明这些副作用真实完成。

最小接入流程

按需压缩目前使用 compact-2026-09-04 beta header,并在请求顶层传入 compaction 参数。实际字段应以当前官方文档和 SDK 类型为准,不要把测试阶段的请求形状长期硬编码在多个服务里。

推荐流程:

  1. 正常发送完整消息历史。
  2. 达到应用设定的阈值后请求 compaction。
  3. 从响应中取出完整的 signed compaction block。
  4. 原子保存 block、模型 ID、会话版本和保留的近期消息。
  5. 后续请求把 block 放在最前,后接未被压缩的近期消息。

伪代码如下:

TypeScript
type AgentCheckpoint = {
  revision: number
  model: string
  compactionBlock: unknown
  recentMessages: Message[]
  businessState: {
    completedToolCalls: string[]
    changedFiles: string[]
    pendingChecks: string[]
  }
}

async function resume(checkpoint: AgentCheckpoint) {
  return client.messages.create({
    model: checkpoint.model,
    messages: [
      checkpoint.compactionBlock,
      ...checkpoint.recentMessages
    ]
  })
}

这里的 unknown 是有意的:应用不应假设自己可以拆开、编辑或重新序列化 block 的内部语义。使用官方 SDK 类型,并完整持久化 API 返回结构。

什么时候触发压缩

不要等到请求已经超过上下文窗口才压缩。触发条件至少要考虑:

  • 当前输入 token。
  • 下一步工具可能返回的最大结果。
  • 模型需要的输出预算。
  • 重试和恢复需要保留的安全余量。

一个可操作的策略是把阈值分成三档:

阶段动作
低水位正常运行,记录 token 和缓存命中
中水位裁剪可重取的工具结果,生成业务 checkpoint
高水位请求 compaction,停止启动新的大结果工具

阈值必须由压测决定。代码仓库大小、工具结果长度和任务类型不同,固定的“对话轮数”没有意义。

哪些近期消息应该原样保留

官方能力允许在 compaction block 后继续保留最近若干轮原文。优先保留:

  • 尚未完成的用户要求。
  • 最近一次工具调用及对应 tool result。
  • 当前失败的测试输出。
  • 等待人工批准的动作。
  • 与下一步直接相关的文件片段。

可以优先压缩:

  • 已经完成且有独立验证记录的探索过程。
  • 能从仓库或 API 再次读取的大段内容。
  • 重复的日志和搜索结果。
  • 已被后续结论取代的方案讨论。

“近期”不应简单等于最后 N 条消息。一次工具调用和它的结果必须作为完整语义单元保留,不能从中间切开。

并发 Agent 最容易出错的地方

如果多个 worker 同时处理同一会话,可能出现两个 compaction block 都基于 revision 12 生成,随后互相覆盖。恢复时模型只看到其中一个分支,另一个分支完成的工具调用却已经产生副作用。

每个 checkpoint 至少要带:

  • conversation_id
  • revision
  • parent_revision
  • model
  • block 的完整值
  • 保留消息的范围
  • 已完成工具调用的幂等键

写入时使用乐观锁:

sql
UPDATE agent_checkpoint
SET revision = 13, payload = :payload
WHERE conversation_id = :id AND revision = 12;

受影响行数为 0 时说明状态已经被别的 worker 更新。此时应重新读取并合并业务状态,不能直接覆盖。

压缩后缓存为什么可能变化

压缩会改变请求前缀。即使语义相近,prompt cache 也可能重新建立,因此压缩后的第一个请求可能出现更高延迟或缓存写入费用。

验收时分别记录:

  • 压缩请求本身的输入、输出和耗时。
  • 压缩后第一次恢复请求的 cache read / cache write。
  • 后续相同前缀请求的缓存命中。
  • 未压缩基线的总成本。

不要只比较单次请求 token。真正要比较的是一个完整任务从开始到验收的总成本和成功率。

与 Claude Code 恢复旧会话不是同一个问题

Claude Code 恢复旧会话时重建 prompt cache,属于客户端产品如何重放历史和建立缓存。Messages API compaction 是自建 Agent 主动决定何时压缩、保存什么以及如何恢复。

两者都会表现为 token 和缓存变化,但控制面不同:

  • Claude Code 用户主要检查版本、会话恢复行为和缓存账单。
  • API 开发者必须设计 checkpoint、版本控制、并发冲突和工具幂等。

因此不能用“Claude Code 能恢复”证明自建 Agent 的 compaction 实现正确。

最小复现应该怎么做

准备一个不会产生真实外部副作用的测试工具:

JSON
{
  "name": "record_step",
  "input_schema": {
    "type": "object",
    "properties": {
      "step_id": { "type": "string" },
      "result": { "type": "string" }
    },
    "required": ["step_id", "result"]
  }
}

让 Agent 完成 20 至 30 个带唯一 step_id 的步骤,然后比较三条路径:

  1. 完整历史直接继续。
  2. 自己生成一段普通文本摘要后继续。
  3. 使用官方 signed compaction block 后继续。

检查它是否能准确回答:

  • 哪些步骤已经完成。
  • 最后一次失败发生在哪里。
  • 下一步应该执行什么。
  • 是否重复调用已经完成的 step_id。

重复执行测试至少三次,并保存 request ID、token、停止原因和工具调用序列。一次成功不代表恢复稳定。

故障时怎么回退

compaction 恢复失败时,不要无限重试同一个 block。推荐回退顺序:

  1. 停止执行有副作用的工具。
  2. 保存失败 block、请求 ID、模型和 revision。
  3. 从最后一个业务 checkpoint 新建会话。
  4. 重新读取仓库、数据库或任务系统中的真实状态。
  5. 用明确的待办清单继续,而不是要求模型猜测丢失历史。

如果切换模型,还要验证目标模型是否接受当前 block。没有明确兼容保证时,从业务 checkpoint 建立新会话更可靠。

上线验收清单

  • [ ] 完整保存 API 返回的 signed compaction block,没有只取摘要文本。
  • [ ] block 总是位于恢复历史最前面。
  • [ ] 被压缩消息不会再次重复发送。
  • [ ] 工具调用和 tool result 不会被拆开保留。
  • [ ] checkpoint 带 revision,并发写入使用乐观锁。
  • [ ] 有副作用的工具使用幂等键。
  • [ ] 业务状态独立于模型 block 保存。
  • [ ] 记录压缩前后 token、缓存、延迟和总任务成本。
  • [ ] block 无法恢复时能从业务 checkpoint 新建会话。
  • [ ] 日志不包含 API Key、完整私有代码或未脱敏工具结果。

常见误区

误区一:压缩后能继续回答,就说明状态完整

模型能生成连贯文本,不代表它记得所有已执行副作用。必须核对工具调用记录和业务系统状态。

误区二:把上下文窗口用满再压缩最省钱

接近上限时,大型 tool result 或一次重试就可能让请求失败。提前预留输出和工具结果空间更稳。

误区三:所有 Agent 共用同一个最新 block

并发分支的父 revision 不同。混用 block 会让模型历史与真实副作用脱节。

什么才算接入完成

接入完成不是“接口返回了 compaction block”,而是压缩、持久化、恢复、并发冲突和失败回退都能重复验证。模型上下文只是一层状态;文件、数据库、测试结果和审批记录仍必须由应用自己管理。

参考来源

Claude Platform release notes - September 14, 2026AnthropicCompactionAnthropicPrompt cachingAnthropic

相关文章

Claude Code 恢复旧会话后为什么重建几十万 token 缓存智能编程 / 约 9 分钟GLM-5.2 接长任务 Agent:1M 上下文仍要做压缩、恢复和回退智能编程 / 约 11 分钟当 Agent 开始记住项目,隐私风险也从一次对话变成了一段关系智能编程 / 约 11 分钟

作者信息