你的 agent 跑长任务时大概率见过这种场面:前二十分钟又快又准,跑到一个小时开始答非所问,一次代码搜索塞进来几万 token 的日志原文,账单按小时往上翻,最后它忘了自己最初要干什么。根因通常不是模型变笨,而是上下文膨胀——历史对话、工具输出、失败重试的残骸一层层叠在窗口里,模型每一步推理都背着全部包袱走。上下文压缩治的就是这个病:把不再需要的部分移出去,把必须保留的部分变薄,让 agent 始终在干净的上下文里工作。
这篇 SOP 按六个步骤走完整流程:先判断你要不要压缩,再把 context-mode 接进现有 harness,然后配阈值与路由,落地分层压缩,最后用前后 token 对账验证效果。主角工具是 mksglu/context-mode(npm 包名 context-mode,TypeScript,27,378 星,10-13 GitHub API 实测)。 仓库地址:github.com/mksglu/context-mode
先把边界说清楚:context-mode 的许可证是 Elastic License 2.0(ELv2),不是传统开源。LICENSE 原文的核心限制只有一条——不得把软件作为托管或管理服务(hosted/managed service)提供给第三方;个人和团队内部使用不受限。拿它给自己团队的 agent 提速没有任何问题,但想包一层做成对外售卖的 SaaS,这条路被许可证明文封死。
一、先判断:你的 agent 真的需要压缩吗
不是所有 agent 都需要上压缩。任务只有三五步、上下文用到不到三成,装压缩机制纯属给自己找事。先对着下面这份症状清单过一遍:
- 变慢:把一次长任务每步的输入 token 打出来,如果曲线随步数线性上涨,第 30 步的输入是第 5 步的十几倍,模型每步都在为冗余历史付推理时间。
- 变贵:API 账单里 input token 占绝对大头。agent 场景下一次任务的输入 token 常常是输出的几十倍,因为这些历史每一步都要重新读一遍。
- 变糊:跑到后期开始忽略早期约束(比如你要求用 TypeScript 它改写成了 JS)、重复做已经失败过的探索、把任务目标越跑越偏。
- 顶窗:任务跑到中途报上下文超限,或者 harness 静默截断了早期内容——被截掉的恰恰可能是关键约束。
检查方法很简单:开一次最有代表性的长任务,在 harness 里打印每步的 prompt 长度和 token 用量(主流 API 的响应里都有 usage 字段),看两条东西——token 曲线形状,以及第 N 步输入里工具输出原文占了多少比例。如果工具输出原文占比超过一半,token 曲线陡增,这就是压缩的明确指征;如果任务本身十步以内就结束、窗口用量不到三成,先不动。
二、安装 context-mode,接入现有 harness
context-mode 是一个 npm 包,通过 MCP 加 hooks 两条通道接进现有 harness。它是 2026 年 2 月创建的项目,最近一次 push 在 10 月 12 日,迭代活跃。热度方面,README 徽章自述 Hacker News 日榜第一、570+ 分,并宣称工具输出沙箱化可达 98% 缩减、经 MCP 加 hooks 跨 17 平台强制路由——这些均为官方宣传口径,本站未独立复测,当参考即可。
安装走 npm:
npm install context-mode接入的第一条通道是 MCP:把 context-mode 注册为一个 MCP server,让 agent 通过标准协议调用它的压缩与检索能力。以 Claude Desktop 或各类支持 MCP 的 harness 为例,在配置文件里加一段(具体命令参数以仓库 README 为准):
{
"mcpServers": {
"context-mode": {
"command": "npx",
"args": ["context-mode", "serve"]
}
}
}第二条通道是 hooks:在 harness 的工具调用钩子上挂 context-mode,让大体积的工具输出在进入上下文之前就被拦截——落盘、替换成文件引用加摘要。这一步是整个方案的核心收益点:模型不再直接吞几万 token 的原始日志,而是拿到一句摘要加一个可以按需读取的引用。
检查点:注册完成后跑一次带大输出的任务(比如让它读一个大文件、跑一次完整测试套件),确认 hook 生效——工具输出被替换、磁盘上出现落盘文件、agent 仍能通过引用取回所需信息。任何一环断了,先修通路再往下配。
三、配阈值与路由:什么时候压、压什么
压缩不该是"到 100% 才一次性清空"的悬崖,而该是分级降级。学术界有个现成参照:OPENDEV 论文提出的 ACC 五阶段渐进压缩(Bui 2026,论文口径)——上下文用到 70% 预算时发警告,80% 做观察掩码,85% 快速剪枝,90% 激进掩码,99% 完全压缩。核心思想是让 agent 在每个压力档位都有对应动作,而不是逼近极限时一刀切。
厂商也在把这件事产品化:据 cloudpro 2026 年 10 月 12 日的文章,OpenAI 的 Responses API 已提供 compaction 能力,示例配置里出现 compact_threshold: 200000 这样的阈值字段;Microsoft Agent Framework 则提供摘要、移除、折叠三类策略。方向是一致的——阈值加策略,成为 agent 基建的标配。
配阈值之外更重要的是配路由:不同内容走不同的压缩管线。
- 大工具输出走 offload(落盘),换引用加摘要;
- 历史对话走 summarize(摘要化);
- 已失效的探索轮次(失败的尝试、已解决的报错)走 prune(直接剪掉);
- 实体信息不进压缩管道:订单号、金额、文件路径、关键约束这类一旦压缩出错任务就废的内容,要么原样保留,要么独立存储。这是中文工程社区总结的七条铁律之一——实体固化(51cto 博客口径),其余几条包括分层记忆、决策独立存储、压缩可追溯、压缩用小模型等,下文会用到。
还有一个容易被忽略的成本项:压缩动作本身会影响缓存命中。Anthropic 的 context engineering 指南把 compaction 列为长程任务的核心策略,同时提醒压缩时要用 cache_control 断点保住前缀缓存(agentpatterns 引述)——上下文前缀一变,之前攒的 prompt cache 全部失效,等于省了 token 却多付了缓存重建的钱。压缩节奏和缓存断点要一起设计。
四、分层压缩落地:offload、summarize、prune 对号入座
方法层面可以借 LangChain Deep Agents 的分层压缩思路(agentpatterns.ai 口径):Tier 1 是大工具输出落盘,换成文件引用加摘要;Tier 2 是历史对话摘要化,保留目标、状态、约束、下一步四要素,丢弃探索性轮次和已解决的报错。把它翻译成三个可执行的动作,对号入座:
offload(对应 Tier 1):工具输出超过设定体积就落盘,上下文里只留"摘要 + 文件引用"。适合测试日志、代码搜索结果、网页抓取这类自包含的大块输出。agent 后续需要细节时按引用回读,需要哪段读哪段。
summarize(对应 Tier 2):历史对话超过阈值就压成摘要,摘要必须包含四要素——任务目标、当前状态、关键约束、下一步计划。丢什么留什么有讲究:探索性轮次(试了三条路两条不通)可以压成一句结论;已解决的报错留结论不留堆栈;而所有实体信息按第三节的规则原样保留或独立存储。
prune(对应 OPENDEV 的 85% 快速剪枝档):确定性剪枝,不需要理解语义——过期的观察掩码、已被新版本覆盖的旧输出、纯粹的重复内容,直接删。成本最低,优先做。
这么分层值不值得?有个经常被引用的实证数字(agentpatterns 引述研究口径):把上下文剪到最近 5 次工具调用对加摘要化,任务完成率 91.6%,对比保留全部上下文的 agent 的 71%——压缩后不但更便宜,完成率反而更高,因为模型不用在噪声里找信号。同样是二手口径,仅供参考方向,不代表你照抄就能复现。
两个工程细节:其一,摘要和压缩本身可以用小模型跑,中文工程实践(51cto 博客口径)认为 1.5B 到 3B 的模型就足够,没必要为主 agent 的大模型再付一遍摘要的钱;其二,每层动作做完都要有检查点——落盘文件真的写进去了吗?摘要里四要素齐了吗?剪掉的内容有没有被后续步骤再次引用?三个问题逐条过。
五、效果测量:前后 token 对账
不上测量,压缩就是玄学。改造前先记一组基线:固定 3 到 5 个有代表性的长任务,记录每个任务的总输入 token、总输出 token、端到端耗时、完成质量(人工或评测脚本打分)。接入 context-mode 并配好阈值路由后,跑同一组任务再记一遍,对账。
token 用量直接从 API 响应的 usage 字段取,harness 里有 hook 的话顺手聚合即可:
ledger = {}
def record(task_id: str, step: int, usage: dict):
entry = ledger.setdefault(task_id, {"input": 0, "output": 0, "steps": 0})
entry["input"] += usage["input_tokens"] # 含 cached_tokens 可拆开记
entry["output"] += usage["output_tokens"]
entry["steps"] += 1
def report(ledger: dict):
for task_id, e in ledger.items():
print(f"{task_id}: input={e['input']} output={e['output']} steps={e['steps']}")对账时看四个数字的比值:总输入 token 降了多少(这是压缩的直接收益)、总耗时降了多少、输出 token 是否异常增长(如果输出暴涨,可能是模型在频繁回读落盘文件,要调摘要质量)、任务完成率有没有下滑(这是底线,完成率跌了其他收益都白搭)。
官方 README 宣称的 98% 缩减是宣传口径,实际降幅取决于任务里工具输出的占比和你的阈值设置——以自己的对账结果为准,别人的数字只能当预期管理。
六、避坑三条
坑一:静默丢失。 激进摘要把"当时看着不重要、后来才发现是关键"的约束丢掉了,任务在几十步后莫名其妙跑偏,而日志里找不到任何报错——因为信息不是被删错了,是被摘要吞了。对策:优先用 offload 而不是 summarize,落盘内容永远可回读,摘要只给对话史用;实体固化,关键数字和约束不进压缩管道;压缩可追溯,每次压缩记录压了什么、压到哪,出问题能倒查。这三条都出自前述七条铁律(51cto 博客口径)。
坑二:过早压缩。 阈值配得太低,agent 还在建立任务理解的早期阶段就被压缩,目标漂移——它带着一份失真的地图走完了全程。对策记住 Anthropic 的建议(agentpatterns 引述):从最大召回起步逐步收敛,不要反向。第一版配置把阈值故意放高(比如 OPENDEV 档位的 70% 警告线往上再留余量),确认任务质量无损后再一档一档往下调,每调一档跑一次回归任务集。
坑三:摘要漂移。 摘要被反复摘要,误差逐层放大,最终 agent 相信一份和事实渐行渐远的"任务简报"。对策:任务目标用原文保留、永不摘要;关键决策独立存储而不是寄存在摘要里;摘要链条控制在有限层数,超出就重建;用第五节的固定任务集定期回归,完成率下滑先查摘要质量。
上下文压缩不是什么高深技术,本质是给 agent 的记忆做定期整理:大件落盘、流水摘要、废料剪掉、要紧的数字抄在便签上贴在显示器边上。工具把管线搭好了,阈值和路由是你的判断,对账数字是唯一的裁判。从今天跑的那个越来越慢的长任务开始,先把每步 token 打出来看看。
延伸阅读
FAQ
Q1:模型上下文窗口已经到百万级 token 了,还有必要做压缩吗? A:有必要。窗口大不等于免费——输入 token 每一步都全量计费,长上下文还会稀释模型注意力,这正是"变糊"的来源。压缩同时解决成本和注意力两个问题,和窗口大小不冲突。
Q2:context-mode 可以商用吗?要注意什么? A:可以内部商用。ELv2 许可证允许个人和团队内部使用,唯一硬性限制是不得把它作为托管或管理服务提供给第三方——也就是说别把它包成 SaaS 卖。上线前自己读一遍 LICENSE 原文确认。
Q3:压缩会丢信息吗?丢了怎么办? A:会,这是压缩最大的风险,尤其 summarize 层。工程上靠三条兜底:大输出优先 offload 落盘保住可回读性、实体信息不进压缩管道、每次压缩留痕可倒查。没有这些兜底的裸摘要压缩不建议上生产。
Q4:阈值定多少合适? A:参照 OPENDEV 五阶段的分级思路(70% 警告、80% 掩码、85% 剪枝、90% 激进掩码、99% 完全压缩),先整体放高保质量,再逐档下调。Anthropic 的建议是方向性的:从最大召回起步逐步收敛,不要一上来就激进来一刀。
Q5:怎么确认压缩没有伤到任务质量? A:固定一组有代表性的长任务做回归,每次调整阈值或路由后重跑,对比完成率和输出质量。只看 token 降幅不看完成率等于自欺欺人——token 降九成、任务做砸了,不如不压。