AI · Agent

Context Engineering: 让 Agent 学会忘记

语言模型自己什么都记不住. 它看起来记得, 是因为每一轮都把前面的对话从头读一遍. 对话一长, 就读不下, 也读不起.

和 AI 聊天时, 模型其实每次回答都是从零开始: 前面所有的对话会被拼在一起, 再加上新说的一句, 整个再喂给它一遍. 这一长串拼起来的东西, 就是上下文 (context). 普通聊天上下文涨得慢, 但 Agent 会自己调用工具: 读文件、搜网页、跑代码. 每调用一次, 就有一大段结果塞回上下文, 一个任务跑下来几十轮, 上下文很快就满了. 我们可以用简单的数学符号来表示这个过程.

不压缩会怎么样

我们先考虑最简单的情况. 第 tt 轮的输入是 ItI_t, 上下文是 CtC_t, 模型的输出是 OtO_t:

Ot=LLM(It,Ct),Ct+1=Ct∣It∣OtO_t = \text{LLM}(I_t, C_t), \qquad C_{t+1} = C_t \mid I_t \mid O_t

竖线表示拼接: 每一轮都把这一轮的输入和输出接在后面, 什么都不扔. 这样有两个问题. 第一, 上下文窗口有上限, 迟早装不下. 第二, 就算装得下, 成本也很高, 因为每一轮都要把整条上下文读一遍. 如果每轮多 kk 个 token, 第 tt 轮就要读大约 tktk 个, 跑 TT 轮一共要读

k+2k+⋯+Tk≈12 k T2k + 2k + \cdots + Tk \approx \tfrac{1}{2}\, k\, T^2

轮数翻一倍, 成本翻四倍.实际的服务会缓存已经读过的前缀, 重复的部分会便宜很多. 但窗口的上限还在, 到顶了还是要处理.

加一个 FF

Context Engineering 做的事, 就是在拼接之后加一步整理:[1]

Ct+1=F(Ct∣It∣Ot)C_{t+1} = F(C_t \mid I_t \mid O_t)

FF 决定下一轮留下什么. 留得太多, 窗口会装不下; 留得太少, 模型就不知道前面发生了什么. 再细一点, 上下文其实可以分成两部分: 这一轮真正读进去的提示词 PP, 和存在外面的记忆 MM. 记忆平时是不占地方的, 要用的时候模型自己调工具去取. 所以模型每一轮真正读的只有 PP:

C={P,M},Ot=LLM(It,Pt)C = \{P, M\}, \qquad O_t = \text{LLM}(I_t, P_t)
上下文里装了什么单位是千 token

原样留着剪过摘要存进文件, 只留路径

18
不压缩或删减, 这一轮要读–
压缩和删减, 这一轮要读–
到这一轮, 一共少读了–

每一轮要读多少. 阴影是到这一轮为止一共读了多少, 也就是成本

不压缩或删减压缩和删减

照这个分法, FF 能做的事大致有两类. 一类是压缩: 把已经在 PP 里的东西变短. 另一类是记忆: 管 PP 和 MM 之间的进出, 什么东西要挪出去, 什么时候要再拿回来、拿多少回来.

压缩方式

Pruning. Agent 调用工具拿回来的结果, 大多只在当下有用. 比如读了一个两千行的文件, 改完其中三行, 后面几十轮还一直带着这两千行, 就很浪费. Pruning 就是按规则把旧的工具结果剪短. 以 OpenClaw 这个 Agent 框架为例, 它分两档.[2] 第一档叫 soft trim: 上下文用到窗口的三成左右, 就把超过 4,000 个字符的工具结果只留开头和结尾各 1,500 个字符, 中间换成省略号. 开头一般能看出这是什么, 结尾常常是报错或者结论, 剪掉的多半是过程. 如果用量还在一半以上, 就到第二档 hard clear: 把整段结果换成一句 “[Old tool result content cleared]”, 只留下调用过这个工具的记录. 轮次一多, 前面那些工具的细节往往已经不重要了, 记得做过这件事就够了.

Summary. Pruning 只管工具结果, 对话本身越来越长, 它就管不了了. 这时可以让模型把前面的对话写成一段摘要, 替换掉原文, 接着往下跑. 再满了, 就再写一次, 写摘要的摘要. 这样理论上永远碰不到窗口的上限. 不过摘要要多调一次模型, 本身就有成本; 更麻烦的是它会丢细节: 哪句话后面会用到, 写摘要的那一刻并不一定知道.

Sub-agent. 这种压缩, 是按任务的结构来压. 主 Agent 把一件具体的事外包给一个 sub-agent, sub-agent 在自己的上下文里搜索、读文件、试错, 最后只把结果带回来, 中间那几十步不回到主线, 相当于一次自动的压缩. 这里面难的是什么时候该外包、外包多大一块. Sun 等人 (2025) 把这件事做成了两个工具: branch 开一个分支去做子任务, return 把分支折叠起来, 只带一段结果回到主线.[3] 分支里干活的还是同一个模型, 只是换了一份干净的上下文, 道理和 sub-agent 一样. 模型靠强化学习学会用这两个工具, 奖励里除了最后答没答对, 还有两项惩罚. 一项是主线的长度超过窗口的一半以后, 主线上的 token 都要扣分, 逼着模型把费 token 的活放进分支. 另一项是分支做了交代范围以外的事, 也要扣分 (由另一个小模型来判断), 免得一个分支一口气把所有事都包了, 停不下来. 训练出来的 Agent 只用 32K 的上下文, 在网页搜索和写代码两类任务上, 都比同一个模型开 327K 窗口时做得更好.

压得太狠, 反而更贵

压缩能省钱, 但不是越狠越好. 摘要丢掉的如果是关键的那一句, 比如某个办法已经试过了、行不通, 模型只好重新去找、去试, 多想多说, 省下的 token 又花了回去. Lindenbauer 等人 (2025) 在写代码的 Agent 上认真比过两种做法:[4] 一种是让模型写摘要, 另一种其实就是 hard clear, 只保留最近几轮的工具结果, 更早的全部换成占位符. 结果后者的成本只有什么都不做时的一半, 解题率却和写摘要差不多, 有时还略高. 两样结合起来, 比只剪枝又便宜了 7%, 比只写摘要便宜了 11%. 所以也许比较稳的一种做法是 先 pruning, 如果还是太长再 summary.

什么时候压、压成什么样, 也很难靠规则一次定好. 光在提示词里交代 “上下文太长了就整理一下”, 效果往往不好, 模型似乎不太愿意删掉自己的记忆, 而专门训练过的模型会好很多.[1] Ye 等人 (2025) 的 AgentFold 就是一个例子.[5] 它让模型每一步都顺手整理自己的历史, 可粗可细: 细的只把刚做完的这一步压成一两句, 粗的把前面好几步, 甚至一整个子任务合成一条. 只用监督微调, 一个总共 30B 参数、每次只用到 3B 的模型, 在网页搜索的基准 BrowseComp 上做到 36.2%, 赶上甚至超过了大二十多倍的开源模型.

记忆

压缩是把东西变短, 记忆是把东西挪走. 挪出去的东西不占 PP 的地方, 但也并没有直接扔掉, 要用的时候还是能拿回来的.

Path. 特别长的结果, 比如一次查询返回的几万行数据, 剪了会丢信息, 摘要也概括不了. 这时可以直接存进文件, 上下文里只留一个路径, 像一枚书签. 模型要用的时候, 再调工具去读需要的那一部分, 或者把路径直接交给下一个工具. Bulle Labate 等人 (2025) 就这样处理大段的工具结果:[6] 在一个材料科学的例子里, 原来的做法因为结果太长根本跑不下来, 换成路径以后就能跑; 两种做法都能跑的时候, 用的 token 少了大约七倍.

Filtering. 从 MM 往 PP 里拿东西, 也可以拿得更少. Agent 的上下文里, 大部分是读进来的文件和网页, 而一个文件里和眼前这一步有关的, 常常只有几十行. Wang 等人 (2026) 的 SWE-Pruner, 做法是让 Agent 读之前先写一句目标, 比如 “重点看错误处理”, 再由一个只有 0.6B 参数的小模型照着这句话, 一行行挑出相关的部分交给 Agent.[7] 在写代码的任务上, token 少了 23% 到 54%, 成功率还略有提高.

Skills. 工具和技能 (skill) 的说明, 也不用全塞进提示词. 以 Anthropic (2025) 的 Agent Skills 为例:[8] 启动的时候, 提示词里只放每个技能的名字和一句说明, 相当于一张目录; 模型觉得某个技能和手上的任务有关, 才去读它完整的说明文件; 说明里提到的其他文件, 用到了才打开. 这样装了几十个技能, 平时也只占几十行的地方. 工具也可以这么管: 只把最常用的几个放进提示词, 其余的放进一个能搜索的目录, 模型需要的时候自己去查.

Playbook. 前面这些, 存什么、怎么存, 大多是人定好的规则. 更进一步, 可以让模型自己维护一份记忆. Suzgun 等人 (2025) 的 Dynamic Cheatsheet 让模型一边做题一边记一张 “小抄”: 每做完一道, 把用得上的解法、代码片段、踩过的坑记下来, 下一道题带着小抄去做.[9] 不改模型的参数, 也不需要标准答案, 只靠这张小抄, GPT-4o 在 24 点游戏上的成功率就从 10% 涨到了 99%.

但小抄如果每次都整份重写, 就会出问题. Zhang 等人 (2025) 在 Agentic Context Engineering 这篇论文里观察到一种现象, 叫 context collapse:[10] 在一个 Agent 的基准上, 第 60 步时小抄有 18,282 个 token, 准确率 66.7; 下一步模型把它整份重写, 只剩 122 个 token, 准确率掉到 57.1, 比完全不用小抄的 63.7 还低. 这正是上一节说的压得太狠. 他们的看法是, 给模型看的上下文不该追求短, 而应该像一本越写越厚的手册 (playbook), 细节都留着, 让模型自己挑. 于是他们把重写拆成三个角色: Generator 负责做任务, Reflector 负责从成功和失败里总结经验, Curator 负责把新经验一条条并进手册. 每次只增改几条, 合并用的是普通的程序, 不让模型整份重写. 这样手册可以一直变长、变细, 但不会一下子塌掉. 在 Agent 和金融两类任务上, 分别比之前的方法高了 10.6% 和 8.6%.

Recursion. Zhang 等人 (2025) 的 Recursive Language Models 走得更远, 连输入本身都放在外面.[11] 一份远超窗口的长文档, 不直接塞给模型, 而是放进一个能跑代码的环境里. 模型写代码去看它的某一段、搜里面的关键词, 必要的时候把一小段交给另一个自己去读, 再把结果拼起来. 这样能处理的输入, 比窗口大两个数量级.

参考资料

  1. 李宏毅, “AI Agent (1/3): 核心技術 Context Engineering 基本概念解說”, YouTube, 2026. youtube.com/watch?v=urwDLyNa9FU.
  2. OpenClaw, “Session pruning”, 文档. docs.openclaw.ai/concepts/session-pruning.
  3. W. Sun et al., “Scaling Long-Horizon LLM Agent via Context-Folding”, 2025. arXiv:2510.11967.
  4. T. Lindenbauer et al., “The Complexity Trap: Simple Observation Masking Is as Efficient as LLM Summarization for Agent Context Management”, 2025. arXiv:2508.21433.
  5. R. Ye et al., “AgentFold: Long-Horizon Web Agents with Proactive Context Management”, 2025. arXiv:2510.24699.
  6. A. Bulle Labate et al., “Solving Context Window Overflow in AI Agents”, 2025. arXiv:2511.22729.
  7. Y. Wang et al., “SWE-Pruner: Self-Adaptive Context Pruning for Coding Agents”, 2026. arXiv:2601.16746.
  8. Anthropic, “Equipping agents for the real world with Agent Skills”, 2025. anthropic.com/engineering/equipping-agents-for-the-real-world-with-agent-skills.
  9. M. Suzgun et al., “Dynamic Cheatsheet: Test-Time Learning with Adaptive Memory”, 2025. arXiv:2504.07952.
  10. Q. Zhang et al., “Agentic Context Engineering: Evolving Contexts for Self-Improving Language Models”, 2025. arXiv:2510.04618.
  11. A. L. Zhang et al., “Recursive Language Models”, 2025. arXiv:2512.24601.