这三件事经常被混为一谈,但它们处在完全不同的位置。
压缩(compaction) 指把接近上限的对话交给模型总结,再用摘要重新初始化一个新窗口。它和随口说的「摘要」有个关键差别:compaction 是 harness 层的状态迁移操作,它决定下一轮推理的初始状态,错了就没有回头路;而摘要通常只是产出给人看的一段文本,错了不影响系统继续跑。
由此得出压缩 prompt 的调优顺序:先最大化召回,再优化精度。第一版应该宁可多留,确认没丢关键信息之后再逐步砍冗余。反过来先追求短,会在不可观测的地方丢状态。
压缩不是单一动作,是一个从轻到重的梯度:清空工具结果(把已消化的大块工具输出替换成占位符,这被明确称为「最安全、最轻手的一种压缩形式」,因为它不动模型自己的推理链)→ 有焦点压缩(由人指定摘要该保留什么)→ 提前压缩(设定窗口填到多满就触发)→ 直接清空(切换到不相关任务时丢弃,比压缩更彻底也更便宜)。
最容易踩空的是「压缩之后什么还在」。 Claude Code 的实际行为分四类,值得当作一般性教训:system prompt 不属于消息历史,原样保留;项目根 CLAUDE.md、auto memory 会从磁盘重新注入;带 paths: frontmatter 的路径规则和子目录里的嵌套 CLAUDE.md 会丢失,直到再次读到匹配文件;被调用过的 skill 正文重新注入时受每个 skill 5,000 token、总计 25,000 token 的上限截断,先丢最旧的,且截断保留文件开头。最后这条有个直接的写作结论:指令文件要把最重要的内容放最前面,因为截断从尾部砍。
窗口变大不取消压缩,只是推迟它。默认 200K 也好,1M 变体也好,机制是一样的。
子代理隔离是另一条路:把会产生大量一次性中间物(搜索结果、日志、文件内容、失败尝试)的工作交给一个拥有独立窗口的子代理,主 agent 只收回蒸馏后的结果。它的价值不在并行加速——那是副产品——而在信息不对称:探索过程的熵留在子窗口,只有结论穿过边界。
量级是可测的:文档里的一个会话示例中,子代理为回答一个研究问题读了 6,100 token 的文件,回到主窗口的结果只有 420 token,约 14.5:1;那 6,100 token 从未占用过主窗口。经验区间是子代理返回 1,000–2,000 token 的凝练摘要。
这里要说清一件事:隔离省的不只是 token。 如果只算 token 账,那 6,100 对 420 只是省了钱。真正的收益有三层——第一,那 6,100 token 里包含大量失败尝试和无关片段,它们进主窗口是干扰项,而我们已经知道单个干扰项就有代价;第二,它们会把后续真正相关的证据往中段挤,直接踩上一节的 U 形曲线;第三,独立窗口能规避三类行为退化:agentic laziness(活干一半)、self-preferential bias(agent 偏袒自己的产出)、goal drift(长回合后目标保真度流失)。让一个新窗口的 agent 来审另一个 agent 的产出,是绕开自我偏好最简单的办法——这是纯 harness 收益,和模型无关。
隔离要成立有个反直觉前提:主 agent 必须写清委派指令——明确的目标、输出格式、任务边界、可用工具。因为子代理看不见主会话,主 agent 脑子里「不言自明」的东西对它就是缺失信息。委派不清的直接后果是几个子代理做重复工作,或者都漏掉同一块。并行规模的经验规则:简单事实查询 1 个子代理(3–10 次工具调用),对比类查询 2–4 个(每个 10–15 次),复杂研究 10 个以上;lead agent 一次并行拉起 3–5 个。代价是同步执行——lead 必须等最慢的那个返回,所以子代理数量增加不必然带来墙钟时间线性下降。
压缩和隔离是竞争关系,不是互补:能预见的大批量读取应该一开始就丢进子窗口烧掉(预防);不可预见的自然增长才走压缩(补救)。用压缩去清理本可以隔离的脏东西,是在为已经付过的注意力代价再付一次总结代价。
最后一层是落盘。 压缩是有损的,重复压缩会累计漂移——第 3 次压缩时,模型总结的是第 2 次摘要的摘要。凡是必须精确的状态(计数、清单、已试过的方案、决策理由、文件路径)都该写到窗口外的外部记忆里,压缩只负责叙事上下文。多 agent 研究系统的做法就是接近 200,000 token 上限时把计划写进外部记忆,而不是指望摘要保住它。Claude 玩 Pokémon 是最直观的案例:靠窗口外的笔记跨数千个游戏步骤维持精确计数,并逐步构建已探索区域的地图——数千步远超任何窗口容量,没有外部笔记这个任务在结构上就不可能完成。
外部记忆有两条纪律。写入时机:可靠的触发点是「状态发生了变化」——完成子任务、推翻假设、拿到不可重算的结果;写太频笔记本身变噪声,写太少压缩来时状态已经丢了。写方法不写快照:记「用 SELECT count(*) FROM x 查当前条数」能长期有效,记「当前 1,283 条」下一轮就是谎言,而模型会把过期数字当事实拿去推理。