ARES Context Lifecycle Management:重新思考 Agent 的上下文生命周期管理
个人观点:
context window is working memory, noy long-tern Memory
不要最大化上下文利用率,而应最大化上下文的信息有效密度,换言之不要给上下文里一个劲的塞垃圾,让垃圾埋没关键信息。
一、agent 上下文压缩阈值应该多少合适?
问大家一个问题,agent 设计中,上下文压缩的阈值多少合适呢? 我之前被人问到过,我当时的回答是,在ARES里上下文阈值设计是45% , 然后被质问“你不知道现在模型上下文很长吗? 现在agent app 的上下文压缩的阈值是多少你不知道吗?” , 我知道“80% 甚至90% +” 。
但我认为,这个问题本身可能存在一个认知偏差:
Context Window 越大,并不意味着 Agent 就应该尽可能多地保留历史信息。模型能够**接收多少信息,与模型能否有效利用这些信息**,是两个不同的问题。
ARES 选择 45% 作为默认上下文治理阈值,并不是因为模型只能有效处理 45% 的上下文,也不是认为其他高阈值策略存在设计缺陷。
这是一次基于 Agent Runtime 长时间运行特征所做的工程取舍。
在 ARES 中,我更关注的不是 Context Utilization(上下文利用率),而是 Context Quality(上下文质量)。
这也是 ARES Context Lifecycle Management 的设计出发点。
二、Context Window 不等于有效上下文
想起个事,早在21年协助同事做一个需要批量生产文件的任务中,偷了个懒,需要短时间内生产上百GIB的数据作为测试用,就很头大,所以写了个循环,对文件进行批量的IO,写入大量的垃圾数据来完成测试需求,但是这成了一个心结,用垃圾数据进行填充,虽然快速完成任务,总觉得差点意思。那么回到这里现在大部分的agent 上下文利用率不也是如此吗? 垃圾数据太多,有价值的数据反而很少,在每一次LLM 摘要的时候宛如在沙里淘金。
言归正传,先阐述一个概念,Context Window 是模型的容量上限,不代表模型能够始终以**相同效率处理窗口内的所有信息**。
对于普通的聊天应用,上下文通常由用户输入和模型回复构成。但是agent 不同,充斥了大量的中间信息:
* tool call 的请求与响应
* 中间推理结果
* RAG 检索内容
* 任务执行日志
* 失败重试记录
* 多 Agent 协作消息
* DAG 节点的执行结果
* 历史任务的上下文
这些信息在产生时可能具有较高价值,但随着任务推进,其中相当一部分会逐渐失去当前使用价值,但是如果不进行治理,这就会占据大量的context space ,这就带来了几个值得思考的问题:
2.1 Lost in the Middle:长上下文中的信息利用不均衡
长上下文研究中,一个经典现象是 Lost in the Middle。
研究发现(本人和EZ社区几个相关领域的博士讨论过),在部分长上下文任务中,模型对位于上下文开头和结尾的信息利用效果,可能明显优于位于中间位置的信息。
这意味着,即使模型能够接收 100K Token,也不代表它能够始终以相同效率利用这 100K Token。
上下文窗口扩大,解决的是**容量问题**。
但信息在长上下文中的有效利用问题,并不会因为窗口扩大而**自动消失**。
对于持续运行的 Agent,这个问题尤其值得关注。
因为 Agent 的上下文不是一次性构建完成的,而是随着任务执行不断增长。
2.2 Context Pollution 过程信息对工作上下文的污染
Agent 的一个典型特征是持续交互。如一个代码分析的agent 经历的过程可能如下:
```shell
Task Initialization ---> Code Repository Analysis ---> Tool Calling--->
Tool Result ---> RAG Retrieval---> Intermediate Reasoning ---> Retry / Validation ---> Final Result
```
在这个过程中,每一次工具调用都可能产生新的消息。
问题在于:
工具调用产生的信息,不一定需要永久保留在当前上下文中。
例如:
* 某个工具返回了大量源代码,但当前分析已经完成。
* 某次检索返回了几十条文档,其中只有两条真正有价值。
* 某次失败重试产生了大量调试信息,但问题已经解决。
* 某个 Agent 已经完成任务,其过程性消息对其他任务不再重要。
如果这些内容一直留在上下文中,就会形成 Context Pollution。它们并不一定是完全无用的信息,但不应该始终占据 Working Context。
2.3 Context Quality 不等于 Context Utilization
Context Utilization 衡量上下文窗口被使用了多少。
Context Quality 则关注当前上下文中的信息是否与任务相关,是否完整,以及是否能够支持模型做出正确判断。
假设 Agent 当前拥有 1M Token 的上下文窗口。
方案 A:
保留 850K Token 的历史工具调用、执行日志、中间推理和当前任务信息。
方案 B:
只保留 400K Token,但经过治理后,主要由当前任务目标、关键事实、必要约束和相关执行状态构成。
我们不能仅凭 Token 数量就断言 B 一定比 A 好。
但至少可以明确:
上下文的容量利用率,并不能直接代表上下文的有效性。
对于长期运行的 Agent,我更倾向于优先保证**信息有效密度**,而不是尽可能填满 Context Window。
三、 为什么大部分的Agent 系统选择80%~90%
当然我并不认为 80%~90% 是错误的设计。相反,它在很多场景下具有合理性。
3.1 尽可能保留原始上下文
高阈值策略最大的优势,是允许 Agent 在更长时间内保留原始信息。
对于一些任务而言,历史信息确实具有很高的价值。
例如:
* 复杂代码分析。
* 长文档研究。
* 多轮工具交互。
* 需要回溯早期决策的任务。
* 依赖大量原始证据的分析任务。
如果过早压缩,可能导致一些后续仍然需要的信息被提前摘要或移出上下文。 尤其是依赖 LLM 生成摘要的压缩策略,本身也存在信息损失风险。
因此,延迟压缩可以让模型保留更多原始上下文。
3.2 减少压缩的频率
高阈值意味着压缩发生得更少。这可以减少上下文治理操作的频率,也可以降低某些系统中的额外处理开销。
不同 Agent 框架采用的压缩方式并不相同。有些系统通过 LLM 生成摘要,有些采用消息裁剪,有些采用规则化处理,还有些采用外部存储与检索相结合的方式。
因此,不能把所有压缩策略视为同一种机制。
如:
* Anthropic 的上下文压缩机制则允许通过 Token 阈值触发压缩。
这些方案的具体实现和预算定义并不完全相同,不能简单地把它们的百分比直接进行横向比较。
3.3 高阈值并不意味着架构落后
我想特别强调这一点。
**高阈值策略有自己的设计目标**:
尽可能延长原始上下文的驻留时间,保留更多信息,减少频繁治理带来的信息损失。
而 ARES 选择 45%,关注的是另一个问题:
如何让 Agent 在长时间运行过程中,**持续维持一个相对干净、相关且可用的工作上下文**。
这两种方案并不是简单的优劣关系,而是不同架构目标下的工程取舍。
真正值得讨论的不是 45% 和 90% 哪个数字更正确,而是:
**你的 Agent Runtime 究竟希望如何管理上下文?**
四、ARES 设计的取舍
ARES 采用 45% 作为默认上下文治理触发阈值。这个设计不是为了追求更低的 Token 使用率,而是为了更早介入上下文生命周期管理。
我主要考虑了四个方面:
4.1 主动治理,而不是被动清理
假设一个 Agent 正在执行一个持续时间较长的任务。随着工具调用、检索和中间执行结果不断产生,上下文逐渐增长。如果等到 80%~90% 才开始治理,就意味着 Agent 在更长的一段执行过程中,都可能携带大量历史过程信息。
ARES 希望尽早处理那些已经失去当前使用价值的内容。
这里需要明确:
45% 并不是模型注意力退化的理论临界点。也不是说上下文达到 46% 就一定会发生注意力下降。它是一个工程默认策略(你甚至可以在yaml里配置到20%、66% etc)。
这么设计的原因是我希望通过更早的治理,缩短低价值历史信息在工作上下文中的驻留时间。
从这个角度来看:
**45% 代表的是主动治理的介入时机,而不是模型能力的边界。**
4.2 Rule-based Compression:不依赖额外 LLM 摘要
这是 ARES 当前实现中一个比较重要的工程特点。
ARES 的 ContextCleaner 采用本地规则进行差异化上下文治理,而不是在每次压缩时额外调用一个 LLM 生成摘要。
其基本思路是:
**不同角色、不同类型的消息,应该采用不同的处理策略**。
如:
* tool result 的处理策略,提取 gist,保留 digest 引用
* 纯推理内容 则是根据规则截断
* 超出 Token Cap 的历史内容,则是通过 trimToTokenCap 进行兜底裁剪
核心实现包括:
* ContextCleaner. Clean():负责角色差异化规则压缩。
* trimToTokenCap():在清理后仍然超出预算时进行兜底裁剪。
这种设计有几个特点:
1.不需要额外调用 LLM。压缩本身是本地 CPU 操作,不需要额外的模型推理请求。
2.额外消耗模型推理预算。与 LLM 摘要不同,规则化 Cleaner 不需要将整个历史上下文再次交给模型处理。
3.处理过程更容易测试和复现。规则明确,输入与输出之间的转换过程可以通过单元测试验证。
当然,Rule-based Compression 并不意味着完全没有信息损失。
规则提取和截断同样可能丢失细节,因此需要对关键消息、因果关系和执行状态设置保护机制。
但它避免了额外 LLM 摘要调用所带来的不确定性和成本。
4.3 高频小量治理:缩短上下文退化窗口
这是我认为 45% 策略最重要的设计考虑。我们可以对比两种治理方式。
方案 A:45% 主动治理:当上下文达到默认治理阈值时,提前清理低价值历史信息。
方案 B:80%~90% 延迟治理 允许 Agent 保留更多原始上下文,直到接近高占用区间再进行处理。
两者最核心的区别是治理介入的时机。
ARES 更倾向于:
* 尽早清理已经失去当前价值的历史内容。
* 减少大量过程信息长期驻留。
* 避免一次性处理过多历史消息。
* 尽可能保护 Tool Call 与 Tool Result 之间的因果关系。
需要注意,高频小量治理并不天然意味着信息损失更小。如果 Cleaner 的规则不合理,即使 45% 就开始压缩,也可能反复丢失重要信息。
因此,真正重要的是治理策略与信息保护机制,而**不是单纯提高压缩频率。**
另外,Prompt Cache 也是一个值得考虑的因素。
如果上下文治理会改变缓存前缀,那么缓存命中率可能受到影响。
因此,未来可以考虑稳定前缀与可变工作上下文分离,尽可能减少对稳定前缀的修改。**但 45% 是否能带来更高的缓存命中率,需要结合具体模型供应商的缓存机制进行实验验证**,不