教程Claude Code系列第 7 / 21 篇

对话太长了怎么办:Claude 的压缩和上下文编辑,各自什么时候用

长对话和跑很久的智能体迟早要处理上下文:要么让服务端把旧的轮次写成摘要(压缩),要么按规则清掉旧的工具结果和思考(上下文编辑)。本文整理两类办法的用法、限制和对缓存的影响。通过中转站实测:上下文编辑能用;两种压缩都用不了,其中一种是参数被悄悄忽略。

发布 · 约 9 分钟读完 · 经人工审核()· 本站的内容怎么来的

本站已实测,测试日期:2026-10-13。

本页目录(7 节)
  1. 先分清两类办法
  2. 一、压缩:三种做法
  3. 二、上下文编辑:清掉旧的工具结果
  4. 三、通过中转站实测到的
  5. 和 Claude Code、Agent SDK 的关系
  6. 花费
  7. 这次实测没有覆盖到的

这篇教程解决一个问题:自己写的智能体或聊天程序,对话越来越长,快要撑满上下文窗口了,或者越长回答越差,该怎么办?

Claude Code 里这件事是自动的(它会自己压缩,你也可以用 /compact)。这篇讲的是自己直接调接口时,官方提供的两类办法。

实测环境
日期 2026-10-13
方式 用 Python 直接发 HTTP 请求
模型 Sonnet 5.5、Opus 5.5
连接方式 通过酷站AI 中转站,不是直连官方

先说实测的结论: 通过这家中转站,上下文编辑能用,两种压缩都用不了。所以压缩那几节是按文档整理的,没有跑通过。

先分清两类办法

压缩 上下文编辑
做什么 把旧的轮次写成一段摘要,用摘要代替它们 按规则直接清掉旧的工具结果或旧的思考
丢了什么 细节。摘要里没写的就没了 被清掉的那些内容,原地留一句“已清除”
你的历史记录 要换成摘要 不用动。清理发生在服务端,你照常保存完整的历史
适合 长聊天、长任务,旧的内容整体不再需要逐字保留 工具调用很多的智能体,旧的工具结果(文件内容、搜索结果)用过就没用了
状态 测试版 测试版

文档的建议是:多数情况用压缩,上下文编辑留给需要更细控制的场合。

为什么不等窗口满了再说:文档反复强调,内容越多,回答的质量越差。压缩不只是为了不超限,也是为了让模型眼前的东西少一些。

一、压缩:三种做法

按需压缩 到阈值自动压缩 自己写摘要
谁决定什么时候压 你,发一个专门的请求 接口,输入到了你设的 token 数就压 你
你要写的代码 一个循环:要摘要,换进历史 普通请求上多一个参数 全部:摘要的请求、提示词、改历史
最近几轮能不能逐字保留 能 能,要让接口压完先停一下 能
能不能在后台压 能 不能,就在触发的那个请求里做 能
保留下来的轮次,思考还有效吗 有效,满足几个条件的话 无效 无效

文档的建议:能用按需压缩就用它。

按需压缩

发一个带 compaction 参数的请求,把到目前为止的对话原样带上。接口不生成回复,只返回一个压缩块:

{
  "model": "claude-opus-5-5",
  "max_tokens": 4096,
  "messages": [ ……到目前为止的对话…… ],
  "compaction": {"type": "summarize"}
}

请求要带 beta 头 compact-2026-09-04。响应的 stop_reason 是 compaction,内容里只有一个 compaction 块,里面是可读的摘要文字和一个签名。

接着用的规则:

  • 压缩块放在 messages 的最前面,代替它概括的那些消息,后面跟你的下一轮。
  • 被概括的消息要删掉。 留在块前面会报 400;留在块后面不报错,但等于把它们又发了一遍。
  • 块要原样发回,签名不能动,一个请求里只能有一个。
  • 之后每个带着这个块的请求都要带 beta 头。
  • max_tokens 要给够几千,它管的是整个摘要过程。

什么时候压,自己定。常见的做法是每轮结束后把上一个响应的输入和输出 token 加起来(开了缓存的话,读缓存和写缓存的也要加上),超过你定的一个数就压。

没拿到摘要的情况要处理:响应仍然是 200,但内容是空的,这时看 stop_reason。是 max_tokens 就调大重发;是 tool_use 说明模型去调工具了,在自定义的摘要提示里写明不要调工具。无论哪种,都可以先不压、接着聊,过后再压。

两个进一步的做法:

  • 保留最近几轮。 没有专门的参数。你在历史里选一个切点:切点之前的发去压缩,切点之后的原样留着,接在压缩块后面。切点不能落在一次工具调用和它的结果之间。
  • 在后台压。 压缩的请求发出去之后不等它,对话照常在完整的历史上继续;摘要回来了,再把当时发出去的那一段换成压缩块,这期间新增的轮次留在后面。

摘要带不走的东西:图片、文档、抓取的网页。被概括的消息里有这些,换成压缩块之后就没有了,后面还要用就得重新给。

到阈值自动压缩

在普通请求上加一个策略,其余不用管:

"context_management": {
  "edits": [
    {"type": "compact_20260112", "trigger": {"type": "input_tokens", "value": 150000}}
  ]
}

beta 头是 compact-2026-01-12。输入到了阈值,接口先写一段摘要,再接着回答。你把响应照常追加到历史里,下一个请求时接口自动丢掉压缩块之前的内容。

  • 阈值默认 15 万 token,最低 5 万。
  • 摘要用的就是请求里的那个模型,不能换一个便宜的。
  • 请求里有工具时,模型偶尔会在写摘要的那一步去调工具,结果压缩块的内容是空的。办法同样是自定义摘要提示,写明不要调工具。

压缩怎么计费

写摘要是额外的一次模型调用,照常收费、照常算进限流。要注意的是顶层的 input_tokens 和 output_tokens 不包含它。开了压缩之后,响应的 usage 里多一个 iterations 数组,每次调用一项,算总用量要把这个数组里的全加起来。

压缩和思考

这是最绕的一处,只有同时满足“模型会保留以前的思考”“你把 thinking 块发回去”“压缩后还留着几轮”这三条才需要管。5.5 这一代的模型会核对以前的 thinking 块和产生它的那段对话是否一致,压缩把一部分对话换成了摘要,本来对不上;但摘要是接口自己写的,所以按需压缩在几个条件下能让保留下来的思考继续有效:每次压缩都用同一个会保留思考的模型;保留的轮次紧跟在被概括的消息后面、原样发送;system 和 tools 不变。

条件不满足时,压缩本身不报错,问题出在后面第一个带着那些思考的请求上:默认是 400。到阈值自动压缩和自己写摘要没有这个待遇,保留的轮次里的思考要去掉。

二、上下文编辑:清掉旧的工具结果

智能体读过的文件、搜过的结果,模型处理完之后多半不再需要,却一直占着上下文。这个策略到了阈值就把最旧的工具结果清掉,原地换成一句占位的话,告诉模型这里的内容被清除了。

"context_management": {
  "edits": [
    {
      "type": "clear_tool_uses_20250919",
      "trigger": {"type": "input_tokens", "value": 30000},
      "keep": {"type": "tool_uses", "value": 3}
    }
  ]
}

beta 头是 context-management-2025-06-27。

配置项 默认 作用
trigger 10 万输入 token 到什么程度开始清。可以按输入 token 数,也可以按工具调用的次数
keep 3 次 清完之后保留最近几次工具调用
clear_at_least 无 每次至少清掉多少 token,清不到这个数就不清
exclude_tools 无 这些工具的结果永远不清
clear_tool_inputs 否 是否连工具调用的参数一起清。默认只清结果

响应里有一项 context_management,告诉你这次清了什么。

实测:六次工具调用,清掉旧的

本站造了一段历史:模型依次读了 a.txt 到 f.txt 六个文件,每个文件的内容几百个 token。然后问它“你现在还看得到哪几个文件的内容”。

设置 清掉了几次 它的回答
只写策略名,全用默认值 0(没到默认的 10 万 token) 六个文件都看得到
按次数触发,阈值 3,保留 1 3 次,1,506 个 token 看得到 d、e、f,“a、b、c 的读取结果已被清除”
按次数触发,阈值 1,保留 1 5 次,2,665 个 token 只看得到 f
按输入 token 触发,阈值 1,000,保留 2 4 次,2,644 个 token 看得到 e、f
按次数触发,阈值 3,保留 5 400 报错:保留的次数不能大于触发的次数

响应里对应的那一项长这样:

"context_management": {
  "applied_edits": [
    {"type": "clear_tool_uses_20250919", "cleared_tool_uses": 3, "cleared_input_tokens": 1506}
  ]
}

三点观察:

  • 模型知道东西被清了。 它没有编造 a.txt 的内容,而是说看不到了。需要的话它可以再读一遍。
  • 第二行不是“只留 1 次”。 阈值是 3 次、保留 1 次的时候,实际清到剩 3 次就停了。从这几次看,它清到不超过阈值为止,keep 是个下限。要清到只剩一次,阈值也得设成 1。
  • 你的历史不用改。 每次都发的是完整的六次调用,清理是服务端在把提示交给模型之前做的。

它和缓存

清掉内容就改了开头,缓存从清的那个位置起作废。实测清理发生的那一次,usage 里是一次全新的缓存写入;同样的请求再发一次,就全部从缓存读了。

所以不要每次只清一点点。用 clear_at_least 保证每次清得够多,值得为它重写一次缓存。

清理旧的思考

另一个策略 clear_thinking_20251015 管的是以前几轮的 thinking 块。各模型默认的做法不一样:Opus 4.5 及之后、Sonnet 4.6 及之后、Haiku 5.5、Fable 默认全留着;更早的只留最近一轮。用这个策略可以改掉默认值。代码要跑在好几档模型上的话,文档建议明确写 keep,不要依赖各模型的默认。

留着思考,缓存不受影响;清掉思考,缓存从清的位置起作废。

三、通过中转站实测到的

功能 结果
上下文编辑:清工具结果 能用,表现和文档一致。不带 beta 头也能用
上下文编辑:清思考 请求被接受。测试的对话里没有思考,没看到效果
到阈值自动压缩 400:context_management.edits[0] has an unsupported strategy
按需压缩 参数被忽略。返回 200,模型把对话当成普通请求接着回答了

最后一条要特别留意。本站带着 compaction 参数和 beta 头发了请求,拿到的不是压缩块,是一段一两千 token 的普通回复,stop_reason 是 end_turn,usage 里也没有 iterations:

请求摘要:HTTP 200 stop_reason=end_turn 块=[text('以下是基于 SQLite + 整数自增主键的主要实体设计…')] output=1421

没有报错,还花了一笔输出的钱。如果你的代码不检查 stop_reason 是不是 compaction,就会把这段回复当成摘要塞回历史里。照着文档写压缩的循环时,一定先检查 stop_reason,这在官方接口上也是必须的。

通过这家中转站要控制长对话的上下文,目前可行的是:用上下文编辑清工具结果;或者自己写摘要,也就是自己发一个普通请求让模型总结,再用总结替换历史。

和 Claude Code、Agent SDK 的关系

  • Claude Code 自己管上下文:快满时自动压缩,也可以手动 /compact。见《Claude Code 会话和上下文》。
  • Agent SDK 底下跑的是 Claude Code,同样是自动的。
  • 官方 SDK 里还有一个客户端压缩(配合 tool runner 用)。文档说它已经不推荐,Python SDK 从 1.0 起去掉了,TypeScript 和 Ruby 里标了弃用。用服务端的压缩代替。

花费

这一轮十五次请求,按官方价估算约 0.15 美元,其中大半花在按需压缩那四次上:参数被忽略,模型各写了一两千 token 的普通回复。到阈值自动压缩原本要一段五万多 token 的对话才能触发,请求直接被拒了,没有产生费用。

这次实测没有覆盖到的

  • 官方接口没有测。
  • 两种压缩都没有跑通,这一家中转站不支持。压缩块的样子、放置的规则、各种报错、计费方式、和思考的配合,全部是按文档整理的。
  • 保留最近几轮、后台压缩没有试。
  • 上下文编辑只测了按规则清工具结果,用的是造出来的历史,不是真的工具循环。clear_at_least、exclude_tools、clear_tool_inputs 没有试,清思考的策略没有看到实际效果。
  • 只测了一家中转站、一天。

来源

通过 API 中转站使用这些模型?到 Veridrop 免费检测中转站给你的是不是它声称的模型,或者看看中转站排行榜前 100 名。

相关文章