跳到主要内容

上下文窗口悬崖:当你的智能体在任务中触及上限时究竟会发生什么

· 阅读需 10 分钟
Tian Pan
Software Engineer

你的智能体完美地完成了第一步到第六步。第七步与第二步相矛盾。第八步幻觉出了一个并不存在的工具。第九步自信地提交了垃圾内容。没有程序崩溃,没有抛出错误。智能体只是忘记了它正在做什么 —— 并且无论如何都在继续。

这就是上下文窗口悬崖(context window cliff):即 AI 智能体积聚的上下文超过其有效推理能力的时刻。它不会优雅地失败,也不会寻求帮助。它会基于部分信息做出自信但错误的决策,而你直到损失造成才会察觉。

标称上下文与有效上下文之间的差距

每个模型都会宣传其上下文窗口 —— 128K token、200K 甚至 100 万。这些数字是营销上限,而非工程保证。

针对 13 个前沿模型在需要真实推理(而非表面模式匹配)的任务上的研究发现,其中 11 个模型在达到 32K token 时,准确率就已跌至基准水平的 50% 以下。GPT-4o 的基准准确率从 99.3% 下降到了 69.7%。从技术层面讲,模型可以接收更多 token,但它们只是无法对其进行推理。

这一差距对智能体来说至关重要。一个探索代码库的编程智能体在做出第一个真实决策之前,可能会积累 50K token 的文件内容、工具输出和推理轨迹。当它到达关键步骤时,它已经处于性能退化区了 —— 这不是因为窗口满了,而是因为它的注意力已经变得不可靠。

“迷失在中间”(lost in the middle)效应加剧了这一问题。模型对上下文的开头和结尾关注度很高,而实际上却忽略了中间部分。一个积聚了 150K token 上下文的智能体,可能会在功能上忽略掉位于窗口中间的 100K token 工具响应。这些信息存在于输入中,但在推理过程中却缺失了。

上下文溢出的三种典型失败特征

上下文溢出并不会导致单一的失败模式。它会产生三种截然不同的特征,每种特征都由不同的截断策略引起 —— 且每一种都以其独特的方式带来危险。

静默截断(Silent truncation) 是最古老也最危险的模式。当上下文超过限制时,框架会悄悄丢弃最旧的消息。智能体会失去原始指令、任务定义以及被赋予的约束条件。它会继续执行 —— 但此时已脱离了目标。系统提示词消失了,安全护栏也化为乌有。智能体开始肆意幻觉,因为本该约束它的上下文已不复存在。

摘要失真(Summarization distortion) 用压缩后的摘要取代了原始历史。这听起来很合理,直到你意识到摘要会以不可预测的方式造成信息丢失。在第二步提到的数值约束 —— “每秒请求数不得超过 500” —— 可能会被概括为 “存在速率限制方面的考虑”。让约束具有可执行性的具体细节消失了。智能体在只模糊意识到存在速率限制的情况下继续工作,但并不知道具体限制是多少,从而做出了虽然在概念上承认该限制、但在实际数值上却违规的决策。

滑动窗口健忘症(Sliding window amnesia) 保留最近的 N 个 token 并丢弃之前的所有内容。这导致智能体只能记住眼前的过去。第七步与第二步相矛盾,并不是因为智能体决定改变路线,而是因为第二步在它的世界里已不复存在。每一个决策在局部看是合理的,但在全局看却是不连贯的。最终的工作在任何特定的时间点看起来都很合理,但当你审视整个轨迹时,它就崩溃了。

为什么智能体不会优雅地降级

根本问题在于 LLM 不知道自己不知道什么。一个忘记了需求的工程师知道自己可能会遗漏某些东西。他们会感到不确定,并会检查自己的笔记。

丢失了上下文的 LLM 不会对丢失的信息感到不确定 —— 它只是根本不知道这些信息曾经存在过。它会基于剩余的上下文自信地生成内容。这就是为什么上下文溢出产生的是“自信的错误”而非“谨慎的错误”。随着上下文质量的下降,智能体不会放慢速度或提出澄清性问题。它的自信心保持不变,而准确性却在崩塌。

Databricks Mosaic 的研究发现,在 32K token 之后,智能体开始倾向于重复其不断增长的历史记录中的动作。智能体进入循环并不是因为它卡住了,而是因为上下文中的近期动作是它拥有的最强信号。原始目标、未探索的替代方案、早期步骤的约束 —— 所有这些都已被累积的近期工具输出所排挤或淹没。

在多步工作流中,这产生了一种典型的失败模式:前几步非常出色,中间步骤逐渐偏离,最后几步虽然与近期上下文保持连贯,但已脱离了原始目标。产出的成果看起来很专业,但它是错误的。

上下文溢出是一个容量规划问题

许多团队将上下文溢出视为一个提示工程 (prompt engineering) 问题。他们尝试编写更短的提示词,使用更简洁的工具输出,或者切换到具有更大窗口的模型。这就像通过购买更多内存来处理内存泄漏一样——它推迟了崩溃,但没有修复原因。

架构上的见解是,上下文溢出是一个容量规划问题。在智能体开始运行之前,你需要大致了解每个步骤将消耗多少上下文,以及总量是否符合你的有效(而非宣传的)上下文预算。

一个材料科学工作流清晰地证明了这一点:传统方法消耗了 2080 万个 token 且失败了。同样的工作流使用内存指针重新设计后,仅消耗 1234 个 token 并取得了成功。区别不在于更好的提示词,而在于更好的架构——智能体操作的是数据的引用,而不是数据本身。

容量规划方法意味着回答诸如以下的问题:该工作流将进行多少次工具调用?平均响应大小是多少?最坏的情况是什么?如果三次文件读取平均每个消耗 1.5 万个 token,那么在进行任何推理之前,你已经消耗了 4.5 万个 token 的上下文。加上工具定义、系统提示词和对话历史,在智能体做出第一个有意义的决策之前,你可能已经处于 10 万个 token 的水平。

主动上下文预算模式

一旦你将上下文视为一种需要预算的有限资源,几种架构模式就会应运而生。

子智能体隔离 (Sub-agent isolation) 将风险较高或上下文密集的操作委托给孤立的子智能体。在进入父智能体的上下文之前,一次 5 万 token 的探索可以被压缩成 2000 token 的摘要。父智能体根据精选的摘要而不是原始的工具输出进行推理。如果子智能体失败了,它不会用 5 万个 token 的失败探索来污染父智能体的上下文。

观察掩码 (Observation masking) 用占位符替换旧的工具输出,同时保留智能体的推理和行动历史。JetBrains 的研究发现,这种方法在匹配或超过全上下文智能体的解题性能的同时,实现了超过 50% 的成本降低。关键见解是:智能体自身的推理轨迹比它所推理的原始数据更有价值。你可以掩盖数据并保留结论。

预算感知压缩 (Budget-aware compression) 将上下文管理表述为一个序列决策问题。智能体监控其剩余的上下文预算,并动态调整压缩强度。对此方法的研究表明,一个拥有 8000 token 预算的 300 亿参数模型,其表现可以超过一个拥有 12.8 万上下文的 2350 亿参数模型——因为具备自律上下文管理的小型模型,其推理基于的高质量信息,优于淹没在累积噪声中的大型模型。

内存指针 (Memory pointers) 用短标识符替换大数据负载。智能体不是将完整的 API 响应转储到上下文中,而是将其存储在外部并通过 ID 引用。当它需要特定字段时,它仅检索这些字段。这在网络搜索评估中实现了 84% 的 token 减少,在分子网格检索任务中实现了 17,000 倍的减少。

基于文件的迭代 (File-based iteration) 将文件系统用作上下文缓冲区。智能体不是将整个文件加载到上下文中,而是读取目标行范围,对其进行处理,将中间结果写入磁盘,然后继续。文件系统变成了具有无限容量的外部存储器,而智能体的上下文保持精简。

构建上下文感知的智能体架构

实践路径分为三个层面。

首先,监测你的上下文消耗。你无法对未测量的内容进行预算。记录智能体工作流中每个步骤的 token 计数。找出哪些工具调用是最大的贡献者。许多团队发现,单个冗长的 API 响应或贪婪的文件读取就消耗了他们一半的上下文。

其次,为每个工作流阶段设置明确的预算。如果你的有效上下文窗口是 3.2 万个 token(即推理保持可靠的范围,而非模型技术上接受输入的范围),且你的工作流有八个步骤,那么每个步骤大约可以获得 4000 个 token 的净新增上下文。需要更多空间的步骤必须进行压缩或外部化。需要较少空间的步骤可以将其预算捐赠给后续阶段。

第三,为上下文失效而设计。假设尽管你制定了预算,某些运行仍会接近极限。内置检查点,让智能体总结其进度,并能从压缩状态恢复。像对待传统软件中的内存溢出错误一样对待上下文溢出:它应该是一个带有恢复路径的受控异常,而不是对结果的无声破坏。

作为架构的上下文预算

20 万 token 的上下文窗口并不是一个 20 万 token 的推理引擎。它更像是一个 3.2 万 token 的推理引擎,外加 16.8 万 token 且日益不可靠的存储。构建可靠运行的智能体意味着要针对有效容量进行设计,而不是理论最大值。

从 AI 智能体中获得最佳结果的团队,并不是那些使用最大上下文窗口的团队。而是那些将上下文视为稀缺资源并精心预算、积极压缩,并设计出让智能体始终基于高质量、相关信息而非不断增长的累积噪声进行推理的架构的团队。

上下文溢出不是模型的 bug。它是忽略了模型实际约束的架构 bug。

References:Let's stay in touch and Follow me for more thoughts and updates