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% 是否能带来更高的缓存命中率,需要结合具体模型供应商的缓存机制进行实验验证**,不
Marky

我是一名独立开发者,MiMo spark 计划的核心开发者,擅长的是Rust,go,pyton . 独立设计开源agent runtime 框架ARES,及《This Week in Rust》 收录的专项FFI 检测器。

六、总结 应该管理上下文,而不是填满上下文 大上下文窗口解决的是模型能够容纳多少信息的问题。但它并没有解决 Agent 应该保留哪些信息的问题。 对于一个长期运行的 Agent 而言,历史信息并不天然具有持续价值Tool Calling、中间推理、执行日志和历史检索结果,在不同任务阶段具有不同的信息价值。 ARES 选择 45% 作为默认上下文治理阈值,并不是因为模型只能有效利用 45% 的上下文,也不是认为 80% 或 90% 的策略不合理。 这是一次架构取舍。我更希望 Agent 在执行过程中持续维护一个高密度、低噪声、可恢复的工作上下文,而不是尽可能延长原始历史信息的驻留时间。 从设计理念上看: 1. Context Monitoring 负责感知上下文状态。 2. Context Compression 负责治理低价值信息。 3. Artifact Store 负责保存可恢复的原始内容。 4. Context Reconstruction 负责按需恢复历史信息。 它们共同构成 Context Lifecycle Management。 Context Window 是 Working Memory,不是 Long-term Memory。 压缩不是删除,历史信息也不应该因为离开当前上下文而失去价值。真正重要的不是上下文有多大,而是 Agent 在当前时刻能够获得多少真正有用的信息。 该文章转载自我的博客,禁止不署名转发
登录并发表评论

评论 · 0