面试前读 · 眼镜端会议 Agent核对日期 2026-10-12作者 菜西

压缩上下文,先删能找回的,最后才让模型改写

Agent 的上下文压缩不是一种技术,是一串按可逆性排好的取舍:能重新取回的工具输出先清,原文先挪到窗口外、留个指针,再把要紧的状态抽成结构化笔记,最后才用摘要重写历史;按 token 删字和压 KV cache 是推理层的手段,前面几层不够时才上。越往后走,省下的 token 越多,丢掉的细节也越难追回,而且几乎每一步都会让 prompt cache 失效一次。

本页按这个顺序讲十种做法的机制、好处、代价、适用场景和会怎么坏,核对 Anthropic 与 OpenAI 截至 2026-10-12 的原生接口,拆解 Sage 的实现,最后落到「两小时会议实时转写」的设计和面试题。每种做法都配了压缩前后的对照图,六个关键机制做成了可逐步播放的动画;赶时间就先读第 00 节的五分钟速览。

005 分钟速览

五分钟版:一条线、十种做法、三句开场

所有做法都在回答两个问题:剪掉哪一段,剪下来的还能不能拿回来。按「能不能拿回来」从上往下排,就是这张图。每一格都能点,跳到对应小节;小节里有动画,可以逐步播放。

总览地图:十种做法按从可逆到有损分为六层,点击任一格跳到对应小节越往下:越有损、越依赖模型判断规则 · 不调模型 · 可预测03截断 / 滑窗04清旧工具输出挪出窗口 · 原文还在07卸载 + 召回08子 Agent 隔离抽成表 · 人能审06结构化状态 · 记忆文件模型改写 · 有损05一次性05滚动05分层推理层 · 删字 / 压 KV09LLMLingua10KV 压缩厂商托管 · 服务端11Anthropic11OpenAI12Sage规则定档留桩可取阶段冻结按账重建块级摘要共享前缀14会议07 原文仓06 状态表05 分层绿底:会议场景的主力。每一格都能点,跳到对应小节。
总览地图 · 十种做法按「剪下来的还能不能拿回来」从上到下排。右栏是 Sage 覆盖到的部分和会议场景要组合的三层。
  1. 03
    截断 / 滑动窗口:按位置删最旧的。零成本,删掉就没了;工具调用和结果必须成对删;窗口每轮都动,缓存就不命中。
  2. 04
    清旧工具输出:旧结果换成一行占位,调用参数保留。Anthropic clear_tool_uses 默认 10 万 token 触发、留最近 3 次,clear_at_least 防止频繁打碎缓存。
  3. 05
    LLM 摘要:一次性(Claude Code /compact,9 节模板)、滚动(会漂移)、分层(每层由下一层生成,可追溯)。
  4. 06
    结构化状态:目标、计划、决定、待办写成固定字段,放在固定位置或文件里,压完从磁盘装回。
  5. 07
    卸载 + 召回:原文写盘只留路径,需要时 grep 或检索取回逐字原文。失败多在模型不知道有东西可取。
  6. 08
    子 Agent 隔离:脏活在别的窗口里干,只交回结论。主窗口干净了,多 Agent 系统的总 token 约为聊天的 15 倍。
  7. 09
    提示词压缩:小模型按信息量删 token,LLMLingua 报告最高约 20 倍。会删掉否定词和数字,代码和 JSON 别用。
  8. 10
    KV 压缩与 prompt cache:KV 压缩在推理服务内部(StreamingLLM、H2O、KIVI、MLA);prompt cache 只认逐字节相同的前缀,Anthropic 读价 0.1 倍、写价 1.25 倍。
  9. 11
    厂商原生:Anthropic 有上下文编辑和服务端压缩,摘要可读;OpenAI 的压缩项是加密的,人读不了。
  10. 12
    Sage:历史只追加,每轮编译视图:按块定档、留桩可 expand、阶段内冻结、按成本不等式开新阶段。缺口是不压对话文字。
  11. 14
    会议场景:原文仓 + 结构化状态 + 分层摘要;实时路径不等摘要;逐字问题走检索。

面试开场三句

  1. 压缩按可逆性排序:先清能重新取回的,再卸到外部留指针,再抽结构化状态,最后才让模型摘要。
  2. 每一刀都会改动前缀、打碎 prompt cache,所以要一次压够、在自然断点压,最好先算账再压。
  3. 会议场景不能只靠摘要:原文仓兜底,状态表对账,分层摘要只负责「聊了什么」。
010 — 窗口上限

要压,不只是因为装不下

先说两个词。token 是模型读写文字的最小单位,中文大致一两个字一个 token,英文大致四个字母一个。上下文窗口(context window)是模型一次能看到的 token 总量:系统提示、工具定义、历史对话、工具返回的结果,全挤在这一个窗口里。Agent 每调一次工具就往里追加一段,窗口只会越来越满。

压缩的理由有四个,后三个往往比第一个更早咬人:

  • 窗口上限。超过就报错,对话没法继续。窗口做到 100 万 token 的模型也一样,只是撞墙晚一点。
  • 成本。API 每一轮都按发出去的全部输入计费。第 50 轮要为前 49 轮的历史再付一次钱,单轮越来越贵,总花费近似按轮数的平方涨。
  • 延迟。模型要先把输入全部读一遍才能吐第一个字,这一步叫 prefill(预填充)。输入越长,首字等待越久。戴在脸上的眼镜,这个等待用户直接感觉得到。
  • 注意力被稀释。窗口里东西越多,模型越难用上其中某一条。Liu 等人的 Lost in the Middle 把关键信息放在长输入的不同位置,发现放在开头或结尾时模型最容易用上,放在中间时最差,曲线呈 U 形。Chroma 2025 年的 Context Rot 报告测了 18 个模型,结论同向:任务不变,输入变长,表现就掉。Anthropic 把这叫「注意力预算」:上下文是边际收益递减的有限资源。
中间的信息最容易被忽略 用上关键信息的概率 中间:最容易被忽略 开头 中间 结尾 关键信息在输入里的位置
图 1 · 关键信息放在长输入中间时最难被用上。这是形状示意,不是论文原始数值,具体数字见 Liu et al. 2023(TACL 2024)的多文档问答实验。由此得一条设计规则:要紧的东西放头或尾,别埋在中间。

所以压缩的目标不是「塞得下」,而是每一轮窗口里只留这一步真正要用的东西。塞得下但塞满了,照样又慢又贵又笨。

一句话压缩不是为了塞得下,而是让每一轮只留这一步要用的东西:省钱、省首字延迟、少被「中间」稀释。

02一张图 · 六种剪法

一条纸带看全部做法:区别在剪哪一段

把上下文想成一条按 token 计长的纸带,从左到右依次是系统提示和工具定义、记忆文件、早期对话、工具输出、最近几轮。所有压缩做法都是在这条纸带上剪、换、贴、挪,区别在于剪哪一段、剪下来的还能不能拿回来。

六种剪法在纸带上的位置 原样 系统 记忆 早期对话 工具输出 对话 工具 最近几轮 截断 / 滑动窗口剪掉的拿不回来 系统 工具 最近几轮 清旧工具输出留桩,可重新调工具 系统 记忆 早期对话 桩 对话 工具 最近几轮 腾出 LLM 摘要模型改写,有损 系统 记忆 摘要块 最近几轮 腾出 卸到外部 + 召回原文全在,按路径取 系统 记忆 早期对话 路径 对话 最近几轮 外部文件 / 检索索引(不占窗口) 子 Agent 隔离脏活在别的窗口里 系统 对话 短结论 最近几轮 子 Agent 自己的窗口:读了 40 个文件
图 2 · 同一条上下文的六种剪法。斜线阴影表示「从此看不见」,绿框表示「换成了更短的东西」,虚线框是腾出来的空间。从上往下,越往后越依赖模型自己的判断。

选法的顺序:可逆的先做,有损的后做;规则能决定的,不交给模型决定。

这条顺序和 Anthropic、Manus 公开的经验一致:Anthropic 的上下文工程文章把清掉旧工具结果称为最安全、最轻的一种压缩;Manus 主张压缩必须「可恢复」,网页正文可以丢,URL 必须留。

一句话区别只有两点:剪哪一段,剪下来的还能不能拿回来。可逆的先做,规则能定的不交给模型。

03规则 · 不可逆

截断与滑动窗口:最便宜,也最粗暴

做法就是按长度砍。截断(truncation)是超了就删最早的消息;滑动窗口(sliding window)是永远只留最近 N 轮或最近 N 个 token,像一扇只往前挪的窗。系统提示通常钉住不删。工具层面也有一种截断:单次工具输出超过若干行或字节就只留头(或头加尾),几乎每个 harness 都做。

动画 1 · 滑动窗口可单步、可点步骤跳转
滑动窗口:窗口只留系统提示和最近 5 轮,新一轮进来最早一轮就被丢掉 上下文(从左到右是时间) 系统 钉住 T1 T2 调用 结果 T5 T6 T7 T8 约束 一对 ! 窗口 = 最近 5 轮 T1 是用户一开始的约束:「别动 public API」。 第 6 轮进来,窗口右移,T1 被丢掉。 约束没了,模型接下来就可能去改 API。 第 7 轮进来,T2 被丢掉。 「调用」和「结果」是一次工具调用的一对。 按条数切:调用出去了,结果还在窗口里。 接口找不到配对的调用,直接返回 400。 修法:成对删。调用和结果一起出去, 窗口里宁可少一轮,也不留半对。 缓存账:窗口每轮都在动,系统提示之后的 前缀每轮都不同,缓存只能命中最前面一段。 命中每轮按全价重读
1 / 1
  1. 窗口装满:系统提示钉住不动,后面只留最近 5 轮。T1 是用户最早给的约束。
  2. 第 6 轮进来,窗口整体右移一格,T1 被丢掉。最先被删的,恰恰是最早、往往也最重要的要求。
  3. 第 7 轮进来,T2 被丢掉。下一格是一次工具调用和它的返回结果,两条消息是一对。
  4. 第 8 轮:如果只按条数切,调用被删、结果还留着,Anthropic 和 OpenAI 的接口都会拒收(400)。
  5. 正确做法是成对删:调用和结果一起出去,窗口宁可少放一轮。
  6. 缓存代价:窗口每轮都动,前缀每轮都变,prompt cache 只能命中系统提示那一小段。
动画 1 · 滑动窗口不调模型、零延迟、完全可预测;代价是被切掉的内容永远拿不回来。斜线阴影表示「已被丢掉」。
机制
按位置删:留系统提示和最近 N 轮,其余丢弃。删要成对删:模型发起的工具调用和它的返回结果必须同进同出,否则 Anthropic、OpenAI 的接口都会拒收。
好处
不调模型,零延迟,完全可预测,好测试。
代价
删掉的就没了。最早的用户要求和约束恰恰在最前面,最先被删。
用在
闲聊机器人、只关心最近状态的任务,以及作为其他做法兜底的最后一道硬上限。
会怎么坏
目标丢失:开头说的「别动 public API」滑出窗口,模型就去动了。悬空调用:只删了工具调用对的一半,请求返回 400。每轮都滑:窗口每轮都动,前缀每轮都变,prompt cache 一次都命中不了(见第 10 节)。

一句话滑窗零成本但不可逆,只配当最后一道硬上限,而且必须成对删。

04规则 · 基本可逆

先删旧的工具输出:最安全的一刀

Agent 上下文里最占地方的不是对话,是工具结果:读进来的整份文件、搜索结果、命令输出。模型读过、用过之后,这些东西大多就没用了,而且多数可以重新取。工具结果清除(tool result clearing)就是把较早的工具结果换成一行占位文字,比如「[此结果已清除]」,工具调用本身(调了什么、参数是什么)保留。

动画 2 · 清掉旧的工具输出参数取自 clear_tool_uses_20250919
工具结果清除:超过触发阈值后,从最旧的开始把工具结果换成占位,保留最近 3 次和被排除的工具 上下文(从上到下是时间,条长 = token 数) 系统 + 工具用户请求 ① read a.ts② memory③ grep ④ read b.ts⑤ bash 测试⑥ read c.ts [已清除] 调用参数仍在 exclude_tools:永不清 [已清除] keep = 3 输入总量 trigger 10 万 六次工具调用,结果一次比一次大,窗口越来越满。 输入越过 trigger(默认 10 万 token),清除触发。 从最旧开始换成占位;memory 被排除,最近 3 次不动。 左侧细线:缓存只命中到第一个占位之前, 之后全部重写,所以每次至少清够 clear_at_least。 之后要 a.ts 的内容:只能再调一次 read, 文件若已被改,拿到的已不是当时那份。
1 / 1
  1. Agent 干活时,工具结果(读文件、搜索、跑测试)是上下文里最占地方的东西。
  2. 输入 token 越过 trigger(默认 100,000),服务端在模型看到请求之前执行清除。
  3. 从最旧的开始,把工具结果换成一行占位,调用本身(工具名、参数)保留;keep 默认保留最近 3 次,exclude_tools 里的工具永不清除。
  4. 清除改动了历史中段,第一个占位之后的缓存全部作废。clear_at_least 规定一次至少清掉多少,清不够就不清,免得为一点点空间付一次缓存重写。
  5. 代价:模型之后若还要那份内容,只能再调一次工具;文件可能已经改过,命令输出也不一定能重现。
动画 2 · 工具结果清除只改「结果」,不改模型说过的话,是最安全的一刀。绿色占位表示「换成了一行字」,底部条是输入总量。
机制
触发条件满足时(比如输入超过某个 token 数),从最旧的开始把工具结果换成占位符,保留最近 K 次调用的完整结果;某些工具可以列为永不清除,比如记忆工具。Anthropic 的 clear_tool_uses_20250919 就是这个做法,参数见第 11 节。
好处
不调模型,不改写模型说过的话;模型知道自己看过什么,需要时可以再调一次工具。社区把 Claude Code 里的这类机制叫 microcompact,Sage 的前身 harness-pi 也有同名插件。
代价
「可以重新调」不等于「能取回原文」:文件可能已经改过,命令输出、网页内容不一定能重现。每次清除都改动了历史中段,清除点之后的前缀缓存作废。
用在
编码 Agent、搜索 Agent 这类工具调用密集、单次结果很大的任务。长任务几乎都该先开这一项。
会怎么坏
重复劳动:模型忘了结论,把同一个文件又读一遍。结论跟着证据一起没了:要紧的数字只在工具结果里,模型没在对话里复述过,清掉就丢。频繁小清:每次只清一点,却每次都打碎缓存,所以要规定每次至少清掉多少。

同类规则还有两种更细的:覆盖淘汰,同一个文件后来又读了一遍,前一次的结果作废;重试淘汰,一次调用出错,紧接着用同一工具、同样参数又调了一次,出错那次的输出作废。两条都完全确定、可复现,Sage 就是这么做的(第 12 节)。

一句话清旧工具输出是最安全的第一刀,但要一次清够,并在清之前让模型把结论写下来。

05模型改写 · 有损

LLM 摘要:省得最多,也最容易悄悄走样

做法是让一个模型(同一个,或更便宜的)读一段历史,写一份短总结,再用总结替换原文。按「多久总结一次、总结谁」分三种。

一次性、滚动、分层三种摘要 A · 一次性摘要 一份摘要 快满时做一次,全部旧历史压成一块。例:Claude Code /compact。 B · 滚动 / 增量摘要 新段 新段 新段 S1 S2 S3 S4 每次:旧摘要 + 新内容 → 新摘要。这是摘要的摘要, 误差逐轮累积:S4 里的事实可能已和原文对不上。 C · 分层摘要 全局摘要 段摘要 1 段摘要 2 段摘要 3 段摘要 4 原文块 → 段摘要 → 全局摘要,每层由下一层生成。 窗口里放全局 + 最近几段;要细节时顺着树往下取原文。
图 5a · 三种摘要的数据流。滚动摘要的风险在于「从摘要生成摘要」;分层摘要每一层都回到下一层去生成,并保留底层原文,所以误差不累积、细节可追溯。

A · 一次性摘要

机制
上下文快满时,把系统提示以外的全部历史交给模型,按模板写一份「交接单」,用交接单替换整段历史,从这里接着干。
好处
一次能把十几万 token 压到几千;实现简单;模板可以按任务定制。
代价
多一次模型调用,要读全部历史(缓存还热时便宜得多,见第 10 节);这一轮用户要等;压完前缀整段换掉,系统提示之后的缓存全部作废。
用在
长编码任务、长对话,最好在自然断点(一个子任务刚做完)时做。
会怎么坏
丢关键细节:文件行号、报错原文、用户随口提的一条约束最容易被概括掉。状态写反:把「已决定」写成「在讨论」,或者反过来。被阈值逼着压:压在子任务中间,正在用的细节被摘掉。

B · 滚动 / 增量摘要

机制
维护一份持续更新的摘要。每过一段(N 轮或 N 分钟),把「上一份摘要 + 这一段新内容」交给模型,产出新摘要。窗口里永远是「当前摘要 + 最近原文」。对话记忆领域的递归摘要(Wang 等 2023)就是这个结构。
好处
每次只处理一小段,耗时和成本稳定;可以放后台异步跑,不阻塞用户;适合没有终点的流式输入。
代价
调用次数多;每次都在改写上一份摘要。
用在
长时间陪伴、客服、会议这类持续输入的场景。
会怎么坏
摘要漂移(summary drift):每次重写都可能把某个事实改动一点,十几次之后,「周三交付」变成「本周交付」,「张三负责」变成「团队负责」。原文早已不在输入里,误差只累积、不回滚。
动画 3 · 滚动摘要怎样一步步走样例子是虚构的会议片段
滚动摘要:每次用旧摘要加新一段生成新摘要,原文离开窗口,事实逐轮漂移;分层摘要每段从原文生成,原文留在仓里 原文(按段到来) 第 1 段张三周三交 第 2 段预算 30 万 第 3 段李四测数据 第 4 段下周复盘 斜线:已离开窗口,摘要器再也看不到 S1张三周三前交付 v2 S2张三周三前交付 v2;预算 30 万 S3团队本周交付 v2;预算约 30 万;李四测数据 S4团队近期交付;预算待定;李四测数据; 下周复盘 = 摘要器(第 1 段) = 摘要器(S1 + 第 2 段) = 摘要器(S2 + 第 3 段) 绿字:已和原文不符 对照 · 分层摘要 张三·周三 预算 30 万 李四·测数据 下周复盘 全会摘要:每次都从这 4 份段摘要重算 第 1 段到来,摘要器写出 S1,事实准确。 S2 = S1 + 第 2 段。第 1 段原文离开窗口。 S3 改写 S2 时把「张三」概括成「团队」, 「周三」写成了「本周」。 再改写一次,「预算 30 万」成了「待定」。 窗口里没有原文,没人能发现这些错。 分层:每份段摘要都从原文生成,不改写别的摘要; 原文留在仓里,问「谁、哪天」时回去查原话。 原文仓:4 段原文全在,按时间戳可取回
1 / 1
  1. 第 1 段进来,摘要器写出 S1:「张三周三前交付 v2」,与原文一致。
  2. 第 2 段进来,把「S1 + 第 2 段」交给摘要器,得到 S2。第 1 段原文离开窗口。
  3. S3 是改写 S2 得来的:「张三」被概括成「团队」,「周三」成了「本周」。这就是摘要漂移。
  4. S4 再改写一次,预算变成「待定」。窗口里只剩 S4 和最新原文,误差只累积、不回滚。
  5. 对照分层摘要:每份段摘要都从原文生成,全会摘要从段摘要重算,原文留在仓里,细节可追溯。
动画 3 · 滚动摘要的风险不在单次总结,而在「从摘要生成摘要」。会议、客服这类没有终点的输入最容易中招。

C · 分层摘要

机制
原文按段切块,每块写一份段摘要;若干段摘要再合成更高一层;最顶层是全局摘要。窗口里放顶层、最近几段的摘要和最新原文。原文和每层摘要都存下来,需要细节时按树往下取。MemGPT 把这推广成操作系统式的分级内存:窗口是内存,外部存储是磁盘,模型自己调函数换入换出。
好处
误差不累积(每层由下一层生成,不由上一份摘要生成);粒度可选;可追溯到原文。
代价
工程量最大:要存储、要索引、要决定在哪切块、何时合并。
用在
超长文档、长会议、跨多天的项目历史。
会怎么坏
切在话题中间:一个决定的前因后果被分到两块,两份段摘要各写一半。上层过时:下层更新了,上层没重算。

Claude Code 的 /compact 和自动 compact

Claude Code 是一次性摘要的标准样本,几个具体事实值得记住(官方文档核对于 2026-10-12):

  • 两种触发。手动 /compact 可以带重点说明,例如 /compact focus on the auth bug fix,摘要就按你指定的重点保留;自动 compact 在上下文接近上限时触发,做的事和 /compact 相同。另有 /rewind:选一条消息,「从这里往后总结」或「总结到这里为止」,只压一段。
  • 阈值。官方「Default auto-compact thresholds」现在的写法是:没设压缩窗口时,在模型的上下文上限处压缩;原生 1M 窗口的模型(Fable 系列、Sonnet 5 及以后、Haiku 5.5、Opus 4.7 及以后)默认在约 967K token 时压;Sonnet 4.6 / Opus 4.6 不开扩展上下文时在 200K 边界压。可用 /autocompact 500k、启动参数 --autocompact、设置项 autoCompactWindow 或环境变量 CLAUDE_CODE_AUTO_COMPACT_WINDOW 修改,范围 100K 到 1M,环境变量优先级最高。
  • 早年的阈值。200K 窗口时代,社区从打包代码里读出的公式是「有效窗口 − 13,000 token 缓冲」,约合 83.5%;CLAUDE_AUTOCOMPACT_PCT_OVERRIDE 只能把阈值调低、不能调高(GitHub issue #31806)。「大约 80% 多触发」是旧版本的事实,现在已改为按窗口大小配置。
  • 摘要模板。官方没有公开全文。社区从发布包中提取的 BASE_COMPACT_PROMPT 要求 9 节:主要请求与意图、关键技术概念、文件与代码片段、错误与修复、问题解决过程、所有用户消息、待办任务、当前工作、可选的下一步。模型先在 <analysis> 里打草稿,再写 <summary>,只保留后者;压缩时明确禁止调工具;「下一步」要求逐字引用最近的对话,原文说明这是为了避免任务理解漂移。「所有用户消息」这一节最值得借鉴:用户的纠正和反馈是最不能丢的信息。
  • 压完之后补回什么。官方「What survives compaction」表:系统提示照旧生效;项目根目录的 CLAUDE.md 和自动记忆从磁盘重新注入;重新读入最近改过的最多 5 个文件,超过 5,000 token 的只给路径;已调用的 skill 正文重新注入,每个最多 5,000、合计最多 25,000 token;带 paths: 的规则和子目录里的 CLAUDE.md 会被一起摘要掉,要常驻就挪到根目录的 CLAUDE.md。
Claude Code 压缩前后:压缩前窗口被历史和工具输出占满;压缩后是系统提示、从磁盘重新注入的 CLAUDE.md 和记忆、9 节摘要、最近改过的最多 5 个文件和已调用的 skill 正文 压缩前 · 接近阈值 系统 CLAUDE 对话 + 工具输出(几十万 token) 最近 摘要请求:同样的前缀 + 末尾一条总结指令 压缩后 系统 CLAUDE 9 节摘要 ≤5 个文件 skill 腾出 从磁盘重新注入 每个 >5k 只给路径 各 ≤5k,合计 ≤25k 摘要模板的 9 节(社区提取版) 1 主要请求与意图2 关键技术概念3 文件与代码片段 4 错误与修复5 问题解决过程6 所有用户消息 7 待办任务8 当前工作9 下一步(逐字引用) 被一起摘要掉:带 paths: 的规则、子目录里的 CLAUDE.md 先在 <analysis> 里打草稿,只保留 <summary>;压缩时禁止调工具。
图 5b · Claude Code 压缩前后。靠得住的东西(规则、记忆、最近文件、skill)压完从磁盘装回来,摘要只负责「聊到哪了」。补回规则出自官方「What survives compaction」;9 节模板来自社区提取,官方未公开全文。

要点:Claude Code 的摘要不是唯一的记忆来源。真正靠得住的东西(规则、记忆、计划、最近文件)都在磁盘上,压完再从磁盘装回来;摘要只负责「我们聊到哪了」。这就是第 6 节的做法。

一句话摘要省得最多也最会走样:用分层不用滚动,模板字段固定,原文要留着。

06规则 + 模型 · 可审

结构化状态:把要紧的事从叙述里抽出来

摘要是一段散文,结构化状态是一张表。做法是让 Agent 在干活过程中把关键状态按固定格式写下来:目标、计划、已做的决定、待办清单、踩过的坑。这张表放在窗口里的固定位置,或者存成文件、每轮读回。历史怎么压,表都还在。

结构化状态前后:压缩前决定和待办散落在历史各处;压缩后它们被抽成固定字段的状态表,放在窗口固定位置,并存成文件,压缩后从磁盘重新注入 之前 · 要紧的事散在叙述里 系统 决定A待办B改计划数字 42 ………… 历史一压,这几处可能被概括掉;放在中间,也最容易被忽略。 Agent 边干边写 / 系统抽取 之后 · 抽成表,钉在固定位置 系统 状态表目标:…计划:1 ✓ 2 … 3决定:A(出处 T12)待办:B · 数字 42 摘要 最近几轮 NOTES.md · todo 写入 压缩后重新注入 磁盘上的文件不受压缩影响
图 6 · 结构化状态把「决定、待办、数字」从散文里抽出来,字段固定,漏了一眼可见。放在稳定前缀之后、易变内容之前:靠前避开「中间被忽略」,又不至于每次更新都打碎整段缓存。
机制
三种常见形态。todo 列表:Agent 用工具维护任务清单,做完一项勾一项,Claude Code 的 TodoWrite 就是这个。笔记文件:Agent 在工作目录写 NOTES.md 或 progress.md 记进度和发现;Anthropic 的文章举过 Claude 玩宝可梦时自己维护笔记、跨越多次上下文重置继续玩的例子。记忆文件:CLAUDE.md / AGENTS.md 这类项目级说明,启动时自动加载,压缩后从磁盘重新注入;Claude Code 还有 auto memory,让模型自己往里积累经验。API 层面,Anthropic 提供 memory 工具(memory_20250818),让 Claude 在客户端托管的目录里增删查改文件。
好处
人能读、能改、能 diff;字段固定,漏了什么一眼可见;与摘要互补,摘要丢了也不怕;放在窗口固定位置(开头或结尾),正好躲开「中间被忽略」。
代价
依赖模型自觉更新,它不写就没有;格式要事先设计;状态块每更新一次,它之后的缓存就作废,所以状态块应放在稳定前缀之后、易变内容之前。
用在
多步任务、跨会话项目、需要对账的场景(待办、决议、数字)。
会怎么坏
状态过期:做完了没勾掉,计划改了表没改。记忆污染:一次错误结论写进记忆文件,以后每次会话都被当成事实加载。文件膨胀:CLAUDE.md 越写越长,自己又成了需要压缩的东西。

一句话要紧的事别只放在散文里:抽成固定字段的表,存在磁盘上,压完再装回来。

07挪出窗口 · 可逆

卸到外部,事后再召回

卸载(offloading)是把大块原文写到窗口外面(文件、数据库、对象存储),窗口里只留一个指针:路径、编号或一句描述。需要时,模型用工具按指针取回,或者系统按当前问题检索相关段落再放回来。后一种就是 RAG(检索增强生成:先检索,再把检索到的内容放进提示让模型回答)。

动画 4 · 卸到外部,再检索回来左:窗口 右:窗口外的存储
卸载与召回:大块工具输出写到磁盘,窗口里只留头尾和路径;需要时按路径或检索取回逐字原文 上下文窗口 磁盘 / 检索索引 系统 + 工具 + 对话 bash: pnpm test 输出… 1,200 行 …Error #1 …Error #2 …Error #3 timeout …… 约 5 万 token 头 20 行 … 尾 5 行全文: logs/run-17.txt 改代码 再跑一次 还空着 问:第 3 个错误是什么? run-17.txt 第 812–816 行Error #3 timeout(逐字) logs/run-17.txt全文,一字不丢Error #1 …Error #2 …Error #3 timeoutBM25 + 向量索引 grep "Error" / 检索 [日志已省略] ← 没有路径和线索 工具一次返回约 5 万 token 的测试日志。 超过阈值:整份写盘,窗口里只留头尾和路径。 继续干活,窗口一直很空;原文全在磁盘上。 用户问到细节:按路径 grep,或按问题检索。 命中的几行原文放回窗口尾部,逐字准确。 失败方式:桩写得太简略,模型看不出里面 有它要的东西,就不去取,转而猜。
1 / 1
  1. 工具一次返回约 5 万 token 的测试日志。大多数时候用不到,偶尔要逐字查。
  2. 超过阈值就整份写到磁盘,窗口里只留头几行、尾几行和文件路径。Sage 的 bash 工具就是这样:超过 30,000 字节整份写盘,留头 20,000、尾 5,000 字节和路径。
  3. Agent 继续干活,窗口保持很空;原文一个字没丢。
  4. 后来用户问「第 3 个错误是什么」:模型按路径 grep / read,或者系统按问题做检索(关键词 BM25 或向量相似度)。
  5. 命中的几行原文放回窗口尾部。召回的是逐字原文,不会有摘要漂移。
  6. 最常见的失败:桩只写「已省略」,没有路径、没有线索,模型不知道有东西可取,就开始猜。
动画 4 · 卸载把「放不下」变成「需要时再取」。压缩可逆,代价是多一次工具往返,上限由检索质量决定。
机制
工具输出超过阈值时整份写盘,只返回「头若干行 + 尾若干行 + 文件路径」;历史中段的大块换成带编号的桩;回答问题时按关键词(BM25)或向量相似度从外部存储召回相关片段。Manus 把沙箱文件系统当作「容量不限、可持久、模型能自己操作的上下文」:网页正文丢掉但留 URL,文档内容丢掉但留路径。
好处
原文一个字不丢,压缩可逆;窗口里只有指针,极省;召回内容是逐字原文,不会有摘要漂移。
代价
召回可能漏,检索质量决定上限;模型得知道「有东西可取」并主动去取;多一次工具往返的延迟。
用在
大文件、长日志、网页、长会议原文,以及任何「大多数时候用不到、偶尔要逐字查」的内容。
会怎么坏
不知道自己不知道:桩写得太简略,模型看不出里面有它要的东西,就不去取,转而瞎猜。召回错段:语义相近,说的却是另一件事。指针失效:文件后来被改或被删,取回的已不是当时那份。

一句话卸载让压缩可逆,成败在桩:写清路径和线索,模型才知道有东西可取。

08隔离 · 只交结论

用子 Agent 隔离上下文:脏活在别的窗口里干

主 Agent 把一个需要大量阅读的子任务(「查清楚这个仓库里谁调用了 X」)派给子 Agent。子 Agent 有自己全新的窗口,读几十个文件,最后只交回一两千 token 的结论。主窗口从头到尾没见过那几十个文件。

动画 5 · 子 Agent 隔离上:主窗口 下:子窗口
子 Agent 隔离:主 Agent 派出任务说明,子 Agent 在自己的窗口里读大量文件,只把短结论交回,子窗口随后丢弃 主 Agent 的窗口 系统 对话 + 计划 派任务 结论 仍很空 目标 · 范围 · 返回格式 子 Agent 自己的窗口(全新) 任务说明 读了 40 个文件、跑了十几次搜索 结论 + 证据路径 子窗口整个丢弃 token 账(Anthropic 公开数据,相对普通聊天) 聊天 1× 单 Agent 约 4× 多 Agent 约 15× 主 Agent 要查清「谁调用了 X」,这要读很多文件。 派任务:写清目标、范围和返回格式,交给子 Agent。 子 Agent 在全新窗口里读几十个文件,越读越满。 它只把一两千 token 的结论和证据路径交回。 子窗口丢弃。主窗口从没见过那 40 个文件。 主窗口干净了,总 token 却大涨。
1 / 1
  1. 主 Agent 的窗口里只有系统提示、对话和计划。下一步要查「谁调用了 X」,需要大量阅读。
  2. 主 Agent 写一段任务说明(目标、范围、返回格式)派给子 Agent。说明写得太短,子 Agent 就会做错事。
  3. 子 Agent 在自己全新的窗口里读几十个文件、跑十几次搜索,窗口越来越满。
  4. 子 Agent 只交回一两千 token 的结论,最好附上文件路径,主 Agent 可以抽查。
  5. 子窗口整个丢弃。主窗口只多了一小块结论,从没见过那几十个文件。
  6. 账:主窗口省了,总 token 却大涨。Anthropic 公开的数字是单 Agent 约为聊天的 4 倍,多 Agent 系统约 15 倍。
动画 5 · 子 Agent 把「读」和「想」分到不同窗口。适合读多写少、能清楚切开的调研;子任务之间有隐含决定要协调时,割裂比省下的空间更贵。
机制
派任务时给子 Agent 一段说明和一组工具;子 Agent 独立跑循环;结束时返回压缩后的结论,有时附上文件路径作为证据。Claude Code 的 subagent 和 Anthropic 的多 Agent 研究系统都是这个结构。
好处
主窗口干净;子任务可以并行;每个子窗口都短,各自不受「中间被忽略」影响。
代价
总 token 大涨。Anthropic 公开的数字:单 Agent 大约用掉聊天 4 倍的 token,多 Agent 系统大约 15 倍。子 Agent 从零开始,不知道主 Agent 之前讨论过的约束。
用在
能清楚切开、读多写少的调研类子任务:代码搜索、资料调研、并行检查。
会怎么坏
上下文割裂:Cognition 的《Don't Build Multi-Agents》举过例子,两个子 Agent 各自做了相互冲突的隐含决定,拼起来就不对。结论失真:子 Agent 交回的总结本身就是一次有损摘要,主 Agent 无从核对。说明写得太短:子 Agent 做的不是你要的事。

一句话子 Agent 用更多总 token 换一个干净的主窗口,适合能切开的阅读型任务。

09删字 · 难读

提示词压缩:按 token 删掉「不重要的字」

前面的做法都以「消息」或「块」为单位。提示词压缩深入到字词:用一个小模型判断每个 token 的信息量,删掉信息量低的,留下一段人读起来像电报、大模型仍然看得懂的文字。

提示词压缩:小模型给每个词打信息量,删掉低信息量的词;删对了意思不变,删掉否定词则意思反了 原文(ASR 转写)· 柱高 = 小模型算出的信息量 嗯 那个 我们 周三 之前 不要 上线 这个 版本 吧 删对了 · 约 2 倍压缩 我们 周三 之前 不要 上线 版本 意思不变 删错了 · 预算再紧一点 周三 之前 不要 上线 版本 意思反了:变成「周三前上线」 信息量 ≈ 小模型「猜不到的程度」。「不」这类短词在上下文里可能很好猜,一旦被判成低信息,就会被删掉。
图 9 · 提示词压缩以字词为单位删。柱高是示意,不是 LLMLingua 的真实打分。会议场景先用规则删语气词,否定词、数字、人名列入「永不删」名单。
机制
LLMLingua(微软,EMNLP 2023)用一个小语言模型算每个 token 的困惑度(perplexity,越难预测信息量越大),删掉容易预测的 token,再由预算分配器决定每段压多少,论文报告最高约 20 倍压缩、性能损失很小。LongLLMLingua 加入「与问题是否相关」的判断,并把相关段落重排到前面,专门对付长上下文和中间丢失。LLMLingua-2(2024)改用 GPT-4 蒸馏出的数据,训练一个 BERT 规模的编码器逐 token 做「留 / 删」分类,比前代快 3 到 6 倍。
好处
与任务无关,任何文本都能压;压缩器小、快;对检索回来的长文档、示例很多的提示效果最明显。
代价
多部署一个模型;压完的文字人基本没法读,调试困难;对本来就紧凑的内容(代码、JSON、表格)收益小、风险大。
用在
RAG 召回的长文档、大量 few-shot 示例。ASR 转写里的语气词、重复和口头禅也是好目标,但先用规则删更稳。
会怎么坏
删掉否定词和数字:「不」「没」、金额、日期被判为低信息 token,意思就反了。弄坏结构:代码和 JSON 少一个括号就用不了。和缓存冲突:按问题动态压缩,每次输出都不同,前缀缓存失效。

一句话按 token 删字适合检索回来的长文和 ASR 噪声,不适合代码、JSON 和带否定词的约束。

10推理层 · 缓存账

KV cache 压缩与 prompt cache:名字很像,是两件事

先把两个词分开。KV cache 是模型推理时为每个读过的 token 存下的中间结果(注意力里的 Key 和 Value 向量);有了它,生成下一个字时不必把前文重算一遍。它的大小和上下文长度成正比,长上下文的显存主要被它吃掉。prompt cache(提示缓存)是服务商把某段前缀的 KV cache 存起来,下次请求只要开头那段逐字节相同就直接复用,并按便宜得多的价格计费。

KV cache 压缩:推理服务内部的事

机制
三条路。淘汰:只留重要 token 的 KV。StreamingLLM 发现开头几个 token 会吸走大量注意力(attention sink,注意力汇),保留它们再加最近一段窗口,就能稳定生成很长的流;H2O 保留累计注意力最高的「重量级」token;SnapKV 用提示末尾一小段观察窗口,挑出每个注意力头关心的位置。量化:把 KV 从 16 位压到 2 到 4 位,例如 KIVI。改架构:GQA 让多个注意力头共享一份 KV;DeepSeek-V2 的 MLA 把 KV 压成低维潜变量,论文报告 KV cache 减少 93.3%。
好处
对上层透明,对话内容一个字没改;省显存、提吞吐,能跑更长的上下文。
代价
只有自己部署模型(vLLM、SGLang 等推理框架)才能做;调闭源 API 时这一层不归你管。
用在
端侧或私有部署的长上下文推理,比如眼镜或边缘盒子上跑的小模型。
会怎么坏
被淘汰的 token 后来又重要了:模型对它「失明」,上层却完全不知道,最难调试。量化太狠会让长距离检索类任务掉点。
KV cache 压缩的几种做法:原始每个 token 一格;StreamingLLM 只留开头的注意力汇和最近窗口;H2O 和 SnapKV 留重要 token;KIVI 把每格量化变薄;MLA 把每格压成低维潜变量 推理服务显存里的 KV cache · 每格 = 一个 token 的 Key/Value 原始长度 ∝ token 数StreamingLLM注意力汇 + 窗口H2O · SnapKV重要 token + 最近KIVI 量化16 位 → 2–4 位MLA 改架构低维潜变量实心:被选中留下的 token;虚线:被淘汰,模型从此「看不见」。对话内容一个字没改,变的只是推理服务内部存的东西。
图 10a · KV cache 压缩发生在推理服务内部,只有自己部署模型(vLLM、SGLang 等)才能动。格子数量和位置是示意;MLA 的「KV cache 减少 93.3%」是 DeepSeek-V2 论文的报告值。

prompt cache:所有压缩做法都要算的那笔账

Anthropic 的缓存读取价是基础输入价的 0.1 倍,5 分钟档的缓存写入是 1.25 倍。Manus 公开说他们把 KV-cache 命中率当作生产环境最重要的单一指标:Agent 的输入输出比大约 100:1,缓存与不缓存的价差是 10 倍。缓存只认逐字节相同的前缀,中间改一个字,后面全部作废。

什么操作会打碎前缀缓存 只往尾部追加 系统+工具 历史(与上一轮相同) 新一轮 命中 中间清掉一个工具结果 系统+工具 桩 命中 之后全部重写缓存 压缩成摘要之后 系统+工具 新摘要 命中 重写,但很短 每轮改系统提示(比如塞时间戳) 一个字都不命中
图 10b · 粗绿线是按缓存价读的部分,斜线阴影是要按全价(外加写入溢价)重读的部分。压缩一次等于付一次重写缓存的钱,换以后每轮少读一些;所以要么一次压够,要么别压。

由此得出三条硬规则:

  1. 稳定的放前面,易变的放后面。系统提示、工具定义、术语表在最前;状态块和摘要其次;最新原文和当前问题最后。别在系统提示里放时间戳。
  2. 一次压够,别频繁小压。Anthropic 的 clear_at_least 参数就是为此设的:清不到这么多就干脆不清。
  3. 压缩请求本身也能吃缓存。Claude Code 文档说明:压缩请求带着同样的系统提示、工具和历史,只在末尾追加一条总结指令,缓存还热时按缓存价读前缀,所以会话中途 /compact 远比上下文大小看上去便宜;隔很久再恢复旧会话时缓存已过期,那一次压缩最贵。

一句话KV 压缩是推理服务内部的事;prompt cache 是每一种压缩都要算的账。

11核对于 2026-10-12

厂商原生方案:Anthropic 给了三把刀,OpenAI 给了一个黑盒

两家都已把「清理」和「摘要」做进服务端。差别在于:Anthropic 的产物你能读、能改;OpenAI 的压缩产物是加密的,人读不了。以下参数全部来自官方文档,beta 功能照抄 beta 名。

三种厂商原生方案的流程:Anthropic 上下文编辑在服务端清旧工具结果;Anthropic 服务端压缩写出可读的 compaction 块;OpenAI 压缩输出加密的 compaction 项Anthropic · 上下文编辑客户端完整历史服务端越过 10 万清旧结果留最近 3 次模型看到精简版客户端历史不用改;清除点之后的缓存失效。Anthropic · 服务端压缩请求越过 15 万服务端写摘要返回compaction 块下一次块前全丢摘要人能读;instructions 会整个替换默认提示。按需模式(compact-2026-09-04)还能放后台跑。OpenAI · Responses请求设阈值服务端同一次响应compaction加密内容下一轮从该项起encrypted_content 人读不了;store=false 对 ZDR 友好。
图 11 · 三种原生方案的数据流。阈值是各自文档的默认值(上下文编辑 100,000、Anthropic 阈值压缩 150,000;OpenAI 的 compact_threshold 由你设,文档示例为 200,000)。绿框是压缩发生的那一步。

Anthropic · 上下文编辑(context editing)

  • beta 头 context-management-2025-06-27,在请求里加 context_management.edits。编辑在服务端、模型看到之前生效,客户端保存的完整历史不用改。
  • 工具结果清除 clear_tool_uses_20250919:trigger 默认 100,000 输入 token(也可按工具调用次数);keep 默认保留最近 3 次工具调用;clear_at_least 规定每次至少清多少,清不到就不清;exclude_tools 列出永不清除的工具;clear_tool_inputs 默认 false,即只清结果、保留调用参数。被清的结果换成占位文字。
  • 思考块清除 clear_thinking_20251015:控制保留最近几轮的 thinking 块,keep 设为 "all" 可保住缓存。两种策略同时用时,它必须排在前面。
  • 缓存影响:文档明说工具结果清除会让被清位置之后的缓存前缀失效,所以要用 clear_at_least 让每次失效都划算。
  • 配合 memory 工具:接近清除阈值时 Claude 会收到自动提醒,先把要紧内容写进记忆文件,再被清除。
  • 响应里的 context_management.applied_edits 报告清了几次、清掉多少 token;token 计数接口可以预览清除后的大小。

Anthropic · 服务端压缩(compaction)

  • 阈值压缩:beta 头 compact-2026-01-12,把策略 compact_20260112 加进 context_management.edits。trigger 只支持 input_tokens,默认 150,000,最低 50,000。达到阈值时服务端自动写摘要并返回一个 compaction 块;下一次请求把响应原样追加,API 会自动丢弃这个块之前的全部内容。instructions 可以自定义摘要提示,但会完全替换默认提示;pause_after_compaction 让 API 写完摘要先停下,你可以把最近几轮原文插回去再继续。
  • 按需压缩:beta 头 compact-2026-09-04,顶层参数 compaction(如 {"type":"summarize"}),由应用自己决定何时压。官方概览页现在的建议是:能用按需压缩就用按需压缩。它支持保留最近几轮逐字不动,也支持后台压缩:摘要请求在后台跑,会话照常在完整历史上继续,摘要回来后只替换当初发出去的那部分历史,期间新增的轮次留在后面。它不能和 context_management 放进同一个请求。
  • SDK 里的客户端压缩 compaction_control 已标记为废弃(Python SDK 1.0 起移除)。它的默认摘要提示分 5 节:任务概览、当前状态、重要发现、下一步、需保留的上下文,包在 <summary> 标签里,可作为自写摘要器的模板。文档也列了不适合压缩的情况:需要精确回忆早期细节、需要在很多变量之间维持精确状态的任务。

OpenAI · Responses API 的 compaction

  • 服务端自动压缩:在 POST /responses 里设 context_management: [{"type": "compaction", "compact_threshold": 200000}]。渲染后的 token 数越过阈值时,服务端在同一次流式响应里跑一次压缩,输出一个压缩项,裁掉旧上下文后继续推理。
  • 独立端点:POST /responses/compact,完全无状态。把整个窗口发过去(它本身必须还塞得进模型窗口),返回一个压缩后的新窗口,里面有一个压缩项,也可能保留部分原有项。文档要求原样作为下一次 /responses 的输入,不要再裁。
  • 产物不可读:压缩项类型为 compaction,内容在 encrypted_content 里,文档原话是「不透明,不打算让人读懂」,携带此前的关键状态和推理。设 store=false 时对零数据保留(ZDR)友好。
  • 串联方式:无状态拼接输入数组时,可以丢掉最新压缩项之前的所有项以降低延迟;用 previous_response_id 串联时不要手动裁剪。

怎么选:要审计、要自定义保留规则、要把摘要给人看(会议纪要),选 Anthropic 或者自己写;想省事、希望模型的推理状态也一并带过去,选 OpenAI,但要接受看不见它留下了什么。两家的服务端压缩都不替你保存原文,原文仓得自己建。

一句话Anthropic 给你能读能改的摘要和清理规则,OpenAI 给你看不见的加密压缩;两家都不替你存原文。

12chasey-myagi/sage @ ac6d7f5

Sage:不改写历史,每轮重新编译视图

Sage 和上面所有方案不在同一条轴上。它从不改写历史:历史是一份只追加的 Log;每一轮调模型之前,由「上下文编译器」从 Log 算出这一轮要发的内容(视图),并留一份清单,写明每一块为什么在、为什么不在。于是压缩变成了「这一轮给每块选什么档位」,而不是「把过去改写成什么样」。以下引用基于仓库 main 分支提交 ac6d7f5(2026-10-12 15:27 北京时间)的源码和文档。

Sage 架构:apps/sage 命令行驱动 core 的 AgentSession;core 通过 ViewProvider 接口向 plugins 里的上下文编译器要视图,检查后写进只追加的 Log,再交给 provider 发出;tools 执行工具并把大输出写盘 packages / apps · 编号是一轮请求的数据流 apps/sageCLI:main.ts · coding-session.ts · --budget · --scorer core session.tsAgentSession每轮:要视图→ 检查 → 发送 view/ 接缝ViewProvider→ CompiledViewassertPaired 等 log/只追加 JSONLkinds.ts:epochmanifest 等 plugins compiler/ · contextCompiler().view chunks · eliminate · budget · decideepoch · freeze · stub · expandcalibrate · subtask-view · rebuild claims/agents-mdprogress-ledgerreminder · catalog scorer/rule · model · jev routing/阶段边界换模型 replay/ · subtask/离线回放 · 子会话 provideranthropic · openai 兼容catalog 价目表(读 / 写价) toolsbash(spill 写盘)· readtruncate · edit · grep … 1 2 3 4 1 内核把 ViewContext(Log 路径、模型、工具)交给编译器 2 编译器返回 CompiledView 3 内核检查后写进 Log 4 发给模型
图 12a · Sage 的分层。内核(core)不压缩、不删、不改写视图,只检查工具调用是否成对、冻结前缀是否被动过,然后先落 Log 再发送;所有「发什么」的决定都在 plugins 的编译器里,经 ViewProvider 这一个接缝接进来。内核默认的视图是 passthroughView(原样发送),CLI 默认换成编译器,加 passthrough 选项才退回原样。
Sage 一轮编译的数据流 Log:只追加的 JSONL 树,先落盘再进内存 消息 · request_header · view_epoch · model_change · manifest indexChunks 切块:一次工具调用 + 它的结果 = 一块 none + 桩 summary 对话 kept 最近 6 块 full 淘汰顺序:recent → superseded_by → retry_intermediate → budget:oldest-first;可选打分器给 none / summary / full chooseEpoch:要不要放弃缓存、开新阶段? (旧−新)×读价×剩余轮数 > 新×写价 − 旧×读价 或:预计输入 > 窗口 90%(护栏,强制重建) 不重建 前缀逐字节冻结,只改尾部 重建 · 新阶段 写 view_epoch,可在此换模型 CompiledView = 冻结前缀 + 尾部 + 清单 阶段头 + 冻结的块(缓存命中) 尾部:新块 · 账本 · 提醒 expand(id):按桩上的编号从 Log 取回原文 不重跑工具,取回的就是当时那份
图 12b · Sage 的一轮编译。历史永远不被改写;省掉的块在视图里留一行桩,原文在 Log 里按编号可取回。每一次「要不要放弃缓存」都过一道成本不等式,并写进清单。
动画 6 · Sage 的上下文编译器,多轮演示规则与常量取自 ac6d7f5
Sage 编译器:Log 只追加,每轮把块定档为全文或桩,阶段内前缀冻结,按成本开新阶段,用 expand 从 Log 取回原文,并写清单 Log(只追加,永不改写)· 每格 = 一次工具调用 + 结果 #1读a #2取✗ #3取 #4搜 #5读b #6读a #7改b #8跑 #9读c #10跑 #11新 这一轮发给模型的视图 #1 #2 #3 #4 #5 #6 #7 #8 #9 #10 #11 桩 桩 桩 桩 最近 6 个工具块:recent,全文 recent 冻结前缀:档位不动,缓存逐字节命中过时 #1 superseded_by:#6 (#6 又读了 a) #2 retry_intermediate (失败后同参数重调) #3 budget:oldest-first (仍超预算,丢最旧) [#2 · fetch · {"url":"…"} · 4.1k tokens · omitted · expand("#2") to retrieve] chooseEpoch:(旧−新)×读价×剩余轮数 > 新×写价 − 旧×读价或预计输入 > 窗口 90% → 开新阶段,写 view_epoch过时的 #5(已被 #7 改写覆盖)这时才清;可顺便换模型 尾部:expand("#1") → 当时的原文 manifest(每轮一份,进 Log){id:"#1", tier:"none", reason:"superseded_by:#6"}{id:"#4", tier:"full", reason:"kept"} …epoch · 预算 · 缓存预测 vs 实测 · 打分器报告 Log 只追加;indexChunks 把它切块,一次工具调用加结果是一块,整进整出,不拆散调用对。 eliminate 按顺序取第一条命中的规则定档:最近 6 块全文;被覆盖、失败重试的块留桩。 仍超预算(默认 40,000)时,从最旧的非最近工具块开始丢。用户和助手的文字一律保留。 省掉的块只留一行桩:编号、工具、参数、大小,以及怎么用 expand 取回。 下一轮 #11 进来,只追加在尾部。#5 已过时,但阶段内档位冻结,先不动,保住缓存。 算账划算或快撑满窗口时开新阶段:前缀从头重编,过时块这时才一起清掉。 模型要看 #1:调 expand,从 Log 读回原文放到尾部,不重跑工具,拿到的就是当时那份。 每轮写一份清单,每块都有 reason。「不允许有不知道为什么在那里的 token」。
1 / 1
  1. indexChunks(chunks.ts)把只追加的 Log 切成块:一次 tool_use 加它的 tool_result 是一块,纯文字消息也是一块。块只能整进整出。
  2. eliminate(eliminate.ts)按顺序取第一条命中的规则:最近 6 个工具块(DEFAULT_KEEP_RECENT)保持全文;#1 的读被后来对同一文件的读覆盖(superseded_by);#2 出错后紧接着用同一工具、同一参数重调(retry_intermediate)。
  3. 仍超预算(DEFAULT_COMPILER_BUDGET = 40_000)时,从最旧的、非最近的工具块开始降为 none(budget:oldest-first)。用户和助手的文字一律 kept。
  4. 被省掉的块由 renderStub(stub.ts)留一行桩:编号、工具名、参数摘要、token 数和 expand("id") 的用法。
  5. 下一轮 #11 只追加在尾部。#5 此时已被 #7 的写覆盖,但 frozenDecisions(freeze.ts)让阶段内档位不变,前缀逐字节相同、缓存命中;#5 记为 staleOmittable。
  6. chooseEpoch / classifyEpoch(decide.ts)算账:省下的读成本超过重建多付的写成本,或预计输入超过窗口 90%,才开新阶段(写 view_epoch),过时块这时一起清;路由策略也只在这一刻换模型。
  7. 模型想看 #1 原文:调 expand(expand.ts),从 Log 读回当时那份放进尾部,不重跑工具。
  8. 每轮写 manifest:每块 {id, tier, reason, tokens},外加预算、阶段决定、缓存预测与实测。
动画 6 · Sage 不改写历史,只决定每一轮每块发什么档位。斜线加「桩」表示这一轮只发一行占位;左侧竖线表示新阶段的开头。图中编号简写为 #1、#2,代码里的真实编号形如 seq:12#toolu_…。

数据结构

  • Log:只追加的树,条目带 id / parentId / seq,先写 JSONL 再进内存,读入时丢掉写了一半的尾行。与压缩相关的条目类型登记在 packages/core/src/log/kinds.ts:view_epoch(开了新阶段,旧前缀原样保留)、model_change(换模型也只是一条记录,不改历史)、manifest(每轮的编译清单)、request_header(system 和工具定义只在哈希变化时存全文)。
  • 块(Chunk):packages/plugins/src/compiler/chunks.ts 的 indexChunks。一次 tool_use 加它的 tool_result 是一块,编号 seq:<助手消息 seq>#<toolUseId>;一条纯文字消息是一块,编号 seq:<seq>。每块带 tokens 和 accesses(这次调用读写了哪些资源)。块只能整进整出,工具调用对不会被拆散。
  • 档位(Tier):full / summary / line / none。历史块用 none / summary / full,插件的申领单四档都能用。
  • 申领单(Claim):claim.ts。插件不直接往上下文里塞文字,而是交一张单子 {id, priority, pinned, placement, tiers}:tiers 是每个档位对应的渲染文字;placement 是 epoch-head(随阶段冻结在开头)、tail(每轮重算放末尾)或 tail-if-changed。现有四个:agents-md、progress-ledger、system-reminder、tool-catalog。
  • 清单(manifest):每块一行 {id, tier, reason, tokens},另有预算、阶段决定、缓存预测值与实测值、打分器报告。reason 必填,例如 recent、superseded_by:<id>、budget:oldest-first、scorer:entry:full;summary-rejected。设计文档的原则是「不允许有不知道为什么在那里的 token」。

什么时候触发、保留什么、丢掉什么

每轮
compiler.ts 的 contextCompiler().view 调 compileView,顺序是:组装冻结视图和从头重编的候选视图 → chooseEpoch → 重建时打分 → openEpoch(可路由换模型)→ 放缓存断点 → 入口打分 → 影子打分 → 写清单。编译每轮都跑,阶段内前缀不变。
定档规则
eliminate.ts 的 eliminate,按顺序取第一条命中的规则:最近 DEFAULT_KEEP_RECENT = 6 个工具块保持全文(recent);一块的每次访问都被后来的成功调用覆盖时作废(superseded_by,读可被后来对同一资源的读、写、搜覆盖,写只能被后来的写覆盖);出错的块,如果下一个工具块是同一工具、同样参数(即重试),出错那次作废(retry_intermediate);仍超预算就从最旧的非最近工具块开始丢(budget:oldest-first)。用户和助手的文字一律保留全文(kept)。
预算
默认 DEFAULT_COMPILER_BUDGET = 40_000,CLI 用 --budget 修改。申领单由 budget.ts 的 allocate 分配:钉住的取最高档、永不降;其余超预算时,挑「当前档位最高、优先级最低」的一张降一档,循环到放得下为止。token 估算 defaultTokenCount 是「字符数 ÷ 4」,再由 calibrate.ts 用实测 usage 校准(固定开销 + 估算 × 比例)。
开新阶段
decide.ts 的 classifyEpoch:预计输入超过窗口 90%(CONTEXT_WINDOW_GUARD_RATIO = 0.9)时强制重建;能省下的不足冻结视图的 20%(DEFAULT_MIN_SAVINGS_RATIO)时不重建;重建当轮就更便宜时立即重建;否则回本轮数不超过预计剩余轮数才重建。剩余轮数 remainingTurnsFor = max(1, 20 − 已过轮数, ⌈0.5 × 已过轮数⌉)。读价、写价取自模型价目表,取不到时回落到 0.1 / 1.25。
阶段内冻结
freeze.ts 的 frozenDecisions:一个块在本阶段第一次被定的档位,阶段结束前不变,以保证前缀逐字节相同。代价是前缀里可能留着已经过时的块,清单记为 staleOmittable,等下一次重建再清。
被省掉的块
stub.ts 的 renderStub 留一行:[#id · 工具名 · 参数(≤80 字符) · 4.1k tokens · omitted · expand("id") to retrieve]。expand.ts 的 expand 工具按编号从 Log 读回原文,不重跑工具,取回的就是当时那份。
摘要档
默认打分器 scorer/rule.ts 的 ruleScorer 什么都不改(全部 full)。改用 --scorer model|jev 才会出现 summary:摘要最长 200 字符(SUMMARY_LIMIT);入口模式只给 ≥ 300 token 的块打分;摘要不足 20 字,或不含路径、符号、数字中的任何一种,就被拒收、退回全文,原因记 summary-rejected。这条规则的起因写在 docs/notes/implemented/2026-09-23-summary-rules.md:一次 1363 token 的 read 被压成「已看过,不再需要」。
结构化状态
claims/progress-ledger.ts:模型调用 update_ledger 写入 {goal, plan[], decisions[]},编译器把 Log 里所有这类调用折叠成一份账本,作为钉住、优先级 100、只有全文档的申领单放在尾部,内容变了才更新。
工具层
tools/src/spill.ts:bash 输出超过 30,000 字节时整份写盘,视图里只留头 20,000 字节、尾 5,000 字节和文件路径;tools/src/truncate.ts 按整行截断 read / find / ls 的输出(列表最多 500 项)。
子任务
subtask-view.ts 的 compileSubtask:子会话的消息从父会话最近一次请求逐字节重建开始,所以直接命中父会话的前缀缓存;子会话自己从不开新阶段。子 Agent 不复制历史,块编号在父子之间指向同一份原文。

逐项对照

表 1 · Sage 与前文各类做法的对应
前文做法Sage 里的对应物差别
截断 / 滑窗工具层 truncate / spill;超预算时 budget:oldest-first按块丢,不拆工具调用对;丢掉的块留桩可取回,不是真删
清工具输出块定档为 none + 桩桩写明编号和大小,expand 取回当时原文,而不是「再调一次工具」;另有覆盖淘汰、重试淘汰两条确定规则
LLM 摘要块级 summary 档(≤200 字符,打分器可选)没有整段历史摘要;摘要逐块生成、有格式校验,原文仍在 Log
结构化状态progress-ledger、agents-md 申领单账本是钉住的申领单,不会被预算挤掉;但只在模型主动调用时存在
卸载 + 召回Log 本身就是原文仓;expand;bash spill 写盘按编号精确取回,没有按语义检索
子 AgentcompileSubtask子会话共享父会话的前缀缓存,不复制历史
提示词压缩无—
KV / prompt cache阶段冻结 + 成本不等式 + 缓存预测与实测对账把「何时打碎缓存」从阈值触发改为算账触发,这是它最独特的地方
厂商服务端压缩不用自己掌握视图,在 Anthropic 和 OpenAI 兼容端点(DeepSeek / Qwen / Kimi)上行为一致

独特之处

  1. 记录和视图分开。别人压缩是改写历史,Sage 只改「这一轮发什么」。任何一次省略都能撤销,任何一轮的视图都能从 Log 逐字节重建、离线回放。
  2. 缓存失效是算出来的,不是阈值逼出来的。每次「要不要放弃缓存」都有一行可复查的账:EpochDecision 里记着旧 / 新 token、读写价和回本轮数。
  3. 每个 token 都有来由。清单里每块都有 reason;expand 的调用率直接就是打分器的漏判率,不用另外埋点。
  4. 在阶段边界换模型,不多付缓存钱,因为那一刻缓存本来就要重建。

缺口

  1. 对话文字从不压缩。eliminate 把用户和助手的文字一律定为 kept,打分器也只看工具块。编码任务问题不大(大头在工具输出),但对话本身很长时,唯一的兜底是 90% 窗口护栏,而护栏重建用的还是同一套规则,文字照样全留。直接搬到会议场景,转写稿全是文字,Sage 现在一个字也不会省。
  2. bash 永远不会被覆盖淘汰。bash.ts 的 accesses() 固定返回空数组,所以 bash 块只能被「最旧优先」丢掉;跑了十次的 pnpm test 输出会一直占着位置,直到预算逼迫。
  3. 中文 token 估算偏低。「字符数 ÷ 4」对英文代码大致成立,对中文会低估好几倍。calibrate.ts 用实测 usage 校准比例能纠正大部分,但每个阶段的第一轮没有校准数据。
  4. 超预算时按新旧丢,不按相关性丢。默认打分器是空操作;接上模型打分器又要为打分付钱。
  5. 账本靠模型自觉。update_ledger 不校验输入,模型不调用就没有账本,也没有自动抽取兜底。
  6. 收益还没被实测证明。docs/status/2026-09-24-sage-status.md 写得清楚:在 DeepSeek flash 上缓存读只要全价的 2%,阶段重建要 37 到 106 轮才回本;默认 40,000 的预算在短任务里从没被触到(omitted=0、epochs=1);同模型入口打分稳定解出 7/10,比不打分的 9/10 少 2 条,费用高 75%。结论是「编译器在 flash 上不出手是对的」,价值要到缓存读价贵的服务商或超长会话上去验证。另外,docs/design/context-compiler.md 头部仍写着「设计提案 v2,未实现」,与 README 和状态页的「M1–M4 全部合入」不一致,属于文档过期。

可以怎么改

  1. 给文字块加分层摘要档,只在阶段边界生成。新增一张 history-digest 申领单,placement: "epoch-head":开新阶段时(缓存本来就要重建),把上一阶段的文字块压成段摘要,原文仍在 Log、仍可 expand。摘要的成本和缓存重建落在同一轮,不额外打碎缓存,正好补上缺口 1。
  2. bash 的覆盖规则按「命令 + 工作区状态」判断。同一条命令、工作区没变,后一次覆盖前一次;或者把输出内容的哈希写进 accesses。
  3. token 计数按文字类型分档。CJK 字符按约 1 token 计,其余按 4 字符计;或者在每个阶段开头调一次服务商的计数接口当锚点。
  4. 超预算淘汰换成便宜的相关性信号。用最近一条用户消息给各块做 BM25 打分,排在「最旧优先」之前,零模型调用。
  5. 账本加兜底抽取。阶段边界时如果账本为空或过期,用便宜模型从最近的文字块抽一次 goal / decisions,写成一张带 reason: auto-extract 的申领单。
  6. 在缓存读价为 0.1 倍的服务商和超长会话上补一组 A/B。不等式的结论最依赖读写价比,这在 flash 上测不出来。

面试时怎么讲

按「问题 → 设计 → 结果 → 迁移」四句讲,控制在两分钟:

  1. 问题:我之前的 harness 是阈值触发压缩,三个插件排队改同一个消息数组,先后顺序只写在注释里;每压一次缓存全丢,而且摘要有损,占位符也取不回原文。
  2. 设计:我把记录和视图分开。历史只追加;每轮由编译器按块定档、留桩,可以 expand 取回;前缀按阶段冻结,开新阶段要过一道成本不等式;每轮写清单,每个 token 都有来由。
  3. 结果:在 DeepSeek flash 上它没有净收益,因为缓存读只要 2% 的价格,回本要几十轮。这是实测出来的,也说明不等式在起作用:它判断不该出手,就没出手。真正的价值场景是缓存贵、会话超长。
  4. 迁移到会议眼镜:转写稿就是 Log;每次用户提问编译一次视图;话题切换处是天然的阶段边界,在那里生成段摘要;决议和待办是钉住的账本申领单;「刚才谁说了什么」用 expand 按时间戳取原话。我也清楚它现在的缺口是不压文字,会议场景必须先补上第一条改进。

最可能的追问:「为什么不直接用厂商的服务端压缩?」答:要跨服务商、要审计每一轮模型看到了什么、要能离线回放比较策略,这三条服务端黑盒都做不到;代价是自己维护一个编译器。

一句话Sage 把压缩改成「每轮给每块选档位」:历史不改写,省略可取回,打碎缓存前先算账;缺口是不压对话文字。

13一页对照

对比表:按可逆性从上往下排

表 2 · 各做法的关键属性。「可逆」指原文能否原样取回;「缓存」指对前缀缓存的影响
做法可逆额外模型调用缓存主要失败会议场景
卸载 + 召回是检索时可能需要召回内容放尾部则无影响不知道去取、召回错段必用:原文仓 + 检索
清旧工具输出部分(可重调)无清除点之后失效结论随证据丢失、重复劳动用于检索结果、日历等工具输出
子 Agent主窗口不受影响多,约 4–15 倍 token子窗口另起上下文割裂、结论失真会后整理、深度问答
结构化状态状态本身可审抽取时需要状态块之后失效过期、污染、漏写必用:决议、待办、术语
分层摘要保留底层原文则可追溯每段一次,外加合并追加新段不碰旧段切在话题中间、上层过时首选的摘要形态
滚动摘要否每段一次每次更新摘要块即失效摘要漂移只作快速概览,须配原文仓
一次性摘要否一次,读全量系统提示之后全部失效丢细节、压在任务中间不适合实时,适合会后
截断 / 滑窗否无每轮都滑则从不命中目标丢失、悬空调用只作最后的硬上限
提示词压缩否小模型一次动态压缩则失效删掉否定词和数字先用规则删语气词
KV 压缩否(上层不可见)无推理框架内部的事被淘汰的 token 后来又重要端侧自部署模型时
Anthropic 服务端压缩否,但摘要可读服务端一次压缩块之前全部丢弃默认提示不懂你的领域可用,需自定义 instructions
OpenAI 服务端压缩否,产物加密不可读服务端一次压缩项之前可丢看不见保留了什么不宜作为纪要来源
Sage 编译器是(Log 不改写)默认无,打分器可选阶段内冻结,按账重建文字不压,漏判靠 expand 兜底框架可用,需补文字摘要档

一句话按可逆性看表:越往下越省,也越难追回。

14两小时 · 实时转写

会议场景:原文仓兜底,三层摘要供读,状态表对账

眼镜端会议助手的上下文有三点和编码 Agent 不同。输入是没有终点的文字流:一小时中文会议大约一两万字,token 数相近。延迟敏感:用户戴着眼镜问「刚才他说的截止日期是哪天」,等三秒就嫌慢。精确性要求极高:人名、数字、日期、谁负责什么,错一个就是事故。此外,ASR(自动语音识别)的转写自带噪声:同音错字、说话人标错、大量「嗯」「那个」。

结论:不要只靠摘要。原文仓保证一字不丢,结构化状态保证要紧事项可对账,分层摘要只负责让模型知道整体聊了什么。

会议助手的上下文分层 眼镜麦克风 → ASR 流(说话人 · 时间戳) 原文仓 只追加 · 按分钟切片 BM25 + 向量索引 后台整理器(异步) 清洗 · 段摘要 · 抽状态 在话题切换处切段 L2 全会摘要(每段结束后从 L1 重算) L1 段摘要(每段约 5–10 分钟,从原文生成) L0 最近 5 分钟原文(逐字) 结构化状态(JSON,每条带时间戳出处) 决议 · 待办(人 / 事 / 期限)· 未决问题 · 数字 · 术语 每次提问的组装顺序 系统+工具+术语表 状态 L2 L1 各段 L0 原文 召回片段+ 问题 几乎总命中 越往右越常变 L1 只追加、不改旧段:新段进来时,旧段那部分前缀仍可命中
图 14 · 会议助手的上下文分层。实时路径只读现成的状态、摘要和最近原文,不等任何摘要调用;所有摘要和抽取都在后台跑。要逐字回答时走检索,从原文仓取原话。

八条具体建议

  1. 原文仓是唯一的真相。转写只追加、不改写,按分钟或按发言切片,带说话人和时间戳;建 BM25 加向量双索引(人名、数字、专有名词靠关键词才找得准)。任何摘要和状态都要能回指到原文时间戳。
  2. 实时路径不等摘要。段摘要和状态抽取放后台异步跑(Anthropic 的后台压缩是同一思路)。用户提问时只拼现成的内容,首字延迟只取决于输入长度和模型速度。
  3. 摘要用分层,不用滚动。L1 段摘要从原文生成,L2 从 L1 重算,任何一层都不改写上一份摘要,避免「周三」漂成「本周」。尽量切在话题切换或长停顿处,不按固定 token 数硬切。
  4. 结构化状态单独抽、单独校验。决议、待办(谁 / 做什么 / 何时)、未决问题、数字、术语表用固定 JSON 结构,每条带出处时间戳。新抽取与旧状态冲突时(比如期限改了),保留两条和时间顺序,不静默覆盖。状态块放在提示的固定位置(靠前),避开「中间被忽略」。
  5. 先用规则清洗,再考虑 LLMLingua。语气词、重复、口头禅用规则删;数字、否定词、人名一律不许删。ASR 同音错字用术语表纠正(术语表放在稳定前缀里,同时作为 ASR 热词)。
  6. 按缓存来排布。系统提示、工具、术语表、会议元信息放最前,整场不动;状态块其次;L1 只追加;L0 和召回内容放最后。前缀里别放当前时间。
  7. 逐字问题走检索,概括问题走摘要。「他原话怎么说」「刚才那个数字」先检索原文仓,把命中片段连同时间戳放进尾部;「这场会主要定了什么」读状态和 L2。回答附上时间戳,用户可以回放核对。
  8. 端云分工。端侧(眼镜或手机)做 VAD(语音活动检测)、ASR、规则清洗和最近几分钟的缓冲;云端做段摘要、抽取和问答。网络断开时端侧仍保存原文,恢复后补传,后台补跑。端侧若跑小模型,KV 压缩(滑窗加 attention sink)才是你要管的那一层。

怎么评估

  • 事实保真:在测试会议里预埋 30 到 50 个「针」(人名、数字、日期、谁负责什么),会后用问答测召回率,并按经历的压缩次数分组,看是否随时间下降。这就是漂移的量化。
  • 待办的召回与精度:人工标注的待办清单对照状态表,人、事、期限分别计分。
  • 延迟与成本:首字延迟 P50 / P95;每小时会议的 token 数;缓存命中率(缓存读取 token 占总输入的比例)。
  • 可追溯:随机抽查摘要里的条目,看能否在 10 秒内回放到原文时间戳。

一句话会议助手 = 原文仓兜底 + 状态表对账 + 分层摘要供读,所有摘要都在后台跑。

15六道题 · 答题要点

面试可能问到的问题

Q1Agent 的上下文压缩有哪些做法?你怎么选?

  • 先给框架:按可逆性排序。卸载和清工具输出可逆或部分可逆,结构化状态可审,摘要有损,token 删减和 KV 压缩在推理层。
  • 选法:规则能决定的不交给模型;可逆的先做;有损的放在自然断点做、一次压够。
  • 每说一种都带上它会怎么坏:截断丢目标、清除丢结论、摘要漂移、子 Agent 割裂、LLMLingua 删掉否定词。
  • 收尾讲缓存:每种做法都会改动前缀,压缩决策必须算缓存账。

Q2两小时会议实时转写、眼镜上随时提问,上下文怎么设计?

  • 三件套:只追加的原文仓加检索;分层摘要(L0 原文 / L1 段 / L2 全会);结构化状态(决议、待办、问题、数字、术语)。
  • 实时路径只拼现成内容,摘要和抽取在后台异步跑;逐字问题走检索,概括问题走摘要和状态。
  • 提示按稳定程度排序以吃缓存;术语表放进前缀,同时用于 ASR 纠错。
  • 端云分工、断网续传;评估看预埋事实召回、待办召回、首字延迟和缓存命中率。

Q3摘要会漂移、会丢细节,怎么发现、怎么防?

  • 防:用分层而不是滚动,每层从原文或下一层生成;摘要模板固定字段(参考 Claude Code 的 9 节,尤其「所有用户消息」和逐字引用的「下一步」);数字、人名、期限单独进结构化状态;摘要条目带原文出处。
  • 测:预埋事实问答,按压缩次数分组看准确率是否下降;压缩前后用同一组问题作答对比;抽样回放原文核对。
  • 兜底:原文仓永远在,答不准就检索原话。Sage 的规则也可以借:摘要不含路径、符号或数字就拒收,退回全文。

Q4压缩和 prompt cache 有什么冲突?怎么平衡?

  • 缓存只认逐字节相同的前缀;清除、摘要、动态压缩都会让改动点之后的缓存失效,下一轮按全价加写入溢价重读。
  • 平衡:稳定内容放前、易变内容放后;一次压够(clear_at_least);在自然断点压;趁缓存还热时发压缩请求。
  • 能算就算:用 Sage 的不等式「(旧−新)×读价×剩余轮数 > 新×写价 − 旧×读价」,省下的读成本超过重建多花的写成本才压。
  • 举反例:在缓存读只要 2% 价格的服务商上,算出来几乎从不值得压,这是实测结论。

Q5什么时候该用子 Agent,什么时候不该?

  • 该用:读多写少、能清楚切开、结果能压成短结论的调研类任务,可以并行。
  • 不该用:子任务之间有隐含决定需要协调(比如分头写同一段代码)、对延迟敏感、预算紧(多 Agent 约 15 倍 token)。
  • 要点:派任务的说明要写足;子 Agent 返回结论时附证据路径,主 Agent 可以抽查;能共享前缀缓存最好(Sage 的 compileSubtask 从父请求逐字节重建)。

Q6讲一个你自己做过的上下文管理设计。

  • 用第 12 节的四句:问题(阈值压缩、缓存全丢、占位符取不回原文)→ 设计(记录与视图分开、按块定档留桩、阶段冻结加成本不等式、清单)→ 结果(flash 上不出手是对的,如实给数字)→ 迁移(转写稿是 Log,话题切换是阶段边界,决议和待办是钉住的账本)。
  • 主动说缺口:对话文字不压,会议场景要补分层摘要档,并且已经想好放在阶段边界生成,不额外打碎缓存。

一句话每道题都按「框架 → 失败方式 → 缓存账 → 自己的例子」来答。

16链接核对于 2026-10-12

出处

  1. Anthropic · Context editing(工具结果清除、思考块清除、配合 memory 工具、SDK 压缩及其默认摘要提示)· platform.claude.com/docs/en/build-with-claude/context-editing
  2. Anthropic · Compaction 概览 · platform.claude.com/…/compaction;按需压缩 · …/compaction-on-demand;后台压缩 · …/compaction-background;阈值压缩参数 · docs.anthropic.com/en/build-with-claude/compaction
  3. Anthropic · Prompt caching(缓存读 0.1 倍、5 分钟写入 1.25 倍)· platform.claude.com/…/prompt-caching
  4. OpenAI · Compaction 指南 · developers.openai.com/api/docs/guides/compaction;/responses/compact 参考 · developers.openai.com/…/responses/methods/compact
  5. Claude Code · Explore the context window(What survives compaction)· code.claude.com/docs/en/context-window;Model configuration(Default auto-compact thresholds)· code.claude.com/docs/en/model-config;Prompt caching(压缩的缓存成本)· code.claude.com/docs/en/prompt-caching
  6. Claude Code 旧阈值与覆盖变量 · anthropics/claude-code#31806;changelog 摘录见 #64520(社区分析,非官方文档)
  7. Claude Code 摘要提示全文(社区从发布包提取,非官方)· codeaashu/claude-code · prompt.ts;ccprompts.info · service-compact-base
  8. Anthropic · Effective context engineering for AI agents · anthropic.com/engineering/effective-context-engineering-for-ai-agents
  9. Anthropic · How we built our multi-agent research system(约 4 倍 / 15 倍 token)· anthropic.com/engineering/built-multi-agent-research-system
  10. Manus · Context Engineering for AI Agents: Lessons from Building Manus(KV-cache 命中率、100:1、10 倍价差、文件系统即上下文)· manus.im/en/blog/…
  11. Cognition · Don't Build Multi-Agents · cognition.ai/blog/dont-build-multi-agents
  12. Liu et al. · Lost in the Middle · arXiv:2307.03172;Chroma · Context Rot · research.trychroma.com/context-rot
  13. Wang et al. · Recursively Summarizing Enables Long-Term Dialogue Memory · arXiv:2308.15022;Packer et al. · MemGPT · arXiv:2310.08560
  14. LLMLingua · arXiv:2310.05736;LongLLMLingua · arXiv:2310.06839;LLMLingua-2 · arXiv:2403.12968
  15. StreamingLLM · arXiv:2309.17453;H2O · arXiv:2306.14048;SnapKV · arXiv:2404.14469;KIVI · arXiv:2402.02750;DeepSeek-V2(MLA)· arXiv:2405.04434
  16. Sage · github.com/chasey-myagi/sage(提交 ac6d7f5):packages/plugins/src/compiler/(compiler、chunks、eliminate、budget、decide、epoch、freeze、stub、expand、calibrate、subtask-view)、packages/plugins/src/claims/progress-ledger.ts、packages/plugins/src/scorer/rule.ts、packages/tools/src/spill.ts、packages/tools/src/bash.ts、packages/core/src/log/kinds.ts、docs/design/context-compiler.md、docs/status/2026-09-24-sage-status.md、docs/notes/implemented/2026-09-23-summary-rules.md

局限:Claude Code 的摘要模板与旧阈值来自社区对发布包的提取,官方未公开全文;Anthropic 两种服务端压缩都还是 beta,参数可能再变;论文数字取自各论文摘要,未逐一复现;图 1、图 2 中的比例是示意,不是实测数据。